Forum: Mikrocontroller und Digitale Elektronik Timer ATtiny 13 Fehler im Code


von Oliver H. (olli_henri)


Angehängte Dateien:

Lesenswert?

Hallo,

Ich habe eine STK500, der Tiny läst sich ansprechen und programieren

nur leider funzt mein Code nicht.

Die LEDs blinken aber die LED an PB0 wird nicht durchgeschaltet auch 
wenn S1 mehrmals gedrückt wurde.

Der TimerA/Counter ist auf Vergleich eingestellt und soll nach 5 mal S1 
drücken T0A/PB0 durchschalten.

Die LED soll dann 0,5 sec brennen und dan zurückgesetzt werden.

Wo liegt der Fehler, kann mir einer freundlicherweise weiter helfen?

Gruß Olli

von Stefan B. (Gast)


Lesenswert?

Musst du Kulitinte sparen? Die Pins hättest du doch angeben können, 
oder?

http://www.atmel.com/dyn/resources/prod_documents/doc2535.pdf

Schalter ist active-high an PB2 (T0).
LEDs sind active-high an PB0, PB1 und PB4

>  PORTB |= (1 << PB3);  // LED an PB3 einschalten
>   if (PB0 == 1)        // wenn der Counter PB0 eingeschaltet hat

Passt nicht zu Schaltplan/Datenblatt

von Stefan B. (Gast)


Lesenswert?

>   if (PB0 == 1)        // wenn der Counter PB0 eingeschaltet hat

Ist auch unsinnig. Nach dem C-Präprozessor steht da: if (0 == 1). Da 
sollte eine Warnung beim Kompilieren kommen.

von Mark .. (mork)


Lesenswert?

@Oliver
PB0 einfach nur als Zahl 0 definiert und nicht an einen Pin gebunden. Um 
zu prüfen, ob ein Bit 1 ist, muss man diesen ausmaskieren und den 
Ausdruck nach einem Wert ungleich 0 überprüfen.
1
 
2
if (PINB & (1<<PB0))        // wenn der Counter PB0 eingeschaltet hat
3
     // dann nach 500ms zur�cksetzen
4
{ 
5
    _delay_ms (500);    // 500 ms warten
6
    PORTB &= ~(1 << PB0);  // PB0 aus, ist OC0A
7
}
Siehe 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Eing.C3.A4nge_.28Wie_kommen_Signale_in_den_.C2.B5C.29

MfG Mark

von Oliver H. (olli_henri)


Angehängte Dateien:

Lesenswert?

Hier noch das Layout mit den zuordnungen der Pins beim ATtiny13.

Ich habe keine Warnungen.

Das erste Problem muß auch schon weiter oben liegen weil der 
Timervergleich schon nicht funktioniert.

in der If Schleife wird ja nur das vom Timer gesetzet Bit am Ausgang 
wieder gelöscht.

> if (PB0 == 1);

kann ich damit nicht auch den Zustand von PB0 abfragen und auswerten?

Gruß Olli

von Stefan B. (Gast)


Lesenswert?

>   TCCR0A |= (1 << CS00) | (1 << CS01) | (1 << CS02);

Falsches Register, müsste TCCR0B sein.

von Stefan B. (Gast)


Lesenswert?

Initialisierung von TCCR0A kommt mir auch Spanisch vor. Ich vermisse den 
CTC Modus.

von Stefan B. (Gast)


Lesenswert?

> if (PB0 == 1);
> kann ich damit nicht auch den Zustand von PB0 abfragen und auswerten?

Abfragen kannst du nur die Register PORTB oder PINB, PB0 ist bloß ein 
#define für die Pinnummer in diesen Registern.

von Oliver H. (olli_henri)


Lesenswert?

Warum soll ich TCCR0B nehmen? Sind A und B nicht gleichwertige 8-Bit 
Timer?

Wenn ich mich für Timer A entscheide muss ich doch alle Register für A 
benutzen?

  > OCR0A = 4;  // Vergleichswert (-1) einstellen, 5xTaster dr�cken

das dürfte doch richtig sein, im Output Compare Register eine vier 
eintragen, dann wird beim darauffolgenden Takt der Signalzustand 
geändert.

  > TCCR0A |= (1 << COM0A0) | (1 << COM0A1); // OC0A ein bei 
Vergleichswert

