Forum: Mikrocontroller und Digitale Elektronik PWM mit Poti steuern, Problem im Code


von Emanuel (Gast)


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
}

von Spess53 (Gast)


Lesenswert?

Hi

>  ADMUX = ( 1<<REFS0 );
>  ADMUX = ( 0<<ADLAR );

>  ADCSRA = ( 1<<ADPS2 ) | ( 1<<ADPS1 );
>  ADCSRA = ( 1<<ADEN );

Du überschreibst die jeweils die erste Zuweisung.

MfG Spess

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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

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.