Forum: Mikrocontroller und Digitale Elektronik ADC/Timer läuft nicht zusammen


von Martin28 (Gast)


Lesenswert?

Hallo zusammen,

Habe ein kleines Problem meinen Timer sowie meinen ADC zusammen laufen 
zu lassen. Also Timer alleine läuft. Genauso wie der ADC...jedoch wenn 
Ich beide laufen lassen will, kommt komischerweise nur der Timer. Der 
ADC wandelt dann dummerweise nicht mehr!?

Hat da jemand einen Rat?

Grüße Martin

von Martin28 (Gast)


Lesenswert?

//---------------------------------------------------------------------- 
-----------------------------
//            Interrupt Service Routine --> AD - Converter
//---------------------------------------------------------------------- 
-----------------------------

ISR(ADC_vect)
{

  uint8_t AD_LOW;
  uint8_t AD_HIGH;

  ADCSRA |= (0<<ADIE);        // Disable ADC Interrupt

      if (ADC_Active_Channel == 6)
      {
        ADC_Active_Channel = 0;
      }

        switch(ADC_Active_Channel)
        {
            case 0:break;  // ADC0 unused
            case 1:break;  // ADC1 unused
            case 2:break;  // ADC2 unused

            case 3:
                LEM_Result = ADCW;
            break;

            case 4:
                //VD_Output_Result = ADCW;
                AD_LOW = ADCL;
                AD_HIGH = ADCH;
                PORTD = AD_LOW;
            break;

            case 5:
                VD_Input_Result = ADCW;
            break;

            default:break;
        }


            ADC_Active_Channel++;
            ADMUX = (0b11111111 & ADC_Active_Channel);  // Set next 
channel

      ADCSRA |= (1<<ADIE);  // Enable
      ADCSRA |= (1<<ADSC);  // Start Conversion
}

von Martin28 (Gast)


Lesenswert?

int main(void)
{

  /***** Ports ******/ //0 = Input ; 1 = Output

  // The Port B Data Direction Register
  DDRB  |= (1<<PB2)|(1<<PB1);
  DDRC  |= (0<<PC5)|(0<<PC4)|(0<<PC3); 
//|(0<<PC2)|(0<<PC1)|(0<<PC0);
  DDRD  |= 
(1<<PD7)|(1<<PD6)|(1<<PD5)|(1<<PD4)|(1<<PD3)|(1<<PD2)|(1<<PD1)|(1<<PD0);


  /***** Timer *****/
  //---------------------------------------------------------------------- 
-------------------------------------------------

  Inital_Timer = 34;

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

  ICR1H = 00;
  ICR1L = 136;

  TCCR1A |= (1<<COM1A1)|(0<<COM1A0);
  TCCR1A |= (1<<COM1B1)|(1<<COM1B0);

  OCR1AH = 00;
  OCR1AL = Inital_Timer;

  OCR1BH = 00;
  OCR1BL = (Inital_Timer + 5);

  TIMSK1 |= (1<<ICIE1);
  TIMSK1 |= (1<<OCIE1B);
  TIMSK1 |= (1<<OCIE1A);
  TIMSK1 |= (1<<TOIE1);


  /***** AD Converter *****/
  //---------------------------------------------------------

  ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(0<<ADPS0);
  // 8MHz / 64 = 125kHz || 110 = 64

  ADMUX  |= (0<<REFS1)|(1<<REFS0);
  ADMUX  |= (0<<ADLAR);

  ADC_Active_Channel = 0;
  ADMUX = (0b11111111 & ADC_Active_Channel);

  //ADCSRB |= (0<<ACME)|(1<<ADTS2)|(1<<ADTS1)|(0<<ADTS0);  // Timer.1 
Overflow

  //ADCSRA |= (0<<ADATE);
  ADCSRA |= (1<<ADEN);    // ADC Enable
  ADCSRA |= (1<<ADSC);    // Start Single Conversion
  ADCSRA |= (1<<ADIE);    // Enable ADC Interrupt

  sei();  // set all Interrupts free

  while(1)
  {
    //state_Machine();
    //change_States();
  }

  return(0);
}

von Martin28 (Gast)


Lesenswert?

Das ist das der Code den Ich Compiliere...

von Georg G. (df2au)


Lesenswert?

Martin28 schrieb:
> ADCSRA |= (0<<ADIE);        // Disable ADC Interrupt

Tippfehler. Bewirkt nichts.

von Stefan E. (sternst)


Lesenswert?

Martin28 schrieb:
> Das ist das der Code den Ich Compiliere...

Da fehlen dann aber noch diverse ISRs. Wenn du die nicht hast, dann 
soft-resettet dein Programm ständig.

von Martin28 (Gast)


Lesenswert?

Stefan Ernst schrieb:
> Da fehlen dann aber noch diverse ISRs. Wenn du die nicht hast, dann
> soft-resettet dein Programm ständig.

Also die für den Timer meist jetzt? ADC_ISR steht ja...

von Thomas E. (thomase)


Lesenswert?

Martin28 schrieb:
> ADCSRA |= (0<<ADIE);        // Disable ADC Interrupt
Was erwartest du denn davon?

