PWM mit Poti steuern, Problem im Code

Gast #1996942
Lesenswert?

Hallo allerseits und ein gutes neues Jahr!!

Ich möchte über zwei Potis eine PWM, an der LEDs hängen, steuern. Dabei 
soll das eine PWM schlicht den Impuls (also den TOP Wert der PWM) 
verändern, das andere soll den Startpunkt nach vorne oder hinten 
schieben - dies wollte ich über delays machen, weil mir nichts besseres 
dazu einfiel.

Ich habe mal meinen Code gepostet. Das Prolblem:
Das Poti (beide übrigens linear!) für die Verstellung der des TOP-Werts 
hat keine Wirkung, obwohl ein ADCWert eingelesen wird - mit 
Codeänderungen etc. getestet. Beide Potis hängen an 5V, genauso wie der 
uC, weshalb ich Werte zwischen 0 und 1024 bekommen kann. Nun soll das 
Poti von der Mittelstellung aus operieren, daher die Berechnung mit der 
Subtraktion von 500 im Code.

Der Code mit dem zweiten Poti funktioniert irgendwie überhaupt nicht, 
sobald dieses als ADC-Eingang läuft, blinken die LEDs langsam und wild 
zweitverzögert, total zufällig. Irgendwie hapert es da mit dem delay...

ich bin ehrlich gesagt überfordert.
Ich habe einen ATMega 644P, nen 7805 als Sp.quelle, davon geht auch die 
Spannung für die Potis raus, die Ref.Spannung hängt an VCC, an AREF ist 
nen Kondensator gegen Masse und AVCC ist mit dem nem 75 Ohm Wiederstand 
an VCC und mit nem 100nF gegen Masse.

Ich denke, das Problem liegt am Code.

Ich hoffe ihr habt Tipps.

Danke


P.S.: Ich habe fast den ganzen Code mal gepostet, da bei mir als 
Anfänger auch Fehler zwischen den Zeilen sein können.
Außerdem: Das Poti "0", genannt auch "Zeitlupe" ist die Veränderung des 
TOP-Wertes, Poti "1" hingegen, genannt "Hoch-Tief", der delay.
Das Projekt soll eine Time-Fountain werden.

1
#include <avr/io.h>
2
#ifndef F_CPU
3
#warning "F_CPU war noch nicht definiert, wird nun mit 8 MHZ definiert"
4
#define F_CPU 8000000UL     /* Quarz mit 8 Mhz */
5
#endif
6
#include <util/delay.h>
7
#include <avr/interrupt.h>  // fuer Interrupts
8

9

10
// Potis: ADC0, ADC1 = PA0, PA1
11
// Poti-Wechseltaster: INT0 = PD2
12
// Potis ein/aus: INT1 = PD3
13
// Taster aktive high: Pin mit GND verbinden
14
// PWM: OC1A = PD5
15
// LEDs fuer Potis: PC0, PC1
16
// LEDs fuer Poti an/aus: an, gruen, PA5
17
//              aus, rot, PA6
18

19

20
extern volatile uint8_t triggerflag_poti = 0;
21
extern volatile uint8_t triggerflag_adjustmode = 0;
22
extern volatile uint8_t timefactor = 100;
23

24

25
// Interrupt-Routine fuer Channelwechsel ADC
26
ISR( INT0_vect )
27
{
28
  if (triggerflag_poti == 0) triggerflag_poti = 1;
29
  else if (triggerflag_poti == 1) triggerflag_poti = 0;
30
}
31

32
// Interrupt-Routine fuer Poti-Einstellen ein/aus
33
ISR( INT1_vect )
34
{
35
  if (triggerflag_adjustmode == 0) triggerflag_adjustmode = 1;
36
  else if (triggerflag_adjustmode == 1) triggerflag_adjustmode = 0;
37
}
38

39

40
// delay-funktion
41
void mydelay(int t);
42

43

