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


von Rush .. (rush)


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?

von Entwickler (Gast)


Lesenswert?

>Jemand eine Ahnung woran sowas liegen könnte?

Das liegt an Deinem Programm.

von Chris L. (kingkernel)


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!

von Michael (Gast)


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?

von Rush .. (rush)


Angehängte Dateien:

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.

von Entwickler (Gast)


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.

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


Lesenswert?

Rush ... schrieb:
> Habe den Code mal dran gehängt.
Böse Sache, das:
1
ISR (INT1_vect)
2
{
3
  _delay_ms(500);
4
  :

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

von Chris L. (kingkernel)


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!

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


Lesenswert?

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

von Chris L. (kingkernel)


Lesenswert?

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

von Rush .. (rush)


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:
1
#include <avr/io.h>
2
#include "usart.h"
3
4
#define BAUD 9600UL      // Baudrate
5
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
6
7
8
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate
9
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD)      // Fehler in Promille, 1000 = kein Fehler.
10
11
#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
12
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
13
#endif
14
15
16
void USART_INIT(void)
17
{
18
  UBRR0 = UBRR_VAL;
19
  
20
  USART_UCSRB |= (1 << USART_TXEN) | (1<<USART_RXEN) | (1<<USART_RXCIE);
21
  USART_UCSRC |= ((1 << UCSZ00) | (UCSZ01));    // muss außer der des Headerfiles angepasst werden
22
}
23
24
void writeChar(unsigned char c)
25
{
26
  while (!(USART_UCSRA & (1<<USART_UDRE)));
27
    USART_UDR = c ;
28
}
29
30
31
uint8_t uart_getc(void)
32
{
33
    while (!(USART_UCSRA & (1<<USART_RXC)));   // warten bis Zeichen verfuegbar
34
    return USART_UDR;                          // Zeichen aus UDR an Aufrufer zurueckgeben
35
}

von Michael (Gast)


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.

von Rush .. (rush)


Lesenswert?

und die uart.h
1
void USART_INIT(void);
2
void writeChar(unsigned char c);
3
uint8_t uart_getc(void);
4
5
#define USART_BAUD_RATE  9600
6
#define USART_UBRRH    UBRR0H
7
#define USART_UBRRL    UBRR0L
8
#define USART_UCSRB    UCSR0B
9
#define USART_UCSRC    UCSR0C
10
#define USART_UCSRA    UCSR0A
11
#define USART_UDRE    UDRE0
12
#define USART_UDR    UDR0
13
#define USART_TXEN    TXEN0
14
#define USART_RXEN    RXEN0
15
#define USART_RXC    RXC0
16
#define USART_RXCIE    RXCIE0

von Michael (Gast)


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.

von Chris L. (kingkernel)


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.

von Rush .. (rush)


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.

von Rush .. (rush)


Lesenswert?

Die ISR steht doch drin:
1
ISR (USART_RX_vect)
2
{
3
  rx[rx_i] = uart_getc();
4
5
    if(rx[rx_i] == '|')
6
    {
7
      rx_valid_command = 1;
8
    }
9
  
10
  rx_i++;
11
  
12
  
13
}

von Rush .. (rush)


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.

von Chris L. (kingkernel)


Lesenswert?

ja, sorry. war untergegangen, ist einfach noch zu früh

von Chris L. (kingkernel)


Lesenswert?

1
ISR (USART_RX_vect)
2
{
3
  rx[rx_i] = uart_getc();
4
5
    if(rx[rx_i] == '|')
6
    {
7
      rx_valid_command = 1;
8
    }
9
  
10
  rx_i++;
11
}

wenn der interrupt auslöst, steht das zeichen schon bereit und du kannst 
es direkt abgreifen. ich würde es so machen:
1
ISR (USART_RX_vect)
2
{
3
  rx[rx_i] = UDR;
4
5
  if(rx[rx_i] == '|')
6
  {
7
    rx_valid_command = 1;
8
  }
9
10
  rx_i++;
11
}

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!

von Rush .. (rush)


Lesenswert?

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

von hans (Gast)


Lesenswert?

lad dir die uart bibliothek von peter fleury runter udn fertig ist der 
lack^^

von Rush .. (rush)


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.

von Chris L. (kingkernel)


Lesenswert?

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

von Rush .. (rush)


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.

von Chris L. (kingkernel)


Lesenswert?

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

von Rush .. (rush)


Lesenswert?

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

von Chris L. (kingkernel)


Lesenswert?

hehe, sitz auch grad in einer vorlesung

von Karl H. (kbuchegg)


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.

von Rush .. (rush)


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.

von Rush .. (rush)


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

von Karl H. (kbuchegg)


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.

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.