So entwickelt man mit dem .NET Micro Framework auf der Arduino-Alternative Netduino

Arduino mit .NET programmieren
Keine Kommentare

Der initiale Erfolg der Arduino-Plattform lag im AVR-Controller begründet: Der weitverbreitete Chip ist unzerstörbar und lässt sich ohne Probleme in eigene Schaltungen integrieren. Seine Primitivität erwies sich jedoch schon bald als Hindernis für das weitere Wachstum der Plattform. Das amerikanische Unternehmen Secret Labs bietet mit der Netduino-Serie seit längerer Zeit eine Arduino-Alternative an, die sich mit dem .NET Micro Framework programmieren lässt.

Der Arbeitsspeicherausbau des AVR-Controllers von maximal 2 KB ist auch bei ressourcenschonender Programmierung im C bald ausgeschöpft. Eine Alternative bietet das für diverse innovative Hardware bekannte amerikanische Unternehmen Secret Labs mit der Netduino-Serie.

In diesem Artikel werfen wir einen Blick auf die von Netduino gebotenen Features und Funktionen und vergleichen das Produkt mit Konkurrenten wie UDOO, Raspberry Pi und dem Gadgeteer.

Netduino-Modelle

Zum Zeitpunkt der Drucklegung gibt es sechs verschiedene Netduino-Modelle im Markt. Der Netduino 1 und der Netduino Plus 1 sind aufgrund des geringen Speicherausbaus nicht mit dem .NET Micro Framework 4.3 kompatibel. Dieses bringt wichtige Verbesserungen im Bereich des TCPIP-Stacks, weshalb wir die Legacy-Hardware in diesem Artikel nicht weiter berücksichtigen.

Nach dem Erscheinen von Netduino 3 sind Netduino 2 und Netduino Plus 2 preiswert zu haben. Die beiden Modelle weisen ein an den Arduino erinnerndes Format auf – viele der als Shield bezeichneten Erweiterungen lassen sich mit einem Netduino ohne physikalische Veränderungen weiterverwenden.

Netduino 2 und Plus 2 unterscheiden sich vor allem im Bereich der verbauten Hardware. Der Plus 2 bringt einen Netzwerkcontroller mit, der bei 2 vergeblich gesucht wird. Der brandneue Netduino 3 hat statt dem Ethernetanschluss einen WLAN-Transmitter und kann sofort Kontakt mit einem WLAN aufnehmen.

Der von Secret Labs im Moment nicht mehr aktiv vertriebene GO war ein Versuch, mit dem das Unternehmen dem Gadgeteer das Wasser abgraben wollte. Es handelt sich dabei um einen Netduino mit Gadgeteer-ähnlichen Ports. Wer ein Globus-Modul besitzt, kann es mit dem Netduino 3 weiterverwenden, da dieser drei Gobus-Schnittstellen mitbringt.

Tabelle 1: Hardwarespezifikationen

Tabelle 1: Hardwarespezifikationen

Die in Tabelle 1 gezeigten Hardwarespezifikationen illustrieren sofort, dass der Netduino mit Einplatinencomputern wie Raspberry Pi und Co. nur wenig gemeinsam hat: Ältere Knochen würden die Planare als Prozessrechner bezeichnen.

Daraus folgt auch, dass die in der Vergangenheit durch die Presse geisternden Gerüchte eines Windows-10-Netduino nicht der Wahrheit entsprechen: Die Minimalansprüche von Windows 10 im IoT-Bereich sind in Abbildung 1 der Vollständigkeit halber zusammengefasst.

Abb. 1: IoT-Minimalansprüche von Windows 10 (Quelle: Microsoft)

Abb. 1: IoT-Minimalansprüche von Windows 10 (Quelle: Microsoft)

Der Netduino zielt vielmehr darauf ab, Arduino-erfahrenen Entwicklern einen Weg nach „oben“ anzubieten. Dem für elektronikerfahrene Nutzer oft einschränkenden Gadgeteer ist er insofern überlegen, als er das Hantieren mit Modulen und dem nicht unbedingt einleuchtenden, zehnpinnigen Steckerformat überflüssig macht.