> ADMUX = (0b11111111 & ADC_Active_Channel);
Oder davon?

http://www.mikrocontroller.net/articles/Bitmanipulation

Dein Programm funktioniert hinten und vorne nicht.

mfg.

von Martin28 (Gast)


Lesenswert?

Thomas Eckmann schrieb:
>> ADCSRA |= (0<<ADIE);        // Disable ADC Interrupt
> Was erwartest du denn davon?

Davon würde Ich erwarten das der AD Wandler in dieser Zeit bis das ADIE 
bit wieder 1 gesetzt wird nicht mit ner neuen Wandlung beginnt. In 
dieser Zeit schreibe Ich mein Ergebnis der Wandlung aus dem 
Datenregister.

Thomas Eckmann schrieb:
>> ADMUX = (0b11111111 & ADC_Active_Channel);
> Oder davon?

Den Multiplexer auf den nächsten Kanal umstellen...

Das es nicht funktioniert habe Ich ja auch schon erwähnt. Aber Merci für 
den Link...

von Thomas E. (thomase)


Lesenswert?

Martin28 schrieb:
> 0b11111111 & ADC_Active_Channel
ADC_Active_Channel = 0;

 1111 1111
&0000 0000
=0000 0000
Damit stellst du MUX auf 0 und schaltest die Referenz auf AREF, also 
extern.

Du darfst im Register nur die Mux-Bits verändern.

Martin28 schrieb:
> ADCSRA |= (0<<ADIE);
Das verändert gar nichts. Wenn du etwas mit 0 ODER-verknüpfst, ändert 
sich der Wert nicht. Das ist ja auch der "Trick", mit dem man ein 
einzelnes Bit setzt.
 0101 0101
|0000 0010
=0101 0111
        ^

Wenn das "ADCSRA |= (0<<ADIE)" so wie du dir das vorstellst 
funktionieren würde, wäre das Ergebnis dieses Beispiels aber
 0000 0000

