Attiny85 Software PWM

OP #4839918
Lesenswert?

Hallo,

bei meinem aktuellen Projekt soll ein Attiny85 zwei leicht verschiedene 
PWM-Signale erzeugen.

Da es am einfachsten war, die Pins 2 und 3 (PB3 und PB4) zu nehmen, 
dachte ich an eine Lösung mittels Software PWM.

Dabei wird über einen Timer (alle 2 us Interrupt) eine Variable 
(counter) hochgezählt. Erreicht diese bestimmte Werte, so werden die 
entsprechenden Pins geschaltet.
1
volatile int counter = 0;
2

3
const int mag_freq = 6240;
4
const int mag_duty = 256;
5

6
const int led_freq = 6211;
7
const int led_duty = 5;
8

9
const int mag = PB3; // vllt
10
const int led = PB4; // tauschen
11

12
int main {
13
  //Set timer0 
14
  //Interrupt every 2 us
15
  cli();
16
  TCCR0A = (1 << WGM01); // set ctc mode
17
  TCCR0B = (1 << CS00); // set no prescaler
18
  OCR0A = 15; // set ctc value
19
  TIMSK = (1 << OCIE0A); // enable interrupt
20

21
  sei();
22

23
  DDRB = (1 << mag) | (1 << led); // set outputs
24

25
  while(1) {
26

27
    if(counter % mag_freq == 0) { // mag on
28
      PORTB |= (1 << mag);
29
    }
30
    else if(counter % mag_freq == mag_duty) { // mag off
31
      PORTB &= ~(1 << mag);
32
    }
33
    if(counter % led_freq == 0) { //led on
34
      PORTB |= (1 << led);
35
    }
36
    else if(counter % led_freq == led_duty) { // led off
37
      PORTB &= ~(1 << led);
38
    }
39
  }
40
}
41

42
ISR(TIMER0_COMPA_vect) {
43
  ++counter;
44
}

Leider, und für mich unverständlicherweise, funktioniert der Code so 
nicht. Auf PB3 erhalte ich gar kein Signal und auf PB4 ein durchgängiges 
HIGH.

Da es ein Weihnachtsgeschenk werden soll, wäre ich für schnelle 
Antworten sehr dankbar!
Gruß Alex
Gast #4839928
Lesenswert?

Hallo,

2µs das ist sportlich, rechne dir bitte die Interrupt Reponsezeit und 
den Zeitbedarf einer ISR aus.

Den Timer0 muss man dann auch konfigurieren.

Bei FCPU = 8MHz sind das nur 16 Takte für alles.
Wählt man 16Mhz ist es mit 32 Takten immer noch sehr eng.
OP #4839947
Lesenswert?

Ja, 16 Takte ist wahrscheinlich zu knapp...

Hab jetzt gerade mal das Timerintervall auf 128 Takte hochgesetzt und 
dementsprechend die konstanten Werte oben runtergesetzt (alle durch 8 
geteilt).

Jetzt erhalte ich auch einen Output an beiden Pins, jedoch weder sehr 
regelmäßig, noch mit der gewünschten Frequenz (gewünscht ~80 Hz, 
tatsächlich ~unter 10 Hz).

Aus meiner Sicht scheint es tatsächlich an den zu kurzen 
Timerintervallen zu liegen, oder?
Gast #4839949
Lesenswert?

Hallo,

Rechne es Dir doch anhand des .lss Listings aus.
Vermutungen helfen Dir nicht weiter.

Das .lss Listing, zeigt des weitern auch noch, was der avr gcc wie 
übersetzt hat und wo man noch etwas optimieren kann.
OP #4839953
Lesenswert?

Vielleicht gibt es aber auch einen ganz anderen Ansatz, den ich bis 
jetzt übersehen habe, deshalb jetzt mal mein Ziel:

Der hier 
(https://github.com/cubic-print/timeframe/blob/master/software/TimeFrame_3_0_simple_instructables.ino) 
zu findene Code funktioniert auf meinem Arduino ganz wunderbar, es kommt 
zum gewünschten Effekt.

Da ich einen Arduino aber nicht im Projekt unterbringen kann (zu groß), 
versuche ich den Code auf einen Attiny85 zu bringen, leider bis jetzt 
ohne wirklichen Erfolg...
OP #4839959
Lesenswert?

Karl M. schrieb:
> Rechne es Dir doch anhand des .lss Listings aus.

Ich benutze die Arduino IDE zum programmieren, ich glaube die erzeugt 
keine solche Datei

S. Landolt schrieb:
> was benötigt diese '%'-Operation?

Damit sollen die unterschiedlichen Frequenzen mit einem counter 
bearbeitet werden können. Immer wenn der counter % einem bestimmten Wert 
== 0, ist eine Periode um
OP #4839986
Lesenswert?

S. Landolt schrieb:
> Nein, die Frage war nicht, was sie bewirkt, sondern wieviele Takte sie
> verbraucht.

Genau kann ich es dir leider nicht sagen, aber auf jeden Fall viel zu 
viele (zumindest in diesem Fall).

Habe die % Operation jetzt ersetzt, durch zwei unabhängige Counter 
Variablen, die mit dem Höchstwert verglichen und bei Übereinstimmung 
zurückgesetzt werden.

Jetzt funktioniert alles so wie es soll!

Vielen Dank für eure Hilfe und schöne Feiertage!
Gruß Alex
(Firma: Vescomp) #4839998
Lesenswert?

Alexander W. schrieb:
> Jetzt erhalte ich auch einen Output an beiden Pins, jedoch weder sehr
> regelmäßig, noch mit der gewünschten Frequenz (gewünscht ~80 Hz,
> tatsächlich ~unter 10 Hz).
>
> Aus meiner Sicht scheint es tatsächlich an den zu kurzen
> Timerintervallen zu liegen, oder?

 Und aus meiner Sicht scheint es an der CKDIV8 Fuse zu liegen.
 Dein Tiny läuft wahrscheinlich mit 1MHz.
#4840214
Lesenswert?

Alexander W. schrieb:
> Jetzt erhalte ich auch einen Output an beiden Pins, jedoch weder sehr
> regelmäßig, noch mit der gewünschten Frequenz (gewünscht ~80 Hz,
> tatsächlich ~unter 10 Hz).

Du erwartest was mit 80 Hz und hast was mit rund 10 Hz? Das klingt nach 
einem aktiven CLKDIV8-Fuse. Setze mal bei der Initialisierung folgendes 
zu beginn:
1
CLKPS = (1 << CLKPCE);
2
CLKPS = 0x00;
#4840396
Lesenswert?

Veit D. schrieb:
> Davon abgesehen würde ich die PWM Funktion der Timer
> nutzen. Einen Timer haste dafür sowieso schon in der Mangel.

Da hat er das Problem, dass er PB3 und PB4 benutzen will (warum auch 
immer, schrieb er oben). Die sind PWM-mäßig aber gekoppelt (PB3: !OC1A, 
PB4: OC1A). Die PWM-Signale sollen aber (leicht) verschieden sein. Mit 
der Hardware-PWM sehe ich da erstmal keinen Weg dass so zu realisieren. 
Gut wäre es natürlich wenn ein Pin sich ändern können würde, z.B. statt 
PB3 PB1 zu benutzten. Dann ginge das mit der Harware-PWM.
#4840412
Lesenswert?

Alexander W. schrieb:
> Dabei wird über einen Timer (alle 2 us Interrupt) eine Variable
> (counter) hochgezählt. Erreicht diese bestimmte Werte, so werden die
> entsprechenden Pins geschaltet.
...
> Leider, und für mich unverständlicherweise, funktioniert der Code so
> nicht. Auf PB3 erhalte ich gar kein Signal und auf PB4 ein durchgängiges
> HIGH.

Wie schon von anderen erwähnt, der Interrupt verbrät fast die ganze 
CPU-Zeit. Was in der Hauptschleife übrig bleibt soll dann für 4 
16Bit-Modulo-Operatoren ("%") ausreichen?
Der 500kHz Counter wird nämlich mit einer wesentlich kleineren Frequenz 
abgetastet. Allein die 4 Modulos brauchen (ohne Interrupt) schon 60μs. 
Da wäre man bei 16kHz, der Interrupt wird grob geschätzt nicht mehr als 
10% Rechenzeit übrig lassen, dann sind es 1,6kHz.
Dabei muß aber der exakte Wert 0 als Modulo-Ergebnis errechnet werden, 
so steht es aktuell da, was bei der Abtastung mit einen 50stel der 
"Eingangsfrequenz" einem Wunder gleichen würde.

Andere Idee: der Timer setzt nur sein Int-Flag, das die Hauptschleife 
als Takt benutzt. Wartet auf Int-Flag, dieses rücksetzen und einen 
Durchlauf machen. Statt Modulo-Operation auf einem "Zähler", bekommt 
jeder Kanal seinen eigenen, der je Durchlauf um 1 erhöht wird und bei 0 
einschaltet, bei PWM-Wert ausschaltet und bei MAX-Wert auf 0 
zurückgesetzt wird. Also einfach 2 16-Bit-Timer in Software, wenn sie 
die HW schon nicht hat.
Dafür werden vermutlich die 32 Takte (8MHz; 2μs "Zähler-Takt) nicht ganz 
reichen, deshalb langsam anfangen und um das "Warten auf HW-Timer" herum 
einen Pin toggeln, um die "übriggebliebene Zeit" zu messen. Vermutlich 
werden 10μs pro Durchlauf hinzubekommen sein.
#4840416
Lesenswert?

M. K. schrieb:
> Veit D. schrieb:
>> Davon abgesehen würde ich die PWM Funktion der Timer
>> nutzen. Einen Timer haste dafür sowieso schon in der Mangel.
>
> Da hat er das Problem, dass er PB3 und PB4 benutzen will (warum auch
> immer, schrieb er oben). Die sind PWM-mäßig aber gekoppelt (PB3: !OC1A,
> PB4: OC1A). Die PWM-Signale sollen aber (leicht) verschieden sein. Mit
> der Hardware-PWM sehe ich da erstmal keinen Weg dass so zu realisieren.
> Gut wäre es natürlich wenn ein Pin sich ändern können würde, z.B. statt
> PB3 PB1 zu benutzten. Dann ginge das mit der Harware-PWM.

Er braucht auch einen 16-Bit-Timer, eher 2, wollte er das mit HW-PWM 
machen, die der kleine 8-Poler gar nicht hat.
#4840479
Lesenswert?

Hallo,

ich würde erstmal das besagte abarbeiten. Dein µC Takt oder Timer Konfig 
scheint nicht zu stimmen. Denn mit 80Hz Solltakt kommt man in keine 
zeitlichen Probleme.

Desweiteren sollte der atomic Zugriff auf counter beachtet werden!

Ob Software oder Hardwaretimer. Er hätte zwei 8Bit Timer zur Verfügung. 
Können also unterschiedlich konfiguriert werden. Aber gut, kommt auf den 
Zweck und Anforderung an.

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