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 ...