PICAXE 18M2 Einstieg

#Einleitung

Mikrocontroller sind eine feine Sache. Ihre Integration ist aber meistens mit etwas Aufwand verbunden. Ich hatte mich das letzte Mal in der Ausbildung mit ihnen auseinander gesetzt.
Aber bei meinem Wärmebildkameraprojekt wollte ich dann doch aus Steuerungsgründen mal einen einbauen. Eine Entscheidung, die ich nicht im geringsten bereut habe.

Bisher hab ich zwar diverse Boards auf Ebay und in Onlineshops gesehen, aber die kosten meistens ja schon ein bisschen. Daraus entsteht auch gleich das Problem, dass das Board dann "zu Wertvoll ist, um es nicht voll auszunutzen". Der hier verwendete Mikrocontroller PICAXE 18M2 hat einen Stückpreis von 3 Euro (ebay) oder 2,40 Pfund (Onlineshop des Herstellers).

Hier ein paar Beispiele, was man mit ihm Betreiben kann:

  • 13 Digitale Ausgänge oder
  • 14 Digitale Eingänge oder
  • 10 Analoge Eingänge 0-255 (3 davon auch 0-1020 Stufen also 8 oder 10 Bit) oder
  • 8 Servos (75-225 also 151 Stufen) oder
  • I2C Bus (100 oder 400 khz) und
  • 2te Serielle Schnittstelle und
  • 2 PWM

Sowie noch ein paar Feinheiten mehr. Vieles davon lässt sich untereinander kombinieren.

Besonders hervorzuheben ist neben der Vielseitigkeit und des Preises auch noch die einfache Beschaltung des PICAXE. In der Grundkonfiguration braucht man 2 Widerstände. Keine Kondensatoren, keine Quarze, kein RS-232 Pegelwandler... einfach nur 22k und 10k einbauen und schon ist er für viele Funktionen direkt einsetzbar. Ich verwende generell 18k und 12k in meiner Schaltung aber nur, weil ich nix anderes da hatte.

Hier wird neben dem Mikrocontroller auch ein 16 Bit I/O Expander verwendet. Der Chip MCP23017 hat 16 Digitale I/O Ports und wird über den I2C Bus verbunden.
Das heißt in der Praxis: 2 Leitungen vom Mikrocontroller gehen an den Chip und jede der Leitungen hat noch einen 4,7k Widerstand gegen 5V... und schon hat man 16 I/O Ports mehr.
Der Expander kommt genau da zum Einsatz, wo ein einfaches Ein/Aus genügt und somit die Ports des Mikrocontroller zu schade wären, da sie meistens auch als Analogeingang oder Servoausgang verwendet werden könnten. Der 16 Bit I/O Expander kostete mich übrigens 2 Euro pro Chip. Hält sich also alles sehr im Rahmen.

#Testaufbau

Testaufbau

Der hier gezeigte Aufbau ist in seiner Funktion noch nicht sonderlich Spektakulär.
Drückt man den Taster, leuchtet die Rote LED. Drückt man ihn nochmal, geht die Rote aus und die Grüne an. Bei jedem weiteren Drücken wechseln sie sich ebenfalls ab. Ein längeres gedrückt halten (ca. 2 Sec.) schaltet beide aus.
Statt über den Taster, kann man die LEDs aber auch per serieller RS-232 Schnittstelle steuern. Hat man das Byte 48 gesendet (Startbyte) wird das nächste empfangende als Befehl gewertet. Damit kann man beide fernsteuern.

Diese Schaltung verbraucht übrigens 161 Byte von 2048 Byte Speicher. Es ist also noch ordentlich Potential zur Erweiterung.
Verwendet werden größtenteils einfache Basic Befehle. Das Grundprogramm so umzuschreiben, dass alle 16 Ports verwendbar sind, ist nicht gerade schwer. Vorteilhaft ist ebenfalls, das viele Analogeingänge und Servoausgänge weiterhin nutzbar sind und nicht für einfache LEDs "verschwendet" werden.

Beispielquellcode (Basic):
                setfreq m16 ;Taktfrequenz auf 16MHz (max. ist 32MHz)
                hi2csetup i2cmaster, 64, i2cfast_16, i2cbyte ;Deviceadresse (MCP23017) festlegen
                hi2cout 0,(%01011111) ;Pinbelegung festlegen (OIOI IIII)
                ;Variablen deklarieren
                symbol LED_R = bit7
                symbol LED_G = bit5
                symbol ser = b10
                ser = 0
                symbol Cnt = b11
main:       serrxd [100],(48),ser ;Serieller Empfang wenn Byte 48 empfangen wurde, Timeout 100ms
                if ser > 0 then gosub Remote ;RS-232 Fernsteuerung
                ser = 0 ;Zurücksetzen, damit pro Befehl nur einmal durchlaufen wird
                gosub Self
                goto main