Im Datenblatt steht das COM0A0 und COM0A1 auf 1 gesetzt im 
Vergleichsmodus bedeutet.

  > TCCR0A |= (1 << CS00) | (1 << CS01) | (1 << CS02);
                    // Externe Clock an T0, steigende Flanke

CS00, CS01, CS02 auf 1 bedeutet steigende Flanke auswerten.

Was ist denn jetzt noch falsch bei der Ini des Timers?

Die If Bedingung habe ich jetzt so wie von Mark vorgeschagen geändert:

if (PINB & (1<<PB0))        // wenn der Counter PB0 eingeschaltet hat
     // dann nach 500ms zur�cksetzen
{
    _delay_ms (500);    // 500 ms warten
    PORTB &= ~(1 << PB0);  // PB0 aus, ist OC0A
}

von Spezi (Gast)


Lesenswert?

Hallo.

>Warum soll ich TCCR0B nehmen? Sind A und B nicht gleichwertige 8-Bit
>Timer?
>Wenn ich mich für Timer A entscheide muss ich doch alle Register für A
>benutzen?

Es gibt keine Timer A oder B; es gibt nur einen Timer0. Und die Register 
TCCR0A und TCCR0B gehören beide zum Timer0 und haben verschiedene 
Funktionen.

Was du meinst, sind die Compare-Einheiten mit Registern "OCR0A" und 
"OCR0B" sowie den Ausgängen OC0A und OC0B. Das sind aber keine Timer ...

von Oliver H. (olli_henri)


Lesenswert?

Aha! ist denn die Ini des TCCR0A richtig? wo steckt der Fehler?

von Stefan B. (Gast)


Lesenswert?

> TCCR0A |= (1 << COM0A0) | (1 << COM0A1); // OC0A ein bei
> Vergleichswert
> Im Datenblatt steht das COM0A0 und COM0A1 auf 1 gesetzt im
> Vergleichsmodus bedeutet.

Richtig, das definiert die Aktion, die bei zutreffendem Vergleich 
durchzuführen ist.

Du brauchst noch die Definition dafrü, was verglichen wird, also TCNT0 
gegen OCR0A, damit dann die Aktion durchgeführt wird. Ich halte den 
CTC-Modus für geeignet, den man mit dem WGM00, WGM01, WGM02 Bits 
einstellen kann.

Leider scheint mein AVR Simulator hier buggy zu sein, so dass ich deine 
Source nicht im Simulator nachvollziehen kann. Daher auch kein 
Codevorschlag.

von Oliver H. (olli_henri)


Lesenswert?

Im Datenblatt steht dass der Timer/Counter 0 TCNT0 ständig mit den 
Output Compare Registern OCR0A und OCR0B verglichen wird. Das muss ich 
also nicht extra einstellen, der Vergleich findet automatisch statt.

Bei Übereinstimmung wird dann das Output Compare Flag OCF0A oder OCF0B 
gesetzt. Falls der Interrupt aktiv ist wird dieser ausgelöst und das 
Flag gelöscht, sonst muß es per Software gelöscht werden.

Da ich mit:

> TCCR0A |= (1 << CS00) | (1 << CS01) | (1 << CS02);
                    // Externe Clock an T0, steigende Flanke

eingestellt habe dass ein externes clock Signal mit steigender Fanke 
ausgewertet werden soll muß doch eigentlich bei Übereinstimmung Pin5 = 
PB0 = OC0A gesetzt werden?

Ohne an WGM00 oder WGM01 etwas einzustellen?

von Oliver H. (olli_henri)


Lesenswert?

Gleichzeitig soll doch nach dem Tutorial mit

TCCR0A |= (1 << CS00) | (1 << CS01) | (1 << CS02);

auch der Timer gestartet werden?

von Oliver H. (olli_henri)


Angehängte Dateien:

Lesenswert?

Gibts hier denn heute keinen der mir mit dem Timer weiter helfen kann 
und den Fehler in meinem Code findet?

Hier nochmal der aktuelle Code....

von Peter D. (peda)


Lesenswert?

Oliver Henrichsen schrieb:
> Der TimerA/Counter ist auf Vergleich eingestellt und soll nach 5 mal S1
> drücken T0A/PB0 durchschalten.

Das wird so nicht klappen, Tasten müssen entprellt werden.
Du solltest den Timer besser dazu nehmen, die Tasten zu entprellen und 
die Flanke zu erkennen.
Und dann zählst Du einfach ganz profan die Drücke mit einer Variable.


