Forum: Compiler & IDEs Verständnisproblem mit Timern


von Christian S. (hunner)


Lesenswert?

Hallo Leute,

ich befasse mich grade mit der C-Programmierung. Dafür nutze ich einen 
atmega8. Ich versuche gerade eine LED am Pin12 (PD6) vom Port D im 
1-Sekunden-Takt zu toggeln. Leider gelingt mir das nicht und ich weiss 
nicht an was es liegt. Ich versuche schon seit gestern meinen Fehler zu 
finden und binn schon einige Forenbeiträge und Tutorials durchgegangen. 
Leider ohne ergolg. Nun habe ich versucht in der IST die LED nur 
einzuschalten, umm einen Fehler im restlichen Code aus zu schließen. Das 
funktioniert aber auch nicht.
Ich hoffe, ihr könnt mir dabei helfen.

Hier ist mein bisheriger Code:
1
//LED1 = Pin11 PD5
2
//LED2 = Pin12 PD6
3
//Taster 1 = Pin4 PD2
4
//Taster 2 = Pin5 PD3
5
//Taster 3 = Pin6 PD4
6
7
/*****************
8
Header
9
******************/
10
11
  #include <avr/io.h>
12
  #include <avr/interrupt.h>
13
  #include <stdlib.h> 
14
  #define F_CPU    1000000
15
16
/*****************
17
initialize timer, interrupt and variable
18
*****************/
19
void timer0_init()
20
{
21
  // Timer 0 konfigurieren
22
  TCCR0 |= (1<<CS00)|(1<<CS02);   // Timer 0 mit Prescaler 1024
23
                                  // (3686400/1024)/256 Hz = 14,0625Hz
24
                                  // bzw.  1/14,0625 s = 71,1 ms
25
26
  sei();   // hier wird das gemacht.
27
28
}
29
30
/*****************
31
Hauptprogramm
32
******************/
33
34
int main(void)
35
{
36
  DDRD = 0x60;    //PortD 0-5 ->Eingang ;6 und 7 Ausgang     
37
/*****************
38
Timer interrupt              innerhalb der main!
39
*****************/
40
 
41
timer0_init();
42
43
44
  while(1)      //Endlosschleife
45
  {
46
    if(PIND & (1<<PD2) || PIND & (1<<PD3 ) || PIND & 0x10)    //Taster1
47
    PORTD |= 0x20;    //LED1 = ein
48
    else
49
    PORTD &= ~0x20;    //Toggle LED1
50
  }
51
  return 0;      //wird nie erreicht
52
}
53
54
/*****************
55
Interrupt-Service-Rutine
56
*****************/
57
58
59
ISR (TIMER0_OVF_vect) 
60
{
61
    PORTD |= 0x40;    //LED2 wird eingeschalten
62
}

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Christian S. schrieb:

> sei();   // hier wird das gemacht.

Hier wird was gemacht? (ist aber egal)

Du hast vergessen, per setzen von TIMSK0 den Timer-Interrupt auch zu 
aktivieren

von no AVR (Gast)


Lesenswert?

Wie sind die Taster angeschlossen?

Du benötigte bestimmt pullup oder pulldown Widerstände.

Du kannst die Eingänge und Ausgänge im Debugger testen. Dort ist das 
Port Register zu sehen.

von mullwark (Gast)


Lesenswert?

Schalte mal den Timer0 Overflow im Register TIMSK ein.
1
TIMSK |= (1<<TOIE0); // ich glaube, daß ist so richtig, habe es jetzt nicht nachgelesen

Mit deiner F_CPU und dem Prescaler wird die ISR mit 3,8 Hz aufgerufen.
F_CPU / (PRESC * 8bit Zählergröße) = 3,81
Dann kannst Du mit einer Zählervariable in der ISR noch weiter teilen, 
und so nahe an 1 Hz kommen. Genauer wird es, wenn Du den nächstkleineren 
Prescaler nimmst und dafür den Softwarezähler größer wählst (oder 
eleganter, den Zähler im CTC-Mode betreiben).

Zum Toggeln eines Pins reicht die Zeile in der ISR
1
PORTD ^= (1<<PIN5); // LED1

von mullwark (Gast)


Lesenswert?

Christian S. schrieb:
> DDRD = 0x60;    //PortD 0-5 ->Eingang ;6 und 7 Ausgang

beißt sich mit

