www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ATMega88 UART nimmt erst zweites Zeichen an


Autor: Rush ... (rush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe für die Hochschule einen Datenlogger auf Basis eines ATMega88 
programmiert. Dieser soll, wenn er ein "R|" über den UART empfängt, die 
im externen EEPROM abgelegten Daten per UART rausschicken. Im Grunde 
funktioniert das ganze. Problem ist allerding:

Beim Erstmaligem Auslesen muss ich die oben genannte Zeichenkette zwei 
mal schicken damit ich die Messdaten bekomme. Das erste "R|" wird 
einfach igoniriert. Die Daten kommen eben erst beim zweiten "R|".

Möchte ich das EEPROM ein zweites mal auslesen, so genügt ein einziges 
"R|", was ja auch richtig ist.

Jemand eine Ahnung woran sowas liegen könnte?

Autor: Entwickler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Jemand eine Ahnung woran sowas liegen könnte?

Das liegt an Deinem Programm.

Autor: Chris L. (kingkernel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kannst du debuggen? wie hast du den uart/usart implementiert? (isr, 
polling)
zeig mal den code und am besten auch den schaltplan, ohne diese 
grundlegenden dinge können wir auch nur raten!

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rush ... schrieb:
> Jemand eine Ahnung woran sowas liegen könnte?

Ich würde, ohne den Programmcode nun konkret gesehen zu haben, sagen, 
dass du den UART nicht ausreichen initialisiert hast. Simulier das Ganze 
doch mal im Simulator des AVR-Studios und schau da wo es beim ersten Mal 
hängt?

Autor: Rush ... (rush)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Richtig initialisiert sollte er eigentlich sein, denn die Zeichen werden 
korrekt übertragen.
Hab mir einfach mal das zurückschicken lassen was ich hinteschickt habe.

Habe den Code mal dran gehängt.

Autor: Entwickler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich sag es ja ungern, aber Deine ISR (INT0_vect)
ist sch...
Mit den Aktionen wie "delay(20ms)" und weiteren EEPROM Schreibaktionen, 
wird dem µC der Interrupt lange Zeit voll gesperrt. Da können keine 
anderen Interrupts durchkommen.

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

Bewertung
0 lesenswert
nicht lesenswert
Rush ... schrieb:
> Habe den Code mal dran gehängt.
Böse Sache, das:
ISR (INT1_vect)
{
  _delay_ms(500);
  :

Sieh einen Interrupt wie die Haustürklingel: wenn du da einen Topf mit 
Milch auf dem Herd hast, dann fertigst du den Postboten an der Haustür 
am besten möglichst schnell ab...

Autor: Chris L. (kingkernel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schmeiß als ersten mal die _delay_ms in den ISR's raus. Eine ISR sollte 
so langsam wir möglich sein, da du sonst den rest deines programms 
komplett blockierst.
und wenn du ein problem mit dem usart hast, solltest du uns schon noch 
die usart.h und die usart.c geben!

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

Bewertung
0 lesenswert
nicht lesenswert
Christian L. schrieb:
> Eine ISR sollte so langsam wir möglich sein...
Sicher?

Autor: Chris L. (kingkernel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, wollte es grad editieren, da kam dein Beitrag dazwischen. Ich 
meine natrülich so kurz wie möglich!!

Autor: Rush ... (rush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, nur kurz zum verständnis.
an dem INT0 hängt mein RTC dran der in dem angegebenen Intervall einen 
Interrupt auslöst und somit die Messung startet. Das delay kommt noch 
weg.
Der INT1 wird ausgelöst, nachdem ich meinen Stecker für den UART 
angeschlossen habe. Und in dieser ISR wird INT0 deaktiviert. Von daher 
dürfte das delay in der ISR INT0 nicht von Bedeutung sein.

Hier nochmal die Initialisierung des UARTS:
#include <avr/io.h>
#include "usart.h"

#define BAUD 9600UL      // Baudrate
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden


#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD)      // Fehler in Promille, 1000 = kein Fehler.

#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
#endif


void USART_INIT(void)
{
  UBRR0 = UBRR_VAL;
  
  USART_UCSRB |= (1 << USART_TXEN) | (1<<USART_RXEN) | (1<<USART_RXCIE);
  USART_UCSRC |= ((1 << UCSZ00) | (UCSZ01));    // muss außer der des Headerfiles angepasst werden
}

void writeChar(unsigned char c)
{
  while (!(USART_UCSRA & (1<<USART_UDRE)));
    USART_UDR = c ;
}


uint8_t uart_getc(void)
{
    while (!(USART_UCSRA & (1<<USART_RXC)));   // warten bis Zeichen verfuegbar
    return USART_UDR;                          // Zeichen aus UDR an Aufrufer zurueckgeben
}





Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es mag eine dumme Frage sein aber warum wartest du nach Eintreten des 
ISR 20ms (500!!! ms)? Welchen Sinn hat das denn? Und bei deinem UART 
fragst du auch nicht ob ein 'R|' kam sondern lediglich nach '|'. 
Initialisiert wird er richtig sein, nutzt ja die AVR-Bibliothek dafür. 
Wie gesagt, schau mal wo der Simulator dir sagt, dass es hängt und 
klemmt.

Autor: Rush ... (rush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
und die uart.h
void USART_INIT(void);
void writeChar(unsigned char c);
uint8_t uart_getc(void);

#define USART_BAUD_RATE  9600
#define USART_UBRRH    UBRR0H
#define USART_UBRRL    UBRR0L
#define USART_UCSRB    UCSR0B
#define USART_UCSRC    UCSR0C
#define USART_UCSRA    UCSR0A
#define USART_UDRE    UDRE0
#define USART_UDR    UDR0
#define USART_TXEN    TXEN0
#define USART_RXEN    RXEN0
#define USART_RXC    RXC0
#define USART_RXCIE    RXCIE0

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achja, was mir noch auffällt: Ich kann auf Anhieb in den ISRs nicht 
sehen, dass du die Interrupts deaktivierst....ist das gewollt? In 20ms 
(500ms) kann ne Menge passieren.

Autor: Chris L. (kingkernel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ähm...

du hast den usart-interrupt per RXCIE eingeschaltet, aber keine 
entsprechende IST drin. mich wundert, dass das überhaupt geht. einen 
aktivierten interrupt ohne entsprechende ISR bringt den AVR dazu, zu 
resetten.

Autor: Rush ... (rush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die lezte konfiguration war so gewesen, dass der Controller im Powerdown 
war, über den INT0 aufgeweckt wurde, dann wurde die Messung gemacht.

Laut Tutorial und Datenblatt kann man den Controll in diesem Modus nicht 
flankengesteuert sondern  nur levelgesteuert aus dem Powerdown holen.

Durch den Interrupt vom RTC wurde die Routine aber mehrmals durchlaufen. 
Deswegen hatte ich als Provisorium das Delay mit reingeschrieben.

Und das 500ms delay in der INT1 habe ich schon rausgeschmissen, ändert 
aber nichts an der Problematik.

Autor: Rush ... (rush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die ISR steht doch drin:
ISR (USART_RX_vect)
{
  rx[rx_i] = uart_getc();

    if(rx[rx_i] == '|')
    {
      rx_valid_command = 1;
    }
  
  rx_i++;
  
  
}

Autor: Rush ... (rush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Michael

Das | dient nur als Abschlusszeichen und gehört nicht zum eigentlichen 
Befehl.

Hier wird nur überprüft ob die Zeichen komplett sind und dann 
rx_valid_command auf 1 gesetzt. Diese 1 wird unten in der main 
abgefragt.

Autor: Chris L. (kingkernel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja, sorry. war untergegangen, ist einfach noch zu früh

Autor: Chris L. (kingkernel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ISR (USART_RX_vect)
{
  rx[rx_i] = uart_getc();

    if(rx[rx_i] == '|')
    {
      rx_valid_command = 1;
    }
  
  rx_i++;
}

wenn der interrupt auslöst, steht das zeichen schon bereit und du kannst 
es direkt abgreifen. ich würde es so machen:
ISR (USART_RX_vect)
{
  rx[rx_i] = UDR;

  if(rx[rx_i] == '|')
  {
    rx_valid_command = 1;
  }

  rx_i++;
}

ansonsten schmeiß mal den rest des codes, der nix mit den usart zu tun 
hat raus und kümmre dich nur um den usart, um sicherzustellen, das der 
erstmal läuft und nix anderes dazwischen funkt
toogle in der isr mal nen freien portpin, um zu schaun, ob er beim 
erstmaligen senden des befehls überhaupt die isr anspringt
[EDIT]Sorry, für den Doppelpost!

Autor: Rush ... (rush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hm, wäre aber doch im prinzip das selbe denn meine Funktion gibt ja auch 
nur das UDR register zurück. oder nicht ?

Autor: hans (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
lad dir die uart bibliothek von peter fleury runter udn fertig ist der 
lack^^

Autor: Rush ... (rush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Er schein beim ersten zeichen garnicht den interrupt aus zu lösen. Denn 
habe alles in der ISR mal auskommentiert und nur das Zeichen 
zurückschicken lassen was angekommen ist. Da kommt es beim ersten mal 
auch nicht zurück.

ist ja gut zu wissen, nur wie zu lösen?
mir fällt einfach nichts mehr ein warum es beim ersten mal nicht geht 
und sonst aber immer.

Autor: Chris L. (kingkernel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sicher, dass das erste Zeichen überhaupt am Portpin des USART ankommt, 
beziehnungsweise dass dein PC überhaupt sendet?

Autor: Rush ... (rush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Senden tut er auf alle fälle. ich sehe es an der TX led vom 
RS232-Wandler (FT232RL).
Ich nehme an es kommt auch an wenns schon raus ist.

Autor: Chris L. (kingkernel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und er springt nicht in die ISR? Schalt mal nen Portpin um, wenn die ISR 
angesprungen wird, um sicher zu gehen.

Autor: Rush ... (rush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
alles klar, werd ich mal versuchen. nach der nächsten vorlesung ;-)

Autor: Chris L. (kingkernel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hehe, sitz auch grad in einer vorlesung

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

Bewertung
0 lesenswert
nicht lesenswert
> Der INT1 wird ausgelöst, nachdem ich meinen Stecker für den UART
> angeschlossen habe.

Wie genau ist das zu verstehen?
Steckst du die UART ein/aus?
Ist das in deinem jetzigen Testcode noch relevant?

Mach deine Tests so einfach wie möglich. Ohne irgendwelche Sonderfälle 
oder Spezialzuckerl.

Zeichn kommt rein - Zeichen wird zurückgeschickt. Alles andere fliegt 
aus dem Testcode raus. Und zwar wirklich: fliegt raus. Nicht "dürfte gar 
nicht mehr aufgerufen werden" oder "hat eh keinen Effekt", sondern 
"fliegt raus".

Alternativ: neues Programm anfangen und von 0 an beginnend aufbauen. Das 
ist schneller gemacht, als das vorhandene abzuspecken.

Autor: Rush ... (rush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja du verstehst schon richtig. Im fertigen Zustand soll das Einstecke 
des UARTs das Aufwachen des Controllers und das Stoppen der Messung 
bewirken. Außerdem wird noch Konfigurationsmöglichket per UART 
relaisiert werden.

Autor: Rush ... (rush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ehm mir ist was ganz anderes aufgefallen. Undzwar das die LED am Wandler 
ab und an mal blinkt obwohl ich nichts über den Port schicke.
Habe mal einen Logic Analyzer an den Controller gehangen und gesehen 
dass in regelmäßigen Zeitabständen immer das selbe ankommt. Nur was 
könnte das sein? Normalerweise kommt doch  nichts über den Port wenn ich 
nicht wirklich was sende...

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

Bewertung
0 lesenswert
nicht lesenswert
Rush ... schrieb:
> ja du verstehst schon richtig. Im fertigen Zustand soll das Einstecke
> des UARTs das Aufwachen des Controllers und das Stoppen der Messung
> bewirken. Außerdem wird noch Konfigurationsmöglichket per UART
> relaisiert werden.

Ich frage deshalb, weil es beim Einstecken eines Steckers schon mal zu 
Knacksern auf den Leitungen kommt. Die UART interpretiert die aber als 
den Beginn einer Übertragung und macht ein Zeichen daraus, welches dem 
Empfängercode dann zugeführt wird. Mit diesem  falschen, zufälligem 
Zeichen muss der klar kommen.

Daher hat man oft auch ein einleitendes Zeichen in einer Übertragung. 
Der Empfänger ignoriert alles, bis er dieses Zeichen sieht.

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.