Self:         if pinC.2 = 1 then
                                inc Cnt ;wenn der Taster betätigt ist Zählervariable +1
                                if Cnt > 51 then
                                                ;Wenn Zählervariable größer 50 ist, beide LEDs abschalten
                                                LED_R = 0
                                                LED_G = 0
                                                hi2cout 18,(b0)
                                endif
                else
                                if Cnt > 50 then
                                                ;beide LEDs sind aus, Zähler zurücksetzen
                                                Cnt = 0
                                elseif Cnt > 1 then
                                                hi2cin 18,(b0) ;Zustand vom 16bit Expander lesen
                                                if LED_R = 1 then
                                                                ;wenn Rot an, dann auf Grün schalten
                                                                LED_R = 0
                                                                LED_G = 1
                                                                hi2cout 18,(b0)
                                                else
                                                                ;wenn Rot aus, dann einschalten
                                                                LED_R = 1
                                                                LED_G = 0
                                                                hi2cout 18,(b0)
                                                endif
                                                Cnt = 0
                                endif
                endif
                return

Remote:   #rem Festlegen, was beim empfangenem Byte gemacht werden soll:
                1 = Grün leuchtet
                2 = Rot leuchtet
                3 = beide an
                4 = beide aus
                #endrem
                If ser = 1 then
                                LED_R = 0
                                LED_G = 1
                                hi2cout 18,(b0)
                endif
                If ser = 2 then
                                LED_R = 1
                                LED_G = 0
                                hi2cout 18,(b0)
                endif
                If ser = 3 then
                                LED_R = 1
                                LED_G = 1
                                hi2cout 18,(b0)
                endif
                If ser = 4 then
                                LED_R = 0
                                LED_G = 0
                                hi2cout 18,(b0)
                endif
                sertxd (49,ser,13) ;bestätigung senden
                return

setfreq m16
Zum Wechseln der Taktfrequenz. Zur Auswahl stehen k31, k250, k500, m1, m2, m4, m8, m16, m32 (k = KHz, m = MHz). Die Taktfrequenz kann man selbst nach bleiben geändert werden. Teilweise ändert der Mikrocontroller sie auch selbstständig, beispielsweise bei der I2C, PWM oder Servofunktion. Er stellt dann die Frequenz ein, die er zum verwenden der Funktion braucht und schaltet nach dem durchlaufen der Funktion wieder auf die vorherige Frequenz zurück. Die Taktfrequenz hat auch direkten Einfluss auf die Übertragungsgeschwindigkeit der seriellen Schnittstelle des PICAXE. Ich verwende standardmäßig die 16MHz. Dies ist die höchstzulässige Taktfrequenz um Servos verwenden zu können.
Taktfrequenz = RS-232 Baudrate
4MHz = 4800
8MHz = 9600
16MHz = 19200
32MHz = 38400

hi2csetup i2cmaster, 64, i2cfast_16, i2cbyte
Damit stellt man den Hardware I2C Bus ein. Der Verwendete PICAXE kann nur Master sein. Es folgen 3 weitere Angaben: Adresse des zu steuernden Gerätes, Übertragungsgeschwindigkeit (i2cslow = 100KHz oder i2cfast = 400KHz) und schließlich die Adressbreite (Byte oder Word)

hi2cout 0,(%01011111)
Ein Befehl, um Daten über den I2C Bus zu senden (hardware i2c output). Gefolgt wird der Befehl von der Adresse des Registers, in das geschrieben werden soll. Dann kommen die Daten. beim hi2cin (hardware i2c input) ist die Abfolge genauso.

serrxd [100],(48),ser
Dieser Befehl Empfängt Daten über die RS232 Schnittstelle. Vorn in der eckigen Klammer, steht der Timeout in ms. Im Handbuch steht "not available on M2 parts", aber es klappt trotzdem. Ohne Timeout, würde der Mikrocontroller an dieser Stelle warten, bis er genug Daten empfangen hat, um alle Variablen zu befüllen. Das würde aber auch bedeuten, dass die Umschaltungen per Taster nur möglich währen, so lange ständig Bytes empfangen werden. Ohne Timeout und Byteempfang, würde der Mikrocontroller nicht auf den Tastendruck reagieren. Allerdings handelt es sich auch um einen Software Befehl (empfangen wird nur, wenn der Mikrocontroller sich aktuell mit dieser Funktion beschäftigt). In Klammern steht der optionale "qualifier", dass ist ein Byte (oder mehrere), das so empfangen werden muss, wie es in der Klammer steht. Erst dann werden folgende Bytes in die Variablen geschrieben.
Mir ist aufgefallen, das nicht alle Bytes direkt hintereinander gesendet werden dürfen, da der Mikrocontroller sonst nicht ganz hinterher kommt. Wenn das erste Byte (qualifier) eintrifft, während der Mikrocontroller noch mit einer anderen Funktion beschäftigt ist, dann wird der Befehl nicht erkannt, da die folgenden Datenbytes nicht als qualifier passten (so passiert es, das einige Befehle mehrfach gesendet werden müssen, bevor sie erkannt und umgesetzt werden).