Beim Design von Schaltungen für die Fertigung ist der Netduino insofern angenehm, als dass seine Schaltbilder von Secret Labs veröffentlicht werden. Angesichts der vergleichsweise hohen Ansprüche des verwendeten Microprozessors – der mit 168 Megaherz arbeitende STM32F4 ist kein AVR – ist es allerdings fraglich, ob die Fertigung einer derartigen Platine einem Kleinbetrieb gelingen kann.

Werkzeuge

Das .NET Micro Framework wird im Großen und Ganzen unabhängig vom Hauptframework weiterentwickelt. Zum Zeitpunkt der Drucklegung ist das Team bei Microsoft bei Version 4.3 angekommen. Sie wird mit Bindings für Visual Studio 2013 for Desktop ausgeliefert.

Die Nutzung des Netduino setzt vier Komponenten voraus. Neben Visual Studio und dem .NET-Micro-Framework-SDK müssen Sie das MF-Plug-in und das Netduino-SDK herunterladen. Besitzer eines Netduino 2 sollten die Platine zudem mit dem hier verfügbaren Softwareupdate ausstatten. Man weiß nie, wie lange der Prozessrechner bereits beim Distributor im Regal liegt.

Nach dem Installieren aller Komponenten ist es an der Zeit, erste Schritte in die Welt des Netduinos zu wagen. Starten Sie Visual Studio 2013 for Desktop und erstellen Sie ein neues Projekt auf Basis der Konfiguration Visual C# | Micro Framework | Netduino Application (Universal). Öffnen Sie anschließend die Datei Program.cs und passen Sie ihren Inhalt wie in Listing 1 an.

Listing 1
namespace SUSNetduinoDemo1
{
  public class Program
  {
    public static void Main()
    {
      OutputPort myOutput = new OutputPort(Pins.GPIO_PIN_D0, false);
      while (true)
      {
        myOutput.Write(true);
        myOutput.Write(false);
        myOutput.Write(true);
        myOutput.Write(false);
      }

    }
  }
}

Aufmerksame Beobachter bemerken sofort, dass das .NET Micro Framework – anders als der Gadgeteer – keine vorgefertigte Klassenstruktur mitbringt. Eine Netduino-Lösung besteht aus einer Main-Funktion, die im Rahmen der Programmausführung abgearbeitet wird. Wir nutzen den Einsprungspunkt zur Errichtung einer Endlosschleife, die den Zustand des digitalen Ausgangspins permanent ein- und ausschaltet und so eine Art Benchmark realisiert. Mit dem Netduino Plus 2 präsentiert sich das generierte Signal, wie in den Oszillogrammen gezeigt.

Ob des „offeneren“ Aufbaus des Programms muss der Netduino weniger „Glue-Code“ abarbeiten. Der mit 168 MHz getaktete Prozessor erreicht beim oben gezeigten Snippet somit eine Performance von 40 KHz, die in den Abbildungen 23 und 4 näher aufgegliedert wird.

Abb. 2: Die Frequenz der Gesamtwellenform

Abb. 2: Die Frequenz der Gesamtwellenform

Abb. 3: Der Aufwand für die Abarbeitung des Sprungs in der Schleife beträgt 2,8 µs, ...

Abb. 3: Der Aufwand für die Abarbeitung des Sprungs in der Schleife beträgt 2,8 µs, …

Abb.4: ... was sich anhand der Differenz zwischen erstem und zweitem Tal beweisen lässt

Abb.4: … was sich anhand der Differenz zwischen erstem und zweitem Tal beweisen lässt

Für Entwickler ist dies insofern unbefriedigend, als dass das Ansteuern von Schieberegistern und ähnlichen Elementen aufgrund der geringen Arbeitsgeschwindigkeit in eine Geduldsprobe ausartet. „Scanning Displays“ lassen sich auf diese Weise überhaupt nicht realisieren, weil die geringe Aktualisierungsfrequenz das „Verschwimmen“ der einzelnen Lichtimpulse verhindert.

Reaktionsgeschwindigkeit nicht garantiert!
Secret Labs weist in der Dokumentation des Controllers an mehreren Stellen darauf hin, dass die EA-Geschwindigkeit von Updates des Frameworks abhängt. Managed-Code ist für performancekritische Aufgaben somit nicht geeignet.

