Forum: Mikrocontroller und Digitale Elektronik Attiny26 Timer0 Tastverhältnis


von Heinz (Gast)


Lesenswert?

Hallo Leute,
leider bin ich aus der Suche im Forum bzw. im Netz allg. nicht so 
richtig schlau geworden. Daher hier noch meine Frage:

Ich möchte mit einem ATTiny26 mit dem Timer0 eine bestimmte Frequenz am 
Ausgang erzielen und bei diesem Signal das Tastverhältnis verstellen 
können. Eigentlich eine relativ simple Sache ... dacht ich.

Mein Gedanke war der, dass jedesmal wenn ich den Ausgang toggle direkt 
den Zähler (TCNT0) anpasse. Ich habe das mit einer if - else Abfrage in 
der ISR erledigt. Möglicherweise ist das nicht das gelbe vom Ei... ist 
aber erstmal egal.

Leider funktioniert das nicht so. Es stellt sich kein anderes 
Tastverhältnis ein.
Irgendwie wird die Frequenz lediglich durch den Zählwert in dem 
else-Teil definiert.

Könnt ihr mir sagen was ich für einen Fehler mache???

Danke


Hier mal der Code.:
1
#define F_CPU 1000000UL
2
#include </usr/local/avr/include/avr/io.h>
3
#include </usr/local/avr/include/util/delay.h>
4
#include </usr/local/avr/include/avr/interrupt.h>
5
6
7
volatile tot_overflow;    //?
8
volatile pulse_ratio = 1;   //Variable Tastverhältnis
9
volatile ratio_Ton=0;
10
volatile ratio_Toff=0;
11
int main(void)
12
{
13
#ifndef TIMER0_OVF_vect
14
#define TIMER0_OVF_vect TIMER0_OVF0_vect
15
#endif
16
init_OUT();    // Initialisierungsmodul der HWAusgänge
17
init_TC();
18
set_MLED();  // Ausgabe MailLED
19
  sei();         // IR aktivieren
20
21
while(1) // Hauptschleife 
22
  {
23
   beat();    // BeatLED
24
//  ratio();
25
//  if(tot_overflow >= 1)
26
//  {
27
//  PORTB^= (1 << PB3);
28
//  tot_overflow=0;
29
  
30
//set_MLED();
31
  }
32
}
33
34
void init_OUT(void)
35
{
36
DDRA |=  (1 << PA2); // setzt PA2 als Ausgang   LED
37
DDRB |=  (1 << PB3); // setzt PB3 als Ausgang  CTRL LT
38
DDRB |=  (1 << PB4); // setzt PB4 als Ausgang  PWM LT
39
}
40
41
void init_TC(void)
42
{  
43
  TCCR0 |= (1 << CS01);// | (1<<CS00);  //Prescaler wählen
44
  TCNT0 =0;
45
  TIMSK = (1 << TOIE0);    //Overflow IR erlauben
46
//  tot_overflow =0;
47
}
48
void set_MLED(void)
49
{
50
PORTB |= (1 << PB4);// PWM MLED auf High
51
//PORTB |= (1 << PB4); //PB4 auf High
52
}
53
void beat(void)
54
{
55
  _delay_ms(500);  //Verzögerung  
56
  PORTA ^= (1 << PA2); //setzt Ausgang auf High
57
  _delay_ms(500);  //Verzögerung  
58
//  PORTA = (0 <<  PA2); //Ausschalten Heartbeat-LED
59
}
60
61
//void ratio(void)
62
//{
63
// Ziel: Umrechnung des Tastverhältnises auf die variablen ratio_cnt1 und ratio_cnt_2 
64
// welche über die Zählervorgabe das Tastverhältnis bestimmen.    
65
//pulse_ratio = 0.1;   //Variable Tastverhältnis
66
//ratio_Ton=pulse_ratio * 255;   //Einschaltimpuls Tastverhältnis * 255
67
//ratio_Toff=255-ratio_Ton;    //Ausschaltimpuls 255-Einschaltimpuls 
68
//}
69
70
ISR (TIMER0_OVF_vect)
71
{
72
if (PORTB,PB3 == 1)
73
{  
74
  PORTB ^= (0 << PB3);
75
  TCNT0 |= 150;
76
}
77
else
78
{
79
  PORTB ^= (1 << PB3);
80
  TCNT0 |= 250;
81
}
82
}