Peter

von Stefan E. (sternst)


Lesenswert?

Oliver Henrichsen schrieb:
> Gibts hier denn heute keinen der mir mit dem Timer weiter helfen kann
> und den Fehler in meinem Code findet?

Ein Fehler wurde schon klipp und klar benannt. Aber trotz einer kleinen 
Diskussion darüber, hast du dich anscheinend entschlossen, einfach zu 
ignorieren, dass TCCR0A das falsche Register ist.

von MWS (Gast)


Lesenswert?

Ich denke, daß die Kollegen hier die Lust verlieren, da Du nur wild 
rumbastelst, Deine Sachen nicht lernst und die Hinweise ignorierst.

Spezi hat Dir geschrieben, Du sollst TCCR0B nehmen, das ist Dir aber 
egal. Dem µC dagegen nicht, denn Dein Code:
1
TCCR0A |= (1 << CS00) | (1 << CS01) | (1 << CS02);
passt nicht, denn CS00..02 stehen nun mal im TCCR0B.

OC0A kann bei Dir gar nix schalten, da er nicht als Output Compare 
Ausgang definiert ist, das dagegen würde man über COM00..01 auf TCCR0A 
einstellen.

Wenn man den OC0A eingeschaltet hat, dann kann man den Portpin nicht 
mehr selbst setzen oder löschen, das steht z.B. im ATT13 DB, hier 
2535I–AVR–05/08, S.70

Weiter, obwohl Du weist, daß ein Compare Match das OCF0A setzt, 
übersiehst Du das dies hier in Verbindung mit CTC die Lösung wäre.

Hier ignorierst Du noch den Rat von Stefan eben den CTC Modus zu nutzen, 
das würde dafür sorgen, daß der Zähler bei 4 zurücksetzt und Du nicht 
256 mal den Taster drücken musst, um wieder eine Reaktion zu erhalten.

Wenn Du fragst, aber dann die Antworten ignorierst, brauchst Du Dich 
über mangelndes Feedback nicht zu beschweren.

Also die Antwort auf Deine Frage: diejenigen die helfen können, gibt's 
hier schon, nur irgendwann wollen die nicht mehr.

von Oliver H. (olli_henri)


Lesenswert?

Sorry und Danke,

Leider versteht man als Anfänger bzw. gelegenheits Bastler manche 
Hinweise nicht gleich, insbesondere wenn sie zu knapp formuliert sind 
und für jemanden der in der Materie steckt alles enthalten was man zur 
Lösung eines Problems braucht. Ich habe die Hinweise nicht ignoriert 
sondern versucht nachzulesen und zu verstehen. Als Anfänger 
experimentiere ich nun mal...zwischen Steckboard, Buch und Datenblatt

Wie auch immer, jedenfalls hat mir die ausführliche Hilfe von MWS 
weitergeholfen und ich habe die richtigen Register gefunden, jetzt 
entprelle ich noch den Schalter mittels flipflop.

von Stefan B. (Gast)


Lesenswert?


von Pal .. (pal)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe mir gerade diesen Beitrag durchgelesen und auch versucht meinen 
Tiny nach meinen Anforderungen zu programmieren.
Ich würde mich freuen, wenn mir jemand kurz sagen kann ob meine 
Anstrengungen richtig waren.

So wie ich die Register gesetzt habe müsste eigentlich alle 5ms mein 
Programm durchlaufen werden. Aber die Pins PB0, PB1, PB2 und PB3 kann 
ich als noramale I/O-Ports nutzen.

Vielen Dank für Eure Hilfe!

mfg
pal



Meine main.c lautet:
1
#include "main.h"
2
3
4
ISR(TIM0_COMPA_vect) {
5
  event++;                               // Erzeuge event in Software
6
}
7
8
9
void init() {
10
  DDRB = 0x00 | (1 << PINB0) | (1 << PINB1);
11
  PORTB &= ~((1 << PINB0) | (1 << PINB1));              // Ausgänge erstmal AUS
12
13
  TCCR0A  = (1 << WGM01);                        // CTC
14
  TCCR0B  = (1 << CS02);                        // Prozessortakt / 256  -->  9,6MHz / 256 = 37,5kHz    -->  0,0000026666 sec  
15
  OCR0A   = 200;                            // Vergleichsregister  --> alle 0,000002666 sec * 200 = 0,00053332 sec
16
  TIMSK0  = (1 << OCIE0A);
17
18
  sei();
19
}
20
21
22
int main(void) {
23
  init();
24
25
26
  for (;;) {
27
28
    if(event >= 10) {                        // Alle  5ms (10 x 0,00053332 sec)
29
      event = 0;
30
      // TODO: Mein Programm
31
    }
32
  }
33
}


