Forum: Compiler & IDEs atmega 8, timer, interrupt, gcc


von Jochen K. (joku)


Angehängte Dateien:

Lesenswert?

Hallo,

im Anhang habe ich ein kleines Testprogramm (mit vielen angelehnten
Codefragmenten); vielleicht kann mir jemand die Ursache erklären....

Hardware ist ein Atmega 8, das Board ist von myavr, an die
Steckerleiste habe ich eine Lochrasterplatine mit Mäuseklavier, einigen
LEDs sowie Widerständen verbaut.

PORTD ist der Digitaleingang, PORTB sind die LEDs zur Anzeige, der
USART dient zur Kommunikation mit einem Rechner (Schaltzustände
weiterleiten).

Nun zu meinem Problem:
ich möchte im Sekundentakt eine LED blinken lassen (von diesem
sekundentakt dann zuätzlich ableiten, dass zB ein Ausgang für 10
Sekunden high bleibt)

PIND2 auf 1 schaltet PORTB0 auf 1, PORTB1 soll blinken.

Ist in main innerhalb der while-Schleife  die Abfrage nicht
auskommentiert, so blinkt die LED ca im Sekundentakt, jedoch kommt es
zu längeren Pausen, also aussetzern bzw längerer HIGH oder LOW-Phase.

Vermuten tu ich zur Zeit, dass PORTD sich mit der seriellen
Schnittstelle in die Quere kommt....

Worin liegt das Problem in meinem Programm bzw wie kann ich sowas
"besser" angehen?

gruss jochen

von johnny.m (Gast)


Lesenswert?

> ISR (USART_RXC_vect)
> {
>  unsigned char ucSign = 0x00;
>
>  ucSign = UARTGetChar();
> //...

Das ist imho nicht wirklich sinnvoll. Wenn der RXC-Interrupt auslöst,
bedeutet das, dass bereits ein Zeichen empfangen wurde. Man braucht
dann nur noch UDR auszulesen. Wozu also der Aufruf von UARTGetChar()?

Außerdem rufst Du in der UART-RXC-ISR die Funktion puthelp() auf, die
sicher eine ganze Weile braucht, um den String auszugeben. Während der
Zeit kann kein Timer-Interrupt bearbeitet werden. Vermutlich ist genau
dieser Funktionsaufruf für die Abweichungen verantwortlich.

BTW:
> if (PORTB & (1 << PB1)) {
>      PORTB &= ~(1 << PB1);
>    } else {
>      PORTB |= (1 << PB1);
>    }

Warum so umständlich? Schreibs doch einfach mit nem Exklusiv-ODER:

PORTB ^= 1 << PB1;

Macht das gleiche, ist aber nur eine Zeile...

von johnny.m (Gast)


Lesenswert?

Nach nochmaligem drüberschauen ist mir nix anderes mehr aufgefallen,
außer, dass die Funktion putvers() noch übler ist, als puthelp().

MERKE: Funktionsaufrufe, insbesondere solche, die viel Zeit brauchen,
also Ausgaben über die serielle Schnittstelle (Stringausgaben...), die
mit Wartezeiten verbunden sind, haben in einer ISR nichts zu suchen, da
während ihrer Ausführung die Bearbeitung aller anderen Interrupts
blockiert ist!

von Jochen K. (joku)


Lesenswert?

Hallo,

zuerst einmal vielen Dank für die Auffrischung des Toggles über das
XOR, ist nicht mehr alles so frisch wie früher.

Meine gestrigen Experimente und Versuche haben ergeben, dass auch wenn
ich den UART mit dem wenig performanten Code/Interrupt aktiviert habe,
die Blinkerei (wenigstens nach Auge) im constanten
Puls-/Pausenverhältnis in den Griff bekomme:

Im der Signalroutine für den Timer setzte ich mir eine globale
Variable, von 0 bis 7 auf 0 und von 8 bis 14 auf 1; in der main-loop
setzte ich abhängig von dieser Variablen den Blink-Ausgang auf HIGH
oder LOW.
Jetzt kann ich am Eingang  PIND2 Pegel nach belieben wechseln, ohne
dass die Hell/Dunkelphase des Blinklichts verändert wird.

Ich denke, mir einen Sekundentakt zu erzeugen und dadurch gesteuert
unterschiedliche Ausgänge für unterschiedliche Zeiten zu altivieren.

Noch eine Kochbuch-Frage zum UART:
wenn ich ohne Interrupt arbeite, für eine kleine Steuerungsaufgabe
sollte das reichen, denke ich, in der main-loop UDR auszulesen und dann
bei Bedarf auf Empfang gehen, indem ich die Empfangsroutine anstosse.
Also pollen.
bei RS485 wird die Adresse durch ein gesetztes 9tes Bit erreicht, diese
Möglichkeit habe ich beim Atmel noch nicht entdeckt.

Ich hoffe, nach knapp 10 Jahren Pause wieder etwas mehr in die
Reglungs-/Steuerungstechnik einzusteigen.

gruss jochen
PS: Übung macht den Meister, aber ich möchte Fallen und Sackgassen
vermeiden

von johnny.m (Gast)


Lesenswert?

Das 9. Datenbit kannst Du selbstverständlich beliebig setzen. Musst nur
drauf achten, dass es vor dem Schreiben von UDR gesetzt wird (bzw. beim
Lesen des empfangenen Zeichens vor UDR gelesen wird).

von Sonic (Gast)


Lesenswert?

>#define UART_UBRR_CALC(BAUD_,FREQ_) ((FREQ_)/((BAUD_)*16L)-1)

Istd as 'L' hinter der 16 richtig und stimmt die kontante 'FREQ'?
Sollte die in der Berechnung nicht 'F_CPU ' sein?
Versuch mal die Baudrate als Kontante (Wert) anzugeben und nicht zu
berechnen. Hatte damit auch mal Probleme.

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.