#Vordefinierte Variablen

Unten ist eine Tabelle, in der die Verwendbaren Variablen eingetragen sind. Gewissermaßen ist jede Zeile eine 2 Byte Speicherzelle. Wenn man beispielsweise in b0 die Zahl 15 Speichert, liest man bei bit0-bit3 eine 1 und bei bit4-bit7 eine 0.
Da einige Variablen den gleichen Speicherplatz belegen, kann man einzelne Bits ändern und schiebt das dazugehörige Byte einfach über den I2C Bus in den Chip. Die anderen werden dann einfach mit den gleichen Werten überschrieben.

Wort  0-65535 Byte  0-255 Bit  1/0
w0 b1: b0 bit15: bit14: bit13: bit12: bit11: bit10: bit9: bit8 / bit7: bit6: bit5: bit4: bit3: bit2: bit1: bit0
w1 b3: b2 bit31: bit30: bit29: bit28: bit27: bit26: bit25: bit24 / bit23: bit22: bit21: bit20: bit19: bit18: bit17: bit16
w2 b5: b4
w3 b7: b6
w4 b9: b8
w5 b11: b10
w6 b13: b12
w7 b15: b14
w8 b17: b16
w9 b19: b18
w10 b21: b20
w11 b23: b22
w12 b25: b24
w13 b27: b26

Die Steuerung des 16 Bit Expanders ist auch recht einfach. Register 0 und 1 sind zur Festlegung der Direktion (Input oder Output). Die Register 18 und 19 sind für die Daten der Ports.
Beispiele:

hi2cout 0,(0) ;Pin 21 - 28 sind Ausgänge
hi2cout 1,(127) ;Pin 1-7 sind Eingänge und Pin 8 ist ein Ausgang
hi2cout 18,(128) ;Pin 21-27 sind Low und Pin 28 ist High

#Steuerung

Testaufbau 1

Zur Steuerung muss wieder einmal ein Windowsrechner mit serieller RS-232 Schnittstelle her halten. Die Software wurde in C# geschrieben und lässt sich auf PC oder PDA mit Windows Mobile starten.
Weitere infos: PDA-Steuerung.

Mit Sharpdevelop 3.2 (nicht 4.0, da wurde es deaktiviert) kann man auch Programme für PocketPCs schreiben. Allerdings ist das Compact Framework nicht korrekt implementiert. Jedes Mal, wenn man den Designer verwendet, erzeugt der Designer automatisch Code für Eigenschaften, die im Compact Framework nicht vorhanden sind.
Beispiel: Button.UseVisualStyleBackColor = false;
Ich habe bisher keine angenehmere Entfernungsmöglichkeit gefunden, außer Suchen & Ersetzen: "UseVisualStyleBackColor" -> "Enabled = true; //". Leider unterstützt das Visual Studio Express keine Mobilen Geräte.
Das Compact Framework ist gewissermaßen eine eingeschränkte Version vom normalen Framework. Was im CF geschrieben wurde, lässt sich ohne weiteres auf PocketPCs und normalen Windowsrechnern starten (ohne die Anwendung umschreiben zu müssen). Dafür verzichtet man auf diverse Eigenschaften und Komponenten.


Testaufbau 2

Bytes über 127
Was man noch beachten sollte (gerade im Bezug auf Mikrocontroller) dass die Übertagung von Bytes richtig klappt. So ist es bei .NET notwendig, das Encoding zu ändern.
Beispiel: SP.Encoding = System.Text.Encoding.Default;
So komisch es klingen mag, aber die Einstellung "Encoding.Default" ist nicht die Default Einstellung von .NET, sondern "Encoding.ASCII".
Das hat zur Folge, dass bis zum Byte 127 alles normal empfangen wird. Ab 128 wird nur noch 63 draus. Das gilt übrigens nicht fürs senden, sondern nur fürs empfangen. Die 63 taucht unter den Einstellungen, bei der Eigenschaft "ParityReplace" auf. Wenn das Encoding auf ASCII steht, scheinen Bytes über 127 einen Paritätsfehler zu verursachen und werden deshalb durch 63 ersetzt.

Deshalb "Encoding.Default" und die Übertragung passt.
Hier ein Beispiel:

Send Recive (ASCII) Recive (Default)
0 0 0
50 50 50
100 100 100
127 127 127
128 63 128
129 63 129
200 63 200
255 63 255

Hardwarecallback
Dies ist eine sehr einfache Art die Schnittstelle zu testen. Die Sende- und die Empfangsleitung (Txd,Rxd) werden einfach miteinander verbunden. Was raus geht, kommt so auch wieder rein.
Wenn man das Beispielprogramm unten ausführt und die beiden Datenleitung überbrückt, dann bekommt man 4 Byte als Übertragungsantwort.
Der Grund dafür ist einfach... da der Mikrocontroller immer 3 Byte als Antwort sendet, wurde das Programm auf 3 Byte empfang ausgerichtet. Zuerst werden 2 Byte gesendet (Startbyte + Befehlsbyte). Da diese direkt durch den Hardwarecallback zurück kommen, liegen nun 2 Byte im Puffer, es werden aber über 2 Byte erwartet. Also läuft der erste Timeout ab (100 ms) und der Sendevorgang wird wiederholt. Dann werden wieder 2 Byte gesendet und nun sind 4 Byte im Puffer, die dann als Antwort ausgewertet werden. Der Hardwarecallback eignet sich auch gut, um eine korrekte Übertragung von Bytes über 127 zu testen.

Das Codebeispiel weiter unten zeigt die serielle Übertragungsroutine.
Wie weiter oben beim Mikrocontroller beschrieben, werden gesendete Befehle nicht ausgeführt, wenn sie "zum falschen Zeitpunkt" eintreffen. Die Funktion unten wird einfach im Programm aufgerufen und bekommt das Byte übergeben, was man senden möchte. Dann wird es gesendet und eine gewisse Zeit auf Antwort gewartet. Wenn diese ausbleibt, wird der Sendevorgang einfach wiederholt.

Beispielquellcode zum Senden (C#):
void send_to_PICAXE(byte ser)
{
     try {
               //Port festlegen und öffnen
               SP.PortName = txt_Port.Text;
               SP.Open();

               //datentransfer
               SP.DiscardInBuffer(); //bisher empfangendes verwerfen
               int n = 0;
               while (true) {
                    if (n > 5) {
                         //6 fehlgeschlagene Sendeversuche -> Abbruch
                         label_status.Text = "Senden fehlgeschlagen";
                         label_status.BackColor = Color.Red;
                         SP.Close();
                         return;
                    }

                    //Daten senden mit kleiner Pause, da der Mikrocontroller etwas träge ist
                    SP.Write(new byte[] {48},0,1); Thread.Sleep(10);
                    SP.Write(new byte[] {ser},0,1);

                    //100 ms Warten (alle 10ms überprüfen)
                    for (int i = 0;i<10;i++ ) {
                         Thread.Sleep(10);
                         if (SP.BytesToRead > 2) {
                              //mindestens 3 Bytes empfangen -> Übertragung abgeschlossen
                              break;
                         }
                    }
                    if (SP.BytesToRead > 2) {
                         //mindestens 3 Bytes empfangen -> Übertragung abgeschlossen
                         break;
                    } else {
                         //Timeout... neuer Sendeversuch
                         n++;
                         continue;
                    }
               }

               //alle empfangenen Zeichen auslesen
               string read = SP.ReadExisting();
               SP.Close();

               byte[] bytes = new byte[read.Length]; //Byte Array erstellen (größe = empfangsmenge)
               char[] chars = read.ToCharArray(); //empfangenes in einzelne Zeichen zerlegen
               bytes = UnicodeEncoding.Default.GetBytes(chars); //umwandeln: Zeichen -> Bytes

               //Bytes als Text ausgeben
               string bytes_s = "";
               foreach (byte B in bytes) {
                    bytes_s += B.ToString()+" ";
               }
               label_status.BackColor = Color.Lime;
               label_status.Text = "Info: "+bytes_s;

               //Beispiel zur Auswertung von Bytes
               if (bytes[1] == 3) {
                    //3 = beide LEDs an
                    MessageBox.Show("Beide LEDs Aktiv.");
               }
          } catch (Exception err) {
               //Fehler als Status ausgeben
               label_status.BackColor = Color.Red;
               label_status.Text = err.Message;
          }
}

#Download

Das Archiv enthält neben dem Quellcode auch das ausführbare Programm. Einfach auf den PDA kopieren und starten.

picaxe (ZIP, 25.73 KB)


Zuletzt geändert am: Mai 02 2013 um 5:31 AM

© by joe-c, 2023 - 2024. All Rights Reserved. Built with Typemill.