Forum: Mikrocontroller und Digitale Elektronik Attiny 13, CTC-Modus für Frequenzerzeugung, erzeugt keine Frequenz


von Matze (Gast)


Lesenswert?

Hallo,

Es wurde hier schon oft diskutiert, aber ich habe dennoch Probleme 
damit.
Vielleicht seht Ihr meinen Fehler.

Ich möchte mit dem Timer 0 eines (neuen) Attiny13 Frequenzen erzeugen.

Hierführ muss:
1. der Pin PB0 auf Ausgang geschaltet sein.
2. Der Timer soll im CTC-Mode genutzt werden
3. Dei Compare-Match soll der Pin B0 toggeln
4. Als Prescaler wurde 0 gewählt
5. Interrupts benötige Ich nicht.

Wo liegt der fehler?
1
int main(void)
2
{    
3
    void initPINs();
4
  void initPWMmodule();
5
    while(1)
6
    {
7
    
8
    }
9
}
10
11
void initPINs() //PortB0 --> Ausgang, Port B4 --> Eingang
12
{
13
  DDRB = (1<<DDB0);  
14
}
15
16
void initPWMmodule()
17
{
18
  //TCCR0A
19
  //COM0A0 //Compare Match Output A-Mode --> Toggle 
20
  //COM0A1 //Compare Match Output A-Mode
21
  //COM0B0 //Compare Match Output B-Mode
22
  //COM0B1 //Compare Match Output B-Mode
23
  //WGM00 //Select Waveform generation Mode
24
  //WGM01 //Select Waveform generation Mode
25
  
26
  TCCR0A =(1 << COM0A0) | (0 << COM0A1) | (0 << WGM00) | (1 << WGM01);
27
  
28
  //OCR0A Output Compare Register A---------------------------------------
29
  OCR0A=0x02;
30
  //OCR0B Output Compare Register B-----------------------------------------
31
  
32
  //TCCR0B-------------------------------------------------------------------------
33
  //FOC0A //Force output compare A
34
  //FOC0B //Force output compare B
35
  //WGM02 //Select Waveform generation Mode
36
  //CS00  //Select Clock
37
  //CS01
38
  //CS02
39
40
  TCCR0B=(1 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (1 << CS00) | (0 << CS01) | (0 << CS02);
41
  
42
  //TCNT0 Timer/Counter-register-----------------------------------------------------
43
44
  //TIMSK0 Timer/Counter Interrupt Mask Register ------------------------------
45
  //OCIE0B //Timer/Counter Output Compare Match B Interrupt Enable
46
  //OCIE0A //Timer/Counter0 Output Compare Match A Interrupt Enable
47
  //TOIE0 //Timer/Counter0 Overflow Interrupt Enable
48
}

von Thomas E. (thomase)


Lesenswert?

Matze schrieb:
> Wo liegt der fehler?

Nicht in deinem Programm.

mfg.

von Felix A. (madifaxle)


Lesenswert?

WGM02 muss auf 1 gesetzt werden, wenn am Pin was ausgegeben werden soll. 
Das FOC0A solltest du auf 0 lassen. Die genaue Funktionsweise habe ich 
selbst noch nicht verstanden, weil nie ausprobiert.

Der Prescaler ist übrigens CK/256 statt 0

: Bearbeitet durch User
von Thomas E. (thomase)


Lesenswert?

Felix A. schrieb:
> WGM02 muss auf 1 gesetzt werden, wenn am Pin was ausgegeben werden soll.
Quatsch.

> Das FOC0A solltest du auf 0 lassen.
Das ist in diesem Fall egal.

> Die genaue Funktionsweise habe ich selbst noch nicht verstanden, weil nie
> ausprobiert.
Dann schreib auch nichts dazu.

> Der Prescaler ist übrigens CK/256 statt 0
Erstens gibt es keinen Prescaler 0
Zweitens steht der Prescaler auf 1

Also mit Ruhm bekleckert hast du jetzt nicht gerade.

mfg.

: Bearbeitet durch User
von Felix A. (madifaxle)


Lesenswert?

Da haste wahr. Ich schreibe die Prescalerbits immer absteigend. Hier ist 
es andersrum. Übersehen.

von Karl M. (Gast)


Lesenswert?

Guten Tag,


Vielleicht sollte man nicht schreiben, Felix wenn man keine Ahnung hat ?
Matze schrieb:
> (1 << CS00) | (0 << CS01) | (0 << CS02)

Felix A. schrieb:
> Der Prescaler ist übrigens CK/256 statt 0

Weder noch, der Prescaler ist 1.

Datenblatt Attiny13:

Table 11-9. Clock Select Bit Description
CS02 CS01 CS00 Description
0 0 0 No clock source (Timer/Counter stopped)
0 0 1 clk I/O /(No prescaling)
0 1 0 clk I/O /8 (From prescaler)
0 1 1 clk I/O /64 (From prescaler)
1 0 0 clk I/O /256 (From prescaler)
1 0 1 clk I/O /1024 (From prescaler)
1 1 0 External clock source on T0 pin. Clock on falling edge.
1 1 1 External clock source on T0 pin. Clock on rising edge.

von Felix A. (madifaxle)


Lesenswert?

Hatte es gerade erklärt. Nicht gelesen?

von Matze (Gast)


Angehängte Dateien:

Lesenswert?

Thomas E. schrieb:
> Nicht in deinem Programm.

Aber woran dann?

Der Schaltplan ist nicht grade kompliziert.

von Thomas E. (thomase)


Lesenswert?

Felix A. schrieb:
> Hatte es gerade erklärt.

Das war zeitgleich.

Aber das einzige, was an deinem gesamten Beitrag richtig ist, ist die 
Rechtschreibung.

mfg.

von Felix A. (madifaxle)


Lesenswert?

Was hast du als Taktquelle eingestellt? Läuft der Controller los? Kannst 
du den Pin ohne den CTC-Mode per Programm high und low setzen?

von Thomas E. (thomase)


Lesenswert?

Matze schrieb:
> Der Schaltplan ist nicht grade kompliziert.

Da sehe ich auch keinen Fehler. Bleibt also noch der Aufbau. Programmer 
ist abgezogen?

Oder du flashst das falsche Hexfile. Da wärest du nicht der Erste.

mfg.

von Matze (Gast)


Lesenswert?

Felix A. schrieb:
> Kannst
> du den Pin ohne den CTC-Mode per Programm high und low setzen?

Schonmal nicht, denn keine der Varianten:

    PORTB=0x01;
    PORTB=0x00;

    PORTB ^= ( 1 << PB0 );

    PORTB|=(1<<PB0);
    PORTB&=~(1<<PB0);

tut es in volgendem Kontext:
1
int main(void)
2
{    
3
  void initPINs();
4
  //void initPWMmodule();
5
    while(1)
6
    {
7
    PORTB|=(1<<PB0);
8
    PORTB&=~(1<<PB0);
9
    }
10
}
11
12
void initPINs() //PortB0 --> Ausgang, Port B4 --> Eingang
13
{
14
  DDRB = (1<<DDB0);  
15
}

Das einzige was funktioniert ist den Pin Initial von Beginn an auf 
High/Low zu setzen. Der Zustand scheint danach nicht mehr änderbar zu 
sein.

Wie kann ich so überhaupt überprüfen ob der Tiny dauerhaft läuft?

Jedenfalls lässt er sich programmieren, und die Device-Signature 
auslesen.

von Felix A. (madifaxle)


Lesenswert?

Wie sind denn die Fuses zum Takt eingestellt?

von Felix A. (madifaxle)


Lesenswert?

Ah, einer hatte gerade versehentlich den Watchdog per Fuse aktiviert. Da 
war das Ergebnis ähnlich...

von Holger L. (max5v)


Lesenswert?

Ich hatte den geposteten Code mal ausprobiert, der so nicht läuft.

Der Funktionsaufruf in dem Programm ist ein Prototyp oder?

Der Code unten funktioniert, ist nur ein wenig angepasst (Prescaler + 
OCR0A) damit man es an einer Led erkennen bzw. mit einem Multimeter 
messen kann.
1
#define  F_CPU 1200000
2
3
#include <avr/io.h>
4
#include <util/delay.h>
5
6
void initPINs() //PortB0 --> Ausgang, Port B4 --> Ausgang
7
{
8
  DDRB = ( 1 << PB4) | (1 << PB0);
9
}
10
11
void initPWMmodule()
12
{
13
  TCCR0A =(1 << COM0A0) | (0 << COM0A1) | (0 << WGM00) | (1 << WGM01);
14
  TCCR0B=(1 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (0 << CS00) | (0 << CS01) | (1 << CS02);
15
  OCR0A=250;
16
}
17
18
int main(void)
19
{
20
  initPINs();
21
  initPWMmodule();
22
  while(1)
23
  {
24
    PORTB ^= ( 1 << PB4);
25
    _delay_ms(1000);
26
  }
27
}

: Bearbeitet durch User
von Matze (Gast)


Lesenswert?

Fie fudes sind:

High: 0xff
Low : 0x6A

Ausgewählt ist der Interne 9,6MHZ RC-Oszillator.

So es Funktioniert!
1
void initPWMmodule()
2
{
3
  TCCR0A =(1 << COM0A0) | (0 << COM0A1) | (0 << WGM00) | (1 << WGM01);
4
  TCCR0B=(1 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (1 << CS00) | (0 << CS01) | (0 << CS02);
5
  OCR0A=0x02;
6
}
7
8
void initPINs() //PortB0 --> Ausgang, Port B4 --> Ausgang
9
{
10
  DDRB = (1 << PB0);
11
}
12
13
int main(void)
14
{
15
  initPINs();
16
  initPWMmodule();
17
  while(1)
18
  {
19
  }
20
}

Holger L. schrieb:
> Der Code unten funktioniert, ist nur ein wenig angepasst (Prescaler +
> OCR0A) damit man es an einer Led erkennen bzw. mit einem Multimeter
> messen kann.

Könnt ihr mir bitte den Fehler nennen, denn ich habe es zwar einfach 
reinkopiert, doch ich sehe nun keinen Unterschied zur ursprünglichen 
Version.

von Felix A. (madifaxle)


Lesenswert?

Es mag Einbildung sein, aber ich hatte mal durch Vertauschen der 
Reihenfolge der Zugriffe auf die beiden TCCR-Register und des OCR die 
Funktion zum Erliegen bekommen. Hier scheint einzig die Reihenfolge 
geändert worden zu sein (OCR wird erst am Ende konfiguriert). Probiere 
das vielleicht nochmal aus, indem du im funktionierenden Code OCR wieder 
zwischen die beiden TCCR-Zugriffe schreibst.

von Holger L. (max5v)


Lesenswert?

Das war nur weil es dann zumindest für mich übersichtlicher ist.

Ich bin kein C -Profi aber die "Funktions Prototypen" müssen vorher 
bekannt gegeben werden. Und zwar vor der Mainschleife.
Eventuell waren die Prototypen einfach in einer .h datei ausgelagert und 
du hast es deshalb übersehen.

So würde es auch funktionieren, macht aber zumindest für mein 
Verständnis keinen Sinn :
1
#define  F_CPU 1200000
2
#include <avr/io.h>
3
#include <util/delay.h>
4
5
void initPINs();
6
void initPWMmodule();
7
8
int main(void)
9
{    
10
    initPINs();
11
    initPWMmodule();
12
13
    while(1)
14
    {
15
    
16
    }
17
}
18
19
void initPINs() //PortB0 --> Ausgang, Port B4 --> Eingang
20
{
21
  DDRB = (1<<DDB0);  
22
}
23
24
void initPWMmodule()
25
{
26
  ...
27
}

von Felix A. (madifaxle)


Lesenswert?

Wenn die Funktionen hinter der Mainfunktion kommen, dann ist das nötig. 
Stehen die Funktionen vor der Mainfunktion, klappt es auch ohne die 
Prototypen. Aber ob das so komplett korrekt ist, weiß ich als Hardwerker 
leider nicht...

von Thomas E. (thomase)


Lesenswert?

Felix A. schrieb:
> Wenn die Funktionen hinter der Mainfunktion kommen, dann ist das
> nötig.
> Stehen die Funktionen vor der Mainfunktion, klappt es auch ohne die
> Prototypen. Aber ob das so komplett korrekt ist, weiß ich als Hardwerker
> leider nicht...

Ja, das ist genau richtig.

Wenn das allerdings der Fehler war, dann macht der TO jetzt 26 Mal 
Kopf-Tisch.

Je 10 Mal für die beiden Warnings, die er ignoriert hat, 5 Mal dafür, 
dass er nicht den ganzen Code gepostet hat und 1 Mal für allgemeine 
Dämlichkeit.

Das entsprechende Video erwarte ich in einer Stunde bei Youtube.

mfg

von Thomas K. (thomas_k39)


Lesenswert?

Matze schrieb:
> int main(void)
> {
>     void initPINs(); // <<- hier
>     void initPWMmodule(); // <<- hier
>     while(1)
>     {
>
>     }
> }

Der Fehler liegt in den beiden markierten Zeilen: das sind 
Funktionsprototypen und keine Funktionsaufrufe!

Weder die Pins noch das PWM-Modul werden so initialisiert!

Für den Compiler sieht die Main effektiv so aus:
1
int main(void)
2
{
3
    while(1)
4
5
    }
6
}

Kein Wunder passiert nichts...

: Bearbeitet durch User
von Matze (Gast)


Lesenswert?

Die Prototypen sind vorher bekannt.

Nun möchte ich die Frequenz verändern, doch auch dass klappt garnicht
0-200-700-2700-3800-4500-5000Hz ich verstehe es nicht?
1
#define  F_CPU 9600000
2
#include <avr/io.h>
3
#include <util/delay.h>
4
5
void initPINs();
6
void initPWMmodule();
7
8
int main(void)
9
{
10
  uint8_t res;
11
  uint8_t erg=0x0000;
12
  initPINs();
13
  initPWMmodule();
14
  while(1)
15
  {
16
    res=res*2;
17
    if(res==0)
18
      res=0x01;
19
    OCR0A=res;
20
    _delay_ms(2000);
21
  }
22
}  
23
24
void initPINs() //PortB0 --> Ausgang, Port B4 --> Ausgang
25
{
26
  DDRB = (1 << PB0);
27
}
28
29
void initPWMmodule()
30
{
31
  TCCR0A =(1 << COM0A0) | (0 << COM0A1) | (0 << WGM00) | (1 << WGM01);
32
  TCCR0B=(1 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (1 << CS00) | (0 << CS01) | (1 << CS02);
33
}

von rüdiger (Gast)


Lesenswert?

Matze schrieb:
> Nun möchte ich die Frequenz verändern, doch auch dass klappt garnicht
> 0-200-700-2700-3800-4500-5000Hz ich verstehe es nicht?

Wie stellst du das denn überhaupt fest? Garnicht gibt es fast garnicht. 
Der Ausgangsport (welcher) wird schon irgendein Potential haben und 
eventuell sogar toggeln. Wie ist der beschaltet?

von Matze (Gast)


Lesenswert?

Der Ausgangsport ist PB0 aus dem Schaltplan, zur Feststellung der 
Frequenz habe ich Oszi und Frequenzzähler.

Im aktuellen Progeramm würde ich erwarten, dass die Frequenz zunächst 
hoch beginnt und sich alle 2 Sekunden halbiert.

Stattdessen, dieses seltsame Ergebniss:

rüdiger schrieb:
> 0-200-700-2700-3800-4500-5000Hz

allein schon die Faktoren:
200-700  --> 3,5
700-2700 --> 3,85
2700-3800--> 1,4
3800-4500--> 1,18
4500-5000--> 1,11

Oder die Differenzen:
200-700  --> 500
700-2700 --> 2000
2700-3800--> 1100
3800-4500--> 700
4500-5000--> 500

Ich verstehe nicht wie dies zu stande kommen kann, sehe keinen sinvollen 
Zusammenhang.

Wenn der Controller @ 9,6Mhz läuft, der Prescaler = 1024 ist dann müsste 
es volgendes ergeben: (Laut 11.7.2 im Datenblatt)
OCR0A=1  --> 2343Hz
OCR0A=2  --> 1562Hz
OCR0A=4  --> 927Hz
OCR0A=8  --> 520Hz
OCR0A=16 --> 275Hz
OCR0A=32 --> 142Hz
OCR0A=64 --> 72Hz
OCR0A=128--> 36Hz

Formel: Foa0=Fclk/(2*prescaler*(1+OCR0A))

2343Hz-1562Hz --> 1,5
1562Hz 927Hz  -->1,68
927Hz 520Hz   -->1,78
520Hz 275Hz   -->1,89
275Hz 142Hz   -->1,93
142Hz 72Hz    -->1,97
72Hz  36Hz    -->2,0

Ich erkenne keinen Zusammenhang zwichen gewünschtem Verhalten und 
ist-Verhalten.

Endziel ist eine vom ADC Wert an PB4 abhängige Frequenz auszugeben.
z.b. 2Hz pro LSB.

Dafür musste der Timer im CTC-Modus geeignet sein?

von rüdiger (Gast)


Lesenswert?

Matze schrieb:
> 0-200-700-2700-3800-4500-5000Hz

Diese Frequenzen hast du am PB0 gemessen?

Ich meine, daß das irgendwie nicht richtig gemessen ist.

Besetze OCRA0 mal mit einem festen Wert - nicht im Programm verändern 
und dann mal in Ruhe mit beiden Meßgeräten die eine ausgegebene Frequenz 
überprüfen.


> Wenn der Controller @ 9,6Mhz läuft, der Prescaler = 1024 ist dann müsste
> es volgendes ergeben: (Laut 11.7.2 im Datenblatt)
> OCR0A=1  --> 2343Hz
> OCR0A=2  --> 1562Hz
> OCR0A=4  --> 927Hz
> OCR0A=8  --> 520Hz
> OCR0A=16 --> 275Hz
> OCR0A=32 --> 142Hz
> OCR0A=64 --> 72Hz
> OCR0A=128--> 36Hz
>
> Formel: Foa0=Fclk/(2*prescaler*(1+OCR0A))

Sehe ich auch so.

> Endziel ist eine vom ADC Wert an PB4 abhängige Frequenz auszugeben.
> z.b. 2Hz pro LSB.
>
> Dafür musste der Timer im CTC-Modus geeignet sein?

Im Prinzip ja aber ob das nun 2Hz pro LSB sein können, rechne ich jetzt 
nicht nach.

von Holger L. (max5v)


Lesenswert?

Matze schrieb:
> Wenn der Controller @ 9,6Mhz läuft
Bist du dir da sicher ?

Matze schrieb:
> Die Fuses sind:
> High: 0xff
> Low : 0x6A

Intern RC OSC 9.6 MHz + CKDIV8 ( divide clock by 8 )
9.6 / 8 = 1.2 MHz

http://www.engbedded.com/fusecalc/

von Rudi D. (rulixa)


Lesenswert?

http://www.radiomuseum.org/forum/einfachster_sinustongenerator.html

Hier das ganze für Sinus. Anpassungen und Filter sind der Frequenz 
entsprechend zu dimensionieren.

In den Oszillogrammen ist das Filter zum Teil sehr hoch gelegt um die 
Funktion besser zu sehen.

Allerdings in Assembler.

von Karl H. (kbuchegg)


Lesenswert?

>
1
> int main(void)
2
> {
3
>   uint8_t res;
4
>

eine nicht initialisiert lokale Variable ist nicht automatisch 0. Sie 
kann 0 sein, muss aber nicht. Welchen Wert sie hat, ist mehr oder 
weniger zufällig und hängt davon ab, wozu dieser Speicher vorher benutzt 
wurde.

D.h. im schlimmsten Fall, wenn die Variable einen Wert ungleich 0 hatte, 
musst du mit deinem Setup (vorausgesetzt die angegebene Taktfrequenz 
stimmt) bis zu 16 Sekunden warten, bis du das erste mal auch wirklich 
deine eingstellten und erwarteten OCR Werte zu Gesicht bekommst.

-> lokale Variablen immer initialisieren und nicht von irgendwelchen 
Werten ausgehen. Das geht regelmässig in die Hose.

: Bearbeitet durch User
von Matze (Gast)


Lesenswert?

Holger L. schrieb:
> Bist du dir da sicher ?

Danke, daran lag es.

Karl H. schrieb:
> eine nicht initialisiert lokale Variable ist nicht automatisch 0.

Ja, da hast du recht.

Es tut mir so leid, aber ich habe schon das nächste Problem:

Ich möchte mit dem AD-Wandler eine 10-Bit Wandlung durchführen und diese 
als Frequenz wiedergeben.

Da der Flash des Attiny13 bei

uint16_t erg=1000;
erg=(erg<<1);

schon überläuft, denn dies erzeugt > 1K-Byte Code.

Habe ich gerade einen Attiny 85 nutzen wollen.
Der sein Timer 0 scheint identsch mit dem T0 des Attiny 13 zu sein.

Sein Clk ist mit 4MHZ gewählt, DIV/8 ist nicht gewählt.

Nun komme ich auf
2KHz --> 4KHZ
1KHz --> 2KHz

Wo kommt der Faktor 2 her?
Unter 6. System-Clock-Options oder 11. Timer0 find ich keinen Grund 
dafür.

Danke für eure bisherige Hilfe.
Hätte nicht gedacht dass es so schwierig wird.
1
#define  F_CPU 4000000
2
#include <avr/io.h>
3
#include <util/delay.h>
4
5
int main(void)
6
{
7
  uint8_t freq=0;
8
  uint16_t ADerg=0;
9
  uint32_t wunsch=2000;
10
  DDRB = (1 << PB0);
11
  TCCR0A =(1 << COM0A0) | (0 << COM0A1) | (0 << WGM00) | (1 << WGM01);
12
  
13
  //freq=(float)(F_CPU/(2*1024*5))-1;
14
  while(1)
15
  {
16
    if (wunsch < 7) //Off
17
    {
18
      TCCR0B=(1 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (0 << CS00) | (0 << CS01) | (0 << CS02);
19
    }
20
    if (wunsch < 30) // Teiler = 1024
21
    {
22
      freq=(float)((1953.125/wunsch)-1);
23
      TCCR0B=(1 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (1 << CS00) | (0 << CS01) | (1 << CS02);
24
    }
25
    else if (wunsch < 122) // Teiler = 256
26
    {
27
      freq=(float)((7812.5/wunsch)-1);
28
      TCCR0B=(1 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (0 << CS00) | (0 << CS01) | (1 << CS02);
29
    }
30
    else if (wunsch < 979) // Teiler = 64
31
    {
32
      freq=(float)((31250/wunsch)-1);
33
      TCCR0B=(1 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (1 << CS00) | (1 << CS01) | (0 << CS02);
34
    }
35
    else if (wunsch < 7842) // Teiler = 8
36
    {
37
      freq=(float)((250000/wunsch)-1);
38
      TCCR0B=(1 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (0 << CS00) | (1 << CS01) | (0 << CS02);
39
    }
40
    else // Teiler = 1
41
    {
42
      freq=(float)((2000000/wunsch)-1);
43
      TCCR0B=(1 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (1 << CS00) | (0 << CS01) | (0 << CS02);
44
    }
45
    
46
    //wunsch=(wunsch<<1);
47
    //if(freq>200)
48
    //  wunsch=1;
49
    OCR0A=freq;
50
    _delay_ms(2000);
51
  }
52
}

von Karl H. (kbuchegg)


Lesenswert?

Matze schrieb:

> Da der Flash des Attiny13 bei
>
> uint16_t erg=1000;
> erg=(erg<<1);
>
> schon überläuft, denn dies erzeugt > 1K-Byte Code.

Das erzeugt doch nicht 1Kb Code.

Aber das
1
      freq=(float)((1953.125/wunsch)-1);
erzeugt Code!

Floating Point Berechnungen sind teuer!

> Sein Clk ist mit 4MHZ gewählt, DIV/8 ist nicht gewählt.

Sicher?

Ist der Tiny auf 4Mhz eingestellt?

Bei
1
#define  F_CPU 4000000
kannst du hinschreiben was du willst, das ist nur die Information an den 
Compiler, wie schnell der Tiny deiner Meinung nach läuft. Aber den Tiny 
selbst tangiert das überhaupt nicht. Der läuft so schnell, wie er in den 
Fuses eingestellt wurde bzw. so schnell wie der Quarz läuft, der an ihm 
drann hängt.

von Karl H. (kbuchegg)


Lesenswert?

Karl H. schrieb:

> Aber das
>
1
>       freq=(float)((1953.125/wunsch)-1);
2
>
> erzeugt Code!
>
> Floating Point Berechnungen sind teuer!

Und vor allen Dingen bei dir völlig sinnlos teuer. Denn
1
  uint8_t freq=0;
2
...
3
4
      freq=(float)((1953.125/wunsch)-1);
5
....
6
7
    OCR0A=freq;

deine Floating Point Rechnerei bringt dir überhaupt nichts, ausser eine 
Beschäftigungstherapie für den Tiny.

von Karl H. (kbuchegg)


Lesenswert?

Da fällt mir noch etwas auf
1
  while(1)
2
  {
3
    if (wunsch < 7) //Off
4
    {
5
      TCCR0B=(1 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (0 << CS00) | (0 << CS01) | (0 << CS02);

dir ist aber schon klar, dass du bei JEDEM Durchlauf durch die 
Hauptschleife immer wieder das TCCR0B beu beschreibst. Und jedesmal ist 
dabei FOC0A gesetzt. Wenn mich mein Gedächtnis nicht trügt, dann ist die 
Bedeutung des FOC0A der, das ein Compare Match forsiert wird. D.h du 
erzeugt hier künstlich weitere Compare Matches, die natürlich dann auch 
die weitere Behandlung nach sich ziehen, wie zb das eingestellte Pin 
Toggeln.

Ich hätte das nicht so geschrieben. Wenn es nur darum geht, den 
Prescaler umzustellen, dann hätte ich auch nur genau das gemacht: die 
Prescaler Bits erst mal auf 0 zwingen und dann die jeweils neuen 
Prescaler Bits setzen. Alle anderen Bits werden an dieser Stelle in Ruhe 
gelassen.

Also zum Beispiel:
1
    else if (wunsch < 7842) // Teiler = 8
2
    {
3
      freq=(float)((250000/wunsch)-1);
4
5
      TCCR0B &= ~((1 << CS00) | (1 << CS01) | (1 << CS02));
6
      TCCR0B |=   (0 << CS00) | (1 << CS01) | (0 << CS02);
7
    }

für die dann immer wiederkehrende 'Phrase'
1
     .... ~((1 << CS00) | (1 << CS01) | (1 << CS02))

könnte man sich ja ein Makro definieren
1
#define PRESCALER_CLEAR   ~((1 << CS00) | (1 << CS01) | (1 << CS02))
wodurch das ganze dann lesbarer und leichter erfassbarer wird
1
    else if (wunsch < 7842) // Teiler = 8
2
    {
3
      freq = (250000/wunsch)-1;
4
5
      TCCR0B &= PRESCALER_CLEAR;
6
      TCCR0B |=   (0 << CS00) | (1 << CS01) | (0 << CS02);
7
    }

Alternativ könnte man auch noch hergehen, und das TCCR0B nur dann neu 
besetzen, wenn sich der neue Teilerfaktor gegenüber dem zur Zeit 
eingestellten Teilerfaktor auch wirklich verändert. Zieht man das dann 
auch noch nach unten zu der Stelle an der das OCR Register verändert 
wird, dann vermeidet das dann auch beim Umschalten des Prescalers, dass 
es einen ganz kurzen Zeitraum gibt, in dem Prescaler und OCR Wert so 
ganz und gar nicht zusammenpassen.

: Bearbeitet durch User
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.