Hallo,
ich habe mich heute ein bisschen in die Timer in Verbindung mit
Interruptfunktionen beschäftigt. Ich würde gerne eine Softwarelösung zum
generieren von zwei PWM Signale realisieren. Ich habe dazu die CTC
Methode verwändet. Der Code hänge ich unten an.
Im Einsatz ist ein ATMEGA8 an einem 16MHz Quarz.
Zum Berechnen des OCR Wertes habe ich folgende Formel benutzt:
OCRnx = e ^ (0,00330082*iBit+5,86166)
Wobei iBit für einen Wert vom AD Wandler steht und somit zwischen
0-1024bit liegt. Die Formel habe ich über Gnumeric ermittelt um den
Bereich von 1,5kHz bis 4,5kHz abzudecken. Über die Formel zum Berechnen
der Freqenzen mit Hilfe folgender Formel hat auch in Exel exakt
gestimmt. Jedoch bekomme ich bei dem unten angehängten Programm exakt
die hälfte der Frequenz. Obwohl der Prescaler auf 1 eingestellt ist.
Freq = (F_CPU/(Prescaler*(OCRnx+1)))
Wie man sie auch hier findet:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR#CTC-Betriebsart_.28Clear_Timer_on_Compare_Match.29
Mir ist kein offensichtlicher Fehler aufgefallen vielleicht habt ihr ja
noch einen Tipp für mich.
1 | volatile uint8_t flag;
|
2 |
|
3 | int OCR(int iBit)
|
4 | {
|
5 | float f_e, f_func_var1, f_func_var2, f_OCR_res, f_OCR_zres;
|
6 | int i_OCR_res;
|
7 | f_e = 2.718282;
|
8 | f_func_var1 = 0.00330082;
|
9 | f_func_var2 = 5.86166;
|
10 | f_OCR_zres = ((f_func_var1 * iBit) + f_func_var2);
|
11 | f_OCR_res = (float) pow(f_e, f_OCR_zres);
|
12 | f_OCR_res += 0.5;
|
13 | i_OCR_res = (int) f_OCR_res;
|
14 | return i_OCR_res;
|
15 | }
|
16 |
|
17 | float frequenz(int i_OCR)
|
18 | {
|
19 | float f_freq_res;
|
20 | f_freq_res = (CPU_T/(PRESCALE*(i_OCR+1)));
|
21 | f_freq_res = (f_freq_res / 1000);
|
22 | return f_freq_res;
|
23 | }
|
24 |
|
25 |
|
26 | ISR (TIMER1_COMPB_vect)//(SIG_OUTPUT_COMPARE1B)
|
27 | {
|
28 | if (flag == 1) {
|
29 | flag = 0;
|
30 | PORTB |= (1<<PB1);
|
31 | PORTB &= ~(1<<PB2);
|
32 | }
|
33 | else {
|
34 | flag = 1;
|
35 | PORTB &= ~(1<<PB1);
|
36 | PORTB |= (1<<PB2);
|
37 | }
|
38 | }
|
39 | int main(void)
|
40 |
|
41 | {
|
42 | ...
|
43 | //PortB Einstellen
|
44 | DDRB |= (1 << DDB1) | (1 << DDB2); //PIN PB1 und PB2 als Ausgang
|
45 | //Timer Einstellen
|
46 | TCCR1B = 0x00;
|
47 | TCCR1B |= (1<<WGM12); //Timer1 mit Auflösung 2¹⁶ in CTC Modus
|
48 | TCCR1B |= (1<<CS10); //Prescaler auf 1
|
49 | TIMSK |= (1<<OCIE1B);// Output Compare Match Interrupt Enable
|
50 | sei();
|
51 | ...
|
52 | //Hauptprogramm starten
|
53 |
|
54 | while(1){
|
55 | ...
|
56 | cli();
|
57 | OCR1A = (uint16_t) iOCR;
|
58 | sei();
|
59 | ...
|
60 | }
|