Forum: Mikrocontroller und Digitale Elektronik ATMega32 UART Empfang stört Timing


von Volker (Gast)


Lesenswert?

Hallo zusammen,
ich hab hier schon gesucht aber nix gefunden was zu meinem Problem 
passt.
Nachdem ich schon eine Weile herumexperimentiert hab, hab ich mein 
Problem auf das wesentlichste reduziert.
Ich habe einen einfachen Testaufbau gemacht.
ATMega32 mit 16Mhz Quartz, dessen UART Eingang (RX) über einen MAX232 an 
meinem PC hängt.
Dann zu Testzwecken eine LED mit Widerstand an einen Pin von Port C.
Ich habe ein kleines Testprogramm geschrieben das im Hauptteil PORTC auf 
Ausgang schaltet, den UART initialisiert (9600Baud) und in einer 
Endlosschleife nachfragt ob ein Byte angekommen ist, es evtl. ausliest 
und dann PORT C auf 0xff setzt  und nach kurzer Zeit wieder auf 0x00.
Mein Oszi sagt mir: PORTC ist für ca 12us auf high und dann kurz (ca. 
2.5us) auf low.
Da am PORTC eine LED hängt leuchtet diese auch wie erwartet (konstant 
Hell).
Iss halt ne Art PWM.

Jetzt sendet ein Programm auf meinem PC irgendwelche Daten an den 
ATMega.
Mein Oszi sagt mir das der Spannugsverlauf auf PORTC ziemlich 
unregelmäßig wird.
Es kommt tatsächlich vor das die LED für kurze Zeit (1/4 sec) ausgeht.
Das irritiert mich. Der UART scheint sich massiv auf das Timing des 
Programmablauf auszuwirken.
Folgendes hab ich probiert:
UART komplett gar nicht initialisiert und nur PORTC an/aus in einer main 
while Schleife.
PORTC an/aus in einer Interruptroutine, UART empfang in main.
Ist dem ATMega völlig egal. Sobald der UART irgendwas empfängt, flackert 
die LED = die PWM auf PORTC kommt völlig durcheinander.
Anbei mein auf das wesentlichste reduzierter code. Ich hoffe es hat 
jemand ne Idee?

Tausend Dank
Volker

#include <avr/io.h>

#define F_CPU 16000000UL  // 16MHz
#define BAUD 9600UL      // Baudrate

// Berechnungen
#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

volatile unsigned char received ;


void uart_init(void)
{
    UBRRH = UBRR_VAL >> 8;             // Wie oben berechnet
    UBRRL = UBRR_VAL & 0xFF;// Wie oben berechnet
    UCSRB = (1<<RXEN) | (1<<TXEN) ;            // UART RX einschalten
    UCSRC = (1<<UCSZ1)|(1<<UCSZ0) |(1<<URSEL);  // Asynchron 8N1
}

void indicateAction(void)
{
  int wait ;
  PORTC = 0b11111111 ;
  // just to wait a bit
  for (wait = 0 ; wait < 10 ; ++wait) ;
  PORTC = 0b00000000 ;
}

int main()
{
  DDRC = 0xFF; // PORTC Ausgang
  uart_init();
  while (1)
    {
    if (!(UCSRA & (1<<RXC)))
    {
      // no character
    }
    else
    {
      received = UDR ;
    }
    indicateAction() ;
    }
}

von Volker (Gast)


Lesenswert?

Als Nachtrag vielleicht noch:
Warum das Ganze?
Plan ist in einer ISR eine LED Matrix per PWM zu steuern.
Die Daten dafür kommen per RS232 vom PC und werden in der main methode 
in einer Schleife aus dem UART gelsen und für die ISR zur Anzeige 
aufbereitet.
Leider wird die ISR duch die UART Empfangsaktivitäten derart gestört das 
die Anzeige inakzeptabel flackert.

von Karl H. (kbuchegg)


Lesenswert?

> Es kommt tatsächlich vor das die LED für kurze Zeit (1/4 sec) ausgeht.
> Das irritiert mich. Der UART scheint sich massiv auf das Timing des
> Programmablauf auszuwirken.

1/4 Sekunde? Mit dem Code?

Das ist zu viel. Viel zu viel. Ich denke du hast ein Hardwareproblem. 
Wie sieht deine Schaltung aus? Abblockkondensatoren an der 
Versorgungsspannung?

Mega32 und PORTC: JTAG ist abgeschaltet?

von Volker (Gast)


Lesenswert?

Danke für die Tipps.
JTAG ist aus.
100uF und 100nF an Vcc, GND direkt vor'm ATMega. MAX232 mit 5x1uF wie es 
"alle" machen.
Analog AGND, AVCC hatte ich nicht angeschlossen. Jetzt schon. Hilft auch 
nix.
ISP Steckplatz am ATMega angeschlossen, aber kein ISP dran.

Was ich natürlich frech verschwiegen habe...
Ich habe hier einen Testaufbau auf einer Experimentier-Steckplatine, 
aber nachdem das mit der PWM LED ohne UART so schon ausgesehen hat, 
frage ich mich ob das mit UART das Problem sein kann?

Evtl. muß ich in den sauren Apfel beißen und doch mal ne 
Testlochrasterplatine löten.

Falls Du noch sachdienliche Hinweise zum Ergreifen des Täters hast... 
wäre ich dankbar.

Gruß
Volker

von Volker (Gast)


Lesenswert?

