Hallöchen habe ein Problem mit dem PWM Mode des ATMega 644
Ich gehe wie folgt vor:
1. Pin low setzen
2. Pin als Ausgang definieren
3. geeignette Wellenform definieren
1
TCCR1A=0x00|(1<<COM1A1)|(1<<WGM10);// nichtinv. PWM 8 Bit (FAST)
soweit so gut
nun möchte ich eine trägerfrequen von 8620,7 Hz definieren. Hierfür muss
ich das Vergleichsregister OCR1A definieren ( Ich glaube mit dem wert
143 - bin mir allerdings nicht sicher und hoffe auf eine Antwort von
euch)
ist es so, dass ich zwei verschiedene Pulse unter dieser Trägerfrequenz
verwenden möchte.
Eine logische 1 = 116 us
Eine logische 0 = 232 us (also genau das doppelte)
Ist es möglich unter dieser Trägerfrequenz die ja immer präsent sein
soll den Output so zu manipulieren, dass bei einer gelesenen 1 (aus
einem vorgegebenen Byte) der Puls 116 us dauert und bei einer 0 doppelt
so lang?
1
voidsende_paket(boolnullodereins)
2
{
3
if(nullodereins==0)
4
{
5
TCCR1A=blubblubbla;
6
TCCR1B=blubblubbla;
7
8
OCR1A=?;
9
OCR1B=?;
10
}
11
else
12
{
13
TCCR1A=blubblubbla;// Hier die gleichen Einstellungen wie oben allerdings andere Vergleichsregister
Hallo Florian,
Interessant zu wissen wäre noch der Prozessor Takt (extern, intern,
frequenz). Wenn Du Timer1 im Fast PWM 8 bit Mode festlegst, dann hängt
Deine PWM Frequenz auch von der Prozessorfrequenz ab:
Beispiel:
fCPU = 16 MHz
fPWM = 16MHz / (Prescaler * 256) (in Deinem Fall läuft Dein Timer noch
nicht da kein Prescaler eingestellt wurde, siehe Datenblatt Tabelle
14-6)
um Deine Frequenz von 8620,7 Hz zu erzeugen würde ich Dir den Timer Mode
14 (Fast PWM) empfehlen. Damit kannst Du dann die PWM Frequenz mittels
ICR1 bestimmen. Beispiel:
fCPU = 16MHz
Prescaler = 1;
fPWM (wanted) = 8620,7 Hz = fCPU / (Prescaler * ICR1)
=> ICR1 = fCPU / (Prescaler * 8620,7) = 1855,99777 also 1856.
Jetzt brauchts noch Deine Pulslängen 116µs und 232µs:
Die minimale Auflösung von Deinem Timer mit oben genannten
Rahmenbedingungen (Takt, Prescaler) ist:
deltaTimer = Prescaler / fCPU = 62,5ns
Damit bekommst Du die Werte für OCR1A bzw. OCR1B mit
116µs / deltaTimer = 1856
232µs / deltaTimer = 3712
Jetzt nur noch den Timer anständig initialisieren und schon gehts ....
Alles roger ?
Grüße,
Michael
Erst einmal vielen vielen Dank Michael, den Timer1 im PWM hab ich
verstanden, nun hapert es wohl nur noch an der Umsetzung.
Ich hatte mir das jetz so gedacht. Aber irgendwie tut das Programm nicht
was es soll. Die Vordefinierten Daten sollen behandelt werden und je
nachdem ob es sich um eine Null oder eine Eins handelt soll der PWM
Ausgang eine Pulsweite von 116 us bzw. 232 us haben.
Wäre furchtbar lieb, wenn man mir da ein-zwei Schläge auf den Hinterkopf
geben könnte.
weil wenn ich mir auf ein blatt Papier mein Sägezahn Pwm aufzeichne mit
dem TOPwert von 2320 (ICR1) und dieses genau das Signal ist welches 116
us anliegen würde, wäre nur noch die doppelte zeit von interesse. Wenn
ich aber OCR1A mit 4640 belege, hab ich einen größeren wert als Top und
dies darf doch nicht sein oder?
Daher wäre es für mich von der Logik her nun so, dass ich den Timer
weiter so initialisiere. ICR1 und OCR1A identisch sind für eine 1 (also
2320) und für eine 0 das Signal einfach doppelt so lange anliegen soll.
Nun stellt sich blos die frage ob das so ohne weiteres umsetzbar ist.
Florian Pramme wrote:
> weil wenn ich mir auf ein blatt Papier mein Sägezahn Pwm aufzeichne mit> dem TOPwert von 2320 (ICR1) und dieses genau das Signal ist welches 116> us anliegen würde, wäre nur noch die doppelte zeit von interesse.
die 2320 definieren ja Deine PWM Frequenz. Damit lädst Du ja ICR1.
Soweit so gut.
> Wenn> ich aber OCR1A mit 4640 belege, hab ich einen größeren wert als Top und> dies darf doch nicht sein oder?
Richtig.
> Daher wäre es für mich von der Logik her nun so, dass ich den Timer> weiter so initialisiere. ICR1 und OCR1A identisch sind für eine 1 (also> 2320) und für eine 0 das Signal einfach doppelt so lange anliegen soll.> Nun stellt sich blos die frage ob das so ohne weiteres umsetzbar ist.
Nicht ganz. Der Timer wird einmalig initialisiert und dann nur noch der
Wert für Dein Compare Register angepasst. In Deinem Fall OCR1A.
Zudem fehlt eine Endlosschleife in Deinem Programm !!!!
Zudem entsprechen 8620,7Hz = 116µ. Damit gehen die 232µ schon gar nicht
mehr! Die Pulsweiten hast Du ja genannt, aber die Frequenz passt nicht
dazu. Mal doch vllt. mal auf was genau für ein Signal Du erzeugen willst
!
In dem Beispiel brauchst Du noch nicht einmal Interrupts, da die PWM
Generierung ja in Hardware funktioniert. Ausser Du willst es mit
Soft-PWM machen. Geht natürlich auch ....
Hier ist ein möglicher Aufbau für Deine PWM Geschicht, wo noch die
eigentliche PWM Frequenz (XXXX) festgelegt werden muss:
1
// Hier die header einbinden
2
3
// Hier die glob. Variablen deklarieren.
4
5
voidInitTimer1()
6
{
7
TCCR1A=(1<<WGM11)|(1<<COM1A1);
8
TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS10);
9
ICR1=XXXX;
10
}
11
12
13
intmain()
14
{
15
DDRD|=(1<<PD5);// Hardware PWM Pin als Ausgang definieren
Noch was ...
Du schaltest den Interrupt mittels TIMSK für den Compare Match A ein:
TIMSK1 = (1<<OCIE1A); // aktiviert CTC interrupt
und danach enable'st du die globalen Interrupts mit:
sei ();
es gibt jedoch keine ISR (Interrupt Service Routine) für den Interrupt !
Somit macht Dein Controller einen Reset.
Grüße,
Michael
ahhhh jetzt haben wirs !
also folgendes:
1: PWM Frequenz 8620,7 (116µs)
0: PWM Frequenz 4310,35 (232µs)
Bei beiden Frequenzen ist das PWM Tastverhältnis 50%
Wir wissen ja schon, dass wir die Frequenz mit dem ICR1 Register
einstellen und das Tastverhältnis mit OCR1A das wir einfach auf ICR1 / 2
setzen.
Jetzt brauchen wir aber den OVF Interrupt, da wir die Einstellungen für
das nächste zu sendende Bit in der ISR einstellen müssen.
1
// Hier die header einbinden
2
3
// Hier die glob. Variablen deklarieren.
4
5
// Interrupt service routine
6
ISR(TIMER1_OVF_vect)
7
{
8
if(NextBit==0)
9
{
10
ICR1=4640;
11
OCR1A=2320;
12
}
13
else
14
{
15
ICR1=2320;
16
OCR1A=1160;
17
}
18
}
19
20
voidInitTimer1()
21
{
22
// Erzeuge am Anfang 0'en
23
ICR1=4640;
24
OCR1A=2320;
25
// Init Timer 1, Mode 14 Fast PWM, Hardware PWM OC1A enabled (clear on compare)
26
TCCR1A=(1<<WGM11)|(1<<COM1A1);
27
TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS10);
28
// Enable overflow interrupt
29
TIMSK|=(1<<TOIE1);
30
}
31
32
33
intmain()
34
{
35
DDRD|=(1<<PD5);// Hardware PWM Pin als Ausgang definieren
36
37
InitTimer1();// Timer initialisieren
38
39
sei();// Interrupts einschalten
40
41
set_sleep_mode(SLEEP_MODE_IDLE);// Sleep mode um Strom zu sparen
42
43
for(;;)// Endlosschleife
44
{
45
sleep_mode();
46
}
47
48
return0;
49
}
so könnts gehen. Hast Du nen Oszi um zu schauen, was hinten auch
rauskommt ? Wenn ja mach am Anfang ein paar Tests mit nur 0en senden und
dann nur 1en und dann z.B. abwechselnd 0 1 0 1 ... wenn das funzt, dann
schieb Deine Daten mal raus ...
Grüße,
Michael
> 1: PWM Frequenz 8620,7 (116µs)> 0: PWM Frequenz 4310,35 (232µs)> Bei beiden Frequenzen ist das PWM Tastverhältnis 50%
Ja das klingt gut hab ich hier auch ausgerechnet
>> Jetzt brauchen wir aber den OVF Interrupt, da wir die Einstellungen für> das nächste zu sendende Bit in der ISR einstellen müssen.
Ok hab ich mir angesehen.
Also denkst du dir das etwa so?
1
/* Includes
2
###########
3
*/
4
#include<avr/io.h>
5
#include<avr/interrupt.h>
6
#include<stdbool.h>
7
#include<stdlib.h>
8
9
/* Defines
10
##########
11
*/
12
#define F_CPU 20000000UL
13
14
15
//volatile uint16_t dcc_preamble = 0b1111111111;
16
//volatile uint8_t dcc_adresse = 0b00001010;
17
//volatile uint8_t dcc_data = 0b01110100;
18
//volatile uint8_t dcc_xor = 0b01111110;
19
20
volatileuint8_tnullen=0;
21
uint8_tNextBit=0;
22
uint8_tdata=0;
23
uint8_tbitzaehler=0;
24
25
26
/* Interrupt Service Routine
27
############################
28
*/
29
ISR(TIMER1_OVF_vect)
30
{
31
if(NextBit==0)
32
{
33
ICR1=4640;
34
OCR1A=2320;
35
}
36
else
37
{
38
ICR1=2320;
39
OCR1A=1160;
40
}
41
}
42
43
/* Timer initialisierung für die Trägerfrequenz von 8620,7 Hz im Fast PWM modus
Noch ein paar Anmerkungen zum Code:
* Variablen die in einer ISR verwendet werden müssen als volatile
deklariert werden (in Deinem Fall NextBit).
> for (bitzaehler = 1; bitzaehler <9; bitzaehler++) // Endlosschliefe
In C werden gängigerweisse die Schleifen bei 8 gestartet
also:
for (bitzaehler = 0; bitzaehler < 8; bitzaehler++)
Zudem fehlt Deine Endlosschleife !
Dein Programm läuft an. Der Timer wird initialisiert dann rattert es
durch die for Schleife und danach steht das Programm. Ich bezeifle, dass
so überhaupt je ein Interrupt ausgelöst wird ! Warum nimmst Du nicht
das Framework von mir ?
Getting isp parameter.. SD=0x0a .. OK
bekomm ich von meinem STK 500 gesagt wenn ich das programm flashe.
Hab einen Logicanalyser an PD5 angeschlossen (da soll das Signal ja
schließlich hin)
1
// Hier die header einbinden
2
#include<avr/io.h>
3
#include<avr/interrupt.h>
4
#include<avr/sleep.h>
5
// Hier die glob. Variablen deklarieren.
6
7
volatileuint8_tNextBit=0;
8
9
// Interrupt service routine
10
ISR(TIMER1_OVF_vect)
11
{
12
if(NextBit==0)
13
{
14
ICR1=4640;
15
OCR1A=2320;
16
}
17
else
18
{
19
ICR1=2320;
20
OCR1A=1160;
21
}
22
}
23
24
voidInitTimer1()
25
{
26
// Erzeuge am Anfang 0'en
27
ICR1=4640;
28
OCR1A=2320;
29
// Init Timer 1, Mode 14 Fast PWM, Hardware PWM OC1A enabled (clear on compare)
30
TCCR1A=(1<<WGM11)|(1<<COM1A1);
31
TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS10);
32
// Enable overflow interrupt
33
TIMSK1|=(1<<TOIE1);
34
}
35
36
37
intmain()
38
{
39
DDRD|=(1<<PD5);// Hardware PWM Pin als Ausgang definieren
40
41
InitTimer1();// Timer initialisieren
42
43
sei();// Interrupts einschalten
44
45
set_sleep_mode(SLEEP_MODE_IDLE);// Sleep mode um Strom zu sparen
sehr fein ! Wobei Simulator mit Vorsicht zu genießen ist. Der hat noch
ein paar Bugs, insbesondere bei den Timern ....
Wennst nen STK hast kannst ja auch verschiedene Datensätze auf
Knopfdruck absenden....
Michael K. wrote:
> sehr fein ! Wobei Simulator mit Vorsicht zu genießen ist. Der hat noch> ein paar Bugs, insbesondere bei den Timern ....
Das ist wohl wahr aber die Werte sind im Simulator schon sehr schick,
0,05 us mehr als der Buchwert hergibt.
Nun will ich mir den Spaß halt noch gern über den Logicanalyser ansehen
da kann man schauen ob die werte sich im rahmen befinden oder ob man
ggf. anpassen muss.
Bis hierhin aber vielen vielen Dank.
> Wennst nen STK hast kannst ja auch verschiedene Datensätze auf> Knopfdruck absenden....
So ist es geplant ;) Mit 8 verschiedenen Datensätzen kann man schon ne
Menge anstellen.
> Das ist wohl wahr aber die Werte sind im Simulator schon sehr schick,> 0,05 us mehr als der Buchwert hergibt.
Passt.
> Nun will ich mir den Spaß halt noch gern über den Logicanalyser ansehen> da kann man schauen ob die werte sich im rahmen befinden oder ob man> ggf. anpassen muss.
Kannst ja mal nen Screener posten.
> Bis hierhin aber vielen vielen Dank.
Gerne.
> So ist es geplant ;) Mit 8 verschiedenen Datensätzen kann man schon ne> Menge anstellen.
Oder über RS232 beliebig viele ...
Grüße und viel Erfolg,
Michael
einfach nur 0en senden funktioniert prima haargenaues Signal auf dem
Logic Analyzer.
Das selbe gilt für 1sen. Beim wechsel von beiden brauch er allerdings
tierisch lang. ca 100 us länger als gesollt um genau zu gehen.
wobei man erkennen kann das eine eins immer ziemlich sauber dargesellt
wird. aber die Null davor, bzw. danach halt viel zu lange ist. Die nach
den angrenzenden Nullen folgenden Nullen sind dann wieder sauber. Somit
muss es damit zu tun haben, dass beim Wechsel von Null auf Eins und
umgekehrt ein fehler ist, bzw. zu viel Zeit vergeht.
Oder liegt es daran, das die Register noch nicht völlig geladen sind?
das signal welches eigentlich nicht in die Folge gehört ist je nachdem
zwischen 290 us und 348 us. Letzere Zahl ergibt sich unter anderem wenn
man die 116 us der 1 und die 232 us der 0 zusammenzieht.
Danke im Voraus
Florian
bekomme ein solches Signal wenn ich 1 Byte einsen sende und dann eine 0.
Nach der Null folgen wieder einsen. (Endlosschleife)
gestrichelt ist angezeigt, wie der ideale verlauf sein sollte.
@ Florian Pramme (chillkroedde)
>Dateianhang: Unbenannt-1.png (1,9 MB, 5 Downloads)Applause *Applause* Applause *Applause* Applause
Du hast den Titel "IT-Depp den Monats" gewonnen.
Als Preis winkt die in Leder gebundene Ausgabe des Sonderhefts
Bildformate !!!
MFG
IT-Supervisor
>>Dateianhang: Unbenannt-1.png (1,9 MB, 5 Downloads)>> Applause *Applause* Applause *Applause* *Applause*>> Du hast den Titel "IT-Depp den Monats" gewonnen.>> Als Preis winkt die in Leder gebundene Ausgabe des Sonderhefts>> Bildformate !!!
Herzlichen Dank aber dir scheint etwas entgangen zu sein. Technische
Zeichnungen sollen in PNG gespeichert werden. Und du willst meine
Handschrift samt dem edlen Timingdiagramm doch wohl nicht abstreiten
eine Technische Zeichnung zu sein, oder?
Aber um deinen Pädagogischen Eingriff zu huldigen - ich werde in Zukunft
jpg verwenden.
Lieben Gruß
Florian
@ Florian Pramme (chillkroedde)
>Herzlichen Dank aber dir scheint etwas entgangen zu sein. Technische>Zeichnungen sollen in PNG gespeichert werden.
Und dir scheint entgangen zu sein, dass es sich dabei um einen SCAN oder
Photo handelt.
> Und du willst meine>Handschrift samt dem edlen Timingdiagramm doch wohl nicht abstreiten>eine Technische Zeichnung zu sein, oder?
Technische Zeichung = Computergeneriert.
Ausnahmen bestätigen die Regel, z.B. eine gescannte technische
Zeichnung, welche vorher gedruckt wurde.
Oder ne alte Tuschezeichung ;-)
>Aber um deinen Pädagogischen Eingriff zu huldigen - ich werde in Zukunft>jpg verwenden.
Schau mal in den Anhang. Und vergleiche.
MFG
Falk
>Das selbe gilt für 1sen. Beim wechsel von beiden brauch er>allerdings tierisch lang. ca 100 us länger als gesollt um genau zu gehen.
Hallo Florian,
durchaus amüsant, die gleichen Fallen lauern überall. Weiter oben hat
schon mal jemand den Rat gegeben, OpenDCC anzusehen. Die Lösung nähert
sich langsam der Implenmentierung dort; ein Falle ist noch bei double
buffering der Timer OCR versteckt.
mfg Wolfgang K, www.opendcc.de