44
// ADC Wert holen
45
uint16_t get_ADC(uint8_t channel);
46

47
  
48

49

50

51
 
52
int main( void )
53
{
54

55
  // INTERRUPTS
56

57
  // INT0 und INT1 akivieren, triggern bei fallender Flanke
58
  EIMSK |= ( 1<<INT0 ) | (1 << INT1 );                  // triggern bei Flankenerkennung
59
  EICRA |= ( 1<<ISC01 ) | ( 0<<ISC00 ) | ( 1<<ISC11 ) | ( 0<<ISC10 );    // triggern bei fallender Flanke
60

61
  DDRD &= ~( 1<<PD2 );    // PD2 an PORTD als Eingang setzen // INT0 interrupt Vektor
62
  DDRD &= ~( 1<<PD3 );    // PD3 an PORTD als Eingang setzen // INT1 interrupt Vektor
63
  PORTD |= ( 1<<PD2 );    // Pullups setzen // interne
64
  PORTD |= ( 1<<PD3 );    // Pullups setzen // interne
65

66

67
  // OC1A  auf Ausgang  
68
  DDRD = ( 1<<PD5 );        // PD5 an PORTD als Ausgang setzen
69

70
  // LED-Pins auf Ausgang:
71
  DDRC = ( 1<<PC0 ) | ( 1<<PC1 );    // PC0 und PC1 fuer Poti LEDs
72
  DDRA = ( 1<<PA5 ) | ( 1<<PA4 );    // PA4 und PA5 fuer LED Potis an/aus
73

74

75

76
  // Timer 1 einstellen
77
  //  
78
  // Modus 14:
79
  //    Fast PWM, Top von ICR1
80
  //
81
  //    WGM13    WGM12   WGM11    WGM10
82
  //      1        1       1        0
83
  //
84
  //    Timer Vorteiler:
85
  //     CS12     CS11    CS10
86
  //       0        0      1
87
  //
88
  //  Steuerung des Ausgangsport: Set at BOTTOM, Clear at match
89
  //     COM1A1   COM1A0
90
  //       1        0
91

92
  TCCR1A = ( 1<<COM1A1 ) | ( 1<<WGM11 )| ( 0<<WGM10 );
93
  TCCR1B = ( 1<<WGM13 ) | ( 1<<WGM12 ) | ( 1<<CS10 ) ;
94

95

96

97

98
  // ADC einstellen
99

100
  ADMUX = ( 1<<REFS0 );          // ADC Referenz Vcc an AVCC
101
    ADMUX = ( 0<<ADLAR );          // Ergebnis rechtsbuendig
102
    ADCSRA = ( 1<<ADPS2 ) | ( 1<<ADPS1 );  // Prescaler 64 --> 125 kHz ADC Takt
103
    ADCSRA = ( 1<<ADEN );          // ADC aktivieren
104

105

106
  //  TOP-Wert
107
  ICR1 = 0xc300;    // Initialisierung: 50000 => 5 ms Impuls
108

109

110
  // Compare-Wert
111
  OCR1A = 0xbb8;
112

113
  sei(); // interrupts aktivieren
114

115

116
    while (1)
117
    {
118
      // falls Poti-Einstellen erlaubt
119
      if (triggerflag_adjustmode == 1)
120
      {
121

122
        // gruene LED am Taster an (rote aus)
123
        PORTA |= ( 1<<PA5 );  // gruen an
124
        PORTA &= ~( 1<<PA4 );  // rot aus
125

126

127
        // Zeitlupe -> Poti 0
128
        if (triggerflag_poti == 0)      // falls Poti 0 zugeschaltet
129
        {
130
          // LED fuer Poti 0 an, Poti 1 aus
131
          PORTC |= ( 1<<PC1 );
132
          PORTC &= ~( 1<<PC0 );
133

134
          uint16_t ADCvalue0;
135
          ADCvalue0 = get_ADC(triggerflag_poti);  // channel ADC0
136

137
          ICR1 += (500 - ADCvalue0)*timefactor;  // TOP-Wert aus ADC Messung berechnen
138
          
139
        }
140
        
141
        // Hoch-Tief -> Poti 1
142
        if (triggerflag_poti == 1)      // falls Poti 1 zugeschaltet
143
        {
144

145
          // LED fuer Poti 1 an, Poti 0 aus
146
          PORTC |= ( 1<<PC0 );
147
          PORTC &= ~( 1<<PC1 );
148

149
          // Werte messen und voneinander abziehen
150
          uint16_t ADCvalue1;
151
          ADCvalue1 = get_ADC(triggerflag_poti);  // channel ADC1, ersten Wert einlesen
152

153
          uint16_t ADCvalue2;
154
          ADCvalue2 = get_ADC(triggerflag_poti);    // zweiten Wert einlesen
155

156
          // hoch oder tief
157
          if ( (ADCvalue1-ADCvalue2) > 10 )    // falls aelterer Wert groesser
158
          {
159
            mydelay ( (ADCvalue1-ADCvalue2)/10 );  // Unterschied durch 10 in ms
160
          }
161
          if ( (ADCvalue2-ADCvalue1) > 10 )    // falls neuer Wert groesser
162
          {
163
            mydelay (ADCvalue2-ADCvalue1);          // Unterschied in ms
164
          }
165

166
        }  
167
      }
168
  return 0;
169
}
170

171

172

173

174
// Funktion ADC Wert holen mit Mittelwert
175
uint16_t get_ADC(uint8_t channel)
176
{
177
    //Zwischenspeicher
178
    uint16_t buffer;
179
    uint8_t i;
180

181
    buffer = 0;
182

183
    //ADC Kanal wählen
184
    ADMUX=(ADMUX &~(0x1F)) | (channel & 0x1F);
185

186
    //4 Messungen mit Mittelwertbildung
187
    for (i=0; i<4; i++)
188
  {
189
        ADCSRA = ( 1<<ADSC );      // Messung starten
190
//    while(ADCSRA & (1 << ADSC));  // wofuer?
191
        buffer += ADCL;          // erst low, dann high lesen und addieren
192
    buffer += (ADCH << 8);
193
    }
194
    //buffer durch 4 teilen und zurückgeben
195
    return(buffer/4);
196

197
}
198

199

200

201

202
// delay-funktion
203
void mydelay(int t)
204
{
205
  int i;
206
  for( i = 0; i <= t; i++ )
207
  {
208
    _delay_ms(1);
209
  }
210
}
Moderator (Firma: Titel) Persönliche Seite #1996981
Lesenswert?

Emanuel schrieb:
> // delay-funktion
Di könntest du auch so schreiben:
1
 void mydelay(int t) 
2
 {
3
   while(t--)
4
      _delay_ms(1);
5
 }

Emanuel schrieb:
1
 ISR( INT0_vect )
2
 {
3
   if (triggerflag_poti == 0) triggerflag_poti = 1;
4
   else if (triggerflag_poti == 1) triggerflag_poti = 0;
5
 }
Pins als Eingänge werden nicht in Interruptroutinen abgefragt... :-o
Oder was soll das Herumgemurkse mit den Interrupts bewirken?
Für mich willst du da offenbar mit einem Taster den Zustand umschalten. 
Wehe, wenn der prellt...
Und wenns unbedingt so sein muß, dann kannst du das auch so schreiben:
1
 ISR( INT0_vect )
2
 {
3
   triggerflag_poti = !triggerflag_poti;
4
 }

Zum eigentlichen Problem:
Hast du da mal fest codierte ADC-Ersatzwerte probiert?
Oder einen ADC-Ersatz von Port-Pins eingelesen?

BTW:
Mit deiner seltsamen Mittelwertbildung lügst du dir selber was in die 
Tasche. Ein Filter sieht normalerweise anders aus...

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