Christian S. schrieb:
>//LED1 = Pin11 PD5
>//LED2 = Pin12 PD6
>//Taster 1 = Pin4 PD2
>//Taster 2 = Pin5 PD3
>//Taster 3 = Pin6 PD4

letzteres ist zwar nur ein Kommentar, läßt aber vermuten, daß Du Deine 
Pinbelegung und LED-Anschlüsse nochmal überprüfen solltest.

von Christian S. (hunner)


Lesenswert?

Hallo:

@ Michael Reinelt: mit sei(); habe ich die globalen interruots 
zugelassen
"// hier wird das gemacht." ist ein Copy&paste Fehler
@  no AVR: ich verwende das Entwicklungsboard von Pollin-Elektronic mit 
der Bestellnummer: 810 038
@ mullwark:Ich habe die Zeile TIMSK |= (1<<TOIE0); unter die Zeile 
TCCR0 |= (1<<CS00)|(1<<CS02); geschrieben. Das brachte aber keine 
Änderungen
Kann ichden PortD nichtmehr verwenden, wenn ich den Timer0 verwende?
Wenn ja, was ist mit Timer2?

Grüße

von Christian S. (hunner)


Lesenswert?

Nochmal Hallo,

die Belegung im Kommentar ist meine HW-Beschaltung.
Also:
>//LED1 = Pin11 PD5
>//LED2 = Pin12 PD6
>//Taster 1 = Pin4 PD2
>//Taster 2 = Pin5 PD3
>//Taster 3 = Pin6 PD4

Was ist an DRD = 0x60; falsch?? Ohne Timer funktioniert der Code

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Christian S. schrieb:
> Nochmal Hallo,
>
> die Belegung im Kommentar ist meine HW-Beschaltung.
> Also:
>>//LED1 = Pin11 PD5
>>//LED2 = Pin12 PD6
>>//Taster 1 = Pin4 PD2
>>//Taster 2 = Pin5 PD3
>>//Taster 3 = Pin6 PD4
>
> Was ist an DRD = 0x60; falsch?? Ohne Timer funktioniert der Code

weil du schrubst:
> DDRD = 0x60;    //PortD 0-5 ->Eingang ;6 und 7 Ausgang

Also was jetzt?  entweder 5 und 6 Ausgang, oder 6 und 7


Generell: gewöhn dir sowas an:

#define LED1_PORT PORTD
#define LED1_DDR  DDRD
#define LED1_BIT  PORTD5

und ab dann arbeitest du nur mehr mit den LED_* Symbolen, keine PORT, 
DDR, und vor allem keine Hex-Zahlen mehr.

: Bearbeitet durch User
von Bitflüsterer (Gast)


Lesenswert?

Zunächst mal sehe ich in Deinem ersten Code keine wirklich 
substantiellen Probleme, bis auf das fehlende setzen von TIMSK.

Die einzige Fehlermöglichkeit die ich konkret sehe, ist die Frage ob Du 
die Jumper JP3 bis JP7 gesetzt hast. Es gibt auch noch ein paar andere 
Fehlermöglichkeiten, daher:

Versuche zunächst einmal einfach nur die LEDs einzuschalten.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdlib.h>
4
5
#define F_CPU    1000000
6
7
#define LED1   PD5
8
#define LED2   PD6
9
10
int main (void)
11
{
12
  DDRD = 0x60;    // PortD 0-4 u. 7 Eingang, 5 und 6 Ausgang
13
  PORTD |= (1 << LED1) || (1 << LED2);   // LED1 und LED2 werden eingeschaltet
14
15
  while (1)
16
    ;

Nun sollten die LEDs leuchten. Solange das nicht geht, brauchst Du sonst 
nichts zu versuchen.
Falls das nicht geht, dann poste mal ein Foto von Deinem Aufbau.

von Bitflüsterer (Gast)


Lesenswert?

Wenn man schon mit defines arbeitet, dann richtig. (Sorry, Mein Fehler)
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdlib.h>
4
5
#define F_CPU    1000000
6
7
#define LED1   PD5
8
#define LED2   PD6
9
10
int main (void)
11
{
12
  DDRD = (1 << LED1) || (1 << LED2);    // PortD 0-4 u. 7 Eingang, 5 und 6 Ausgang
13
14
  PORTD |= (1 << LED1) || (1 << LED2);   // LED1 und LED2 werden eingeschaltet
15
16
  while (1)
17
    ;
18
}

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Bitflüsterer schrieb:

> dies und jenes

F_CPU gehört ins makefile (sofern sowas existiert) ansonsten vor alle 
includes (tlw. verlassen die sich drauf)

#define LED1   PD5

mag ich persönlich gar nciht. Wenn dann die ganze latte mit PORT, DDR, 
PIN (sofern benötigt) und Bit.

von Bitflüsterer (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Bitflüsterer schrieb:
>
>> dies und jenes
>
Das ist kein Zitat von mir! In dem ganzen Thread kommt diese Phrase 
nicht vor.

Abgesehen davon, mag das wohl alles sein, spielt aber erstmal keine 
Rolle. Meinst Du nicht auch?

von Christian S. (hunner)


Lesenswert?

Hallo,

@ Michael Reinelt: meine Pinnbelegung geht ja von PD0 bis PD7
die beiden LEDs hängen an Pin11(LED1)PD5 und Pin12(LED2)PD6.
Binär ist dass die 00110000....ok Fehler meinerseits müsste 0x30 
heissen.

@Bitflüsterer: die LEDs habe ich im ersten Schritt leuchten lassen. Das 
hat funktioniert.

Das mit den Definitionen ist eine gute Idee, vorallem wenn der Code 
länger und somit unübersichtlicher wird.

Grüße

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Bitflüsterer schrieb:
> Michael Reinelt schrieb:
>> Bitflüsterer schrieb:
>>
>>> dies und jenes
>>
> Das ist kein Zitat von mir! In dem ganzen Thread kommt diese Phrase
> nicht vor.

Echt, hey? Kann ich mir nicht vorstellen...

> Abgesehen davon, mag das wohl alles sein, spielt aber erstmal keine
> Rolle. Meinst Du nicht auch?

Nein, meine ich nicht. Wenn man einen Anfänger vor sich hat, sollte man 
dem keinen schlechten Code vorwerfen.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Christian S. schrieb:
> @ Michael Reinelt: meine Pinnbelegung geht ja von PD0 bis PD7
> die beiden LEDs hängen an Pin11(LED1)PD5 und Pin12(LED2)PD6.
> Binär ist dass die 00110000....ok Fehler meinerseits müsste 0x30
> heissen.

Darüber solltest du nochmal nachdenken...

Christian S. schrieb:
> Das mit den Definitionen ist eine gute Idee, vorallem wenn der Code
> länger und somit unübersichtlicher wird.


Nein, das ist immer eine gute Idee. So klein kann das Programm gar 
nicht sein, das ist immer sinnvoll.

von Bitflüsterer (Gast)


Lesenswert?

Michael Reinelt schrieb:

Naja. Lassen wir das. Ich ignoriere Deine Beiträge in Zukunft.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Bitflüsterer schrieb:
> Ich ignoriere Deine Beiträge in Zukunft.

Ist sicher eine gute Idee. Danke!

: Bearbeitet durch User
von Christian S. (hunner)


Lesenswert?

@  Michael Reinelt: des is aber wieder der Wert vom Anfang meines 
Posts???
____________________
|Pin |7|6|5|4|3|2|1|0|
|Bin |0|1|1|0|0|0|0|0|
|Hex |   6   |   0   |

Habe ich da was verdreht?

Gruß

von Bitflüsterer (Gast)


Lesenswert?

Christian S. schrieb:
> @Bitflüsterer: die LEDs habe ich im ersten Schritt leuchten lassen. Das
> hat funktioniert.

Super. OK. Dann lass uns mal probieren, ob Deine LEDs auf Deine Taster 
reagieren.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdlib.h>
4
5
#define LED1   PD5
6
#define LED2   PD6
7
8
#define TASTE1  PD2
9
#define TASTE2  PD3
10
#define TASTE3  PD4
11
12
int main (void)
13
{
14
  DDRD = (1 << LED1) || (1 << LED2);    // PortD 0-4 u. 7 Eingang, 5 und 6 Ausgang
15
16
  while (1) {
17
    if (PIND & (1 << TASTE1))
18
      PORTD |= (1 << LED1);   // LED1 wird eingeschaltet
19
    else
20
      PORTD &= ~(1 << LED1);   // LED1 wird ausgeschaltet
21
    if (PIND & (1 << TASTE2))
22
      PORTD |= (1 << LED2);   // LED2 wird eingeschaltet
23
    else
24
      PORTD &= ~(1 << LED2);   // LED2 wird ausgeschaltet
25
}

Sowas wie das Prellen der Tasten lassen wir erstmal weg. Wenn Du eine 
der beiden Tasten gedrückt hälst, dann muss die entsprechende LED dauern 
leuchten. Sobald Du sie loslässt, sollte sie wieder ausgehen.

von Bitflüsterer (Gast)


Lesenswert?

Ups. Da fehlt eine schliessende geschweifte Klammer.
Hättest Du aber sicher selbst gemerkt.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdlib.h>
4
5
#define LED1   PD5
6
#define LED2   PD6
7
8
#define TASTE1  PD2
9
#define TASTE2  PD3
10
#define TASTE3  PD4
11
12
int main (void)
13
{
14
  DDRD = (1 << LED1) || (1 << LED2);    // PortD 0-4 u. 7 Eingang, 5 und 6 Ausgang
15
16
  while (1) {
17
    if (PIND & (1 << TASTE1))
18
      PORTD |= (1 << LED1);   // LED1 wird eingeschaltet
19
    else
20
      PORTD &= ~(1 << LED1);   // LED1 wird ausgeschaltet
21
    if (PIND & (1 << TASTE2))
22
      PORTD |= (1 << LED2);   // LED2 wird eingeschaltet
23
    else
24
      PORTD &= ~(1 << LED2);   // LED2 wird ausgeschaltet
25
  }
26
}

von Christian S. (hunner)


Lesenswert?

Hallo Bitflüsterer,
Das habe ich auch schon erfolgreich mit dem letzten Code versucht
1
    if(PIND & (1<<PD2) || PIND & (1<<PD3 ) || PIND & 0x10)    //Taster1
2
    PORTD |= 0x20;    //LED1 = ein
3
    else
4
    PORTD &= ~0x20;    //Toggle LED1
Gruß

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Christian S. schrieb:
> @  Michael Reinelt: des is aber wieder der Wert vom Anfang meines
> Posts???
> ______________________
> |Pin |7|6|5|4|3|2|1|0|
> |Bin |0|1|1|0|0|0|0|0|
> |Hex |   6   |   0   |
>
> Habe ich da was verdreht?

Jetzt nicht mehr.
Denk nochmal über die #define Methode nach. Vielleicht kommst du dann 
zum Schluss, dass dann kein nachdenken mehr notwendig ist. Weil 
nachdenken verbraucht Energie und verursacht Kopfschmerzen, deshalb 
sollte man jede Möglichkeit nützen, nicht nachdenken zu müssen :-)

Christian S. schrieb:
> if(PIND & (1<<PD2) || PIND & (1<<PD3 ) || PIND & 0x10)    //Taster1

Gewöhn dir klammern an. Oder weisst du asuwenig aus dem Stehgreif und 
kannst mit Quellen belegen, dass & stärker bindet als ||?

Siehe oben. Nachdenken vermeiden.
1
if((PIND & (1<<PD2)) || (PIND & (1<<PD3)) || (PIND & 0x10))    //Taster1

Natürlich ginge das noch besser:
1
if (PIND & ((1<<PD2) | (1<<PD3) | (1<<PD4)))

oder noch besser:
1
if (PIND & ((1<<KEY1_BIT) | (1<<KEY2_BIT) | (1<<KEY3_BIT)))
vorausgesetzt du hast die #define Methode verinnerlicht

von Bitflüsterer (Gast)


Lesenswert?

Christian S. schrieb:
> Hallo Bitflüsterer,
> Das habe ich auch schon erfolgreich ... versucht

Schön. Das hättest Du aber doch mal im ersten Post schreiben sollen.
Leider schreibst Du ja nur, das "es" nicht funktioniert. Wir konnten 
also nicht wissen, an was es nun genau liegt.

OK. Es bleibt also der Timer.

Das setzen des TIMSK ist Dir ja schon genannt worden. Mit dem Code oben 
wird die LED einfach nur immer wieder eingeschaltet. Sie wird also, 
ständig leuchten - unabhängig davon, was Du mit den Tastern tust.

Was genau funktioniert denn nun nicht? Präziser: Was erwartest Du und 
was geschieht?

von Bitflüsterer (Gast)


Lesenswert?

Was natürlich auch noch ein oft gemachter Fehler ist: Du hast den 
Controller hoffentlich in den Projekteinstellungen korrekt gesetzt, 
oder?

von Christian S. (hunner)


Lesenswert?

HallovMichael Reinelt,

ich verstehe die nachfolgenden Sätze von dir nicht. Du schreibst "
> Jetzt nicht mehr.
> Denk nochmal über die #define Methode nach. Vielleicht kommst du dann
> zum Schluss, dass dann kein nachdenken mehr notwendig ist. Weil
> nachdenken verbraucht Energie und verursacht Kopfschmerzen, deshalb
> sollte man jede Möglichkeit nützen, nicht nachdenken zu müssen :-)"

Wieso jetzt nicht mehr? dass ist doch der selbe Hexwert wie im ersten 
Tread?
Verstehe ich das richtig, dass ich die Portbelegung als define 
hinterlegen soll?
Gruß

von Christian S. (hunner)


Lesenswert?

Zu Beginn wurde ich vom Atmel Studio gefragt und da habe ich den mega8 
angegeben. Kann ich das irgendwo kontrollieren?
Gruß

von Christian S. (hunner)


Lesenswert?

@ Bitflüsterer:
Ich habe es nicht weiter erwähnt, da ich dachte, dass es reicht, wenn es 
im Code steht.
In diesem Code wollte nur testen, ob grundsätzlich der Interrupt 
aufgerufen wird. Da die LED aber aus bleibt, gehe ich davon aus, dass 
die Rutine gar nicht aufgerufen wird

Gruß

von Bitflüsterer (Gast)


Lesenswert?

Im AVRStudio Version 4, gibt es drei(vier) Stellen, an denen das gesetzt 
werden kann.

1. Beim anlegen eines Projektes
2. In dem Dialog "Project->Configuration Options", dort im Tab "General" 
rechts neben dem Punkt "Device".
3. Für den Simulator in dem Dialog "Debug->Select Platform and Device".
4. Beim Programmieren. Die Details hängen vom verwendeten Adapter und 
seiner Software ab. Die Hilfe zum AVRStudio und/oder dem Adapter resp. 
der Software sollte das genau erklären.

von Visitor (Gast)


Lesenswert?

AVR-Studio hat einen prima Simulator, mit dem man testen kann, ob 
zumindest das Programm wie erwartet arbeitet.

von Bitflüsterer (Gast)


Lesenswert?

Christian S. schrieb:
> @ Bitflüsterer:
> Ich habe es nicht weiter erwähnt, da ich dachte, dass es reicht, wenn es
> im Code steht.

Nun, wir konnten dennoch nicht wissen, ob Du die einzelnen Teile 
getestet hattest. Es geht ja hier auch nicht nur um Softwaretests 
sondern auch um Hardwaretests. Nebenbei gesagt: Sehr oft entstehen 
Fehler weil Teile, die für sich genommen funktionieren, zusammengefügt 
werden.

> In diesem Code wollte nur testen, ob grundsätzlich der Interrupt
> aufgerufen wird. Da die LED aber aus bleibt, gehe ich davon aus, dass
> die Rutine gar nicht aufgerufen wird
>
> Gruß

Und die LED bleibt auch aus, nachdem Du das setzen von TIMSK hinzugefügt 
hast? Zeige mal den Code den Du aktuell verwendest.

von Christian S. (hunner)


Lesenswert?

Hallo,

ich habe gerade festgestellt, dass ich bei der erstellung eines Projekts 
nicht nach dem verwendeten Clntroller gefragt werde und im makefile CU = 
atmega128 steht. Kann ich das im Nachhinein ändern (nur da?).
Ich muss jetzt leider weg. Melde mich aber morgen wieder
Grüße und vielen Dank bisher

von Bitflüsterer (Gast)


Lesenswert?

Christian S. schrieb:
> ... Kann ich das im Nachhinein ändern ...

Ja. Siehe: 
Beitrag "Re: Verständnisproblem mit Timern" 
unter Punkt 2.

von Christian S. (hunner)


Lesenswert?

Hallo Bitflüsterer,

ich habe nur gefragt, da ich mir nicht sicher war, ob es evtl. sonst 
noch Stellen gibt, an denen noch etwas geändert werden muss.
Ich habe meinen Code mit AtmelStudio 4.16 simuliert. Nach dem init des 
timers 0 war der Haken bei TCCR0, CS02 zu sehen, den Haken bei CS00 
konnte man nicht sehen, da dort "no clock source" drüber stand.
Danach habe ich auf Version 4.19 upgedatet und die AVR Toolchain 
3.4.2-1573 neu installiert. Es stand dann über CS00 "running no 
prescalling". Und jetzt, ohne dass ich bewusst an der Software etwas 
geändert habe, stürzt das Programm vor der Simmulation ab.
Grüße

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.