FloB Geschrieben September 12, 2013 at 11:16 Geschrieben September 12, 2013 at 11:16 Hallo bin gerade dabei Tinkerforge mit dem Raspberry Pi zu steuern. Dazu hab ich mein C-Programm, welches ich unter Windows geschrieben habe, auf den RasPi kopiert, die Pfade der Header-Dateien angepasst und kompiliert. Dann hab ich es gestartet und es lief einmal durch und hat sich dann selbst beendet. Das Programm soll verschiedene Werte (Temperatur, Helligkeit, etc.) auf einem Display ausgeben. Ist mit Callbacks gelöst. Erst als ich die Zeilen zum beenden des Programms entfernt habe: printf("Press key to exit\n"); getchar(); ipcon_destroy(&ipcon); // Calls ipcon_disconnect internally und statt dessen eine Endlosschleife eingefügt habe: while(1) { } hat es funktioniert. Allerdings ist jetzt die Auslastung meines RasPi auf 100%. Ist das bei euch auch so oder habt Ihr das anders gelöst? Zitieren
photron Geschrieben September 12, 2013 at 11:28 Geschrieben September 12, 2013 at 11:28 Der Trick mit getchar() an der Stelle ist, dass das getchar() erst returnt wenn eine Taste gedrückt wird. Wüsste spontan nicht warum das Probleme machen sollte. Was meinst du denn mit "es hat erst funktioniert" als du das geändert hast? Hat sich das Programm dann vorher einfach direkt wieder beendet, oder lief es aber die Callbacks taten nichts? Als Alternative kannst du while(1) { sleep(10); } nehmen, dann belegt dein Programm nicht mehr 100% CPU. Zitieren
FloB Geschrieben September 12, 2013 at 11:49 Autor Geschrieben September 12, 2013 at 11:49 Bevor ich das geändert habe, lief das Programm durch, das LCD ging an (Backlight) und die Grundanzeige wird angezeigt. Dann, wenn die Callbacks kommen, kommt nur 1 max. 2 Werte und dann passiert nichts mehr. Wenn ich dann mit "htop" das Programm suche, ist es aus der Aufgabenliste verschwunden. Danke für den Tipp, werde es mal mit "sleep" probieren. Zitieren
FloB Geschrieben September 12, 2013 at 15:37 Autor Geschrieben September 12, 2013 at 15:37 Also erst einmal vielen Dank für den Tipp mit dem "sleep" in der While-Schleife. Jetzt ist die Auslastung wieder im normalen Bereich (ca. 10%). Warum das mit dem "getchar()" nicht funktioniert, kann ich leider auch nicht erklären, obwohl ich jetzt verschiedene Sachen damit ausprobiert habe. Bei mir funktioniert nur die while-Schleife mit dem sleep while(1) {sleep(10);} Zwischenzeitlich hatte ich noch ein anderes Problem. Ich wollte, dass das Programm beim Hochfahren des RasPi startet. Leider hat das Programm auch immer wieder abgebrochen, sobald eine Callback-Funktion aufgerufen wurde. Die Lösung für das Problem fand ich dann beim Schreiben der Logdatei. Jedes Mal, wenn eine Callback-Funktion aufgerufen wird, wird ein Eintrag in der Logdatei erstellt. Bei dieser Logdatei hatte ich einfach nur die Datei angegeben: char* Logfile = "Logdatei.txt" Er hat da wahrscheinlich ein Schreibproblem gehabt, weil mit dem absoluten Pfad funktioniert es: char* Logfile = "/var/www/test/Logdatei.txt" Leider war das nicht der Fehler, warum das "getchar()" nicht funktioniert, weil das funktioniert weiterhin nicht. Aber die Lösung, die ich jetzt habe, ist auch okay. Zitieren
remotecontrol Geschrieben September 12, 2013 at 16:48 Geschrieben September 12, 2013 at 16:48 Ein sleep(10) wartet ja jeweils 10 Sekunden. Um mit der Tinkerforge-API (auch auf einer schwachen CPU wie dem Raspi) eine Auslastung von 10% zu erreichen, muss Du schon relativ viel machen. Das hört sich noch danach an, dass da etwas nicht stimmt. Wenn Du unter Linux einen Dienst über ein init-Skript startest, dann ist (ohne besondere Massnahmen) das Arbeitsverzeichnis das root-Verzeichnis ("/"). Dort hat der root-User Schreibrechte. Init-Dienste haben auch kein stdin, d. h. der getchar() müsste sofort EOF liefern. Du solltest vielleicht man die ganzen Sourcen posten, dann ist Hilfestellung leichter. Zitieren
FloB Geschrieben September 13, 2013 at 06:21 Autor Geschrieben September 13, 2013 at 06:21 Hier mal der komplette Code: #include <stdio.h> #include <wchar.h> #include "../bindings/ip_connection.h" #include "../bindings/brick_master.h" #include "../bindings/bricklet_linear_poti.h" #include "../bindings/bricklet_temperature_ir.h" #include "../bindings/bricklet_lcd_20x4.h" #include "../bindings/bricklet_ambient_light.h" #define HOST "localhost" #define PORT 4223 #define UID_MASTER "6K7GEW" // UID - Master Brick #define UID_AL "8GN" // UID - Ambient Light Bricklet #define UID_LCD "9Mu" // UID - LCD 20x4 Bricklet #define UID_TEMP_IR "9wu" // UID - Temperatur IR Bricklet #define UID_LIN_POTI "9Nf" // UID - Linear Poti Bricklet Master master; LinearPoti poti; TemperatureIR tir; LCD20x4 lcd_20x4; AmbientLight al; char* Logfile = "/var/www/test/Logfile.txt"; // Callback function for position callback (parameter has range 0-100) void cb_position (uint16_t position, void *user_data) { (void)user_data; //avoid unused parameter warning printf("Position: %d\n", position); char text1[30] = {'\0'}; sprintf(text1, "%3.f", position/1.0); lcd_20x4_write_line(&lcd_20x4, 0, 10, text1); FILE *datei; datei = fopen (Logfile, "a+"); fprintf (datei, "Position: %d\n", position); fclose (datei); } //Callback functions for object/ambient temperature callbacks // (parameters have unit °C/10) void cb_object (uint16_t temperature, void *user_data) { (void)user_data; //avoid unused parameter warning printf("Object Temperature: %.1f %cC.\n", temperature/10.0, 248); char text2[30] = {'\0'}; sprintf(text2, "%5.1f \xdf%c", temperature/10.0, 67); lcd_20x4_write_line(&lcd_20x4, 2, 10, text2); FILE *datei; datei = fopen (Logfile, "a+"); fprintf (datei, "Object Temperature: %.1f °C.\n", temperature/10.0); fclose (datei); } void cb_ambient (uint16_t temperature, void *user_data) { (void)user_data; //avoid unused parameter warning printf("Ambient Temperature: %.1f %cC.\n", temperature/10.0, 248); char text3[30] = {'\0'}; sprintf(text3, "%5.1f \xdf%c", temperature/10.0, 67); lcd_20x4_write_line(&lcd_20x4, 3, 10, text3); FILE *datei; datei = fopen (Logfile, "a+"); fprintf (datei, "Ambient Temperature: %.1f °C.\n", temperature/10.0); fclose (datei); } // Callbakc function for illminance callback (parameter has unit Lux/10) void cb_illuminance (uint16_t illuminance, void *user_data) { (void)user_data; //avoid unused parameter warning printf("Illuminance: %4.1f Lux.\n", illuminance/10.0); char text4[30] = {'\0'}; sprintf(text4, "%5.1f lx", illuminance/10.0); lcd_20x4_write_line(&lcd_20x4, 1, 10, text4); FILE *datei; datei = fopen (Logfile, "a+"); fprintf (datei, "Illuminance: %4.1f lx.\n", illuminance/10.0); fclose (datei); } // Function To Show UNICODE on LCD // Maps a wchar_t string to the LCD charset static void wchar_to_ks0066u(const wchar_t *wchar, char *ks0066u, int ks0066u_length) { const wchar_t *s = wchar; char *d = ks0066u; char *e = ks0066u + ks0066u_length; char c; uint32_t code_point; while (*s != '\0' && d < e) { // If wchar_t is UTF-16 then handle surrogates if (sizeof(wchar_t) == 2 && *s >= 0xd800 && *s <= 0xdbff) { code_point = 0x10000 + (*s - 0xd800) * 0x400 + (*(s + 1) - 0xdc00); s += 2; } else { code_point = *s++; } // ASCII subset from JIS X 0201 if (code_point >= 0x0020 && code_point <= 0x007e) { // The LCD charset doesn't include '\' and '~', use similar characters instead switch (code_point) { case 0x005c: c = 0xa4; break; // REVERSE SOLIDUS maps to IDEOGRAPHIC COMMA case 0x007e: c = 0x2d; break; // TILDE maps to HYPHEN-MINUS default: c = code_point; break; } } // Katakana subset from JIS X 0201 else if (code_point >= 0xff61 && code_point <= 0xff9f) { c = code_point - 0xfec0; } // Special characters else { switch (code_point) { case 0x00a5: c = 0x5c; break; // YEN SIGN case 0x2192: c = 0x7e; break; // RIGHTWARDS ARROW case 0x2190: c = 0x7f; break; // LEFTWARDS ARROW case 0x00b0: c = 0xdf; break; // DEGREE SIGN maps to KATAKANA SEMI-VOICED SOUND MARK case 0x03b1: c = 0xe0; break; // GREEK SMALL LETTER ALPHA case 0x00c4: c = 0xe1; break; // LATIN CAPITAL LETTER A WITH DIAERESIS case 0x00e4: c = 0xe1; break; // LATIN SMALL LETTER A WITH DIAERESIS case 0x00df: c = 0xe2; break; // LATIN SMALL LETTER SHARP S case 0x03b5: c = 0xe3; break; // GREEK SMALL LETTER EPSILON case 0x00b5: c = 0xe4; break; // MICRO SIGN case 0x03bc: c = 0xe4; break; // GREEK SMALL LETTER MU case 0x03c2: c = 0xe5; break; // GREEK SMALL LETTER FINAL SIGMA case 0x03c1: c = 0xe6; break; // GREEK SMALL LETTER RHO case 0x221a: c = 0xe8; break; // SQUARE ROOT case 0x00b9: c = 0xe9; break; // SUPERSCRIPT ONE maps to SUPERSCRIPT (minus) ONE case 0x00a4: c = 0xeb; break; // CURRENCY SIGN case 0x00a2: c = 0xec; break; // CENT SIGN case 0x2c60: c = 0xed; break; // LATIN CAPITAL LETTER L WITH DOUBLE BAR case 0x00f1: c = 0xee; break; // LATIN SMALL LETTER N WITH TILDE case 0x00d6: c = 0xef; break; // LATIN CAPITAL LETTER O WITH DIAERESIS case 0x00f6: c = 0xef; break; // LATIN SMALL LETTER O WITH DIAERESIS case 0x03f4: c = 0xf2; break; // GREEK CAPITAL THETA SYMBOL case 0x221e: c = 0xf3; break; // INFINITY case 0x03a9: c = 0xf4; break; // GREEK CAPITAL LETTER OMEGA case 0x00dc: c = 0xf5; break; // LATIN CAPITAL LETTER U WITH DIAERESIS case 0x00fc: c = 0xf5; break; // LATIN SMALL LETTER U WITH DIAERESIS case 0x03a3: c = 0xf6; break; // GREEK CAPITAL LETTER SIGMA case 0x03c0: c = 0xf7; break; // GREEK SMALL LETTER PI case 0x0304: c = 0xf8; break; // COMBINING MACRON case 0x00f7: c = 0xfd; break; // DIVISION SIGN default: case 0x25a0: c = 0xff; break; // BLACK SQUARE } } // Special handling for 'x' followed by COMBINING MACRON if (c == (char)0xf8) { if (d == ks0066u || (d > ks0066u && *(d - 1) != 'x')) { c = 0xff; // BLACK SQUARE } if (d > ks0066u) { --d; } } *d++ = c; } while (d < e) { *d++ = '\0'; } } // start MAIN int main() { // Create IP connection IPConnection ipcon; ipcon_create(&ipcon); // Create device object linear_poti_create(&poti, UID_LIN_POTI, &ipcon); temperature_ir_create(&tir, UID_TEMP_IR, &ipcon); lcd_20x4_create(&lcd_20x4, UID_LCD, &ipcon); ambient_light_create(&al, UID_AL, &ipcon); master_create(&master, UID_MASTER, &ipcon); // Conncet to brickd if(ipcon_connect(&ipcon, HOST, PORT) < 0) { fprintf(stderr, "Could not connect\n"); exit(1); } // Dont't use device before ipcon is connected // CALLBACK - LINEAR-POTI // Set Period for position callback to 0.05s (50ms) // Note: The position callback is only called every 50ms if the // position has changed since the last call! linear_poti_set_position_callback_period(&poti, 50); // Register position callback to function cb_position linear_poti_register_callback(&poti, LINEAR_POTI_CALLBACK_POSITION, (void *)cb_position, NULL); // CALLBACK - TEMPERATUR IR // Set Period for temperature callbacks to 1s (1000ms) // Note: The callbacks are only called every second if the // value has changed since the last call! temperature_ir_set_object_temperature_callback_period(&tir, 1000); temperature_ir_set_ambient_temperature_callback_period(&tir, 1000); // Register object temperature callback to function cb_object temperature_ir_register_callback(&tir, TEMPERATURE_IR_CALLBACK_OBJECT_TEMPERATURE, (void *)cb_object, NULL); // Register ambient temperature callback to function cb_ambient temperature_ir_register_callback(&tir, TEMPERATURE_IR_CALLBACK_AMBIENT_TEMPERATURE, (void *)cb_ambient, NULL); // CALLBACK - AMBIENTLIGHT // Set Period for illuminance callback to 1s (1000ms) // Note: The illuminance callback is only called every second if the // illuminance has changed since the last call! ambient_light_set_illuminance_callback_period(&al, 1000); // Register illuminance callback to function cb_illuminance ambient_light_register_callback(&al, AMBIENT_LIGHT_CALLBACK_ILLUMINANCE, (void *)cb_illuminance, NULL); // Clear LCD display lcd_20x4_clear_display(&lcd_20x4); // Turn backlight on lcd_20x4_backlight_on(&lcd_20x4); // Write to LCD lcd_20x4_write_line(&lcd_20x4, 0, 0, "Position: "); lcd_20x4_write_line(&lcd_20x4, 1, 0, "Licht: "); lcd_20x4_write_line(&lcd_20x4, 2, 0, "O-Temp 1: "); lcd_20x4_write_line(&lcd_20x4, 3, 0, "A-Temp 2: "); // Write to LCD // Leere-Werte! lcd_20x4_write_line(&lcd_20x4, 0, 10, "---"); lcd_20x4_write_line(&lcd_20x4, 1, 10, "---.- lx"); lcd_20x4_write_line(&lcd_20x4, 2, 10, "--.-"); lcd_20x4_write_line(&lcd_20x4, 3, 10, "--.-"); //printf("Press key to exit\n"); //getchar(); //ipcon_destroy(&ipcon); // Calls ipcon_disconnect internally while(1) {sleep(10);} return 0; } Zur Info mit dem Autostart: Ich starte die Datei unter einem anderen Benutzer: su www-data -c "PFAD/ZUR/DATEI &" Und noch einen Hinweis zu der Auslastung: Bei den 10% läuft auch noch die Shell mit HTOP. Ich weiß jetzt nicht wie viel das verbraucht? Zitieren
remotecontrol Geschrieben September 13, 2013 at 08:59 Geschrieben September 13, 2013 at 08:59 OK, das erklärt ein paar Punkte: * bei dieser Startart ist stdin geschlossen, d. h. der getchar() beendet sich sehr schnell. Zu der Zeit sind einige IPConnection-Threads noch in der "Startphase" aktiv und das ganze kommt durcheinander weil direkt im Start alles wieder beendet wird und der Stack mit dem IPConnection-Objekt weg ist. => der sleep(10) löst das * ein fopen liefert NULL, wenn die Log-Datei nicht geöffnet werden kann, der fprintf bringt das Programm dann zu Absturz. Der User hatte auf das Arbeitsverzeichnis keine Schreibrechte, mit dem ganzen Pfad geht es dann. * Hast Du einen Temperature-IR Sensor angeschlossen oder nur einen einfachen Temperatur-Sensor? Wenn Du einen Temperature-IR Sensor dran hast, sieht alles gut aus. Dann kommt die Last eher vom HTOP plus die Aktivität auf der Console. Zitieren
FloB Geschrieben September 13, 2013 at 11:30 Autor Geschrieben September 13, 2013 at 11:30 Danke nochmal für die tolle Erklärung. Besonders die Erklärung, warum das "getchar()" nicht funktioniert. Und, ja ich habe einen Temperatur-IR Sensor angeschlossen. Also vom Programm her ist alles in Ordnung. Ja, so was habe ich mir schon gedacht, das ein Großteil der Auslastung von HTOP kommt. Zitieren
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.