Jump to content

[C/C++] Raspberry Pi - Programm verändern?


Recommended Posts

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?

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

 

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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.

 

 

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...