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
intmain(void)
2
{
3
voidinitPINs();
4
voidinitPWMmodule();
5
while(1)
6
{
7
8
}
9
}
10
11
voidinitPINs()//PortB0 --> Ausgang, Port B4 --> Eingang
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
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.
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.
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.
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
intmain(void)
2
{
3
voidinitPINs();
4
//void initPWMmodule();
5
while(1)
6
{
7
PORTB|=(1<<PB0);
8
PORTB&=~(1<<PB0);
9
}
10
}
11
12
voidinitPINs()//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.
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
voidinitPINs()//PortB0 --> Ausgang, Port B4 --> Ausgang
voidinitPINs()//PortB0 --> Ausgang, Port B4 --> Ausgang
9
{
10
DDRB=(1<<PB0);
11
}
12
13
intmain(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.
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.
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
voidinitPINs();
6
voidinitPWMmodule();
7
8
intmain(void)
9
{
10
initPINs();
11
initPWMmodule();
12
13
while(1)
14
{
15
16
}
17
}
18
19
voidinitPINs()//PortB0 --> Ausgang, Port B4 --> Eingang
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...
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
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:
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
voidinitPINs();
6
voidinitPWMmodule();
7
8
intmain(void)
9
{
10
uint8_tres;
11
uint8_terg=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
voidinitPINs()//PortB0 --> Ausgang, Port B4 --> Ausgang
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?
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?
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.
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.
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.
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.
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.
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:
wodurch das ganze dann lesbarer und leichter erfassbarer wird
1
elseif(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.