Forum: Mikrocontroller und Digitale Elektronik Problem while-Schleife durch UART


von Mike (Gast)


Angehängte Dateien:

Lesenswert?

Hallo.

Hab ein Programm geschrieben,dass per Timer-Interrupt ca. aller 1Sekunde 
die Daten eines Sensors über I2C einliest und diese dann mittels UART an 
den PC überträgt (Ausgabe auf HyperTerminal).Wenn der Interrupt nach 
dieser Sekunde ausgelöst wird,zeigt es mir dies durch toggeln einer LED.
Ich benutze einen Atmega16,STK500,JTAGICE mkII

Nun zum Problem:

Bei Nutzung von sprintf innerhalb der Programmschleife gibt mir 
HyperTerminal verlässliche Werte aus.Das Problem dabei ist aber,dass 
meine while(1)-Schleife verlassen wird und somit z.B. der UART oder 
Timer jedesmal neu initialisiert wird.

Nutze ich innerhalb der Programmschleife keine UART-Funktion (somit auch 
keine Ausgabe auf HyperTerminal möglich),dann verlässt das Programm zwar 
die while(1)-Schleife nicht,demzufolge wird auch nicht ständig neu 
initialisier(UART,Timer),dafür kommen dann aber über die 
I2c-Schnittstelle komische Werte vom Sensor an!(teilweise liest er die 
Datenregister mit "0" aus).

Woran kann das liegen?

Anbei mein Programm-Code.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

>> char buffer1[10],buffer2[10],buffer3[10];  // array for output-values
Ist das nicht ein bisschen wenig???

EDIT:
warum eigentlich 3 Puffer, wenn du sowieso alles nacheinander machst?
Nimm besser 1 Puffer mit ausreichender Länge:
1
char buffer[30];  // array for output-values
2
:
3
   sprintf(buffer,"testx: %i\n\t",testx);  // output test variable 
4
   uart_puts(buffer);                      // and send it to uart

von Mike (Gast)


Lesenswert?

Du hast natürlich recht.Ist viel sinnvoller mit einem Puffer.
Trotzdem bleibt noch das besagte Problem bestehen! ;-)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Ist viel sinnvoller mit einem Puffer.
Und der ist jetzt groß genug?

von Mike (Gast)


Lesenswert?

Ja ist er.Hab ihn jetz bei buffer[50].
In der uart_init() hab das TXCIE-Bit im UCSRB-Register wieder gelöscht 
und siehe da: die while(1)-Schleife wird nicht mehr verlassen und die 
LED blinkt demzufolge in meinem eingestellten Intervall.

Allerdings spinnen die Sensorwerte immer noch,da sie wie schon vorher 
beschrieben teilweise leere Datenregister ausgeben.
Da ich den Sensor aber auch schon an einem Fujitsu-Board dran hatte und 
dies dort nicht der Fall war,muss es einen bestimmten Grund dafür 
geben?!?

von Karl H. (kbuchegg)


Lesenswert?

Wo ist eigentlich deine Transmit-ISR?
Du hast zwar den Interrupt aktiviert aber anscheinend keine ISR dafür -> 
die Runtime Lib sorgst in so einem Fall dafür, dass der µC resettet 
wird.

von Karl H. (kbuchegg)


Lesenswert?

Wozu soll das
1
ISR(TIMER1_OVF_vect)        // 16 bit timer ISR
2
{
3
 TIMSK &= (1 << TOIE1);        // clear timer overflow interrupt bit 
4
 inter++;          // increment variable for 1second interrupt
5
}
gut sein?

Du deaktivierst innerhalb der Overflow ISR den Overflow. Ich sehe aber 
innerhalb deiner Schleife nicht, wie dieser Overflow jemals wieder 
aktiviert werden könnte.

