Hallo, ich bin momentan dabei, mir eine Zeitmessung zu basteln, komme selbst eher aus der OO-Welt der Windows-Programmierung und möchte es mit Codevision AVR und einem Atmel 90S8515 realisieren. Dabei wird ein Triggersignal über den UART empfangen. Es werden 8 Einzelkanäle getriggert. Daraufhin soll eine (relative) Zeit für diesen Kanal (seit dem letzten Triggersignal) ausgegeben werden (über einen SoftUART oder über einen Port - ist noch unklar). Da ich noch nicht allzu viel Erfahrung habe mit AVR-Programmierung, möchte ich euch fragen, welche Vorgehensweise ihr mir empfehlen würdet für die Berechnung der relativen Zeit. Diese Zeit sollte milisekundengenau sein. Meine erste Überlegung ist, einen Timer laufen zu lassen und bei Überlauf in der Interrupt-Routine einen Counter (unsigned long int) hochzuzählen. Diesen Counter möchte ich dann als Zeitstempel missbrauchen, indem ich beim Empfang des Triggers am UART das Zeit-Delta für den getriggerten Kanal berechnen und ausgebe... Was haltet ihr davon? Wenn ich mir Codeexamples von Stoppuhren o.ä anschaue, dann habe ich bei diesem Code immer das Problem, dass er ungeeignet ist für meine Anwendung, da ich ja eine Art Multithreading benötige (mein Zeitspempel muss nebenher konstant weiterlaufen), um den Trigger zu empfangen und entsprechend die Zwischenzeiten zu berechnen und auszugeben. Wie gesagt, mein Kopf ist noch auf OO geeicht und hat daher sicherlich nicht die beste Lösung gefunden :-) Daher mein Bitte an euch und eure Unterstützung, was die Ideenfindung angeht. Wie würdet ihr - beschrieben in Worten oder Code - diese Anforderung grob lösen? Danke und Grüße Peter
> Art Multithreading das erledigt dir der Timer Interrupt. Du initialisierst dir den Timer und dann zaehlt der munter Hardware-getrieben ganz für sich alleine dahin. Fuer die Triggerung durch den UART verwendest du den UART-Receive Interrupt. Der macht dann nichts anderes als den momentanen Zaehlerstand auszulesen und das Ergebnis auf den Weg bringen. Interrupt Routinen kurz halten! Fang mal klein an: Einen Timer aufsetzen, der still und leise vor sich hintickt. Anstatt in ms lässt du den im Sekundenbereich arbeiten, dann kannst du ganz einfach zur Kontrolle eine LED anhängen die dann vor sich hinblinkt.
Das mit dem 1ms Timerinterrupt ist schon voll o.k. so. Dann hast Du 8000 Zyklen (8MHz Quarz) zwischen 2 Interrupts, das sollte dicke reichen, um die 8 Eingänge abzufragen. Peter
danke schon mal. ich sitze jetzt gerade wieder dran... ich verwende ja den 90s8515. er hat einen 8bit-timer0 und einen 16bit-timer1. aber beide sind doch zu klein, um damit eine zeitmessung mit ms und s aufzubauen? wenn ich den 16bit-timer nehme, habe ich ja nur 2^16 verschiedene zeitstempel, oder?
oder meint ihr, dass ich den timer-interrupt bei overflow auslösen soll und damit dann einen int hochzählen soll? je nach taktung wäre mein int-wert ja dann meine sekunde und mein timerwert meine ms, oder?
also, ich habe jetzt zunächst mal das einfache beispiel (langsamer timer und bei jedem overflow per interrupt eine ausgabe auf eine led) gemacht - funktioniert! dann habe ich versucht, meine anwendung anzugehen. dazu habe ich eine globale variable fürs auslesen des timerwerts (unsigned int) und eine für einen absoluten zeitstempel (unsigned long int) genommen. bei overflow wird der zeitstempel hochgezählt und beim uart receive interrupt wird sowohl der zeitstempel, als auch der aktuelle timerwert ausgelesen. ist das soweit richtig? jetzt gehts aber weiter: wie bekomme ich nun meine 3 werte (zeitstempel, timerwert, inhalt des uart) an den pc übertragen? entweder brauche ich ja da einen software-uart (da ich nur einen in der hardware habe) oder ich muss es parallel ausgeben. was meint ihr?
Du kannst ja auch über die vorhandene UART das Ergebnis zurückschicken. Schalte den Transmitter einfach ein und weise dem Register UDR den gewünschten Wert zu. Vorher noch abfragen ob die UART bereit zum senden ist. Im AVR-GCC Tutorial findest du auch Funktionen zum Versenden mttels UART. Ich weiss schon: du benutzt einen anderen Compiler, aber das Prinzip des Sendens ist das gleiche.
ok, und was macht man am besten, wenn man eine 16bit oder eine 32bit-zahl über den uart schicken möchte? ich hab die zahl ja als unsigned int im c-code. wie bekomme ich die in 8bit-teile und danach auch wieder zusammen?
Wenn man Werte verschicken will, muß man erst überprüfen, ob die Byteorder des Zielsystems die gleiche ist. Deshalb mache ich es lieber so, daß ich nen Wert als Text verschicke, wenn die Geschwindigkeit nicht maximal sein muß. Das Zeilsystem liest dann eine Zeile ein und wandelt es per scanf, atoi oder atof zurück. Durch das Zeilenende hat man auch eine Synchronisation. Schickt man 4 Bytes binär, muß man noch eine Synchronisation dazubasteln, falls mal ein Byte verloren geht oder gestört ist. Wichtig ist immer, daß man alles, was von außen kommt, auf Gültigkeit überprüft. Das machen leider nur MC-Programmierer für zuverlässige Steuerungen. In der PC-Welt wird aber überhaupt nichts überprüft und nur deshalb haben Viren per Stackoverflow o.ä. überhaupt eine Chance. Peter
wie würdest du es dann bewerkstelligen, eine 32bit integer zahl über den uart zu schicken? ich hab kein codeexample dazu gefunden :-( du hast doch da bestimmt ein stückchen code :-) danke!
ich meine damit gerade das konvertieren in nen string und auf der gegenseite wieder das zusammensetzen!
noch was dazu: ich will die daten vom avr über ein usb-modul an den pc schicken, wo sie dann per java-programm ausgewertet werden. die zahlen sind 2 mal int und 1 mal unsigned long int. wie bekomm ich die byteweise rüber?
Zum wandeln einr Zahl in einen String gibt es mehrere Möglichkeiten: sprintf _itoa selbst eine Funktion schreiben zb. char Buffer[20]; int xyz; sprintf( Buffer, "%d", xyz ); /* in Buffer steht jetzt der String, wird mit normalen UART String-sende Funktionen verschickt */ sprintf benötigt ziemlich viele 'Resourcen', daher ist _itoa (oder itoa je nach Compiler) die einfachere Variante. Wie man die Funktion benutzt: Helpfile lesen.
danke! der CodeVision compiler bietet die funktion: void ltoa(long int n, char *str) damit könnte ich doch auch den unsigned long int in einen char buffer[] schreiben. wie kann ich bei während der implementierung testen, was jetzt in meinem buffer[] steht bzw. wie groß er nun ist? ich möchte nämlich zu dem long int noch 2 int hinzu stecken und auch mit senden.
noch eine frage dazu: bei der vorgeschlagenen lösung steht doch im buffer[] pro index eine zahl als string drin. wenn ich z.b. die zahl 12345 mit itoa konvertiere, erhalte ich einen buffer["1","2","3","4","5"], richtig?
> steht doch im buffer[] pro index eine zahl als string drin. Mir scheint da herrscht jetzt ein Missverständniss. 1) Den Buffer gibst Du als Programmierer vor. d.h. Du legst fest wie gross der sein soll. Damit ist die Frage > bzw. wie groß er nun ist? eine sinnlose Frage. Denn du weist ja wie gross du das Feld dimensioniert hast. Auch steht nicht in jedem Index eine Zahl als String drin. Der Buffer ist ein ganz normales Array. Und jedes Array Element nimmt genau einen Character auf. Da hier zusätzlich von Strings die Rede ist, ist diese gespeicherte Sequenz mit einem '\0' Character abgeschlossen. > wenn ich z.b. die zahl 12345 mit itoa konvertiere, erhalte ich > einen buffer["1","2","3","4","5"], richtig? Ich bin mir nicht sicher ob du das richtige meinst, daher: Du gibst den Buffer vor: char buffer[40]; // Platz für 40 Zeichen ltoa( 12345, buffer ); dann enthält buffer: buffer[0] = '1' buffer[1] = '2' buffer[3] = '3' buffer[4] = '4' buffer[5] = '5' buffer[6] = '\0' alle restlichen buffer-Einträge, also die Indizes 7 bis 39 haben undefinierten Inhalt. Das '\0'-Zeichen markiert das Ende das Strings, so wie das in C üblich ist. > wie kann ich bei während der implementierung testen, was jetzt > in meinem buffer[] steht bzw. wie groß er nun ist? Ich denke du meinst damit: wie lange der String ist der in buffer gespeihwert wurde. Alles andere macht keinen Sinn, denn buffer ist in obigem Beispiel 40 Zeichen lang. Genau so wurde er deklariert und genau soe viele Zeichen kann er aufnehmen. Der Stgin hingegen, der in buffer gespeichert wurde, hat eine ganz andere Länge. Der ist 5 Zeichen lang, und die Funktion strlen() würde dir das zb. als Rückgabewert geben. > ich möchte nämlich zu dem long int noch 2 int hinzu stecken und > auch mit senden. Dann konvertier dir die Einzelteil einzeln in eigene Buffer und füge die Einzelteile hinterher zusammen. Dafür gibt es Funktionen. strcat(), strcpy(), bzw. Überhaupt die ganze Familie an str... Funktionen. Und wieder komm ich nicht umhin, meine übliche Beschwörung ans Ende zusetzen: Jungs, kauft euch Bücher! String-Handling in C ist zwar nicht allzu schwer aber auch nicht trivial. Dafür ist es aber in jedem, und ich meine jedem, Buch über C ausführlich beschrieben.
ok, nun ist es klar. auf der seite des sender-avrs habe ich nun ein anderes problem. das hier ist mein hauptprogramm: while (1) { // if(PINB!=0xFF){ delay_ms(1); if(PINB!=0xFF){ car=PINB; if(car==0x80){car = 0x08;} if(car==0x40){car = 0x07;} if(car==0x20){car = 0x06;} if(car==0x10){car = 0x05;} if(car==0x08){car = 0x04;} if(car==0x04){car = 0x03;} if(car==0x02){car = 0x02;} if(car==0x01){car = 0x01;} putchar(car); PORTA=car; delay_ms(1000); } } PORTA=0x00; } } das bedeutet, dass ich die lichtschranke entprellt auslesen möchte (ein Pin von PINB), diesen wert in "char car" zwischenspeichern möchte und danach eben den wert konvertieren möchte in den korrekten zahlenwert im bcd-format. zur kontrolle gebe ich den wert von "car" noch an den leds an PORTA aus. nun mein problem: an PORTA leuchtet immer nur die LED, dessen taster ich gedrück habe. also funktionien meine if-abfragen wohl nicht. ich habe schon probiert, mit: if(car==0b00000001)... abzufragen, aber auch das geht nicht. wo ist das problem? wieso konvertiert er mir nicht meine variable "car"? grüße peter müller
war ein denkfehler: die eingänge sind ja invertiert... damit gings jetzt: while (1) { // if(PINB!=0xFF){ delay_ms(1); if(PINB!=0xFF){ //car=PINB; if(PINB==0x7F){car = 0x08;} if(PINB==0xBF){car = 0x07;} if(PINB==0xDF){car = 0x06;} if(PINB==0xEF){car = 0x05;} if(PINB==0xF7){car = 0x04;} if(PINB==0xFB){car = 0x03;} if(PINB==0xFD){car = 0x02;} if(PINB==0xFE){car = 0x01;} putchar(car); PORTA=car; delay_ms(1000); } } PORTA=0x00; } }
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.