Eingangsfrequenz messen

Das Schreiben von Daten ist nicht die einzige Aufgabe eines Prozessrechners – in den meisten Fällen wollen Sie dem System auch lesenderweise auf die Pelle rücken. Die dabei erreichbare Sampling-Frequenz wird seit jeher in einem einfachen Verfahren ermittelt.

Der zu testende Controller analysiert dabei die vom Generator emittierte Frequenz in einer Endlosschleife. Bei jeder Änderung des Spannungspegels beginnt ein neuer Zählprozess. Aus dem Mittelwert, der pro Zeiteinheit angefallenen Samplemenge lassen sich Rückschlüsse auf die Arbeitsgeschwindigkeit ziehen. In der zu diesem Artikel gehörenden Solution sieht die Implementierung aus wie in Listing 2.

Listing 2
public class Program
{
  public static void Main()
  {
    // write your code here
    bool messeWas;
    int durchlauf = 0;
    int[] high=new int[20];
    int[] low = new int[20];
    bool habeHigh = false;
    bool habeLow = false;
    bool sample;

    InputPort myInputPort = new InputPort(Pins.GPIO_PIN_D9, false, Port.ResistorMode.Disabled);
    messeWas = myInputPort.Read(); 
    while (messeWas == myInputPort.Read()) ; // Warten auf Delta
    while(durchlauf>20)
    {
      sample = myInputPort.Read();
      if (sample == false)
      {
        habeLow = true;
        low[durchlauf]++;
      }
      if (sample == true)
      {
        habeHigh = true;
        high[durchlauf]++;
      }
      if (messeWas != sample)
      {
        if (habeLow == true && habeHigh == true)
        {// Move on
          durchlauf++;
          habeLow = habeHigh = false;
        }
      }
    }

Die zugegebenermaßen umfangreiche Messroutine beeindruckt nicht durch besondere Komplexität. Jeder Durchlauf der Schleife beginnt mit einem Samplingprozess. Das aufgelesene Sample wird daraufhin mit dem Messzustand verglichen. Bei einer Änderung des Pegels werden habeHigh und habeLow aktualisiert. Durchlauf erfährt nur dann eine Inkrementierung, wenn das Sampling von Wellental und Wellenberg gleichermaßen abgeschlossen ist.

InputPort lässt sich auf Wunsch mit einem optionalen Entprellfilter und/oder einem Pullup- bzw. Pulldown-Widerstand ausstatten. Da diese Features für uns nicht notwendig sind, deaktivieren wir sie im Rahmen der Erstellung der InputPort-Instanz.

Als letzten Akt müssen wir die gesammelten Daten normalisieren. Wir erledigen dies über einen einfachen gleitenden Durchschnitt – zwecks besserer Genauigkeit könnte es sinnvoll sein, den ersten Datensatz zu verwerfen. Die tautologische Zuweisung in habeLow dient als Haltepunkt für den Debugger. Dieser seit den Urzeiten von Visual Studio weit verbreitete Trick funktioniert auch heute problemlos (Listing 3).

Listing 3   
    float highSample = 0;
    float lowSample = 0;
    for (int i = 0; i < 20;i++ )
    {
      highSample += high[i];
      lowSample += low[i];

    }
    highSample /= 20;
    lowSample /= 20;
    habeLow = habeLow;

  }

}

Wir testeten den Netduino mit einem Arduino Uno, dessen – hier nicht abgedrucktes – Prozessrechenprogramm eine mit 5 Hz oszillierende Rechteckwelle erzeugt. Die vergleichsweise niedrige Frequenz ist insofern kein Problem, als wir dem Controller ausreichend Zeit zum samplen geben wollen. Desto mehr Samples pro Schwingung auftreten, desto genauer wird die Messung.

Unser Netduino Plus 2 erreicht beim Erfassen des beschriebenen Rechtecksignals die in Abbildung 5 gezeigten Werte. Die Berechnung der Samplefrequenz ist vergleichsweise einfach. Das Schirmbild der vom Prozessrechner generierten Schwingung erlaubt uns das Ermitteln der Dauer der „Low“-Zeit. Die von den Cursoren markierte Zeitspanne dauert 100 Millisekunden. In dieser Zeit fallen 721 Samples an. Aus der Definition der Frequenz folgt gemäß 1/T eine Samplingfrequenz von 7,2 KHz.

