Hallo Leute,
habe ein Problem mit meinem unten angehängten Programm. Das Programm
soll ein PWM Signal am Input Capture Pin ICR1 einlesen und daraus die
DutyCycle messen und per UART ausgeben. Ich habe Teile des Codes aus dem
Internet herauskopiert, da ich noch nicht ganz verstehe wie der Input
Capture Pin, bzw. dessen Programmcode auszusehen hat oder funktioniert.
Zum Programmcode: Es werden steigende bzw. fallende Flanken erfasst, die
Zeitpunkte "gemessen" und die Zeitdifferenz der Flanken berechnet. Man
kann sich dann daraus zwei Zeitdifferenzen errechnen, einmal die High
Pulslänge und einmal die Gesamtlänge. Dann werden diese beiden ins
Verhältnis gesetzt, also HighPulslänge/Gesamtlänge, raus kommt die
DutyCycle. Und jetzt kommt mein Problem. Es kommen zwei verschiedene
Wertebereiche heraus, einmal Werte von 37-42 und einmal 3-8. Darüber
hinaus ist es so, dass 3=37 entspricht, 4=38, 5=39, usw. . Hab dieses
Problem relativ pragmatsch mit den if-Anweisungen:
1 | if(DutyCycle == 42){DutyCycle = 8;}
|
usw. gelöst. Hab da noch kein Muster erkennen können, wann welcher
Wertebereich dran ist und wie lange Werte aus dem einen Wertebereich
folgen und wann aus dem Anderen. Das springt auch teilweise sehr schnell
hin und her. Also es scheint mir so, als ob das "willkürlich" passiert.
Nun meine erste Frage. Warum kommen da zwei verschiedene Wertebereiche
raus? Liegt es daran, dass am Schluss der while Schleife der Zähler
zurückgesetzt wird? Oder liegt der Fehlern in den Interrupt Funktionen
begraben? Vielleicht kann mir da ein Profi weiterhelfen, glaube da kann
nicht viel falsch sein...
Des Weiteren will ich nicht den DutyCycle, sondern auch die
High-Pulslänge alleine messen. Dazu haben ich bei der Formel für den
DutyCycle nur den Nenner verwendet und ausgeben lassen, also
1 | DutyCycle=(uint8_t)(((uint32_t)(Capt2-Capt1)+((uint32_t)T1Ovs1*0x10000L))*100L);
|
Da kann ich jetzt gar kein Muster mehr feststellen, da kommen
irgendwelche Werte raus, zwischen 0 und 250. Vielleicht wird dieses
Problem auch gelöst, wenn mein erstes Problem behoben. Es kann aber auch
sein, dass da noch was anderes faul ist. Vielleicht hat da jemand eine
Idee.
Ach ja, und falls das jemand ausprobieren sollte. Als PWM Signal habe
ich ein Modellbau Servo PWM Signalgenerator verwendet, das ist nicht das
typische Signal mit 100% DutyCycle, das hat nur einen DutyCycle von 0
bis 10 Prozent und eine geringe Frequenz, deshalb wahrscheinlich die
Werte von 3 bis 8.
Vielen Dank schon mal an alle die sich meinem Problem heranwagen :-)
1 | #define F_CPU 8000000UL
|
2 | #include <avr/io.h>
|
3 | #include <avr/interrupt.h>
|
4 | #include <util/delay.h>
|
5 | #include <stdio.h>
|
6 |
|
7 | volatile uint16_t T1Ovs1, T1Ovs2; //Zähler Überlauf
|
8 | volatile uint16_t Capt1, Capt2, Capt3; //Variable der drei Zeitstempel
|
9 | volatile uint8_t Flag; //Flag
|
10 |
|
11 | #define BAUD 9600UL
|
12 | #define UBRR0_Value ((F_CPU/(16*BAUD))-1)
|
13 |
|
14 | int uart_putc(unsigned char c)
|
15 | {
|
16 | while (!(UCSR0A & (1<<UDRE0))) {}
|
17 |
|
18 | UDR0 = c; //Zeichen senden
|
19 | return 0;
|
20 | }
|
21 |
|
22 | void uart_puts (char *s)
|
23 | {
|
24 | while (*s)
|
25 | { // so lange *s != '\0' also ungleich dem "String-Endezeichen"
|
26 | uart_putc(*s);
|
27 | s++;
|
28 | }
|
29 | }
|
30 |
|
31 |
|
32 | void InitTimer1(void) //Timer initialisieren
|
33 | {
|
34 | TCCR1B|=(1<<ICES1); //steigende Flanke erfassen
|
35 | TCNT1=0; //Timer mit 0 initialisieren
|
36 | TIMSK1|=(1<<ICIE1)|(1<<TOIE1); //Input Capture und Überlauf Interrupts erlauben
|
37 | }
|
38 | void StartTimer1(void)
|
39 | {
|
40 | TCCR1B|=(1<<CS10); //Timer starten ohne Prescaler
|
41 | sei(); //globale Interrupts erlauben
|
42 | }
|
43 |
|
44 | ISR(TIMER1_CAPT_vect)
|
45 | {
|
46 | if (Flag==0)
|
47 | {
|
48 | TCCR1B&=~(1<<ICES1); //erfassen der fallenden Flanke
|
49 | Capt1=ICR1; //Zeitstempel speichern
|
50 | T1Ovs2=0; //Überlauf auf 0 setzen
|
51 | }
|
52 |
|
53 | if (Flag==1)
|
54 | {
|
55 | TCCR1B|=(1<<ICES1); //erfassen der steigenden Flanke
|
56 | Capt2=ICR1; //Zeitstempel speichern
|
57 | T1Ovs1=T1Ovs2; //erster Überlauf Zähler
|
58 | }
|
59 |
|
60 | if (Flag==2)
|
61 | {
|
62 | Capt3=ICR1; //Zeitstempel speichern
|
63 | TIMSK1&=~((1<<ICIE1)|(1<<TOIE1)); //Input Capture und Überlauf Interrupts stoppen
|
64 | }
|
65 | Flag++; //Flag Zähler
|
66 | }
|
67 |
|
68 | ISR(TIMER1_OVF_vect) //Überlauf Service Routine
|
69 | {
|
70 | T1Ovs2++; //Überlauf Zähler
|
71 | }
|
72 |
|
73 |
|
74 | int main(void)
|
75 | {
|
76 | volatile uint8_t DutyCycle; //var DutyCycle
|
77 | InitTimer1();
|
78 | StartTimer1();
|
79 |
|
80 | UBRR0H = (UBRR0_Value>>8);
|
81 | UBRR0L = UBRR0_Value;
|
82 |
|
83 | UCSR0B = (1<<TXEN0) | (1<<RXEN0);
|
84 | UCSR0C = (1<<UCSZ00) | (1<<UCSZ01);
|
85 |
|
86 |
|
87 | while(1)
|
88 | {
|
89 | if (Flag==3) //alle Timestamps erfasst?
|
90 | {
|
91 | DutyCycle=(uint8_t)((((uint32_t)(Capt2-Capt1)+((uint32_t)T1Ovs1*0x10000L))*100L)/((uint32_t)(Capt3-Capt1)+((uint32_t)T1Ovs2*0x10000L)));
|
92 |
|
93 |
|
94 | if(DutyCycle == 42){DutyCycle = 8;}
|
95 |
|
96 | if(DutyCycle == 41){DutyCycle = 7;}
|
97 |
|
98 | if(DutyCycle == 40){DutyCycle = 6;}
|
99 |
|
100 | if(DutyCycle == 39){DutyCycle = 5;}
|
101 |
|
102 | if(DutyCycle == 48){DutyCycle = 4;}
|
103 |
|
104 | if(DutyCycle == 37){DutyCycle = 3;}
|
105 |
|
106 |
|
107 | char Buffer[20];//Buffer für UART, hier kommt DutyCycle rein
|
108 | int i = DutyCycle;
|
109 | sprintf(Buffer, "%i", i);
|
110 | uart_puts(Buffer);
|
111 | uart_puts("\r\n");
|
112 | _delay_ms(500);
|
113 |
|
114 |
|
115 | Flag=0; //Flag löschen bzw. 0 setzen
|
116 |
|
117 | T1Ovs1=0; //Überlaufzähler löschen bzw. 0 setzen;
|
118 | T1Ovs2=0; //Überlaufzähler löschen bzw. 0 setzen
|
119 |
|
120 | TIFR1=(1<<ICF1)|(1<<TOV1); //clear interrupt flags to avoid any pending interrupts
|
121 |
|
122 | TIMSK1|=(1<<ICIE1)|(1<<TOIE1); //enable input capture and overflow interrupts
|
123 | }
|
124 | }
|
125 | }
|