Forum: Compiler & IDEs Zu schnelles Blinken


von Alex (Gast)


Lesenswert?

Hallo zusammen. Für einen Test einer neuen Schaltung wollte ich ein 
Programm schreiben, welches im Sekundentakt eine LED blinken lässt.
Doch die LED flackert nur so, anstatt im Sekundentakt zu blinken.
Ich habe dem Timer1 das Comparematch Interrupt programmiert und lasse 
ihn beim gewünschten Zählerstand zurücksetzen. Das Interrupt lässt die 
LED blinken.
Den Wert habe ich wie folgt gerechnet für das OCR1A 
(Vergleichsverzeichnis):
1'000'000 (FCPU) / 256 (Prescaler) = 3900

Was mache ich falsch?
1
#ifndef F_CPU
2
#define F_CPU 1000000
3
#endif
4
#define DDRLED DDRC
5
#define PORTLED PORTC
6
#define LED PC1
7
#define COMPAREAT 3900
8
9
#include <avr/io.h>
10
#include <avr/interrupt.h>
11
12
int main(void)
13
{
14
  cli();
15
  DDRLED |= 1 << LED;
16
  PORTLED |= 1 << LED;
17
  
18
  TCCR1A = 0x00;
19
  TCCR1B = (1 << CS12) | (1 << WGM12);
20
  TIMSK = (1 << OCIE1A);
21
  OCR1AH = (uint8_t)(8 >> COMPAREAT);
22
  OCR1AL = (uint8_t) COMPAREAT;
23
  sei();
24
  
25
    while(1)
26
    {
27
        
28
    }
29
  return 0;
30
}
31
32
ISR (TIMER1_COMPA_vect)
33
{
34
  if (PORTLED & (1 << LED))
35
  {
36
    PORTLED &= ~(1 << LED);
37
  }
38
  else
39
  {
40
    PORTLED |= 1 << LED;
41
  }
42
}
Gruss Alex

von Alex (Gast)


Lesenswert?

Danke für die schnelle Hilfe^^ bin selbst auf den Fehler gekommen :)
1
OCR1AH = (uint8_t)(8 >> COMPAREAT);

muss natürlich:
1
OCR1AH = (uint8_t)(COMPAREAT >> 8);

lauten

Gruss Alex

von Karl H. (kbuchegg)


Lesenswert?

Jetzt hast du gesehen, was da alles passieren kann und in Zukunft 
schreibst du ganz einfach
1
  OCR1A = COMPAREAT;


Es gibt für dich keinen Grund, dich um so "lästige" Details wie das 
Aufteilen der Bytes an dieser Stelle kümmern zu müssen, wenn der 
Compiler das genausogut für dich erledigen kann.

PS: der gcc hat für alle Registerpärchen, die aus jeweils einem H und 
einem L Register bestehen, eine entsprechende Definition mit. Lass 
einfach immer den Buchstaben H bzw. L weg und tu so als ob das ein 16 
Bit Register wäre an das du ganz einfach zugreifst bzw. von dem du ganz 
einfach liest. Den Rest macht der Compiler.

von Alex (Gast)


Lesenswert?

Das ist für jeden Fall wirklich gültig???

Wieso ist davon im Avr-Gcc Tutorial nichts vermerkt?
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#16-Bit_Register_.28ADC.2C_ICR1.2C_OCR1x.2C_TCNT1.2C_UBRR.29


Da steht sogar, dass man es einzeln behandeln MUSS.

Bei anderen Registern, wie zum Beispiel Baudraten-Register, liegen High- 
und Low-Teil nicht direkt nebeneinander im SFR-Bereich, so dass ein 
16-Bit Zugriff nicht möglich ist und der Zugriff zusammengebastelt 
werden muss:


Ist das dann neu? Kann ich in Zukunft also darauf verzichten?
Und wie sieht es mit Lesezugriffen aus? Das selbe?
Und beim Zugriff auf manche 16Bit Register sollte man ja die Interrupts 
deaktivieren. Da muss man sich dann trotzdem noch drum kümmern? In der 
Art:
cli();
temp = OCR1A;
sei();

Gruss Alex

von Karl H. (kbuchegg)


Lesenswert?

Alex schrieb:

> Da steht sogar, dass man es einzeln behandeln MUSS.

Erwischt. An das Baudratenregister hab ich nicht mehr gedacht.

> Und wie sieht es mit Lesezugriffen aus? Das selbe?

Jep.

> Und beim Zugriff auf manche 16Bit Register sollte man ja die Interrupts
> deaktivieren. Da muss man sich dann trotzdem noch drum kümmern?

Ja. Das hat sich nicht verändert. Wenn eine Chance besteht, dass ein 
Register in einer ISR verändert werden kann, dann gilt genau das gleiche 
wie für jede andere 16-Bit Variable: Um atomares Lesen zu garantieren 
muss das Auslesen unter Interrupt Sperre erfolgen.

> In der
> Art:
> cli();
> temp = OCR1A;
> sei();


Die ATOMIC_xx Makros sind eleganter
http://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html

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.