Forum: Compiler & IDEs Atmega88 und Fast PWM Mode14. Ein Drama


von Horsti (Gast)


Lesenswert?

Hallo Männer,

ich bin mal wieder am verzweifeln und brauche mal wieder ernsthafte 
Hilfe

Es geht um folgende Aufgabestellung.

Ich möchte ein PWM Signal erzeugen ähnlich wie es im Modellbau gemacht 
wird.

Die Gesamtperiode hat eine Länge von 9ms. Es gibt 4 variable Pulse, die 
zwischen 0,5ms und 1ms liegen können. Zwischen den Pulsen liegt eine 
Pause von 0,2ms und nach dem 4 Puls folgt eine Pause, so das insgesamt 
9ms herauskommen. Danach geht es wieder von vorne los.

Ich dachte, ich mache das ganze mit Fast PWM (Mode 14) mit einem 
Atmega88.

Hier mein Beispiel-Code
1
/*
2
 Hardware
3
 ATMEGA88, Takt 8 Mhz intern
4
 Output OC1A 
5
6
*/
7
8
#include <avr/io.h>
9
#include <avr/interrupt.h>
10
11
#define CHANNELS 4
12
13
volatile uint16_t port[ CHANNELS];
14
volatile uint16_t pause = 0;
15
volatile uint16_t sync_len = 200;  // 0,2ms
16
volatile uint16_t per_len = 9000;  // Gesamt-Laenge
17
volatile uint8_t active = 0;       // aktueller Port
18
volatile uint8_t channels = CHANNELS;
19
volatile uint16_t counter = 0;
20
21
22
ISR( TIMER1_OVF_vect) 
23
{
24
 OCR1A = port[ active];
25
26
 if( active != channels -1)
27
  ICR1  = OCR1A + sync_len;
28
 else
29
   ICR1 = OCR1A + per_len - ((channels-1) * sync_len) - pause;
30
 
31
 if( active == 0) // erster Port
32
 {
33
  pause = port[ active];
34
  ++counter;
35
 }
36
 else
37
 {
38
  pause += port[ active];
39
 }
40
 active = (active+1) % channels; // active = 0 - 3
41
} // ISR
42
43
44
int main( void)
45
{
46
 uint8_t i = 0;
47
 uint16_t t ;
48
49
 for( i = 0; i < 4; ++i)
50
 {
51
  port[ i] = 800;
52
 }
53
   
54
 DDRB = (1 << DDB1); // OC1A auf output
55
 
56
 TCCR1A = ( 1<< COM1A1)| ( 1<< COM1A0)| ( 1<< WGM11);
57
 TCCR1B = ( 1<< WGM13) | ( 1<< WGM12) | ( 1<< CS11); // Teiler/8
58
  
59
 TCCR1C = 0;
60
  
61
 OCR1A = port[ 0];
62
 ICR1  = OCR1A + sync_len;
63
64
 TIFR1  = (1 << TOV1);//| (1 << OCF1A);
65
 TIMSK1 = (1 << TOIE1);
66
67
 sei();
68
 
69
 t = counter;
70
 i = 0;
71
 
72
 while (1)
73
 {
74
  if( counter - t == 40) // kleines test
75
  {
76
   cli();
77
   port[ 1] = 900 + (((++i) % 2)? 0 : 400);
78
   sei();
79
   t = counter;
80
  } // if
81
 } // while
82
 return 0;
83
}

Ich gehe/ging davon aus, dass das Test-Programm 4 Pulse je 0,8ms liefert 
mit jeweils einer 0,2ms Pause und am Ende dann ca. 5,2ms low. Ich kann 
das so schlecht beschreiben :-(

Was passiert ist, das die Pulse völlig unterschiedlich lang sind. Nehme 
ich in der ISR die if Abfrage raus, in der ICR1 einmal berechnet wird 
(ICR1 = per_len...) , ist das Gesamtsignal ok. In dem Moment, wo ich 
ICR1 einmal verändere, passt nichts. Alternativ kann ich auch ICR1 immer 
um syn_len größer als OCR1A lassen. Aber wenn in der while Schleife 
port[1] oder [2] geändert wird, bricht das Gesamtsignal wieder zusammen.

Ist meine Vorgehensweise evtl grundsätzlich falsch, oder ...

von Stefan E. (sternst)


Lesenswert?

1) Wieso inverting-mode? Dieses "am Ende dann ca. 5,2ms low" legt doch 
eher nahe, dass es positive Pulse sind, oder?

2) Ich habe den Code jetzt nicht bis ins letzte Detail analysiert, aber 
ich denke du hast folgendes nicht ausreichend (wenn überhaupt) bedacht:
1
The OCR1x Register is double buffered when using any of the twelve
2
Pulse Width Modulation (PWM) modes.
3
...
4
The double buffering synchronizes the update of the OCR1x Compare Register
5
to either TOP or BOTTOM of the counting sequence.
6
...
7
The ICR1 Register is not double buffered.

von Horsti (Gast)


Lesenswert?

Stefan Ernst schrieb:
> 1) Wieso inverting-mode? Dieses "am Ende dann ca. 5,2ms low" legt doch
> eher nahe, dass es positive Pulse sind, oder?

Das ist ein Fehler beim Kopieren des Codes gewesen. ( 1<< COM1A0) gehört 
da natürlich nicht rein.

zu 2
Ehrlich gesagt verstehe ich nicht, was mir das Zitat sagen will. Ich 
habe das in der Doku mehrfach gelesen, verstehe aber den Sinn nicht.

von Peter D. (peda)


Lesenswert?

Horsti schrieb:
> Ehrlich gesagt verstehe ich nicht, was mir das Zitat sagen will.

ICR wird sofort übernommen, OCRA einen Durchlauf später.
Sie passen also nicht zusammen.


Peter

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.