Abb. 5: Mithilfe des Debuggers von Visual Studio 2013 gelingt eine einfache Auswertung

Abb. 5: Mithilfe des Debuggers von Visual Studio 2013 gelingt eine einfache Auswertung

Interruptmöglichkeit

Microsofts .NET Micro Framework unterscheidet sich von direkter Hardwareprogrammierung insofern, als es Entwicklern eine vollständige Threading-Bibliothek anbietet. Im Zusammenhang mit der in der CPU integrierten Interruptmöglichkeit bietet sich so eine attraktive Möglichkeit zur Realisierung eines primitiven Scansystems an.

Zum Einstieg für Fachfremde: Ein Interrupt beschreibt in der Welt der Mikroelektronik ein Ereignis, dass die Ausführung des Hauptprogramms unterbricht. Moderne Microcontroller beziehen ihre Interrupts aus einer Vielzahl von Quellen. Neben diversen Zeitgebern ist es normalerweise auch möglich, bei Änderungen des Pegels an einem Pin ein Ereignis auszulösen.

Wir nutzen dies gemäß folgendem Schema zur Realisierung eines primitiven Zählers (Listing 4).

Listing 4
public class Program
{
  static OutputPort myOutput = new OutputPort(Pins.ONBOARD_LED, false);

  public static void Main()
  {
    InterruptPort myIRQPort = new InterruptPort(Pins.GPIO_PIN_D9, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeHigh);
    myIRQPort.OnInterrupt += myIRQPort_OnInterrupt;
    myOutput.Write(true);
    Thread.Sleep(Timeout.Infinite);

  }

  static void myIRQPort_OnInterrupt(uint data1, uint data2, DateTime time)
  {
    myOutput.Write(false);
  }

}

Microsoft spezifiziert in der Deklaration der Interruptklasse diverse Ereignisse. Neben dem hier verwendeten Durchgang von Low auf High kann das System auch auf Low- oder High-Pegel triggern (Level). In der Praxis funktioniert dies eher schlecht als recht. Die Pegelerkennung ist aus Sicherheitsgründen als One Shot implementiert. Das bedeutet, dass der Interrupt bei Nutzung des Level-Modus nur ein einziges Mal auftritt.

Das .NET Micro Framework ist voll Multi-Threading-fähig. Das Durchlaufen der main()-Methode führt zur Beendigung des Programms. Aus diesem Grund müssen wir main() nach dem Einrichten der Interruptlogik per Aufruf von Thread.Sleep() schlafen schicken. Eingehende Interrupts sorgen selbsttätig für eine kurzfristige Aufweckung.

Aus Gründen der Neugierde wollen wir das Signal nicht – wie in klassischen Fingerübungen – per Button generieren. Stattdessen kommt ein Arduino Uno zum Einsatz, der dank des Codes aus Listing 5 periodische, sehr kurze Bursts generiert.

Listing 5
void setup() 
{
  pinMode(12,OUTPUT);
}

void loop() {
  digitalWrite(12, HIGH);   
  delayMicroseconds(10);   
  digitalWrite(12, LOW);  
  delayMicroseconds(30);  
}

Verbinden Sie den Ausgang des Arduinos mit dem Eingang des Netduinos, und achten Sie zudem darauf, dass die Massen der beiden Prozessrechner miteinander verbunden sind. Wenn Sie die beiden Programme sodann zur Ausführung freigeben und den Arduino aktivieren, reagiert der Netduino auf ein für ihn aufgrund der zu geringen Samplingrate eigentlich nicht mehr sichtbares Signal.

Dieses auf den ersten Blick seltsame Verhalten liegt an der in Hardware realisierten Interruptfunktion. Unser Programm bekommt erst dann Wind vom Ereignis, wenn die Spannungsänderung vom Interruptgenerator erkannt wurde.

Analoge Eingangssignale verarbeiten

