mikrocontroller.net

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


Autor: Mike (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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:
char buffer[30];  // array for output-values
:
   sprintf(buffer,"testx: %i\n\t",testx);  // output test variable 
   uart_puts(buffer);                      // and send it to uart

Autor: Mike (Gast)
Datum:

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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

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

Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?!?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wozu soll das
ISR(TIMER1_OVF_vect)        // 16 bit timer ISR
{
 TIMSK &= (1 << TOIE1);        // clear timer overflow interrupt bit 
 inter++;          // increment variable for 1second interrupt
}
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum bürdest du deinem µC hier
void uart_puts(const char *name )    // send string over uart
{
  int c = 1;
  
  while (c)                 
  {
einen Zwischenschritt über 16 Bit Arithmetik auf?
void uart_puts(const char *name )    // send string over uart
{
  int c = 1;
  
  while (c)                 
  {
    c = *name++;        
    
    if (c == 10)
    send_uart(13);        
    send_uart(c);                     
  }
}

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

void uart_puts(const char *name )    // send string through uart
{
  while( *name )
    send_uart( *name++ );
}

void send_uart(unsigned char data)
{
  if( data == '\n' )   // preceed New Line with a Carriage Return
    send_uart( '\r' );

  while(!(UCSRA & (1 << UDRE)))
  {
  }                    // wait for transmit buffer empty

  UDR = data;          // 1Byte into UART data register
}

Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

:(

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann würde ich an deiner Stelle hier ansetzen
   PORTB ^= (1 << LED1);      // LED1 an PB1 an-/ausschalten
   startmagnetismus();        // readout the sensor

   testx = sign12(puzzle_x);      // get 12bit from x-axis
   testy = sign12(puzzle_y);      // get 12bit from y-axis
   testz = sign12(puzzle_z);      // get 12bit from z-axis

   arcx = (double) testx;      // typecast x-avlue to calculate atan2
   arcy = (double) testy;      // typecast y-value ..
   kurs = atan2(arcx,arcy)/PI*180;    // calculate heading by atan2 (so result is also possible if
            // 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
void uart_puti( int number )
{
  char buffer[20];
  itoa( number, buffer, 20 );
  uart_puts( buffer );
  uart_puts( "\n" );
}

void uart_debug( const char* text, int number )
{
  uart_puts( text );
  uart_puts( " " );
  uart_puti( number );
  uart_puts( "\n" );
}

schreiben.
Mit dieser Hilfsfunktion ist es dann zb einfach, in den Programmcode 
Zwischenausgaben einzufügen.
zb
   PORTB ^= (1 << LED1);      // LED1 an PB1 an-/ausschalten
   startmagnetismus();        // readout the sensor

   uart_debug( "Vor sign12 X:", testx );
   uart_debug( "Vor sign12 Y:", testy );
   uart_debug( "Vor sign12 Z:", testz );

   testx = sign12(puzzle_x);      // get 12bit from x-axis
   testy = sign12(puzzle_y);      // get 12bit from y-axis
   testz = sign12(puzzle_z);      // get 12bit from z-axis

   uart_debug( "Nach sign12 X:", testx );
   uart_debug( "Nach sign12 Y:", testy );
   uart_debug( "Nach sign12 Z:", testz );

   arcx = (double) testx;      // typecast x-avlue to calculate atan2
   arcy = (double) testy;      // typecast y-value ..
   kurs = atan2(arcx,arcy)/PI*180;    // calculate heading by atan2 (so result is also possible if
            // 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.