Forum: Mikrocontroller und Digitale Elektronik AVR libc 328p, (Verständnis)Probleme mit Timern


von Alexander G. (jasmir)


Lesenswert?

Hallo zusammen,

ich habe zwei Probleme mit Timern und komme nicht weiter:

1) Es funktioneren nicht zwei Timer gleichzeitig. Wenn ich im u.a. 
Programm den Timer2 wieder einkommentiere, tut die ISR für den Timer0 
genau garnichts mehr. Hat hier jemand nen Tipp für mich?

2) Der Timer (in diesem Fall Timer2) gibt eine ganz andere Frequenz 
zurück als erwartet. Der 328p sitzt auf nem Arduino-Nano Board, das mit 
16MHz Taktfrequenz angegeben ist. Die Kommentare im Code spiegeln meine 
Erwartung  & die Realität wieder. Vertue ich mich da irgendwie mit den 
Prescalern & dem Zähler, oder ist es normal das die Arduino-Boards 
derartig ungenau sind?


Hier das Programm:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdint.h>
4
5
// ********** Config **********
6
7
volatile uint32_t seconds = 68400;  // Startzeit bei PowerUp (19:00 Uhr)
8
uint8_t daemmerungSeconds = 10;    // Dauer der Daemmerung pro PWM-Stufe
9
uint8_t pwmTicksMax = 50;     // Anzahl der moeglichen PWM-Werte
10
11
12
uint32_t lichtAn_Kanal_1[2] = {25200,57600};  // Licht-An Zeiten (7 & 16 Uhr)
13
uint32_t lichtAusKanal_1[2] = {46800,79200};  // Licht-Aus Zeiten (13 & 22 Uhr)
14
volatile int8_t pwmDirKanal_1 = 1;      // PWM Vector bei Startzeit (1 -> wird heller, -1 -> wird dunkler, 0 bleibt so. Andere Werte sind properitär)
15
16
17
// ********** Config Ende **********
18
19
// http://www.avrfreaks.net/forum/tut-c-newbies-guide-avr-timers?name=PNphpBB2&file=viewtopic&t=50106
20
// https://sites.google.com/site/qeewiki/books/avr-guide/timers-on-the-atmega328
21
22
volatile uint16_t octalMilliseconds = 0;
23
uint8_t pwmTicks = 0;
24
25
volatile uint8_t pwmCurrentKanal_1 = 1;
26
volatile uint8_t pwmChangeTickKanal_1 = 0;
27
28
29
int main(void)
30
{
31
    TCCR0A |= (1 << WGM01);  // Uhr-Timer auf CTC setzen
32
    OCR0A = 0x02;    // Zaehlgrenze setzen (2)
33
    TIMSK0 |= (1 << OCIE0A);  // Set the ISR COMPA vect
34
    TCCR0B |= (1 << CS02);  // Prescaler auf 256 setzen
35
36
/** 
37
    TCCR2A |= (1 << WGM21);  // PWM-Timer auf CTC setzen
38
    OCR2A = 0x02;    // Zaehlgrenze setzen (2)
39
    TIMSK2 |= (1 << OCIE2A);  // Set the ISR COMPA vect
40
    TCCR2B |= (1 << CS21) | (1 << CS21);  // Prescaler auf 256 setzen
41
**/
42
43
    sei();      // Interrupts an
44
45
    DDRD = 0b11111100;    // Port D auf Output setzen, Pin 0 & 1 bleiben Input (Serial RX und TX)...
46
    PORTD = 0b00000000;    // und erstmal alle Ausgaenge auf 0.
47
48
    while(1) {
49
//        if(octalMilliseconds >= 31250) { // Sollten mit dem Prescaler 256 und der Zaehlgrenze von 2 genau eine Sekunde sein...
50
        if(octalMilliseconds >= 20838) { // Das ist wirklich eine Sekunde (ungefaehr...)
51
      seconds++;
52
      octalMilliseconds = 0;
53
            if(seconds >= 86400) {  //Reset der Sekunden am Tagesende
54
                seconds = 0;
55
            }
56
            // PWM-Setzen Kanal 1
57
            if((seconds == lichtAn_Kanal_1[0]) || (seconds == lichtAn_Kanal_1[1])) {
58
                pwmDirKanal_1 = 1;
59
            }
60
            if((seconds == lichtAusKanal_1[0]) || (seconds == lichtAusKanal_1[1])) {
61
                pwmDirKanal_1 = -1;
62
            }
63
      if(seconds == 75600) {  // Extra: Kanal um 21:00 Uhr runterdimmen
64
          pwmDirKanal_1 = -2;
65
      }
66
            if(pwmDirKanal_1 != 0) {
67
                if (pwmChangeTickKanal_1 == daemmerungSeconds) {
68
                    pwmChangeTickKanal_1 = 0;
69
                    pwmCurrentKanal_1 = pwmCurrentKanal_1 + pwmDirKanal_1;
70
        if ((pwmDirKanal_1 == -2) && (pwmCurrentKanal_1 <= 9)) {  // Extra: Kanal um 21:00 Uhr runterdimmen
71
            pwmDirKanal_1 = 0;
72
        }
73
                    if ((pwmCurrentKanal_1 == pwmTicksMax) || (pwmCurrentKanal_1 == 0)) { // wenn PWM-Max oder 0 erreicht sind, PWM-Dir wieder auf 0 setzen
74
                  pwmDirKanal_1 = 0;
75
              }
76
          }
77
          pwmChangeTickKanal_1++;
78
            }
79
            // ###################
80
        }
81
    }
82
}
83
84
/**
85
ISR (TIMER0_COMPA_vect)  // timer0 Uhr, alle 8 msec
86
{
87
    octalMilliseconds++;
88
}
89
**/
90
91
//ISR (TIMER2_COMPA_vect) {  // timer2 PWM, alle 32µsec
92
ISR (TIMER0_COMPA_vect) {  // Da keine zwei Timer funktionieren, Umbau auf nur einen Timer fuer alles
93
    // PWM-Teil
94
    if(pwmTicks <= pwmCurrentKanal_1) {
95
        PORTD |= (1 << PD7);  // Pin 7 auf 1
96
    }
97
    else {
98
        PORTD &= ~(1 << PD7);  // Pin 7 wieder auf 0
99
    }
100
    // ##############
101
102
    if(pwmTicks >=pwmTicksMax) {  // PWM-Zyklus resetten
103
      pwmTicks=0;
104
    }
105
    pwmTicks++;
106
    octalMilliseconds++;
107
}


PS: Das sind zwei Premieren für mich: Erstes Programm in C und erstes 
mal nen µC Programmieren. Sonstige Kritik ist erwünscht!

: Verschoben durch User
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.