Forum: Mikrocontroller und Digitale Elektronik Attiny85/45/25 Soft-PWM mit Timer 1 - 12bit


von Sven (Gast)


Lesenswert?

Guten Abend,

ich möchte mit einem Attiny85 eine 12bit RGB-Steuerung realisieren.

Allgemeine Problematik von RGB Steuerungen:
Um möglichst weiche Farbübergänge zu erzeugen sollte die RGB-Steuerung 
mit einer möglichst hohen Auflösung arbeiten. Dabei muss aber 
gleichzeitig auf die Frequenz des PWM-Signals geachtet werden, dass 
diese nicht flimmert.
Außerdem soll die nicht lineare Kennlinie des menschlichen Auges 
berücksichtigt werden um so einen linearen Helligkeitsverlauf der Farben 
zu erzeugen.

Kurz zu meiem Programm:
Ich möchte den Timer 1 des Attiny85 im asynchronen Modus mit 64Mhz 
betreiben um eine möglichst hohe PWM Frequenz zu erreichen. Rechnerisch 
ergäbe sich meines Verständnisses nach in meinem Programm eine 
PWM-Frequenz von ca. 61Hz (siehe Kommentar). Leider sehe ich ein starkes 
Flackern, sodass ich sagen kann die Frequenz liegt bei vllt 10 Hz 
(geschätzt). Leider habe ich kein Oszilloskop oder Ähnliches um mir das 
erzeugte PWM-Signal anzeigen zu lassen.

Meine Frage:
Wo liegt also mein Fehler? Warum beträgt die PWM-Frequenz nicht meine 
errechneten 61Hz?
1
#ifndef F_CPU
2
#define F_CPU 8000000UL 
3
#endif
4
5
#include <avr/io.h>
6
#include <util/delay.h>
7
#include <avr/interrupt.h>
8
9
#define rot_an    PORTB |= (1 << PB1)
10
#define rot_aus    PORTB &= ~(1 << PB1)
11
12
#define gruen_an    PORTB |= (1 << PB3)
13
#define gruen_aus    PORTB &= ~(1 << PB3)
14
15
#define blau_an    PORTB |= (1 << PB4)
16
#define blau_aus    PORTB &= ~(1 << PB4)
17
18
// Variablen definieren
19
volatile uint8_t rot;
20
volatile uint8_t gruen;
21
volatile uint8_t blau;
22
volatile uint16_t timer; 
23
24
uint16_t Helligkeit[99]   = {
25
  0,    1,    1,    1,    1,    1,    2,    2,    2,    2,
26
  2,    3,    3,    3,    3,    4,    4,    4,    5,    5,
27
  5,    6,    6,    7,    8,    8,    9,    10,    11,    12,
28
  13,    14,    15,    16,    18,    20,    21,    23,    25,    27,
29
  30,    32,    35,    38,    42,    46,    50,    54,    59,    64,  
30
  70,    76,    83,    90,    98,    106,  116,  126,  137,  150,
31
  163,  177,    193,  210,  229,  249,  271,  295,  321,  349,  
32
  380,  414,  451,  491,  534,  581,  633,  689,  750,  816,
33
  889,  967,  1053,  1146,  1248,  1359,  1479,  1610,  1752,  1908,
34
  2077,  2261,  2461,  2679,  2916,  3174,  3456,  3762,  4095
35
};
36
37
// ***** Timer1-Overflow-Interrupt ****** --> PWM Frequenz = 64MHz/256(Oerflows pro Sek)/4096(Timer)/1(Prescaler) = 61 Hz
38
ISR (TIMER1_OVF_vect){ 
39
40
if (timer < 4095) {timer++;}
41
else {timer = 0;}
42
43
if (timer < Helligkeit[rot]) {rot_an;}
44
else {rot_aus;}
45
if (timer < Helligkeit[gruen]) {gruen_an;}
46
else {gruen_aus;}
47
if (timer < Helligkeit[blau]) {blau_an;}
48
else {blau_aus;}
49
}
50
51
// ***** Hauptprogramm *****
52
int main(void){
53
// Variablen setzen
54
rot = 0; 
55
gruen = 0;
56
blau = 0;
57
timer = 0;
58
59
// PortB 345 zu Ausgängen und auf 0
60
DDRB |= (1<<DDB3)|(1<<DDB4)|(1<<DDB1);
61
PORTB &= ~(1<<PB3)|(1<<PB4)|(1<<PB1);
62
                
63
//asynchronen Modus aktivieren (64Mhz) - dazu laut Datenblatt: 1) PLL aktivieren 2) Warten bis PLL eingerastet 3) PCKE setzen
64
PLLCSR |= (1<<PLLE);
65
_delay_us(100); 
66
while(!(PLLCSR & (1<<PLOCK)));
67
PLLCSR |= (1<<PCKE);
68
69
// Timer 1 konfigurieren: Clock = PCK 
70
TCCR1 |= (1<<CS10); 
71
72
//Overflow Interrupt Timer 1 aktivieren
73
TIMSK |= (1<<TOIE1);
74
75
// Global Interrupts aktivieren
76
sei();
77
78
// ***** Endlosschleife *****
79
while(1){
80
81
while (rot<98) {rot++; _delay_ms(1);}
82
while (rot>0) {rot--; _delay_ms(1);}
83
84
} //eof while
85
} //eof main