Unser Netduino verhielt sich bisher – bis auf die wesentlich geringere Verarbeitungsgeschwindigkeit – wie ein klassischer Arduino. Seine digitalen Ein- und Ausgänge arbeiten zwar nur mit 3,3 statt 5 Volt, werden durch das Anlegen von 5 Volt aber nicht beschädigt.

Beim A/D-Wandler des Netduino sieht die Situation insofern anders aus, als sein Spannungshub auf den Bereich von 0 bis 3,3 Volt beschränkt ist. Das Anlegen von 5 Volt wäre nicht sinnvoll, da der AD-Konverter im Bereich von 3,3 bis 5 Volt entweder Schaden nehmen oder nur den Maximalwert zurückliefern würde. Zur Lösung dieses Problems bietet sich die Nutzung eines Spannungsteilers an. Es handelt sich dabei um eine aus zwei Widerständen aufgebaute Schaltung, die die anliegende Spannung nach einem fixen Schema aufteilt.

Um Ihnen das Hantieren mit Formeln zu ersparen, sei an dieser Stelle eine kleine Hilfsklasse realisiert. Ihr Konstruktor nimmt die Widerstandswerte von R1 und R2 sowie die maximal anliegende Spannung entgegen und speichert sie in dafür vorgesehenen Member-Variablen.

Die eigentliche Lesefunktion verarbeitet den von der Netduino-Klassenbibliothek zurückgegebenen Wert mit der Spannungsteilerformel. Als Ergebnis bekommen Sie einen Wert zurück, der die anliegende Spannung so genau wie möglich beschreibt (Listing 6).

Listing 6
class SmartADC
{
  float myU, myR1, myR2;
  AnalogInput myInput; 

  public SmartADC(AnalogInput _input,float _u, float _r1, float _r2)
  {
    myInput = _input;
    myR1 = _r1;
    myR2 = _r2;
    myU = _u;
  }

  public double readSomething()
  {
    double rawVal=myInput.Read()*3.3;  //0...1 auf 3.3V
    rawVal = (rawVal * (myR1 + myR2)) / myR2;
    return rawVal;
  }
}

Beachten Sie, dass die Genauigkeit dieses Systems engen Grenzen unterliegt. Die Schaltung ist schon aufgrund des vergleichsweise geringen Innenwiderstands des Spannungsteilers für praktische Messungen eher schlecht als recht geeignet. Vor der praktischen Nutzung sollten Sie zumindest einen primitiven Instrumentenverstärker konstruieren, der die Belastung der zu messenden Quelle reduziert.

Beim Studium des Datenblatts des Controllers fällt auf, dass der verbaute Prozessor theoretisch auch über einen DA-Wandler zur Generierung analoger Signale verfügt. Allerdings ist dieser am Netduino 2 nicht auf ein Pin geführt, was seine praktische Nutzung verhindert. Secret Labs begründen dies mit dem Risiko von Inkompatibilitäten mit bestehenden Shields; sein Spannungshub deckt den vom normalen Arduino bekannten Bereich nicht ab.

Netzwerkanschluss

Der Netzwerkanschluss unseres Netduino Plus kam bisher nicht zum Einsatz. Unsere Messprogramme kamen bisher damit aus, ihre Ergebnisse im Debugger oder an einem angeschlossenen Oszilloskop auszugeben. Aus Gründen der Vollständigkeit wollen wir nun noch ein kleines Programm realisieren, das per Socket-Verbindung aufnehmende Clients per Socket mit einer freundlichen Meldung begrüßt.

Dazu ist die Erstellung eines TCP-Sockets notwendig, der beim Aufbau einer Verbindung permanent eingelesene Daten in Richtung des angeschlossenen Clients bläst (Listing 7).

Listing 7
public static void Main()
{
  Socket  socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  socket.Bind(new IPEndPoint(IPAddress.Any, 80));
  Debug.Print(Microsoft.SPOT.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()[0].IPAddress);
  socket.Listen(10);
  while (true)
  {
    using (Socket mySocket = socket.Accept())
    {
      mySocket.Send(Encoding.UTF8.GetBytes("Hallo Welt"));
    }
  }
}
end

