ATTINY84 16-Bit PWM mit wählbarer Frequenz

Gast #5385757
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
Gast #5385779
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.
Gast #5385949
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren