www.mikrocontroller.net

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


Autor: Emanuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

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


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


extern volatile uint8_t triggerflag_poti = 0;
extern volatile uint8_t triggerflag_adjustmode = 0;
extern volatile uint8_t timefactor = 100;


// Interrupt-Routine fuer Channelwechsel ADC
ISR( INT0_vect )
{
  if (triggerflag_poti == 0) triggerflag_poti = 1;
  else if (triggerflag_poti == 1) triggerflag_poti = 0;
}

// Interrupt-Routine fuer Poti-Einstellen ein/aus
ISR( INT1_vect )
{
  if (triggerflag_adjustmode == 0) triggerflag_adjustmode = 1;
  else if (triggerflag_adjustmode == 1) triggerflag_adjustmode = 0;
}


// delay-funktion
void mydelay(int t);


// ADC Wert holen
uint16_t get_ADC(uint8_t channel);

  



 
int main( void )
{

  // INTERRUPTS

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

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


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

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



  // Timer 1 einstellen
  //  
  // Modus 14:
  //    Fast PWM, Top von ICR1
  //
  //    WGM13    WGM12   WGM11    WGM10
  //      1        1       1        0
  //
  //    Timer Vorteiler:
  //     CS12     CS11    CS10
  //       0        0      1
  //
  //  Steuerung des Ausgangsport: Set at BOTTOM, Clear at match
  //     COM1A1   COM1A0
  //       1        0

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




  // ADC einstellen

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


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


  // Compare-Wert
  OCR1A = 0xbb8;

  sei(); // interrupts aktivieren


    while (1)
    {
      // falls Poti-Einstellen erlaubt
      if (triggerflag_adjustmode == 1)
      {

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


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

          uint16_t ADCvalue0;
          ADCvalue0 = get_ADC(triggerflag_poti);  // channel ADC0

          ICR1 += (500 - ADCvalue0)*timefactor;  // TOP-Wert aus ADC Messung berechnen
          
        }
        
        // Hoch-Tief -> Poti 1
        if (triggerflag_poti == 1)      // falls Poti 1 zugeschaltet
        {

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

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

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

          // hoch oder tief
          if ( (ADCvalue1-ADCvalue2) > 10 )    // falls aelterer Wert groesser
          {
            mydelay ( (ADCvalue1-ADCvalue2)/10 );  // Unterschied durch 10 in ms
          }
          if ( (ADCvalue2-ADCvalue1) > 10 )    // falls neuer Wert groesser
          {
            mydelay (ADCvalue2-ADCvalue1);          // Unterschied in ms
          }

        }  
      }
  return 0;
}




// Funktion ADC Wert holen mit Mittelwert
uint16_t get_ADC(uint8_t channel)
{
    //Zwischenspeicher
    uint16_t buffer;
    uint8_t i;

    buffer = 0;

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

    //4 Messungen mit Mittelwertbildung
    for (i=0; i<4; i++)
  {
        ADCSRA = ( 1<<ADSC );      // Messung starten
//    while(ADCSRA & (1 << ADSC));  // wofuer?
        buffer += ADCL;          // erst low, dann high lesen und addieren
    buffer += (ADCH << 8);
    }
    //buffer durch 4 teilen und zurückgeben
    return(buffer/4);

}




// delay-funktion
void mydelay(int t)
{
  int i;
  for( i = 0; i <= t; i++ )
  {
    _delay_ms(1);
  }
}


Autor: Spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Emanuel schrieb:
> // delay-funktion
Di könntest du auch so schreiben:
 void mydelay(int t) 
 {
   while(t--)
      _delay_ms(1);
 }

Emanuel schrieb:
 ISR( INT0_vect )
 {
   if (triggerflag_poti == 0) triggerflag_poti = 1;
   else if (triggerflag_poti == 1) triggerflag_poti = 0;
 }
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:
 ISR( INT0_vect )
 {
   triggerflag_poti = !triggerflag_poti;
 }

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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.