Du künstelst mir da insgesamt ein wenig zu sehr mit den Interrupt Bits 
rum. Im Regelfall funktioniert das so: Die Interrupts werden in der 
Initialisierungsphase des Programms auf die gewünschten Werte 
eingestellt und während der Bearbeitung muss man sie nicht mehr 
angreifen, weil alles seinen Weg geht. Es gibt natürlich Ausnahmen, das 
ist klar (Umkonfigurieren von fallender Flanke auf steigende Flanke, 
UART mit Ausgabepuffer in Interruptbetrieb, etc) aber bei dir scheint 
nichts davon der Fall zu sein.

von Karl H. (kbuchegg)


Lesenswert?

Warum bürdest du deinem µC hier
1
void uart_puts(const char *name )    // send string over uart
2
{
3
  int c = 1;
4
  
5
  while (c)                 
6
  {
einen Zwischenschritt über 16 Bit Arithmetik auf?
1
void uart_puts(const char *name )    // send string over uart
2
{
3
  int c = 1;
4
  
5
  while (c)                 
6
  {
7
    c = *name++;        
8
    
9
    if (c == 10)
10
    send_uart(13);        
11
    send_uart(c);                     
12
  }
13
}

Das ist insgesamt unklug. Bei Strings wird also für einen Line Feed noch 
ein Carriage Return vorangestellt. Das ist ja grundsätzlich so ok. Aber 
wäre es nicht besser diese Funktionalität in die send_uart zu 
verfrachten? Dann würde nämlich dieser Automatismus auch dann 
funktionieren, wenn jemand einen einzelnen Line Feed ausgeben muss. (Und 
verwende doch bitte die C-Schreibweise für Sonderzeichen. Dann muss man 
nicht ständig eine ASCII Tabelle daneben liegen haben um zu wissen von 
welchem Zeichen hier die Rede ist)

Das geht natürlich nur dann, wenn du nur textuelle Übertragung machst. 
Sobald binäre Übertragung im Spiel ist, soll die send_uart nur das 
machen was auch drauf steht: In Byte verschicken. Ev. wäre es besser da 
noch eine 3. Funktion ins Spiel zu bringen
 * send_uart           Basisfunktion. Verschickt ein Byte so wie
                       Gott das gewollt hat
 * uart_putc           Verschickt ein ASCII Zeichen. Macht die
                       \n -> \r\n
                       Erweiterung
 * uart_puts           Verschickt einen String via uart_putc

1
void uart_puts(const char *name )    // send string through uart
2
{
3
  while( *name )
4
    send_uart( *name++ );
5
}
6
7
void send_uart(unsigned char data)
8
{
9
  if( data == '\n' )   // preceed New Line with a Carriage Return
10
    send_uart( '\r' );
11
12
  while(!(UCSRA & (1 << UDRE)))
13
  {
14
  }                    // wait for transmit buffer empty
15
16
  UDR = data;          // 1Byte into UART data register
17
}

von Mike (Gast)


Lesenswert?

> TIMSK &= (1 << TOIE1);

Recht hast du.Das ist Unsinn. :)
Auch das mit den uart-Funktionen leuchtet ein.Danke für deine Hilfe 
bisher.

Trotzdem bleibt der Fehler weiterhin bestehen,dass die Sensorwerte 
irrsinnig sind.

:(

von Karl H. (kbuchegg)


Lesenswert?

Dann würde ich an deiner Stelle hier ansetzen
1
   PORTB ^= (1 << LED1);      // LED1 an PB1 an-/ausschalten
2
   startmagnetismus();        // readout the sensor
3
4
   testx = sign12(puzzle_x);      // get 12bit from x-axis
5
   testy = sign12(puzzle_y);      // get 12bit from y-axis
6
   testz = sign12(puzzle_z);      // get 12bit from z-axis
7
8
   arcx = (double) testx;      // typecast x-avlue to calculate atan2
9
   arcy = (double) testy;      // typecast y-value ..
10
   kurs = atan2(arcx,arcy)/PI*180;    // calculate heading by atan2 (so result is also possible if
11
            // x = 0 or y = 0)

und die Werte für testx, testy und testz mit bekannten Werten fix 
besetzen und erst mal nachsehen ob die Ausgabekette bis zum 
Hyperterminal den Fehler verursacht.

WEnn gesichert ist, dass das fehlerfrei funktioniert (auch die sign12 
Funktion), kann der Fehler nur noch irgendwo in startmagnetismus() 
stecken :-)

Sukzessive eine Fehlerquelle nach der anderen ausschliessen.
Angefangen wird immer bei den Ausgabefunktionen. Die müssen als erstes 
getestet werden, denn sie sind deine einzige Möglichkeit Einblick in die 
Porgrammfunktion zu gelangen.

Ich würde mir an deiner Stelle auch eine Funktion
1
void uart_puti( int number )
2
{
3
  char buffer[20];
4
  itoa( number, buffer, 20 );
5
  uart_puts( buffer );
6
  uart_puts( "\n" );
7
}
8
9
void uart_debug( const char* text, int number )
10
{
11
  uart_puts( text );
12
  uart_puts( " " );
13
  uart_puti( number );
14
  uart_puts( "\n" );
15
}

schreiben.
Mit dieser Hilfsfunktion ist es dann zb einfach, in den Programmcode 
Zwischenausgaben einzufügen.
zb
1
   PORTB ^= (1 << LED1);      // LED1 an PB1 an-/ausschalten
2
   startmagnetismus();        // readout the sensor
3
4
   uart_debug( "Vor sign12 X:", testx );
5
   uart_debug( "Vor sign12 Y:", testy );
6
   uart_debug( "Vor sign12 Z:", testz );
7
8
   testx = sign12(puzzle_x);      // get 12bit from x-axis
9
   testy = sign12(puzzle_y);      // get 12bit from y-axis
10
   testz = sign12(puzzle_z);      // get 12bit from z-axis
11
12
   uart_debug( "Nach sign12 X:", testx );
13
   uart_debug( "Nach sign12 Y:", testy );
14
   uart_debug( "Nach sign12 Z:", testz );
15
16
   arcx = (double) testx;      // typecast x-avlue to calculate atan2
17
   arcy = (double) testy;      // typecast y-value ..
18
   kurs = atan2(arcx,arcy)/PI*180;    // calculate heading by atan2 (so result is also possible if
19
            // x = 0 or y = 0)


wenn du keine Hilfsmittel zum debuggen hast, dann musst du dir eben 
selbst welche machen! Ziel ist es, auf der UART Texte und Zahlen 
ausgeben zu können, so dass du mit dieser Mitschrift mitverfolgen 
kannst, was im Programm passiert, welche Werte woher kommen etc.
Dazu muss die UART Ausgabe unter allen Umständen funktionieren und 
deshalb wird die als erstes getestet und fehlerfrei gemacht.

Systematisch vorgehen!
Vergiss, dass es auf einem anderen Board schon funktioniert hat. Das 
interessiert hier nicht. Du bist jetzt auf diesem Board und da fängst du 
bei 0 an. Nimm nichts als funktionierend an und nimm eine Komponente 
nach der anderen in Betrieb. In der Reihenfolge so dass du auf eine 
jeweils getestete Komponente aufbauen kannst.
Nicht raten, sondern Fakten schaffen. Im Programm Zwischenergebnisse 
ausgeben lassen, so dass du aus den Zwischenergebnissen Rückschlüsse 
ziehen kannst. Dann hört das Raten auf was das Problem sein könnte und 
du fängst an, am Problem zu arbeiten.
Ergänze das Programm mit Ausgaben zwischendrinn, so dass dir das 
Programm selber hilft, Fehler im Programm zu finden. Wenn dann alles 
läuft, kann man diese Ausgaben immer noch entfernen. Aber besser jetzt 3 
Minuten für ein paar Hilfsfunktionen investieren als 3 Stunden 
Rätselraten.

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.