Forum: Mikrocontroller und Digitale Elektronik ATTINY84 16-Bit PWM mit wählbarer Frequenz


von Max (Gast)


Lesenswert?

Hallo,
kann mir jemand weiterhelfen?
Ich versuche auf dem Attiny84 ein PWM-Signal mit einstellbarer Frequenz 
zu erzeugen.
Dazu benutze ich den 8-bit Timer der über Timer Interrupts beim Compare 
Register A einen Port anschaltet und beim Compare Register B wieder aus.
Zusätzlich wird dann noch der Timer zurückgesetzt.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
int main(void)
5
{
6
DDRA=0xFF;
7
sei();//enable global interrupts
8
TIMSK0|=(1<<OCIE0A);//enable OCR0A interrupt
9
TIMSK0|=(1<<OCIE0B);//enable OCR0A interrupt
10
//TCCR0B|=(1<<CS00);//no prescaler
11
TCCR0B|=(1<<CS01);//prescaler 8
12
OCR0A=50;//offtime
13
OCR0B=200;//ontime+offtime
14
15
while (1)
16
{
17
}
18
19
}
20
21
ISR(TIM0_COMPA_vect)//compare register A interrupt
22
{
23
PORTA=0xFF;//turn on Port A
24
}
25
26
ISR(TIM0_COMPB_vect)//compare register A interrupt
27
{
28
PORTA=0x00;//Turn off Port A
29
TCNT0=0;//reset Timer 1
30
}

Das funktioniert auch ohne Probleme, jedoch reicht für meine Anwendung 
die Auflösung nicht, weshalb ich jetzt versuche das ganze über den 
16-Bit Timer zu realisieren. Dazu verwende ich einen ähnlichen Code mit 
angepassten Registern.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
int main(void)
5
{
6
7
       DDRA=0xFF;//Port A output
8
9
       OCR1AL=0xFF;//offtime low bit
10
       OCR1AH=0x01;//offtime high bit
11
12
       OCR1BL=0xFF;//ontime+offtime low bit
13
       OCR1BH=0xFF;//ontime+offtime high bit
14
15
       //TCCR1B|=(1<<CS10);//no prescaler
16
       TCCR1B|=(1<<CS11);//prescaler 8
17
18
       TIMSK1|=(1<<OCIE1A);//enable OCR1A interrupt
19
       TIMSK1|=(1<<OCIE1B);//enable OCR1B interrupt
20
21
       sei();//enable global interrupts
22
23
       while (1)//wait
24
       {
25
       }
26
27
}
28
29
ISR(TIM1_COMPA_vect)//compare register A interrupt
30
{
31
       PORTA=0xFF;//turn Port A on
32
}
33
34
ISR(TIM1_COMPB_vect)//compare register B interrupt
35
{
36
       PORTA=0x00;//turn Port A off
37
       cli();//disable global interrupts just to be sure
38
       TCNT1L=0;//reset counter1 low bit
39
       TCNT1H=0;//reset counter1 high bit
40
       sei();//enable global interrupts just to be sure
41
}

Dieser Code funktioniert allerdings nicht. Egal welche Werte ich 
einstelle bekomme ich immer etwa 50% PWM.
Ich vermutete das Problem bei den 16-Bit Vergleichsregistern also lies 
ich mir deren Werte über LEDs ausgeben.
Es scheint, als würden die High Register nicht funktionieren. OCR1AH ist 
immer 0 und OCR1BH ist immer 0b01000011 egal welchen Wert ich in die 
Vergleichsregister schreibe. Die Interrupts werden natürlich auch zum 
falschen Zeitpunkt ausgelöst.

Liebe Grüße und Danke schonmal im Voraus,
Max

von S. Landolt (Gast)


Lesenswert?

Beim Schreiben von Registern gilt: erst H, dann L, s.a. Datenblatt unter 
'Accessing 16-bit Registers'. Aber in C geht das doch besser ohne H und 
L, um die Reihenfolge kümmert sich der Compiler.

von Jacko (Gast)


Lesenswert?

Wenn du nicht den gesamten PortA umschalten musst, geht
das auch automatisch über PortA-5 (OC1B) im fast PWM-Mode 14.

Dann genügt ein Interrupt (T1-Overflow) um die Gesamtperiode
(ICR1) und die aktive Zeit (OCR1B) zu ändern.

Die Polarität für die aktive/nichtaktive Zeit wählst du mit
COM1B1/0.

von Max (Gast)


Lesenswert?

Vielen Dank für die schnelle Hilfe.
Ich habe jetzt das Register direkt mit einem 16-Bit Wert beschrieben und 
den Compiler die genaue Zuordnung erledigen lassen und es funktioniert 
problemlos.

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.