Forum: Mikrocontroller und Digitale Elektronik 3fach Software PWM reizt Tiny44 voll aus.


von Rene K. (draconix)


Lesenswert?

...joar... ich habe ein kleines Problem...

Ich habe einen Tiny44 welcher einfach eine Software PWM für 3 LED (RGB) 
zur Verfügung stellt. Leider jedoch muß ich meinen 8Bit Timer ohne 
Prescaler laufen lassen, welches den Tiny dann doch recht hart in die 
Knie zwingt.

Mit dem Oszi und dem Multimeter nachgemessen, ergaben sich ohne 
Prescaler gerade mal ~122Hz an den Pins, bei 8Mhz internem Takt.

Ich finde das schon recht wenig. Könnte jemand kurz über den Code 
schauen und sagen ob ich eventuell versuche dem falschen Lösungsansatz 
zu folgen?!
1
// Tiny44 - 8Mhz int. - MicroC - EasyAVR6
2
 
3
#define RedLED PortA.B2
4
#define GreLED PortA.B1
5
#define BluLED PortA.B0
6
7
volatile unsigned short Red, Blue, Green;
8
volatile unsigned short Runner;
9
unsigned short rRed, rGreen, rBlue;
10
11
volatile unsigned short pwmtable[32] = {0, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 10, 11,
12
                                    13, 16, 19, 23, 27, 32, 38, 45, 54, 64, 76,
13
                                    91, 108, 128, 152, 181, 215, 255};
14
15
void Timer0Overflow_ISR() org IVT_ADDR_TIM0_OVF                   //PWM OVF
16
 {
17
      Runner++;                                                      //Runner läuft über
18
      
19
      if(Runner >= Red)   RedLED = 0; else RedLED = 1;
20
      if(Runner >= Green) GreLED = 0; else GreLED = 1;
21
      if(Runner >= Blue)  BluLED = 0; else BluLED = 1;
22
 }
23
24
void GenRandom()
25
 {
26
          rRed = pwmtable[runner*32/255];delay_ms(11);
27
          rBlue = pwmtable[runner*32/255];delay_ms(97);
28
          rGreen = pwmtable[runner*32/255];
29
 }
30
31
32
33
void main() {
34
   unsigned short Runner2;
35
36
   SREG_I_bit = 1;                                     //Interrupt einschalten
37
   TIMSK0 = (1<<TOIE0);                                //Timer 0 Timer Overflow Interrupt
38
   TCCR0B = (1<<CS00);                                 //Prescaler 0 Timer 0
39
40
   DDRA   = 0xFF;                                      //PortB auf Ausgang
41
   PORTA  = 0;                                         //PortB aus
42
   delay_ms(1000);                                     //Einschaltverzögerung
43
44
   while(1)
45
   {
46
       Runner2++;                         //Runner2 läuft über
47
       
48
       if(Runner2==1) {                   //Farben per "Zufall" wählen
49
         GenRandom();
50
       }
51
       
52
           if(rRed > Red) {               //durch Farben faden
53
             Red = Red +1;
54
           } else if(rRed < Red) {
55
             Red = Red -1;
56
           }
57
58
           if(rBlue > Blue) {
59
             Blue = Blue +1;
60
           } else if(rBlue < Blue) {
61
             Blue = Blue -1;
62
           }
63
64
           if(rGreen > Green) {
65
             Green = Green +1;
66
           } else if(rGreen < Green) {
67
             Green = Green -1;
68
           }
69
70
         delay_ms(20);
71
   }
72
}

von Lehrmann M. (ubimbo)


Lesenswert?

Rene K. schrieb:
> Mit dem Oszi und dem Multimeter nachgemessen, ergaben sich ohne
> Prescaler gerade mal ~122Hz an den Pins, bei 8Mhz internem Takt.

Das klingt jetzt nicht unbedingt falsch - kannst ja mal einen 
Taschenrechner nehmen und das durchrechnen =)

von Rene K. (draconix)


Lesenswert?

8.000.000Hz / 2 = 4.000.000Hz / 256 Timer Stufen = 15.625Hz... ohne 
Code... Aber der Code zieht doch den Tiny nicht von 15Khz auf 122Hz 
runter?!

von Rene K. (draconix)


Lesenswert?

Ahhh..... Geistesblitz komme -.-

Ich lasse ja den Timer bis 256 überlaufen UND Runner als PWM Signal bis 
256 laufen....

Man man, manchmal sieht man echt den Wald vor lauter Bäumen net mehr -.-

von yx<bcx (Gast)


Lesenswert?

20ms Delay sollten doch eigentlich nur noch 50 Hz ergeben?

yx<bcx

von Joachim (Gast)


Lesenswert?

In der GenRandom Funktion sind auch nochmal 2 Delays drinne. Für was 
sind die denn gut?

