Impulse schwanken im oberen Spannungsbereich?

Gast #1199608
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
Angehängte Dateien:
Gast #1199615
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
}
Angehängte Dateien:
Gast #1199623
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.
Gast #1199775
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren