Elektronik-Labor
Projekte
Mikrocontroller PicoBasic
Die PicoBasic-Version 2.1 enthält eine
neue Schaltfläche: TestLab. Mit einem Klick darauf öffnet man ein
zusätzliches Fenster mit einem kompletten kleinen Testlabor für
unterschiedliche Messungen und Software-Tests. Bei der Entwicklung hat
das Arduino-Messlabor Pate gestanden. Der Unterschied ist aber, dass ein
gerade gestartetes PicoBasic-Programm gleichzeitig läuft und damit zu
einem Teil des Testlabors wird. Damit hat man unendliche Möglichkeiten
für ganz spezielle Messungen und Tests.
Während ein PicoBasic-Programm läuft, lauscht die Firmware auf Signale von
der seriellen Schnittstelle. Das erste ankommende Zeichen wird analysiert.
Handelt es sich um ein p oder ein e, soll ein Programm ins RAM oder ins EEPROM
übertragen werden. Dann wird das laufende Programm angehalten und das neue
Programm geladen. Handelt es sich um eine Ziffer 0…9, soll offensichtlich eine Zahl übertragen
werden, die mit Input A vom Programm gelesen werden kann.
Eine Datenübertragung im Hintergrund funktioniert also reibungslos und ohne
den Programmablauf zu stören. Da könnte man also auch noch ganz andere Dinge
tun und z.B. bei laufendem Programm die AD-Wandler oder die Ports abfragen. Zur
Unterscheidung von den bisherigen Daten wird festgelegt, dass die neuen Kommandos
zur direkten Kommunikation im Hintergrund mit Großbuchstaben beginnen. Ein A soll z.B. bedeuten, dass der
aktuelle Inhalt der Variablen A ausgelesen werden soll, und mit E wird die Spannung
an AD0 gemessen. Im Laufe der Entwicklung
kamen immer noch mehr Funktionen dazu, sodass inzwischen Kommandos von A bis V existieren.
Sie werden als Direkt-Kommandos bezeichnet, weil sie ohne ein Programm in einer
direkten Kommunikation mit dem PC ausgeführt werden. Die meisten Funktionen sind
fast identisch mit den entsprechenden Funktionen für den Basic-Interpreter.
void d65(){Serial.println(a);} //A
void d66(){Serial.println(b);} //B
void d67(){Serial.println(c);} //C
void d68(){Serial.println(d);} //D
void
d69(){Serial.println(analogRead(A0)>>2);}
//E AD0
void
d70(){Serial.println(analogRead(A1)>>2);}
//F AD1
void
d71(){Serial.println(analogRead(A2)>>2);}
//G AD2
void d72(){Serial.println(255 &
gpio_get_all());} //H Pin
void d73(){weiter = 0xFFFFFFFF;}
//I Stop!
void d74(){weiter = 0;} //J Go!
void d75(){uint16_t n =
Serial.parseInt();gpio_set_dir_masked (mask, n);} //K DIR
void d76(){uint16_t n =
Serial.parseInt();gpio_put_masked (mask, n);} //L OUT
void d77(){uint16_t n =
Serial.parseInt();for(int j=0; j<8; j++){gpio_set_pulls(j,1
&(n>>j), 0);}} //M Pullup
void d78(){uint16_t n =
Serial.parseInt();for(int j=0; j<8; j++){gpio_set_pulls(j, 0,1
&(n>>j));}} //N Pulldown
void d79(){uint16_t n =
Serial.parseInt();pwm_set_gpio_level(8,n*2); pw1=n;} //O PWM1
void d80(){uint16_t n =
Serial.parseInt();pwm_set_gpio_level(9,n*2); pw2=n;} //P PWM2
void d81(){for(int j=0; j<256;
j++){uint16_t n = Serial.parseInt();ram[j]=n;}} //Q RAM füllen
void d82(){uint16_t n =
Serial.parseInt();a = n;} //R A=
void d83(){uint16_t n =
Serial.parseInt();b = n;} //S B=
void d84(){uint16_t n = Serial.parseInt();c =
n;} //T C=
void d85(){uint16_t n = Serial.parseInt();d =
n;} //U D=
void d86(){ //V PWM-Vorteiler
uint16_t n = Serial.parseInt();
pwm_set_enabled(4,true);
pwm_config cfg =
pwm_get_default_config();
pwm_config_set_clkdiv_int
(&cfg, n);
pwm_init(4, &cfg, true);
pwm_set_wrap(4, 511);
pwm_set_gpio_level(8,pw1*2);
pwm_set_gpio_level(9,pw2*2);
pwm_set_enabled(4,true);
}
void (*direkt[22])() = {
d65, d66, d67, d68, d69, d70, d71, d72,
d73, d74, d75, d76, d77, d78, d79, d80,
d81, d82, d83, d84, d85, d86};
...
}
if (ch>64 &&
ch<88){
direkt[ch-65]();
}
Was man mit diesen direkten Zugriffen anfangen kann, zeigt ein Beispiel aus der Anwendersoftware. Hier wurde ein PicoBasic-DDS-Programm gestartet, das einen Sinusgenerator mit dem PWM1-Ausgang bildet. Dann wurde das TestLab gestartet. Die Kurvenform wird mit der Schaltfläche „Sin“ in das 256 Byte lange Datenarray übertragen. Das Ausgangssignal durchläuft ein zweistufiges Tiefpassfilter und wird bei laufendem DDS-Generator mit dem Zweikanal-Oszilloskop angezeigt.
Die Arduino-Software
gibt für die PWM-Ausgänge eine Frequenz von 1 kHz vor. Allerdings kann der Rpi Pico
wesentlich mehr. Weil vor allem für die Signalgeneratoren höhere PWM-Frequenzen
sinnvoll sein können, wurde die PWM-Ausgabe mit nativem C umgeschrieben. Deshalb
gibt es nun mit dem Direktkommando V die Möglichkeit, die PWM-Frequenz zwischen
1 kHz und 250 kHz einzustellen. An dieser Stelle geht das TestLab über die Möglichkeiten
von PicoBasic hinaus.
Für die Umstellung
mussten die PWM-Ausgänge im Setup anders initialisiert werden. Entsprechend ändert sich auch der Zugriff in den PicoBasic-Befehlen.
Um glatte PWM-Frequenzen zu bekommen, wurde der Prozessortakt auf 128 MHz
eingestellt. Die PWM-Kanäle laufen tatsächlich mit einer Auflösung von 9 Bit,
sodass die PWM-Timer den Takt durch 512 teilen. Bei der Übergabe eines Bytes müssen daher die Bits
um eine Stelle nach links geschoben werden. Dabei entsteht die höchste PWM-Frequenz
von 250 kHz. Mit dem 8-Bit-Vorteiler können nun mit dem Direktkommando V mehrere
glatte Frequenzen gewählt werden: 1 kHz, 1,5 kHz, 2 kHz, 2,5 kHz, 5 kHz, 10 kHz,
12,5 kHz, 25 kHz, 50 kHz, 125 kHz und
250 kHz.
void setup1() {
gpio_init_mask (mask);
gpio_put_masked (mask, 0);
gpio_set_function(8,GPIO_FUNC_PWM);
gpio_set_function(9,GPIO_FUNC_PWM);
pwm_config cfg =
pwm_get_default_config();
pwm_config_set_clkdiv_int
(&cfg, 250);
pwm_init(4, &cfg, true);
pwm_set_wrap(4, 511);
pwm_set_gpio_level(8,0);
pwm_set_gpio_level(9,0);
pwm_set_enabled(4,true);
}
void k25(){warten = dat;adr++;} // Dekay ms
void k26(){warten = dat*1000;adr++;} // Delay s
void k27(){warten = dat*60000;adr++;} // Delay min
…
direkt[ch-65]();
}
}
if(warten>0){weiter = millis()+warten;
warten = 0;}
if(millis()>weiter){
kom = code[adr] >> 8;
dat = code[adr] & 255;
befehl[kom]();
}
PicoBasic
enthält neben den Variablen A, B C und D ein 256 Byte langes Daten-Array, das
man mit [B+] = A beschreiben und mit A = [B+] auslesen kann. Die vier Variablen
können nun auch im Direktmodus mit den Kommandos R, S, T und U beschreiben
werden. Mit dem Kommando Q gibt es die Möglichkeit, das Array mit
256 Datenbytes zu füllen. Im TestLabor hat man drei Schaltflächen (sin, rec,
tri), mit denen die Signalverläufe Sinus, Rechteck und Dreieck übertragen
werden. Das ist vor allem für programmierte Signalgeneratoren sinnvoll.
Das
Messergebnis zeigt ein ausgegebenes Dreiecksignal an einem
zweistufigen Tiefpassfilter. Durch Setzen von D = 2 wurde der DDS-Generator auf
die dreifache Grundfrequenz eingestellt. Man sieht ein stark abgerundetes Dreiecksignal
und nach der zweiten Filterstufe bereits ein sinusähnliches Signal.