: Bearbeitet durch User
von Thomas E. (thomase)


Lesenswert?

Heinz schrieb:
> if (PORTB,PB3 == 1)
> {
>   PORTB ^= (0 << PB3);

was erwartest du denn von diesen beiden Konstruktionen?

mfg.

http://www.mikrocontroller.net/articles/Bitmanipulation

von Karl H. (kbuchegg)


Lesenswert?

Was soll denn das sein?`
1
if (PORTB,PB3 == 1)
2
{  
3
  PORTB ^= (0 << PB3);
4
  TCNT0 |= 150;
5
}

wenn du dich mit Timern rumschlägst, sollten aber einfache Bit-Abfragen 
bzw. Bitsetzereien kein Problem mehr sein.

von Karl H. (kbuchegg)


Lesenswert?

Du scheinst überhaupt ein Problem mit Bit-Sachen zu haben.

Kannst du mal in einfachen Worten erklären, was du dir davon
1
  TCNT0 |= 150;
erhoffst?


Im übrigen: Hat der Timer auf dem µC keinen CTC oder PWM-Modus mit 
einstellbarer Obergrenze? CTC würde gehen, macht aber Ärger in der 
Synchronisierung. PWM mit einstellbarer Obergrenze ist genau das, was du 
eigentlich willst, wenn du sowohl Frequenz als auch Tastverhältnis 
einstellbar haben willst.

von spess53 (Gast)


Lesenswert?

Hi

>Im übrigen: Hat der Timer auf dem µC keinen CTC oder PWM-Modus mit
>einstellbarer Obergrenze? CTC würde gehen, macht aber Ärger in der
>Synchronisierung.

Hat der nicht. Die Nachfolger, ATTiny261/461/861, sind da besser 
ausgestattet.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

spess53 schrieb:

> Hat der nicht.

Oh je.
Ok, dann hat er Pech und muss das wirklich 'händisch' mittels 
Timer-Vorladen in der ISR bewerkstelligen. Mit allen Nachteilen und/oder 
Problemen, die sonst die Hardware erledigen würde. Geht nicht anders.

: Bearbeitet durch User
von Thomas E. (thomase)


Lesenswert?

Karl Heinz schrieb:
> spess53 schrieb:
>
>> Hat der nicht.
>
> Oh je.
> Ok, dann hat er Pech und muss das wirklich 'händisch' mittels
> Timer-Vorladen in der ISR bewerkstelligen. Mit allen Nachteilen und/oder
> Problemen, die sonst die Hardware erledigen würde. Geht nicht anders.

Oder Timer1 nehmen.

mfg.

von heinz (Gast)


Lesenswert?

Vielen Dank erstmal für eure Antworten.

Ich fange mit dem Beantworten mal von unten an:
@thomase: Richtig, der ATtiny26 ist nicht gerade üppig ausgestattet was 
die Timer betrifft. Da ich den Timer1 eventuell für eine komplexere 
Aufgabe nehmen will, bleibt mir nix anderes übrig als es mit dem Timer0 
händisch zu machen.

Nun zum eigentlichen Problem... den Bitmanipulationen.
Ich werd mir das ganz nochmal durcharbeiten müssen.
Die if Abfrage ist natürlich bei dem toggeln relativ sinnlos, da das 
toggeln ja eigentlich nur invertiert.


@karlheinz
Mit dem Befehl:
TCNT0 |= 150;
hatte ich erhofft das er statt bei 0 gleich bei 150 anfängt zu zählen
und dadurch eher die IRS auslöst.
Dabei war mir noch so in Erinnerung, das der Compiler das auflöst.
Was ich aber übersehen habe ist die ODER verknüpfung (|).
Wobei ich mich nun frage... wann genau hat der TCNT0 den Wert 0?
Wenn der Fall eintritt 0 ODER 150 (bzw.:10010110) dann ergibt das doch 
wieder 150 bzw:10010110.

Igendwie hab ich noch einige grobe Denkfehler darin.

Trotzdem Danke schonmal für die Hinweise

von Karl H. (kbuchegg)


Lesenswert?

heinz schrieb:

> Die if Abfrage ist natürlich bei dem toggeln relativ sinnlos, da das
> toggeln ja eigentlich nur invertiert.

Wir bekritteln nicht die if-Abfrage an sich.
WEnn du das Tastverhältnis einstellen willst, dann musst du das 
unterscheiden können und dazu brauchst du ein if.
Aber:

Das hier
1
  if (PORTB,PB3 == 1)

macht ganz sicher nicht das, was du beabsichtigt hast!
Das ist zwar kein Syntaxfehler, und daher gibt es auch keinen Error vom 
Compiler. Aber abgesehen davon ist das purer Nonsense.

UNd NB: genau das ist auch die Ursache, warum bei dir immer der else zu 
Zug kommt. Denn 3 ist nun mal immer und ewig ungleich zu 1.
Denk mal über diesen letzten Satz nach und sieh in deinem C-Buch nach, 
was denn eigentlich der Komma-Operator macht.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

heinz schrieb:

> Mit dem Befehl:
> TCNT0 |= 150;
> hatte ich erhofft das er statt bei 0 gleich bei 150 anfängt zu zählen

Dir ist klar, dass es einen Unterschied macht, ob man einem Register 
einen Wert einfach als ganzes zuweist, oder ob man in dem Register zu 
den bereits gesetztn Bits noch andere Bits mit dazusetzt?


> Was ich aber übersehen habe ist die ODER verknüpfung (|).
> Wobei ich mich nun frage... wann genau hat der TCNT0 den Wert 0?
> Wenn der Fall eintritt 0 ODER 150 (bzw.:10010110) dann ergibt das doch
> wieder 150 bzw:10010110.

Du magst da sogar GLück haben. Sobald allerdings andere Interrupts ins 
Spiel kommen und die Abarbeitung der ISR ein wenig warten muss, steht 
dann eben nicht mehr 0 in TCNT0. Selbiges wenn der Timer mit einem 
Prescaler von 1 operiert.

> Wobei ich mich nun frage... wann genau hat der TCNT0 den Wert 0?

Der genaue Zeitpunkt ist: Exakt zu dem Zeitpunkt an dem das Interrupt 
Flag gesetzt wird. Das iat aber nicht der Zeitpunkt, an dem die ISR zu 
laufen beginnt und es ist auch nicht der Zeitpunkt an dem diese 
Anweisung ausgeführt wird. Je nach Prescaler kann der Timer da schon 
wieder weiter gezählt haben.

> Igendwie hab ich noch einige grobe Denkfehler darin.
1
  TCNT0 = 150;

zu einfach?

: Bearbeitet durch User
von Thomas E. (thomase)


Lesenswert?

Karl Heinz schrieb:
> Der genaue Zeitpunkt ist: Exakt zu dem Zeitpunkt an dem das Interrupt
> Flag gesetzt wird. Das iat aber nicht der Zeitpunkt, an dem die ISR zu
> laufen beginnt und es ist auch nicht der Zeitpunkt an dem diese
> Anweisung ausgeführt wird. Je nach Prescaler kann der Timer da schon
> wieder weiter gezählt haben.
>
>> Igendwie hab ich noch einige grobe Denkfehler darin.
>
>
1
>   TCNT0 = 150;
2
>
>
> zu einfach?

TCNT0 += 150;

mfg.

von heinz (Gast)


Lesenswert?

if(PORTB & (1 <<PB3))
{
}
else
{
}

klappt hervorragend.


Was macht das PORTB,PB3 eigentlich?
Habe das nur bei den Makrofunktionen gefunden (jetzt eben erst)

Ich kann aber auch nicht mehr sagen wie das reingeraten ist.
...

Vielen vielen Dank.

von Thomas E. (thomase)


Lesenswert?

heinz schrieb:
> Was macht das PORTB,PB3 eigentlich?

if(PORTB,PB3 == 1)
{
...
}
else...

Der Kommaoperator sorgt dafür, daß zwei(oder mehrere) Ausdrücke 
ausgeFÜHRT werden. Statt üblicherweise nur einem.
AusgeWERTET wird aber nur der letzte!
Da der Ausdruck "PORTB" nichts hergibt, wird gar nichts gemacht, da PB3 
eine Konstante mit dem Wert 3 ist, wird auch die Bedingung, die 
eigentlich ausgewertet werden soll, nie erfüllt. Also ist das vollkommen 
sinnlos. Selbst wenn PB3 1 wäre, wäre das sinnlos, da die Bedingung dann 
immer erfüllt wäre.

mfg.

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.