und die entsprechende main.h:

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
5
volatile uint8_t event;

von Karl H. (kbuchegg)


Lesenswert?

pal ... schrieb:


> ich habe mir gerade diesen Beitrag durchgelesen und auch versucht meinen
> Tiny nach meinen Anforderungen zu programmieren.

Schön.
Trotzdem würden wir es hier begrüßen, wenn du keine Leichenfledderei 
betreiben würdest. Das Original hier stammt aus 2009 und ist für dein 
'Problem' nicht wirklich relevant. Fang in so einem Fall einen neuen 
Thread an, und alle sind glücklich.
(Und vor allen Dingen liest niemand alte Beiträge und überlegt sich 
Antworten ehe er drauf kommt, dass der Thread 4 Jahre alt ist.)


> Ich würde mich freuen, wenn mir jemand kurz sagen kann ob meine
> Anstrengungen richtig waren.

Warum probierst du es nicht einfach aus.
Dein µC sagt dir am Allerbesten, ob es richtig ist oder nicht. Entweder 
eine LED blinkt oder sie blinkt nicht.


> So wie ich die Register gesetzt habe müsste

MÜSSTE?

In der Programmierung gibt es kein müsste. Entweder es tut oder es tut 
nicht. Das nennt man testen.

> eigentlich alle 5ms mein
> Programm durchlaufen werden.

Und, tut es das auch? Dazu gleich noch mehr

> Aber die Pins PB0, PB1, PB2 und PB3 kann
> ich als noramale I/O-Ports nutzen.

Ja natürlich. Das eine hat ja mit dem anderen erst mal nichts zu tun.


>     if(event >= 10) {                        // Alle  5ms (10 x
> 0,00053332 sec)

Du fragst hier ab, ob event größer gleich 10 ist. Laut deiner Rechnerei 
müsste das 5ms ergeben (ich hab nicht nachgerechnet). Jetzt wird es dir 
wahrscheinlich auch so gehen wie mir: Wie kontrolliert man das ohne 
Oszi?

>       event = 0;
>       // TODO: Mein Programm

so jedenfalls nicht.
Wenn man nichts anderes hat, dann ist eine LED an einem Portpin ein 
mächtiges Werkzeug. Kabel dir eine LED an einen Pin ran und jedesmal 
wenn event größer gleich 10 ist, setzt du nicht nur event um, sondern 
schaltest auch die LED in den jeweils anderen Zustand. D.h. deine LED 
blinkt. Blinkt die LED, dann weißt du, dass event tatsächlich erhöht 
wird, was aber nur passieren kann, wenn der Timer arbeitet und die 
Interrupts uaslöst, die zum Aufruf der ISR führen. D.h. alleine dadurch, 
dass die LED blinkt hast du einen Test ob eine relativ komplexe Kette 
von Ereignissen tatsächlich so abläuft wie vorgesehen.

Jetzt erhebt sich noch eine 2. Frage. Wenn die LED blinkt, tut sie es 
dann auch in der richtigen Geschwindigkeit?

5ms sind nicht viel. Durch das umschalten der LED blinkt sie mit der 
halben Geschwindigkeit, was einer Zykluszeit von 10ms entspricht, und 
das sind wiederrum (f=1/t) gleich 100Hz. 100Hz siehst du aber mit freiem 
Auge nicht mehr.

AAAAAber:
Du musst ja nicht das Blinken auslösen, wenn event größer gleich 10 ist. 
Du kannst ja für deine Tests auch erst mal 100 hinschreiben. Dadurch 
wird alles um einen Faktor 10 langsamer, was bedeutet, dass die LED 
jetzt mit 10Hz blinkt. Und das sieht man dann schon. Aber warum bei 100 
stehen bleiben? 200 bringt dir nochmal einen Faktor 2 und somit sind wir 
bei 5Hz. D.h. die LED blinkt in einer Sekunde 5 mal auf. Und das kann 
man schon ganz gut und zuverlässig schätzen.