Ich hab ein 32fach PWM mit je 32 Schritten auf dem ATTiny88 (8MHz) 
laufen und bekomm pro Ausgang 500Hz PWM Frequenz.

Genug Power hat der µC also.

Gruß Joachim

von sven (Gast)


Lesenswert?

wenns dann nochmal schneller werden muss eignet sich an der stelle auch 
ein wenig asm...

Gerade wenn man mehr als einen PWM Kanal hat kann man das folgendermaßen 
machen:


cp counter, pwm1 //carry wird gesetzt wenn counter > pwm1
rol r_tmp //bit0 ist gesetzt wenn counter > pwm1

cp counter, pwm2
rol r_tmp
...
out PORTX, r_tmp //bit0 wenn counter > pwm2, bit1 wenn counter > pwm1


Man braucht also pro Kanal nur noch 1x cp, 1x rol und vermutlich 
irgendwo ein paar lds. Dazu kommt noch ein out. Macht 3 + Kanalanzahl*4 
Takte

Damit schafft man dann doch einiges.

von Peter D. (peda)


Lesenswert?

Dein Compiler macht "unsigned short" wirklich als 8Bit?
Sehr ungewöhnlich.

Laut C-Standard muß "unsigned short" mindestens 16-bittig sein.
Nur "unsigned char" darf 8-bittig sein.
Besser ist aber "uint8_t" zu verwenden.


Peter

von Rene K. (draconix)


Lesenswert?

Ich habe nun ein Comparematch eingefügt, den Vorteiler auf 8 und somit 
noch einige Resourcen offen.

yx<bcx schrieb:
> 20ms Delay sollten doch eigentlich nur noch 50 Hz ergeben?
>
> yx<bcx

Ist für die PWM Erzeugung relativ uninteressant. Da die Frequenz 
ausschließlich in der Interruptroutine generiert wird.

Joachim schrieb:
> In der GenRandom Funktion sind auch nochmal 2 Delays drinne. Für was
> sind die denn gut?

Eigentlich nur um einen relativ unaufwendigen Randomizer zu bekommen. Er 
übernimmt einfach nur die Werte vom Runner der interruptroutine. 
Funktioniert eigentlich ganz gut, im ferigen Code wird dies natürlich 
nicht vorkommen, da der Tiny durch einen anderen µC gesteuert wird.

Joachim schrieb:
> Ich hab ein 32fach PWM mit je 32 Schritten auf dem ATTiny88 (8MHz)
> laufen und bekomm pro Ausgang 500Hz PWM Frequenz.
>
> Genug Power hat der µC also.

Jaja, das ist mir durchaus bewußt, das solch ein µC dies eigentlich 
links aus der Hüfte schaffen sollte.

sven schrieb:
> wenns dann nochmal schneller werden muss eignet sich an der stelle auch
> ein wenig asm...
>
> Gerade wenn man mehr als einen PWM Kanal hat kann man das folgendermaßen
> machen:
>
>
> cp counter, pwm1 //carry wird gesetzt wenn counter > pwm1
> rol r_tmp //bit0 ist gesetzt wenn counter > pwm1
>
> cp counter, pwm2
> rol r_tmp
> ...
> out PORTX, r_tmp //bit0 wenn counter > pwm2, bit1 wenn counter > pwm1
>
>
> Man braucht also pro Kanal nur noch 1x cp, 1x rol und vermutlich
> irgendwo ein paar lds. Dazu kommt noch ein out. Macht 3 + Kanalanzahl*4
> Takte
>
> Damit schafft man dann doch einiges.

Wirklich ein sehr sehr guter Ansatz! Damit werde ich mich mal 
auseinandersetzen!

Peter Dannegger schrieb:
> Dein Compiler macht "unsigned short" wirklich als 8Bit?
> Sehr ungewöhnlich.
>
> Laut C-Standard muß "unsigned short" mindestens 16-bittig sein.
> Nur "unsigned char" darf 8-bittig sein.
> Besser ist aber "uint8_t" zu verwenden.
>
>
> Peter

Jep, bei meinem Compiler (MicroC PRO AVR) ist short 8bit / 1Byte groß. 
Hier mal die übersicht, float und double haben 4byte:


bit                    1–bit          0 or 1
sbit                   1–bit          0 or 1
(unsigned) char        1              0 .. 255
signed char            1              -128 .. 127
(signed) short (int)   1              -128 .. 127
unsigned short (int)   1              0 .. 255
(signed) int           2              -32768 .. 32767
unsigned (int)         2              0 .. 65535
(signed) long (int)    4              -2147483648 .. 2147483647
unsigned long (int)    4              0 .. 4294967295

von Falk B. (falk)


Lesenswert?

Siehe Soft-PWM

von sven (Gast)


Lesenswert?

@Peter:

Ging mir ums Prinzip, hatte garnich auf die Datentypen geschaut.

Und mit 16Bit isses dann auch nur 1 cpc pro Kanal mehr :)

Gruß,
Sven

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.