Ach ja, habe auch schon 2 ATMega ausprobiert. Identischer Effekt.

von Karl H. (kbuchegg)


Lesenswert?

Volker schrieb:

> Was ich natürlich frech verschwiegen habe...
> Ich habe hier einen Testaufbau auf einer Experimentier-Steckplatine,
> aber nachdem das mit der PWM LED ohne UART so schon ausgesehen hat,
> frage ich mich ob das mit UART das Problem sein kann?

Glaub ich nicht.
Kannst ja mal folgendes probieren:

am Anfang in main() schaltest du eine LED in einem bestimmten Muster 
ein/aus. Das Muster an sich ist egal, du musst es nur eindeutig 
wiedererkennen können.
Wenn meine Hypothese stimmt, dann hast du sporadische Resets, die den 
Controller resetten. Sprich: dein Programm läuft immer wieder von vorne 
an. Das ausgegebene Muster auf der LED am Programmanfang würde dir das 
zeigen.

von cskulkw (Gast)


Lesenswert?

Hallo Volker,

Dein Code oben pollt nur. Habe ich das richtig verstanden, dass Dein 
Timing nur bei der RX-ISR aus dem Tritt kommt?

Benutzt Du eine ISR für das asynchrone Empfangen eines Zeichnens über 
die UART?

Wenn ja, solltest Du Dir angewöhnen nach dem Eintreten in eine 
Interrupt-Service-Routine das allgemeine Interruptflag wieder zu setzen.

Solange eine Interrupt bearbeitet wird, sperrt der AVR jedes weitere 
Interruptereignis. Er hat keine Priorisierung.

Man kann das aber mit

ISR bla bla bla
{
   sei();  // läßt die Unterbrechung dieses Interruptes zu.
   mache was schlaues

}

umgehen. Dann wird kann dieser aktuelle Interupt wieder von einem 
anderen unterbrochen werden.

Ich treibe ein Grafikdisplay über UART, einen CAN-Controler, ein Modem 
und einen Schedulerinterrupt parallel auf einem ATmega1280 bei 16Mhz und 
es kommt zu keinen bemerkenswerten Aussetzern.

Deshalb würde ich in den ISRs suchen. Die sollten natürlich kurz und 
knapp programmiert sein.

Vielleicht helfen meine Anregungen. Viel Glück

von Volker (Gast)


Lesenswert?

cskulkw schrieb:
> Hallo Volker,
>
> Dein Code oben pollt nur. Habe ich das richtig verstanden, dass Dein
> Timing nur bei der RX-ISR aus dem Tritt kommt?

Habe keine RX ISR. Hatte ich auch nicht vor. Ich wollte eine ISR auf 
Timer Basis haben, die alle x ms ein paar LEDs ansteuert. Das ganze als 
ISR damit mir da nix dazwischenfunkt und die LEDs flackern.
Den Empfang der Daten vom RS232 wollte ich weiterhin gepollt machen und 
das Ergebnis dann per volatile Übergabearray für die ISR bereitstellen.

>
> Benutzt Du eine ISR für das asynchrone Empfangen eines Zeichnens über
> die UART?

Nein. Siehe oben.

>
> Wenn ja, solltest Du Dir angewöhnen nach dem Eintreten in eine
> Interrupt-Service-Routine das allgemeine Interruptflag wieder zu setzen.
>
> Solange eine Interrupt bearbeitet wird, sperrt der AVR jedes weitere
> Interruptereignis. Er hat keine Priorisierung.
>
> Man kann das aber mit
>
> ISR bla bla bla
> {
>    sei();  // läßt die Unterbrechung dieses Interruptes zu.
>    mache was schlaues
>
> }
>
> umgehen. Dann wird kann dieser aktuelle Interupt wieder von einem
> anderen unterbrochen werden.
>
> Ich treibe ein Grafikdisplay über UART, einen CAN-Controler, ein Modem
> und einen Schedulerinterrupt parallel auf einem ATmega1280 bei 16Mhz und
> es kommt zu keinen bemerkenswerten Aussetzern.
>
> Deshalb würde ich in den ISRs suchen. Die sollten natürlich kurz und
> knapp programmiert sein.
>
> Vielleicht helfen meine Anregungen. Viel Glück

Danke für Deine Anregungen.
Ich hatte wir wie gesagt überlegt:
LED per PWM in einer ISR ansteuern, die per timer ausgelöst wird. Da das 
zeitkritisch ist möchte ich das nicht unterbrechen lassen.
Daher RS232 Empfang in der Main Loop.

von Volker (Gast)


Lesenswert?

@Karl Heinz
Deine Idee mit dem Reset des ATMega ist goldrichtig.
Hab jetzt mal als erstes im main() PORT A an und aus gehen lassen.
Ohne RS232 Empfang => nix passiert.
Sobald RS232 Zeichen empfangen werden => Ich sehe am Oszi Resets 
auftauchen (PORTA hat Spitzen).

Ich schätze ich habe soetwas ähnliches ...
=> Beitrag "UART verursacht Reset(?)"

Weil der MAX232 auf meinem Steckboard nicht sooooo weit weg ist von 
meinem Quartz habe ich jetzt mal CKOPT gefused und siehe da:
Aktuell sehe ich keine Spitzen mehr => keine Resets mehr. Die 
eigentliche Test LED leuchtet konstant hell und flackert nicht mehr.

Ich denke also der CKOPT hat geholfen.

Danke für Eueren Support
Gruß
Volker

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.