D.h. Ändere zu Testzwecken dein Programm wie vorgeschlagen um und sieh 
nach, ob eine LED an einem Portpin pro Sekunde 5 mal aufblinkt. Tut sie 
das, dann funktioniert dein Programm wie vorgesehen. Tut sie es nicht, 
dann gibt es 2 Möglichkeiten
* entweder sie blinkt überhaupt nicht
  Dann hast du entweder einen Fehler beim LED_Blinken oder die ganze
  Timer-Einstellung stimmt nicht
* oder aber sie blinkt, aber mit der falschen Geschwindigkeit
  Dann stimmt zwar die grundsätzliche Timereinstellung, aber du hast
  dich irgendwo verrechnet und die Steuerkonstanten in den Registern
  stimmen nicht.


Zum Programmieren gehört auch, dass man selber seine Programme testen 
kann und sich überlegt, wie man einen Test inszenieren kann, der einem 
verrät, was man wissen möchte.

Dann gibt es auch kein 'müsste' mehr. Entweder es tut oder es tut nicht.

Dein µC ist geduldig. Der führt auch stundenlang den immer gleichen Code 
aus, während du dir überlegst, wie du mit einer Programmänderung die 
Dinge in Erfahrung bringen kannst, die du wissen willst.

von Pal .. (pal)


Lesenswert?

Hallo,

vielen Dank für deine Antwort.

Ja das Problem ist tatsächlich, dass ich kein Oszi habe. Das Programm 
läuft auf jeden Fall wie ich jetzt festgestellt habe.
Nur bei der Geschwindigkeit bin ich mir nicht sicher.

Aber auch hier noch mal danke für den Tip - ich werde einfach mal eine 
LED blinken lassen und zählen.

> Schön.
> Trotzdem würden wir es hier begrüßen, wenn du keine Leichenfledderei
> betreiben würdest.

Sorry, hier wusste ich einfach nicht was besser ist. In Zukunft werde 
ich einen neuen Thread eröffnen.

lg pal

von Karl H. (kbuchegg)


Lesenswert?

Eines noch
Das hier

>  Tut sie das, dann funktioniert dein Programm wie vorgesehen.

ist nicht ganz richtig.
Denn es gilt:

Durch Testen kann man immer nur die Anwesenheit von Fehlern feststellen, 
nicht die Abwesenheit.

D.h. wenn scheinbar das Programm genau das tut was es soll, heißt das 
noch lange nicht, dass es fehlerfrei ist. Es kann auch sein, dass man 
einfach nur noch nicht den Test gefunden hat, der den Fehler zeigen 
würde.

D.h. mit solchen Dingen wie "ist getestet, muss also funktionieren" 
immer ein wenig vorsichtig sein.

von Stefan K. (steffleo)


Lesenswert?

Hallo, also evtl. kann mir jemand bei meiner Fehlersuche helfen,

Ich Bekomme es ohne Probleme hin auf ein ATtiny85 IR Infrared Obstacle 
Sensor Modul das wenn ich über den Sensor meine Hand halte das die LED 
angeht und wieder aus.

ich Möchte jetzt gern das selbe Prinzip nur mit  2 Sende Module auf 
einen ATtiny85 Bringen, Natülich pro Modul eine LED.


unten mal den Code für ein IR Infrared Obstacle

was müsste ich denn ändern damit es geht? sorry auf dem Gebit kenne ich 
mich noch nicht besonders gut aus, denoch hoffe ich auf eure Hilfe

LG




int LED = 4; // Use the onboard Uno LED
int isObstaclePin = 1;  // This is our input pin
int isObstacle = HIGH;  // HIGH MEANS NO OBSTACLE



void setup() {
  pinMode(LED, OUTPUT);
  pinMode(isObstaclePin, INPUT);



}

void loop() {
  isObstacle= digitalRead(isObstaclePin);
  if (isObstacle == LOW)


  {

    digitalWrite(LED, HIGH);

  }
  else
  {
    digitalWrite(LED, LOW);

  }
  delay(1);
 }

: Bearbeitet durch User
von Hubert G. (hubertg)


Lesenswert?

Es ist nicht gut einen alten Tread zu verwenden.
Der von dir gezeigte Code ist für einen Arduino Uno, passt daher nicht 
für einen Tiny85.
Ändern muss man bei dem Code sonst nichts wesentliches, nur etwas 
dazuschreiben.

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.