Servus,
bin neu hier im Forum und habe ein Problem mit der Programmierung meines
RP pico.
Ich will die Timerfunktion verstehen. Sie soll ja den Prozessor nicht
blockieren wie dir Sleepfunktion. Dazu habe ich ein Program geschrieben
bzw zusammenkopiert, das eine Led 2 Sekunden leuchten läßt und
währenddessen ein Thermometer Und Feuchtigkeitsmesser (dht11) ausliest.
Hier der Code: 1 | #include <stdio.h>
| 2 | #include <math.h>
| 3 | #include "pico/stdlib.h"
| 4 | #include "hardware/gpio.h"
| 5 |
| 6 | const uint LED_PIN = PICO_DEFAULT_LED_PIN;
| 7 | //const uint DHT_PIN = 15;
| 8 | const uint DHT_PIN = 0;
| 9 | const uint MAX_TIMINGS = 85;
| 10 | bool led_status = false;
| 11 | bool nix_schalter = false;
| 12 | struct repeating_timer timer; //structure declaration
| 13 | typedef struct {
| 14 | float humidity;
| 15 | float temp_celsius;
| 16 | } dht_reading;
| 17 |
| 18 |
| 19 | bool tCallback( repeating_timer_t *timer){
| 20 | led_status = !led_status;
| 21 | gpio_put(LED_PIN, led_status);
| 22 | printf("das ist der nix_schalter am Eingang %i, \n ",nix_schalter);
| 23 | nix_schalter = false;
| 24 | printf("das ist der nix_schalter am Ausgang %i, \n",nix_schalter);
| 25 | return true;
| 26 | }
| 27 |
| 28 |
| 29 | void read_from_dht(dht_reading *result);
| 30 | uint DHT11_Read_Data(dht_reading *result);
| 31 | int main() {
| 32 | uint32_t i,k, l;
| 33 | i=k=l=0;
| 34 |
| 35 | // Pico pios initialisieren
| 36 | stdio_init_all();
| 37 | gpio_init(LED_PIN);
| 38 | gpio_init(DHT_PIN);
| 39 | gpio_set_dir(LED_PIN, GPIO_OUT);
| 40 | gpio_put(LED_PIN, false);
| 41 | sleep_ms(10000); // Warten, daß ich nach dem Start das Terminal aufmache
| 42 |
| 43 | printf("das kommt jetzt %d \n",i);
| 44 | i++;
| 45 | // Sensoren auslesen
| 46 | dht_reading reading;
| 47 | DHT11_Read_Data(&reading);
| 48 | float fahrenheit = (reading.temp_celsius * 9 / 5) + 32;
| 49 | printf("Humidity = %.1f%%, Temperature = %.1fC (%.1fF)\n",reading.humidity, reading.temp_celsius, fahrenheit);
| 50 |
| 51 | // Timer starten
| 52 | add_repeating_timer_ms(2000,tCallback,NULL,&timer); //starting the timer
| 53 | l++;
| 54 | // Schleife um die Sensoren nach dem Timeraufruf einmal auszulesen
| 55 | while(1) {
| 56 | printf("das ist der nix_schalter am Anfang der Whileschleife %i, \n",nix_schalter);
| 57 | l++;
| 58 | // nix_schalter abfragen, damit nur einmal ausgelesen wird
| 59 | if (!nix_schalter) {
| 60 | printf("das kommt jetzt %d, %d, %f, %i, \n",k,l); // Ausgabe um zu sehen was er alles so gemacht hat
| 61 | k++;
| 62 | i++;
| 63 | dht_reading reading;
| 64 | DHT11_Read_Data(&reading);
| 65 | float fahrenheit = (reading.temp_celsius * 9 / 5) + 32;
| 66 | printf("Humidity = %.1f%%, Temperature = %.1fC (%.1fF)\n",reading.humidity, reading.temp_celsius, fahrenheit);
| 67 | }
| 68 | l=l+1;
| 69 | nix_schalter = true; // nix_schalter auf true setzen, damit er beim nächsten Durchlauf die Sensoren nicht ausliest.
| 70 | i++;
| 71 | }
| 72 | }
|
Das ganze Drumrum um das Auslesen der Sensoren hab ich nicht angehängt
Die meisten Zähler und print Befehle hab ich nur eingefügt um zu sehen
wann er was macht bzw. nicht macht.
Das Problem erscheint nach dem Aufruf von "add_repeating_timer_ms" in
Zeile 52.
Wenn ich die Zeile prinf... (Zeile 56) habe durchläuft es die
Whileschleifen sauber und wenn nicht (auskommentiert oder gelöscht) dann
nicht! Ich will aber den ganzen Mist den er mir dann schickt nicht haben
und ich will das Verhalten verstehen. Zum Schluß: bin mir nicht sicher
ob ich die Ausgaben richtig eingebunden habe, hab aber nix gefunden wie
die formatiert werden sollten.
Und jetzt erst mal vielen Dank für Antworten.
Das ist die Ausgabe mit Zeile 56:
das kommt jetzt 0
Humidity = 56.0%, Temperature = 20.0C (68.0F)
das ist der nix_schalter am Anfang der Whileschleife 0,
das kommt jetzt 0, 2, 0.000000, 536876024,
Humidity = 0.0%, Temperature = 0.0C (32.0F)
das ist der nix_schalter am Anfang der Whileschleife 1,
das ist der nix_schalter am Anfang der Whileschleife 1, ...ca 33000 mal
dann
das ist der nix_schalter am Eingang 1,
das ist der nix_schaltdas ist der nix_schalter am Anfang der
Whileschleife 1,
das kommt jetzt 1, 33390, 0.000000, 0,
Humidity = 56.0%, Temperature = 20.0C (68.0F)
das ist der nix_schalter am Anfang der Whileschleife 1,
das ist der nix_schalter am Anfang der Whileschleife 1, ... usw
Hier die Ausgabe ohne Zeile 56:
das kommt jetzt 0
Humidity = 55.0%, Temperature = 20.0C (68.0F)
das kommt jetzt 0, 2, 0.000000, 536876024,
Humidity = 0.0%, Temperature = -infC (-infF)
das ist der nix_schalter am Eingang 1,
das ist der nix_schalter am Ausgang 0,
das ist der nix_schalter am Eingang 1,
das ist der nix_schalter am Ausgang 0, ... usw.
Falls Du einen zweiten Pico hast, kannst Du den zweiten Pico als
Debug-Probe benutzen:
https://www.raspberrypi.com/documentation/microcontrollers/pico-series.html#swd
Oder Du kaufst eine Pico-Probe.
Es steht zu befürchten, dass:
eine ISR ist. Und wenn dort drin globale Variablen modifiziert werden 1 | bool led_status = false;
| 2 | bool nix_schalter = false;
|
wird das Hauptprogramm dies ohne weitere sachdienliche Anweisungen wohl
gar nicht erst mitbekommen.
Danke für die Antworten,
an Datenreisender: hab nen 2. pico, muß mir aber erst noch Kabel
besorgen. Ein Pico-probe schadet sicher auch nix, wenn ich mir den
zuleg. Das wird also noch etwas dauern, werd ich aber auf jeden Fall
angehen.
an der_Norbert:
"led_status" ist nicht das Problem, die Leds werden geschaltet.
"nix_schalter" wird geschaltet, wenn die ominöse printf-Zeile drin ist,
und nicht, wenn sie nicht drin ist.
Ich versteh die Abhängigkeit von dem printf - Kommando nicht.
Theo H. schrieb:
> "nix_schalter" wird geschaltet, wenn die ominöse printf-Zeile drin ist,
> und nicht, wenn sie nicht drin ist.
Das ist eine (verständliche) Fehlannahme.
"nix_schalter" wird in der ISR geschaltet, aber das Hauptprogramm
bekommt es nicht mit weil es mit einer, nennen wir es mal ›lokalen,
temporären Kopie‹ arbeitet!
Wenn es dir nichts ausmacht (Achtung Insiderwitz) knietief durch Blut zu
waten, dann suche im Forum mal nach volatile.
Theo H. schrieb:
> an Datenreisender: hab nen 2. pico, muß mir aber erst noch Kabel
> besorgen. Ein Pico-probe schadet sicher auch nix, wenn ich mir den
> zuleg. Das wird also noch etwas dauern, werd ich aber auf jeden Fall
> angehen.
Drei Kabel reichen:
https://pip-assets.raspberrypi.com/categories/610-raspberry-pi-pico/documents/RP-008276-DS-1-getting-started-with-pico.pdf?disposition=inline
Seite 17 zeigt Dir die Verkabelung.
> an der_Norbert:
> "led_status" ist nicht das Problem, die Leds werden geschaltet.
> "nix_schalter" wird geschaltet, wenn die ominöse printf-Zeile drin ist,
> und nicht, wenn sie nicht drin ist.
> Ich versteh die Abhängigkeit von dem printf - Kommando nicht.
Norbert wollte Dir den type qualifier "volatile" nahelegen: Deine
Callback ist eine ISR (ich nehme mal an), und da kann alles moegliche
passieren (https://de.wikipedia.org/wiki/Volatile_(Informatik)). Es kann
auch sein, dass durch die Optimierung des Compilers die Reihenfolge der
Kommandos veraendert wurde.
Theo H. schrieb:
> printf("das kommt jetzt %d, %d, %f, %i, \n",k,l); // Ausgabe um zu
> sehen was er alles so gemacht hat
Also das ist zumindest mal sehr suspekt! Ich unterstelle mal keine üblen
Nebenwirkungen, aber ausschließen würde ich das nicht. Die Anzahl der
Parameter stimmt nicht wirklich mit dem Formatstring überein.
So Danke an alle,
es funktioniert. Habe die zwei Variablen als volatile deklariert und
schon geht's. Bin in C nur etwas mehr als oberflächlich Vertraut und da
fehlt's halt schon an einigen Stellen aber man kann ja lernen.
Danke
Theo
P.S. habe gerade festgestellt es funktioniert nur so lala, sprich da
gibt es Aussetzer. Aber da muß ich erst mal versuchen das selber zu
lösen bevor ich Euch da weiter belästige.
Theo H. schrieb:
> Aber da muß ich erst mal versuchen das selber zu
> lösen bevor ich Euch da weiter belästige.
Quatsch. Du hast doch eine legitime Frage gestellt und zusätzlich mit
code unterstützt. Das ist keine Belästigung.
Da haben wir hier ganz andere ›Spezialisten‹
Verwendest Du beide Cores des RP2040?
Wenn ja, dann siehst Du evtl. die Effekte von nebenläufiger Ausführung.
Das Thema ist leider gar nicht so einfach sauber zu lösen. Entweder weiß
man genau was der verwendete Core in der Lage ist zu tun und beschränkt
sich auf ganz klar definierte Operationen (also z.B. nur Core1 schreibt
Variable X und die darf nur ein uint32_t sein) oder man beginnt über
Locking und Critical Sections nachzudenken.
Wenn das mehr als ein paar sehr wenige Stellen werden, empfiehlt es sich
über ein RTOS nachzudenken - das muss man zwar einmal einbinden und
initialisieren, bietet einem dann aber praktische Mechanismen um mit
solchen Problemen gut umgehen zu können.
Beispiele für RTOSse, falls es Dich interessiert:
FreeRTOS
https://www.freertos.org/Documentation/01-FreeRTOS-quick-start/01-Beginners-guide/01-RTOS-fundamentals
ChibiOS
https://www.chibios.org/dokuwiki/doku.php?id=chibios:documentation:books:rt:start
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|