Vielen Dank für eure Hilfe!

Freundliche Grüße,
Sven

von Mark L. (m2k10) Benutzerseite


Lesenswert?

Mir fallen da mehrere Sachen auf. Zum einen, ich persönlich sehe sogar 
bei 150Hz noch Flackern, hab aber gelesen, dass ab 100-120Hz die meisten 
Menschen kein Flackern mehr wahrnehmen. Vielleicht sind die 61Hz 
insgesamt schon etwas zu wenig.

Aber egal, bei Software von dir passiert folgendes:
Du lässt zwar den Timer mit 64MHz laufen, aber der AVR arbeitet dennoch 
mit 8MHz seine Befehle ab. Du hast daher alle 32 Takte einen Overflow 
vom Timer und dein AVR kommt da nicht mehr mit die ISR abzuarbeiten und 
verschluckt daher entsprechend viele (bei ca. 10Hz würde er eine 
abarbeiten und 5 überspringen). Selbst in reinem Assembler würde das 
knapp. Der Compiler sichert schlimmstenfalls alle Register und benötigt 
dafür alleine 132 Takte.

Die 64MHz bringen nichts, wenn man nur den Timeroverflow ohne die PWM 
verwendet. Ist das gleiche, als wenn du den Timer normal bis 31 laufen 
lässt (außer, dass es eher auffällt, dass es so nicht geht).

Mark

von Sven (Gast)


Lesenswert?

Vielen Dank!

Jetzt habe ich meinen Denkfehler(nach einigen Tagen nahe der 
Verzweifelung) verstanden!

Also kann ich wohl eine höhere Auflösung mit diesem AVR (bei gleichem 
Takt) und Soft-PWM nicht erreichen.

Schönen Abend noch!

von Falk B. (falk)


Lesenswert?

Siehe Soft-PWM. Allerdings ist bei ~10 Bit Auflösung Feierabend. 
Reicht aber meist, siehe LED-Fading.

MFG
Falk

von Frank B. (foobar)


Lesenswert?

Man kann den PWM-Ausgang direkt rausschalten, sodaß du also nicht per 
Interrupt die LEDs manuell an- und ausschalten musst, was bei der hohen 
Frequenz wegen dem Jitter sowieso zu starken Ungenauigkeiten bei der 
Helligkeit führen würde. Ich weiss allerdings nicht, wieviel 
PWM-Ausgänge der Chip hat, also RGB wird damit dann ggf. nicht gehen, 
aber du kannst es ja mal für eine LED ausprobieren. Sollte dann nicht 
flackern. Die 100 Hz kannst du per Soundkarte aufnehmen und mit einen 
der vielen verfügbaren Soundkarten Oszilloskope analysieren.

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.