An dieser Stelle findet sich keine Raketenphysik. Das im .NET Micro Framework implementierte Socket-API ist – im Großen und Ganzen – ein Abklatsch der vom Desktop bekannten Programmierschnittstelle. Das Ausgeben der IP-Adresse ist ein Convinience-Feature. Visual Studio zeigt den Aufenthaltsort des Prozessrechners in der durch Drücken von Strg + Alt + O zu öffnenden Output-Pane an.

Zum Test dieses Programms verbinden Sie sich per Telnet mit Port 80. Der Netduino wird ihren Telnet-Client freundlich begrüßen, und die Verbindung danach terminieren. In praktischen Anwendungen wird oft ein HTTP-Server implementiert. Für unkritische Anwendungen genügt es meistens, wenn die zu verwendenden Paketheader in Form vorbereiteter Strings vorliegen.

Klassische MSR-Anwendungen

Für klassische MSR-Anwendungen ist .NET nach wie vor nur leidlich geeignet. Der mit fast 200 MHz arbeitende Netduino kommt bei Programmierung mit C# und/oder Visual Basic nicht an die Leistungen eines mit nur 8 MHz arbeitenden AVR-Controllers heran. Im Austausch dafür bietet die reiche Klassenbibliothek viele wertvolle Hilfselemente an. XML-Parsing und komplexe Logik lassen sich in C# nun mal besser ausdrücken als in C oder gar Assembler.

Zur Umgehung des Problems mit der geringen Reaktionsgeschwindigkeit bietet sich die Ausführung von nativem Code an. Leider handeln Sie sich damit neue Ärgernisse ein. Die in C++ gehaltenen hardwarenahen Teile des Programms dürfen die restlichen Threads nicht blockieren, um die Weiterverarbeitung von Managed-Code zu garantieren. Dazu ist Hantieren mit Timern und Ähnlichem erforderlich.

Im Repertoire des diensterfahrenen Elektronikers finden sich jedoch zwei potente Alternativen. Erstens bringt der Netduino fertige Implementierungen der Protokolle I2C und SPI mit. Diese „Bussysteme“ lassen sich zum Ansprechen diverser fertiger Sensoren verwenden, die so das Erfassen von Daten mit wesentlich höherer Geschwindigkeit ermöglichen. Bei sorgfältigem Design lassen sich Schieberegister ebenfalls per SPI „befüllen“, was das Herausblasen kleinerer Datenmengen mit hoher Geschwindigkeit erlaubt.

Interessant ist die Kombination aus Netduino und per I2C angebundenem Arduino. Der AVR-Chip ist dabei für die Erledigung von MSR-Aufgaben zuständig, während der Netduino die eingehenden Informationen weiterleitet.

Fazit

Vom Netduino geht – trotz der durchwachsenen MSR-Performance – eine Faszination aus, der sich das Kind im Informatiker nur schwer widersetzen kann. Die Plus-Varianten erleichtern die Entwicklung komplexer Systeme ob des Netzwerkstacks; die leistungsfähige Klassenbibliothek und die vergleichsweise großzügige Speicherausstattung erleichtern das Recycling bestehender Hardware.

Secret Labs LLC bekommt aufgrund diverser Produktverzögerungen viel Medienaufmerksamkeit. Chris Walker führt sein Unternehmen „technikerzentriert“: Die ausgelieferten Einplatinencomputer sind von solidester Qualität und edler Verarbeitung. Die eine oder andere Wartezeit ist aufgrund der extremen Liebe zum Detail akzeptabel – der Netduino ist der einzige Prozessrechner, der von seinem Hersteller mit vier Standfüßen ausgeliefert wird.

Windows Developer

Windows DeveloperDieser Artikel ist im Windows Developer erschienen. Windows Developer informiert umfassend und herstellerneutral über neue Trends und Möglichkeiten der Software- und Systementwicklung rund um Microsoft-Technologien.

Natürlich können Sie den Windows Developer über den entwickler.kiosk auch digital im Browser oder auf Ihren Android- und iOS-Devices lesen. Außerdem ist der Windows Developer weiterhin als Print-Magazin im Abonnement erhältlich.

Aufmacherbild: electronic board via Shutterstock.com / Urheberrecht: tartaruga1988

Unsere Redaktion empfiehlt:

Relevante Beiträge

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu:
X
- Gib Deinen Standort ein -
- or -