Forum: Compiler & IDEs Ideensuche für getriggerte Zwischenzeitmessung


von Peter Müller (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

> 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.

von peter dannegger (Gast)


Lesenswert?

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

von Peter Müller (Gast)


Lesenswert?

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?

von Peter Müller (Gast)


Lesenswert?

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?

von Peter Müller (Gast)


Angehängte Dateien:

Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Peter Müller (Gast)


Lesenswert?

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?

von peter dannegger (Gast)


Lesenswert?

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

von Peter Müller (Gast)


Lesenswert?

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!

von Peter Müller (Gast)


Lesenswert?

ich meine damit gerade das konvertieren in nen string und auf der
gegenseite wieder das zusammensetzen!

von Peter Müller (Gast)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Peter Müller (Gast)


Lesenswert?

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.

von Peter Müller (Gast)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

> 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.

von Peter Müller (Gast)


Lesenswert?

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

von Peter Müller (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.