Forum: Mikrocontroller und Digitale Elektronik Impulse schwanken im oberen Spannungsbereich?


von Gunter (Gast)


Angehängte Dateien:

Lesenswert?

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

von Gunter (Gast)


Angehängte Dateien:

Lesenswert?

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
}

von holger (Gast)


Lesenswert?

>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.

von Gunter (Gast)


Lesenswert?

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.

von Gunter (Gast)


Lesenswert?

Hallo

>>Poste besser mal den Schaltplan. Da wird der Wurm drin stecken.

mach ich....muss ich noch raussuchen

von Gunter (Gast)


Angehängte Dateien:

Lesenswert?

Hallo

hier ist der Schaltplan. Ich hofe es hilt weiter:

von Gunter (Gast)


Angehängte Dateien:

Lesenswert?

Hallo

hab vergessen den ADC Kanal einzuzeichnen ;)

von STK500-Besitzer (Gast)


Lesenswert?

AVCC sollte doch auch an 5V liegen, oder?

von Gunter (Gast)


Lesenswert?

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

von Gont (Gast)


Lesenswert?

Hallo

keine Ideen woran es liegen könnte bzw. wo der Fehler eventuell im 
Schaltplan/Code ist?

Grüsse

von Peter (Gast)


Lesenswert?

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.

von Gont (Gast)


Lesenswert?

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...

von Gont (Gast)


Lesenswert?

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

von Gunter (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.