Arbeite den Link intensiv durch. Das ist elementar. Im Moment 
interpretierst du diesen Quatsch (XYZ |= (0 << ABC), den man leider 
andauernd sieht, auch noch vollkommen falsch.

mfg.

von Martin28 (Gast)


Lesenswert?

Danke für die ausführliche Erklärung Thomas.

Werde mir das auf jeden Fall genau ansehen.

Grüße Martin

von Martin28 (Gast)


Lesenswert?

Habe das mit dem umstellen des Multiplexers geändert.

Sieht jetzt so aus:

ADMUX = (ADMUX & ~(0x1F)) | (ADC_Active_Channel & 0x1F);

Die übrigen ISR Routinen wie oben erwähnt eingebaut:
(zur Vollständigkeit) damit kein Softreset durchgeführt wird.

ISR(TIMER1_CAPT_vect
{
  TIFR1 |=(1<<ICF1);
}

ISR(TIMER1_COMPA_vect)
{
  TIFR1 |=(1<<OCF1A);
}

ISR(TIMER1_COMPB_vect)
{
  TIFR1 |=(1<<OCF1B);
}

ISR(TIMER1_OVF_vect)
{
  TIFR1 |=(1<<TOV1);
}

Aber komischerweise laufen die immer noch nicht zusammen...wo könnte 
noch eine Fehlerquelle sein?

Bin hier grad bisschen am verzweifeln

Grüße Martin

von Martin28 (Gast)


Lesenswert?

Im obigen post ist die Klammer

ISR(TIMER1_CAPT_vect)
{
  TIFR1 |=(1<<ICF1);
}

natürlich geschlossen...

von Karl H. (kbuchegg)


Lesenswert?

Wenn du vernünftige Hilfe willst, dann poste den ganzen Code. 
Vollständig.

Wir können uns natürlich noch 25 andere Szenarien ausdenken, was in 
deinem Code noch alles schief gegangen sein könnte. Einfacher ist es 
aber für dich und für uns, wenn du ganz banal dein C-File nimmst und als 
Anhang anhängst.

von Karl H. (kbuchegg)


Lesenswert?

Aber mal ein Schnellschusss
1
  ADCSRA |= (1<<ADEN);    // ADC Enable
2
  ADCSRA |= (1<<ADSC);    // Start Single Conversion
3
  ADCSRA |= (1<<ADIE);    // Enable ADC Interrupt

Ich würde das mal aus logischen Gründen umdrehen.
Erst den ADC einschalten
dann den ADC konfigurieren
und erst dann, wenn eingeschaltet und konfiguriert ist, erst dann starte 
ich den ADC.

Ich weiß nicht, ob es was ändert. Aber es wäre zumindest erst mal DIE 
logische Reihenfolge der Ereignisse. Und im Zweifelsfall hat es sich 
noch immer bewährt, wenn man sich erst mal daran hält.

von Martin28 (Gast)


Lesenswert?

int main(void)
{

  /***** Ports ******/ //0 = Input ; 1 = Output

  // The Port B Data Direction Register
  DDRB  |= (1<<PB2)|(1<<PB1);
  DDRC  |= (0<<PC5)|(0<<PC4)|(0<<PC3);
  DDRD  |= 
(1<<PD7)|(1<<PD6)|(1<<PD5)|(1<<PD4)|(1<<PD3)|(1<<PD2)|(1<<PD1)|(1<<PD0);


  /***** Timer *****/
  //---------------------------------------------------------------------- 
------------

  Inital_Timer = 17;

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

  ICR1H = 00;
  ICR1L = 69;

  TCCR1A |= (1<<COM1A1)|(0<<COM1A0);
  TCCR1A |= (1<<COM1B1)|(1<<COM1B0);

  OCR1AH = 00;
  OCR1AL = Inital_Timer;

  TIMSK1 |= (1<<ICIE1);
  TIMSK1 |= (1<<OCIE1B);
  TIMSK1 |= (1<<OCIE1A);

  /***** AD Converter *****/
  //---------------------------------------------------------------------- 
-----------

  ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(0<<ADPS0);      /
  // 8MHz / 64 = 125kHz || 110 = 64

  ADMUX  |= (0<<REFS1)|(1<<REFS0);
  ADMUX  |= (0<<ADLAR);

  ADC_Active_Channel = 0;
  ADMUX = (ADMUX & ~(0x1F)) | (ADC_Active_Channel & 0x1F);


  //ADCSRB |= (0<<ACME)|(1<<ADTS2)|(1<<ADTS1)|(0<<ADTS0);  // Timer.1 
Overflow

  ADCSRA |= (1<<ADEN);    // ADC Enable
  ADCSRA |= (1<<ADSC);    // Start Single Conversion
  ADCSRA |= (1<<ADIE);    // Enable ADC Interrupt

  sei();  // set all Interrupts free

  while(1)
  {
    // state_Machine();
    // change_States();
  }

  return(0);
}

von Martin28 (Gast)


Lesenswert?

//---------------------------------------------------------------------- 
-----------------------------
//            Interrupt Service Routine --> AD - Converter
//---------------------------------------------------------------------- 
-----------------------------

ISR(ADC_vect)
{

    /*  if (ADC_Active_Channel == 6)
      {
        ADC_Active_Channel = 0;
      }
    */
        switch(ADC_Active_Channel)
        {
            case 0:break;  // ADC0 unused
            case 1:break;  // ADC1 unused
            case 2:break;  // ADC2 unused

            case 3:
                //LEM_Result = ADCW;
                  AD_LOW = ADCL;
                  AD_HIGH = ADCH;
                  PORTD = AD_LOW;
            break;

            case 4:
                VD_Output_Result = ADCW;
            break;

            case 5:
                VD_Input_Result = ADCW;
            break;
            /*
            AD_LOW = ADCL;
            AD_HIGH = ADCH;
            PORTD = AD_LOW;
            */
            default:break;
        }

      ADCSRA |= (1<<ADSC);  // Start Conversion
}


//---------------------------------------------------------------------- 
-----------------------------
//            Interrupt Service Routine --> Timer.1
//---------------------------------------------------------------------- 
-----------------------------

ISR(TIMER1_CAPT_vect)
{
  TIFR1 |=(1<<ICF1);
}

ISR(TIMER1_COMPA_vect)
{
  TIFR1 |=(1<<OCF1A);
}

ISR(TIMER1_COMPB_vect)
{
  TIFR1 |=(1<<OCF1B);

von Karl H. (kbuchegg)


Lesenswert?

Und wenn du jetzt noch sagst, welcher AVR das ist, dann könnte man den 
Code mal in den Simulator überführen und nachsehen, was da wirklich 
passiert, bzw. auf den realen Chip, denn auch der Simulator ist nicht 
fehlerfrei.

von Martin28 (Gast)


Lesenswert?

Manchmal sieht man den Wald vor lauter Bäumen nicht!!!

ISR(ADC_vect)
{

    /*  if (ADC_Active_Channel == 6)
      {
        ADC_Active_Channel = 0;
      }
    */
        switch(ADC_Active_Channel)
        {
            case 0:break;  // ADC0 unused
            case 1:break;  // ADC1 unused
            case 2:break;  // ADC2 unused

            case 3:
                //LEM_Result = ADCW;
                  AD_LOW = ADCL;
                  AD_HIGH = ADCH;
                  PORTD = AD_LOW;
            break;

            case 4:
                VD_Output_Result = ADCW;
            break;

            case 5:
                VD_Input_Result = ADCW;
            break;
            /*
            AD_LOW = ADCL;
            AD_HIGH = ADCH;
            PORTD = AD_LOW;
            */
            default:break;
        }

      ADC_Active_Channel++;
      ADMUX = (ADMUX & ~(0x1F)) | (ADC_Active_Channel & 0x1F);

      ADCSRA |= (1<<ADSC);  // Start Conversion
}

von Martin28 (Gast)


Lesenswert?

ADC_Active_Channel++;
ADMUX = (ADMUX & ~(0x1F)) | (ADC_Active_Channel & 0x1F);

Komischerweise hatte Ich das rausgelöscht...Fehler gefunden!

Läuft jetzt!

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.