Hallo Ich benutze einen Atmega8L zur Impulserzeugung. Zunächst was ich vor habe (siehe Bild): Ich habe vor mittels zweier 8 Bit Timer (T0,T2) und einen ADC Impulse zu erzeugen. Beispiel: Ich stelle eine analoge Spannung von 2,5 Volt am ADC Kanal ein und erwarte eine bestimmte Breite des Impulses (zB. T = ca. 33 ms). Die Breite hängt dabei natürlich von meinem Preskaler (128), aktuellem ADC Wert (128) und CPU Takt (1MHz, internal RC) ab: 2,5 V --> entspricht 128 --> 1/(1000.000/128)*(255-128) = 32,768 ms Stelle ich eine andere Spannung ein, so ändert sich auch die Impulsbreite. Soweit klappt alles gut. --> ABER nun das Problem: Im unteren Spannungsbereich ( bis ca. 3,5 V) sind die Impulse stabil bzw konstant. Sobald ich aber einen bestimmten Spannungsbereich ( > ca. 3,5 V) überschreite, fangen an die Impulse an zu schwanken. Aus irgendeinem Grund erhalte ich keine konstanten Impulsbreiten mehr, sondern, die Impulsperioden schwanken sehr. Hab einenOszi drangehangen und ich konnte messen, dass es mal 10 ms Impulsbreiten sind und mal 6,7 ms. Ich kann nicht wirklich verstehen woran das liegen kann und grübele schon seit Stunden. Der Code ist eigentlich sehr simple aufgebaut (siehe Anhang). Aber ich kann den Fehler nicht finden. Habe auch die ganze Zeit mit den Preskalern gespielt, aber da hat sich auch nix geändert. Wäre super, wenn jemand mal über den Code schauen könnte und vielleicht erkennt wo der Wurm steckt ;) Ich komme da wirklich nicht weiter vielen Dank im voraus!!! Gruss Gunter
1 | //// Impulse erzeugen mittels Timer Interrupt ////////////
|
2 | |
3 | #ifndef F_CPU
|
4 | /* prevent compiler error by supplying a default */
|
5 | #define F_CPU 1000000UL
|
6 | #endif
|
7 | |
8 | |
9 | #include <avr/interrupt.h> |
10 | #include <avr/io.h> |
11 | |
12 | volatile char Pulslaenge = 0; // Volatile aufgrund von Interrupt |
13 | char S1 = 0; // Impulssignal |
14 | char ImpulseStarten = 1; // Impulserzeugung starten mit PD4 |
15 | |
16 | |
17 | //////////////////////////////////////////////////////////////////////////////////////////////
|
18 | // ADC auslesen: ISR(ADC_vect)-Routine wird ausgeführt, wenn ADC Wandlung fertig ist! ///////
|
19 | //////////////////////////////////////////////////////////////////////////////////////////////
|
20 | |
21 | ISR(ADC_vect) |
22 | {
|
23 | |
24 | Pulslaenge = ADCH; // Nur die obersten 8 Bit werden übernommen |
25 | |
26 | }
|
27 | |
28 | |
29 | ///////////////////////////////////////////////////////////////////////////////////////////////
|
30 | // Timer0 interrupt für ADC : alle 5 ms wird der ADC gestartet! ///////////////////////////////
|
31 | ///////////////////////////////////////////////////////////////////////////////////////////////
|
32 | |
33 | ISR(TIMER0_OVF_vect ) |
34 | {
|
35 | ADCSRA |= (1<<ADSC); // ADC Messung Starten |
36 | TCNT0 = 235; // 1/(1000.000/256)*(255-235)= 5ms |
37 | }
|
38 | |
39 | |
40 | ///////////////////////////////////////////////////////////////////////////////////////////////
|
41 | // Timer2 interrupt: Pulslänge -> kalkuliere nächstes Signal /////////////////////////////////
|
42 | ///////////////////////////////////////////////////////////////////////////////////////////////
|
43 | |
44 | ISR(TIMER2_OVF_vect ) |
45 | {
|
46 | |
47 | //Impulse starten
|
48 | if (ImpulseStarten) |
49 | { //___ ___ |
50 | if (S1==1) { S1 = 0; } // Mit jedem neuen Interrupt wird //entweder High oder Low erzeugt __| |___| |__ |
51 | else { S1 = 1; } |
52 | |
53 | }
|
54 | |
55 | // Ansonsten mach nix
|
56 | else if (!ImpulseStarten){;} |
57 | |
58 | |
59 | if (S1) { PORTD |= (1<<PD1); } else { PORTD &= ~(1<<PD1); } |
60 | |
61 | TCNT2 = Pulslaenge; //Zählregister aktualisieren: abhängig vom //aktuellem ADC Wert! |
62 | }
|
63 | |
64 | |
65 | ///////////////////////////////////////////////////////////////////////////////////////////////
|
66 | // Initialisierung Atmega8L ///////////////////////////////////////////////////////////////////
|
67 | ///////////////////////////////////////////////////////////////////////////////////////////////
|
68 | |
69 | void init() |
70 | {
|
71 | //Ouputs:
|
72 | DDRD = (1 << PD1); // Impulsausgang um z.B //eine LED anzusteuern |
73 | |
74 | //Inputs:
|
75 | DDRD &= ~(1 << PD4); // Impulse starten |
76 | |
77 | |
78 | // Init Timer 0
|
79 | TCCR0 = ( 1 << CS02 ); // Preskaler: 256 |
80 | TIMSK = ( 1 << TOIE0 ); // Overflow Interrupt //einschalten |
81 | TCNT0 = 235; // init Wert: overflow //alle 5ms |
82 | |
83 | // Init Timer 2
|
84 | TCCR2 = ( 1 << CS20 )|( 1 << CS22 ); // Preskaler: //128 |
85 | TIMSK |= (1 << TOIE2); // Overflow Interupt //einschalten |
86 | TCNT2= Pulslaenge; // Aktueller ADC Wert //(Pulslaenge) an Zählregister übergeben |
87 | |
88 | //ADC Konfiguration //
|
89 | ADMUX = 0; // //Kanal ADC0 gewählt |
90 | ADMUX |= (0<<REFS1) | (1<<REFS0) | (1<<ADLAR); // //AVCC als Referenzspannung nutzen; left adjustet ADC Register (ADLAR) //gewählt (für ADCH) |
91 | ADCSRA |= (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0) | (1<<ADIE); // ADC //Einstellungen: ADC Enable, Teilungsfaktor muss zwischen 5 und 20 liegen: //8 gewählt, |
92 | // (ADC Interrupt Enable)
|
93 | ADCSRA &= ~((1<<ADPS2)|(1 << ADFR)); // //Diaktiviere Rest |
94 | |
95 | |
96 | // First Read Out, um den ADC warmlaufen zu lassen //
|
97 | ADCSRA |= (1<<ADSC); // Start ADC-Wandlung |
98 | while ( ADCSRA & (1<<ADSC) ) { ; } // Warten bis ADC Wandlung //fertig ist |
99 | }
|
100 | |
101 | |
102 | /////////////////////////////////////////////////////////////////////////////////////////////
|
103 | ///// MAIN
|
104 | /////////////////////////////////////////////////////////////////////////////////////////////
|
105 | |
106 | int main() |
107 | {
|
108 | init(); // Initialisierug |
109 | |
110 | sei(); // Enable Interrupts |
111 | |
112 | while ( 1 ) {} |
113 | |
114 | return 0; |
115 | }
|
>Wäre super, wenn jemand mal über den Code schauen könnte und vielleicht >erkennt wo der Wurm steckt ;) Poste besser mal den Schaltplan. Da wird der Wurm drin stecken.
Hallo noch was zum Verfahren: Der Timer0-ISR holt alle 5 ms den aktuellen ADC Wert ab und der Timer2-ISR verarbeitet den ADC Wert zu einem Impuls mit entsprechender Pulsbreite. Der ADC-ISR wird ja immer ausgeführt, wenn die ADC Wandlung beendet ist.
Hallo
>>Poste besser mal den Schaltplan. Da wird der Wurm drin stecken.
mach ich....muss ich noch raussuchen
Hallo hier ist der Schaltplan. Ich hofe es hilt weiter:
Hallo hab vergessen den ADC Kanal einzuzeichnen ;)
Hallo ja natürlich...in der eile hab ich es vergessen einzuzeichnen :) benutze VCC für den ADC. Ist mit AVCC verbunden!!# Danke für den Hinweis
Hallo keine Ideen woran es liegen könnte bzw. wo der Fehler eventuell im Schaltplan/Code ist? Grüsse
warum schreibst du das überhaupt hin? // Ansonsten mach nix else if (!ImpulseStarten){;} da kannst du es doch auch weglassen. Ändert aber vermutlich nichts an dem Problem. Du könntest aber versuchen z.b. 4 ADC Messungen zu machen und dann der Ergebniss runden. Um schwankungen am ADC auszugleichen.
Hallo die ADC Spannungist am Eingang stabil...kann also nicht daran liegen. Würde auch nicht erklären warum nur im oberen Spannungsbereich die Schwankung auftritt...
Hallo Kann es vielleicht daran liegen, dass der ADC Takt anders gewählt werden muss. Also anstatt einen Teiler von 8 einen 16 Teiler wählen? Grüsse
Hallo, meint ihr man kommt mit dem CTC modus besser klar für dei IMPULSERZEUGUNG? Hat da jemand Erfahrung?
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.