Hallo ich benutze einen Atmega8 um in Abhängigkeit des ADC-Kanals variable Impulslängen zu erzeugen. Ich benutze dabei ADC-Interrupt, Timer0 und Timer1-Interrupt. Der ADC wird alle 1ms ausgelesen (siehe code). Was ich eigentlich vor habe, ist Impulse zu erzeugen mit Periodendauern von ca. mindestens 10ms und 500 us maximal. Um dies zu realisieren habe ich folgenden Code geschrieben und auch getestet. funktioniert eigentlich super, ABER: Nun hab ich vor die Zeiten zu ändern, sprich ca. mindestens 15ms bis maximal 2ms (oder 1,5ms). Wie kann man das kontrolliert machen ohne irgendwelche Prescaler werte einzustellen und zu messen? Ich meine, gibt es eine Formel, mit der man es ausrechnen kann? Komme mit den ganzen Prescalern und Faktoren durcheinander... Zusatzfrage: Müssen die Variablen S0, S1 auch volatile, da sie sich auch in der ISR befinden? Vielen dank schonmal für eure Tipps!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CODE: _________________________________________________ //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////// // // // Possible Impulse Frequence: Min (Period): 8.4ms Max (Period): 400µs // //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////// #ifndef F_CPU /* prevent compiler error by supplying a default */ #define F_CPU 1000000UL #endif #include <util/delay.h> #include <avr/interrupt.h> #include <avr/io.h> volatile char pulselength = 0; //Volatile aufgrund von Interrupt.. char S1 = 0; char S2 = 0; char Direction = 1; volatile uint16_t AdcValue = 0; //////////////////////////////////////////////////////////////////////// ///////////////////// // ADC Conversion read out //////////////////////////////////////////////////////////////////////// ///////////////////// ISR(ADC_vect) { //Nur die MSB werden übernommen// pulselength = ADCH; } //////////////////////////////////////////////////////////////////////// ///////////////////// //////////////////////////////////////////////////////////////////////// ///////////////////// // Timer 0 interrupt ADC Conversion //////////////////////////////////////////////////////////////////////// ///////////////////// ISR(TIMER0_OVF_vect ) { ADCSRA |= (1<<ADSC); // ADC Messung Starten TCNT0 = 130; //130 => jede 1ms ADC-Abfrage } //////////////////////////////////////////////////////////////////////// ///////////////////// //////////////////////////////////////////////////////////////////////// ///////////////////// // Timer 2 interrupt Pulse length -> calculate next signal //////////////////////////////////////////////////////////////////////// ///////////////////// ISR(TIMER2_OVF_vect ) { //Vorwärtsbetrieb if (Direction) { if ((S1==1) && (S2==1)) { S1 = 0; S2 = 1; } else if ((S1==1) && (S2==0)) { S1 = 1; S2 = 1; } else if ((S1==0) && (S2==0)) { S1 = 1; S2 = 0; } else if ((S1==0) && (S2==1)) { S1 = 0; S2 = 0; } } // Rückwärtsbetrieb else if (!Direction) { if ((S2==1) && (S1==1)) { S2 = 0; S1 = 1; } else if ((S2==1) && (S1==0)) { S2 = 1; S1 = 1; } else if ((S2==0) && (S1==0)) { S2 = 1; S1 = 0; } else if ((S2==0) && (S1==1)) { S2 = 0; S1 = 0; } } if (S1) { PORTD |= (1<<PD1); } else { PORTD &= ~(1<<PD1); } if (S2) { PORTD |= (1<<PD2); } else { PORTD &= ~(1<<PD2); } TCNT2 = pulselength; //Zählregister } //////////////////////////////////////////////////////////////////////// ///////////////////// //////////////////////////////////////////////////////////////////////// ///////////////////// // Initialisierung // //////////////////////////////////////////////////////////////////////// ///////////////////// void init() { //::::::Port Configuration::::::// //PortD Data Direction Register: //Ouputs: PD0 = Hall1_R, PD1 = Hall2_R, PD2 = Hall1_L, PD3 = Hall2_L DDRD |= (1 << PD0) | (1 << PD1) | (1 << PD2) | (1 << PD3); //Inputs: PD4 = Open, PD5 = Close, PD6 = SetHall_High, PD7 = SetHall_Low DDRD &= ~((1 << PD4) | (1 << PD5) | (1 << PD6) | (1 << PD7)); // Init Timer 0 TCCR0 = ( 1 << CS01 ); // Teiler: 8 //1ms ADC Value messung TIMSK = ( 1 << TOIE0 ); // Overflow Interrupt einschalten TCNT0 = 130; // init Wert: Zähle 125 bis ersten overflow (1ms) // Init Timer 2 TCCR2 = ( 1 << CS21 ); //prescaler 8 TIMSK |= (1 << TOIE2); // Overflow Interupt einschalten //OCR2=200; // Vergleichsregister TCNT2= pulselength; //200 // Zählregister //ADC Configuration //////////////////////////////////////////////////////////////////////// /////////// ADMUX = 0; // Kanal waehlen (ADC0) ADMUX |= (0<<REFS1) | (1<<REFS0) | (1<<ADLAR); // AVCC als Referenzspannung nutzen, left adjustet ADC Register (ADLAR) ADCSRA |= (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0) | (1<<ADIE); ADCSRA &= ~((1<<ADPS2)|(1 << ADFR)); //// First Read Out um den ADC warmlaufen zu lassen //////////////////////////////// ADCSRA |= (1<<ADSC); // Start ADC-Wandlung while ( ADCSRA & (1<<ADSC) ) { // Warten bis ADC Wandlung fertig ist ; } } //////////////////////////////////////////////////////////////////////// ///////////////////// //////////////////////////////////////////////////////////////////////// ///////////////////// //////////////////////////////////////////////////////////////////////// ///////////////////// // MAIN //////////////////////////////////////////////////////////////////////// ///////////////////// //////////////////////////////////////////////////////////////////////// ///////////////////// int main() { init(); sei(); // Enable Interrupts while ( 1 ) {} return 0; } ____________________________________________________
..und jetzt mit formatierten code ;) CODE: _______________________________________________
1 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
2 | //
|
3 | //
|
4 | // Possible Impulse Frequence: Min (Period): 8.4ms Max (Period):
|
5 | 400µs |
6 | //
|
7 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
8 | |
9 | |
10 | #ifndef F_CPU
|
11 | /* prevent compiler error by supplying a default */
|
12 | #define F_CPU 1000000UL
|
13 | #endif
|
14 | |
15 | #include <util/delay.h> |
16 | #include <avr/interrupt.h> |
17 | #include <avr/io.h> |
18 | |
19 | volatile char pulselength = 0; //Volatile aufgrund von Interrupt.. |
20 | char S1 = 0; |
21 | char S2 = 0; |
22 | char Direction = 1; |
23 | |
24 | volatile uint16_t AdcValue = 0; |
25 | |
26 | |
27 | /////////////////////////////////////////////////////////////////////////////////////////////
|
28 | // ADC Conversion read out
|
29 | /////////////////////////////////////////////////////////////////////////////////////////////
|
30 | ISR(ADC_vect) |
31 | {
|
32 | //Nur die MSB werden übernommen//
|
33 | pulselength = ADCH; |
34 | |
35 | }
|
36 | /////////////////////////////////////////////////////////////////////////////////////////////
|
37 | |
38 | |
39 | /////////////////////////////////////////////////////////////////////////////////////////////
|
40 | // Timer 0 interrupt ADC Conversion
|
41 | /////////////////////////////////////////////////////////////////////////////////////////////
|
42 | ISR(TIMER0_OVF_vect ) { |
43 | ADCSRA |= (1<<ADSC); // ADC Messung Starten |
44 | TCNT0 = 130; //130 => jede 1ms ADC-Abfrage |
45 | }
|
46 | /////////////////////////////////////////////////////////////////////////////////////////////
|
47 | |
48 | |
49 | /////////////////////////////////////////////////////////////////////////////////////////////
|
50 | // Timer 2 interrupt Pulse length -> calculate next signal
|
51 | /////////////////////////////////////////////////////////////////////////////////////////////
|
52 | ISR(TIMER2_OVF_vect ) |
53 | {
|
54 | |
55 | |
56 | //Vorwärtsbetrieb
|
57 | if (Direction) |
58 | {
|
59 | if ((S1==1) && (S2==1)) { S1 = 0; S2 = 1; } else |
60 | if ((S1==1) && (S2==0)) { S1 = 1; S2 = 1; } else |
61 | if ((S1==0) && (S2==0)) { S1 = 1; S2 = 0; } else |
62 | if ((S1==0) && (S2==1)) { S1 = 0; S2 = 0; } |
63 | }
|
64 | |
65 | // Rückwärtsbetrieb
|
66 | else if (!Direction) |
67 | {
|
68 | if ((S2==1) && (S1==1)) { S2 = 0; S1 = 1; } else |
69 | if ((S2==1) && (S1==0)) { S2 = 1; S1 = 1; } else |
70 | if ((S2==0) && (S1==0)) { S2 = 1; S1 = 0; } else |
71 | if ((S2==0) && (S1==1)) { S2 = 0; S1 = 0; } |
72 | }
|
73 | |
74 | |
75 | if (S1) { PORTD |= (1<<PD1); } else { PORTD &= ~(1<<PD1); } |
76 | if (S2) { PORTD |= (1<<PD2); } else { PORTD &= ~(1<<PD2); } |
77 | |
78 | TCNT2 = pulselength; //Zählregister |
79 | |
80 | }
|
81 | /////////////////////////////////////////////////////////////////////////////////////////////
|
82 | |
83 | |
84 | /////////////////////////////////////////////////////////////////////////////////////////////
|
85 | // Initialisierung
|
86 | //
|
87 | /////////////////////////////////////////////////////////////////////////////////////////////
|
88 | void init() { |
89 | |
90 | //::::::Port Configuration:::::://
|
91 | //PortD Data Direction Register:
|
92 | |
93 | //Ouputs: PD0 = Hall1_R, PD1 = Hall2_R, PD2 = Hall1_L, PD3 = Hall2_L
|
94 | DDRD |= (1 << PD0) | (1 << PD1) | (1 << PD2) | (1 << PD3); |
95 | |
96 | //Inputs: PD4 = Open, PD5 = Close, PD6 = SetHall_High, PD7 =
|
97 | SetHall_Low
|
98 | DDRD &= ~((1 << PD4) | (1 << PD5) | (1 << PD6) | (1 << PD7)); |
99 | |
100 | |
101 | // Init Timer 0
|
102 | TCCR0 = ( 1 << CS01 ); // Teiler: 8 //1ms ADC Value messung |
103 | TIMSK = ( 1 << TOIE0 ); // Overflow Interrupt einschalten |
104 | TCNT0 = 130; // init Wert: Zähle 125 bis ersten overflow (1ms) |
105 | |
106 | // Init Timer 2
|
107 | TCCR2 = ( 1 << CS21 ); //prescaler 8 |
108 | TIMSK |= (1 << TOIE2); // Overflow Interupt einschalten |
109 | //OCR2=200; // Vergleichsregister
|
110 | TCNT2= pulselength; //200 // Zählregister |
111 | |
112 | //ADC Configuration
|
113 | ///////////////////////////////////////////////////////////////////////////////////
|
114 | ADMUX = 0; // Kanal waehlen (ADC0) |
115 | ADMUX |= (0<<REFS1) | (1<<REFS0) | (1<<ADLAR); // AVCC als |
116 | Referenzspannung nutzen, left adjustet ADC Register (ADLAR) |
117 | ADCSRA |= (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0) | (1<<ADIE); |
118 | ADCSRA &= ~((1<<ADPS2)|(1 << ADFR)); |
119 | |
120 | |
121 | //// First Read Out um den ADC warmlaufen zu lassen
|
122 | ////////////////////////////////
|
123 | ADCSRA |= (1<<ADSC); // Start |
124 | ADC-Wandlung |
125 | while ( ADCSRA & (1<<ADSC) ) { // Warten bis ADC |
126 | Wandlung fertig ist |
127 | ;
|
128 | }
|
129 | |
130 | |
131 | }
|
132 | /////////////////////////////////////////////////////////////////////////////////////////////
|
133 | |
134 | |
135 | |
136 | /////////////////////////////////////////////////////////////////////////////////////////////
|
137 | /////////////////////////////////////////////////////////////////////////////////////////////
|
138 | // MAIN
|
139 | /////////////////////////////////////////////////////////////////////////////////////////////
|
140 | /////////////////////////////////////////////////////////////////////////////////////////////
|
141 | int main() |
142 | {
|
143 | init(); |
144 | |
145 | sei(); // Enable Interrupts |
146 | |
147 | while ( 1 ) {} |
148 | |
149 | return 0; |
150 | }
|
Kann es sein, dass du zwei Zehnerpotenzen verwechselst? µ ist etwa tausendmal kleiner als m... Wenn du Probleme mit dem Vorteiler hast, dann mußt du halt eine "Schaltschwelle" programmieren, an der der Vorteiler umgeschaltet wird. Die Schwelle kannst du ziemlch einfach herausfinden, da du ja einen proportionalen Zusammenhang zwischen ADC-Wert und Periodendauer erzeugen willst. Für einen bestimten Bereich eine bestimmten Vorteiler-Faktor und für einen anderen einen anderen. Dann muß man nur noch den Vergleichswert berechnen, mit dem der Timerwert verglichen werden soll.
hallo nein, eigentlich micht: Ich meinte 10ms und und 500 us umgesetzt sind ca 8,4ms und 400 us. hmmm..daran hab ich nicht gedacht. stimmt, man könnte den prescaler umschalten, nachdem ein bereich des Timer Zählerns überschritten wird gibt es denn beispiele wie sowas aussehen könnte? so z.B.?:
1 | ....
|
2 | |
3 | TCNT2 = pulselength; //Zählregister |
4 | |
5 | if(TCNT2 < 100) |
6 | {
|
7 | TCCR2 = ( 1 << CS21 ); //Prescaler 8 |
8 | }
|
9 | |
10 | else
|
11 | {
|
12 | TCCR2 |= ( 1 << CS21 ) | ( 1 << CS20 ) ; //Prescaler 32 |
13 | }
|
vermutlich mudd man den Prescaler in der Ini entfernen?
Fragender4 wrote: > > TCNT2 = pulselength; //Zählregister > > if(TCNT2 < 100) > { > TCCR2 = ( 1 << CS21 ); //Prescaler 8 > } > > else > { > TCCR2 |= ( 1 << CS21 ) | ( 1 << CS20 ) ; //Prescaler 32 > } > > [/c] Das wird so wohl nicht funktionieren, da es ja einen Zusammenhang gibt, zwischen dem Wert, den du in TCNT2 laden musst, dem Vorteiler und er Verzögerung die du erreichen willst. So ein Timer ist ja kein Hexenwerk. Der zählt einfach nur still und leise vor sich hin. Wie schnell er zählt, hängt von der Prozessortaktfrequenz ab und dem Vorteiler der eingestellt ist. Ist die Taktfrequenz 1Mhz, dann zählt der Timer in 1 Sekunde bis 1 Million (würde er gerne, wenn nicht voerher ein Overflow dazwischen kommen würde). Ist ein Vorteiler von 64 eingestellt, dann kommt der Zähler in 1 Sekunde nicht mehr bis 1 Mio, sondern nur noch bis 1000000 / 64 = 15625 Wenn du also einen hypotetischen Timer so eingestellt hättest, dass er bei 2536000 etwas macht (zb einen Interrupt auslöst), dann braucht es bei 1Mhz Timerfrequenz 2.536 Sekunden, bis dieser Event eintritt. Bei einem Vorteiler von 64 dauert es aber 2536000/15625 = 162.3 Sekunden. Das sind alles nur mathematische Schlussrechnungen, die hier notwendig sind. Wenn dir klar ist, wie so ein Timer eigentlich funktioniert (und das ist in der Tat sehr simpel), dann kann man sich die 'Formeln' ganz leicht selber überlegen.
>nein, eigentlich micht: Ich meinte 10ms und und 500 us >umgesetzt sind ca 8,4ms und 400 us. Das muß ich immer noch nicht verstehen, oder? Untere Grenze der Periodendauer sollen 10ms sein und obere 500µs? Das passt nicht. 10ms sind 20mal mehr als 500µs. Oder meinst du mit Periodendauer vielleicht die Pulsdauer?
hallo ja ich meinte die pulsdauer ;) also im oberen bereich impulse mit ca 500us (Periodendauer) erzeugen und im unteren bereich impulse mit 10 ms erzeugen. hallo karl heinz, ich verstehe nicht wo das problem liegt. ich kann doch in meiner ISR den Prescaler bei einer bestimmten Schwelle einfach umschalten um so andere pulsdauern zu erhalten:
1 | /////////////////////////////////////////////////////////////////////////////////////////////
|
2 | // Timer 2 interrupt Pulse length -> calculate next signal
|
3 | /////////////////////////////////////////////////////////////////////////////////////////////
|
4 | ISR(TIMER2_OVF_vect ) |
5 | {
|
6 | |
7 | |
8 | //Vorwärtsbetrieb
|
9 | if (Direction) |
10 | {
|
11 | if ((S1==1) && (S2==1)) { S1 = 0; S2 = 1; } else |
12 | if ((S1==1) && (S2==0)) { S1 = 1; S2 = 1; } else |
13 | if ((S1==0) && (S2==0)) { S1 = 1; S2 = 0; } else |
14 | if ((S1==0) && (S2==1)) { S1 = 0; S2 = 0; } |
15 | }
|
16 | |
17 | // Rückwärtsbetrieb
|
18 | else if (!Direction) |
19 | {
|
20 | if ((S2==1) && (S1==1)) { S2 = 0; S1 = 1; } else |
21 | if ((S2==1) && (S1==0)) { S2 = 1; S1 = 1; } else |
22 | if ((S2==0) && (S1==0)) { S2 = 1; S1 = 0; } else |
23 | if ((S2==0) && (S1==1)) { S2 = 0; S1 = 0; } |
24 | }
|
25 | |
26 | |
27 | if (S1) { PORTD |= (1<<PD1); } else { PORTD &= ~(1<<PD1); } |
28 | if (S2) { PORTD |= (1<<PD2); } else { PORTD &= ~(1<<PD2); } |
29 | |
30 | if( pulselength < 100) // bei Schwellwert 100 sind es ca. 8ms |
31 | {
|
32 | TCCR2 |= ( 1 << CS21 ) | ( 1 << CS20 ) ; //Prescaler 32 |
33 | |
34 | TCNT2 = pulselength; //Zählregister |
35 | }
|
36 | else
|
37 | {
|
38 | TCCR2 = ( 1 << CS21 ); //Prescaler 8 |
39 | pulselength = (pulselength - 30) //um bei Schwellwert > 100 bei der //selben Pulsdauer (ca. 8ms) zu beginnen.. |
40 | TCNT2 = pulselength; |
41 | }
|
Sollte doch so funktionieren? Wüsste jetzt nicht warum es nicht gehen soll? Gruss } //////////////////////////////////////////////////////////////////////// /////////////////////
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.