Datum:
Hallo, gerade bin ich dabei, ein Programm in C zu schreiben, welches Temperaturdaten vom Arduino empfängt und in einer Datenbank ablegt. Das Programm macht inzwischen, was ich möchte. Das Problem ist, dass ich eine Schleife geschrieben habe, die eine bestimmte Zeit misst und nicht optimal ist.
while((diff=difftime(stop=time(NULL),start)) != 15); |
Dummerweise hat diese Art der Programmierung den Nachteil, dass die CPU immer in Beschäftigung ist. Wie kann ich unter Linux einen Timer programmieren, der am Besten interruptgesteuert ist, so wie ich es auch beim AVR machen würde? Hier ist mein kleines Programm: Bitte erschlagt mich nicht, falls ich grundlegende Dinge nicht beachtet haben sollte. Es ist mein erstes Programm unter Linux. Für konstruktive Hinweise bin ich natürlich dankbar.
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <sys/types.h> #include <fcntl.h> #include <mysql.h> // globale Variablen deklarieren int port; char puffer[100]; char puffer2[150]; MYSQL_RES *res; MYSQL_ROW row; int bytes; char buffer[1]; int i = 0; int x; int y; // Instanz von mysql MYSQL *mysql; /* Bricht bei Fehler (mysql_error != 0) das Programm ab. */ void check_error(void) { if (mysql_errno(mysql) != 0) { fprintf(stderr, "Fehler: %s\n", mysql_error(mysql)); exit(EXIT_FAILURE); } } /* Baut eine Verbindung zum Datenbankserver auf. * Passen Sie ggf. Usernamen und Passwort und, sofern * andere Parameter benötigt werden, diese an Ihre * Bedürfnisse selbst an. */ void verbinden(void) { mysql=mysql_init(mysql); check_error(); /* mysql_real_connect ( * my, // Zeiger auf MYSQL-Handler * NULL, // Host-Name * NULL, // User-Name * NULL, // Passwort für user_name * NULL, // Name der Datenbank * port_num, // Port * socket_name, // Socket * 0 ) // keine Flags */ mysql_real_connect(mysql, "localhost", "root", "", "arduino", 0, NULL, 0); check_error(); } /* Serververbindung wieder schließen und den Speicher für die * Struktur MYSQL wieder freigeben */ void verbindung_schliessen(void) { mysql_close(mysql); } int arduino(void) { // jetzt soll ein 'A' an die serielle Schnittstelle ausgegeben werden buffer[0] = (char)'A'; //printf(buffer); //printf("\n"); write(port, buffer, sizeof(buffer)); //printf("Zeichen wurde gesendet\n"); // Zeichen von der seriellen Schnittstelle einlesen // es wird bis Zeilenende oder max. 80 Zeichen gelesen y=0; for (x=0; x<80; x++) { // Jetzt können Daten gelesen werden bytes = read(port, buffer, sizeof(buffer)); printf(buffer); if (buffer[0] >= ' ') { puffer[y]=buffer[0]; y++; } if (buffer[0] == '\n') { break; } } puffer[y] = (char)'\0'; printf("\n"); //SQL-Abfrage sprintf( puffer2, "INSERT INTO `temperatur` (wert) VALUES('%s')", puffer); printf(puffer2); mysql_query(mysql, puffer2); check_error(); } int main(int argc, char *argv[]) { time_t start, stop; double diff; // serielle Schnittstelle für die Kommunikation zum Arduiono öffnen // beim Arduino wird dadurch ein RESET durchgeführt, Grund: DTR geht kurz auf LOW port = open("/dev/ttyACM1", O_RDWR); // prüfen, ob die Schnittstelle erfolgreich geöffnet wurde if (port == -1) { // das ist der Fehlerfall printf("Schnittstelle konnte nicht geöffnet werden.\n"); return(1); } // Erste Zeile nach dem Reset einlesen (dient nur zur Kontrolle für den Test) for (x=0; x<30; x++) { // Jetzt können Daten gelesen werden bytes = read(port, buffer, sizeof(buffer)); printf(buffer); if (buffer[0] == '\n') { break; } } // Verbindung zur Datenbank herstellen verbinden(); int A=1; while(A=1) { // Zeitschleife (alle 15 Sekunden werden Daten abgerufen) printf("Einen Augenblick bitte ...\n"); start=time(NULL); while((diff=difftime(stop=time(NULL),start)) != 15); printf("%.1f Sekunden vorbei!!\n",diff); arduino(); } // Verbindung zur Datenbank beenden verbindung_schliessen(); // serielle Schnittstelle beenden close(port); } |
Gruß Guido
Datum:
sleep() alarm() /dev/rtc
Datum:
Hier noch mehr: (SEE ALSO beachten)
USLEEP(3)
Linux Programmer's Manual
USLEEP(3)
NAME
usleep - suspend execution for microsecond intervals
SYNOPSIS
#include <unistd.h>
int usleep(useconds_t usec);
Feature Test Macro Requirements for glibc (see
feature_test_macros(7)):
usleep(): _BSD_SOURCE || _XOPEN_SOURCE >= 500
DESCRIPTION
The usleep() function suspends execution of the calling process
for (at least) usec microseconds. The sleep may be lengthened slightly
by any system activity or by the time spent pro‐
cessing the call or by the granularity of system timers.
RETURN VALUE
0 on success, -1 on error.
ERRORS
EINTR Interrupted by a signal; see signal(7).
EINVAL usec is not smaller than 1000000. (On systems where that
is considered an error.)
CONFORMING TO
4.3BSD, POSIX.1-2001. POSIX.1-2001 declares this function
obsolete; use nanosleep(2) instead. POSIX.1-2008 removes the
specification of usleep().
On the original BSD implementation, and in glibc before version
2.2.2, the return type of this function is void. The POSIX version
returns int, and this is also the prototype used
since glibc 2.2.2.
Only the EINVAL error return is documented by SUSv2 and
POSIX.1-2001.
NOTES
The type useconds_t is an unsigned integer type capable of
holding integers in the range [0,1000000]. Programs will be more
portable if they never mention this type explicitly. Use
#include <unistd.h>
...
unsigned int usecs;
...
usleep(usecs);
The interaction of this function with the SIGALRM signal,
and with other timer functions such as alarm(2), sleep(3), nanosleep(2),
setitimer(2), timer_create(2), timer_delete(2),
timer_getoverrun(2), timer_gettime(2), timer_settime(2),
ualarm(3) is unspecified.
SEE ALSO
alarm(2), getitimer(2), nanosleep(2), select(2), setitimer(2),
sleep(3), ualarm(3), time(7)
COLOPHON
This page is part of release 3.23 of the Linux man-pages project.
A description of the project, and information about reporting bugs, can
be found at http://www.kernel.org/doc/man-
pages/.
2007-07-26
USLEEP(3)
Datum:
Guido Scheidat schrieb: > Wie kann ich unter Linux einen Timer programmieren, der am Besten > interruptgesteuert ist, so wie ich es auch beim AVR machen würde? man setitimer Das ist exakt das Pendat zun einem Interrupt-Timer. Statt eines Interrupts bekommst du ein Signal, aber die Handhabung ist sehr ähnlich. Du hast dann aber immer noch eine Hauptschleife, die die CPU-Last auf 100% hält, wenn du da nicht was dagegen tust. Das kannst du z.B. machen, indem du in der Haupstschleife mit select() ohne Dateideskriptoren und einer sehr langen Wartezeit wartetst. Das wird durch das Signal automatisch unterbrochen. Der Rest ist dann wie am µC: Im Signal-Handler ein Flag setzen (Als Typ empfielt sich sig_atomic_t) und in der Hauptschleife testen.
Datum:
Vielen, vielen Dank! Ich habe jetzt USLEEP eingesetzt. Die Genauigkeit reicht für diesen Zweck aus. Es funktioniert ganz Klasse, die Idle-Time der CPU liegt bei 99-100%. So hatte ich es mir vorgestellt. Danke!
Datum:
Wenn man eh select() nimmt, kann man dem doch auch gleich die Wartezeit geben? Rolf Magnus schrieb: > indem du in der Haupstschleife mit select() ohne Dateideskriptoren und > einer sehr langen Wartezeit wartetst
Datum:
Klaus Wachtler schrieb: > Wenn man eh select() nimmt, kann man dem doch auch gleich die Wartezeit > geben? Kommt halt drauf an, was das Ziel ist. Wenn man ein Timing will, das nicht davonläuft, kommt man um einen periodischen Timer nicht rum. Denn zu der Wartezeit des select() kommt ja immer noch die (womöglich variable) Laufzeit für den Rest der Schleife dazu. Wenn das egal ist, kann man sich den Timer natürlich sparen. Ich hatte mich hier auch speziell auf diese Frage bezogen: Guido Scheidat schrieb: > Wie kann ich unter Linux einen Timer programmieren, der am Besten > interruptgesteuert ist, so wie ich es auch beim AVR machen würde? Die von mir genannte Variante ist der Art, wie man beim AVR mit Timer-Interrupts arbeitet, am ähnlichsten, ohne dabei aber 100% CPU-Last zu produzieren.



