www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Timer INterrupt + ADC Interrupt Probleme


Autor: Fabian Hof (Firma: keine) (eimer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Leute,

hab mal wieder eine Problem, das ich nicht gebacken bekomm.

Also kurze Beschreibung was ich haben möchte.

Muss ein Signal max 2kHz abtasten und den RMS bilden. Jetzt hab ich mir 
das so vorgestellt ich taste immer mit 8192Hz ab. Das habe ich über 
einen Timer Interrupt gelöst der mit externem Quarz funktioniert.
Ok: wenn ich jetzti in dem Timer_interrupt bin möchte ich den AD-Wandler 
anscmeißen er soll mir 1!-Wert auslesen und sich wieder ausstellen.
Nach dem 8192 Aufruf wird RMS gebildet, das ganze geht von vorne los.

Jetzt zum Problem, der Timer geht ohne Probleme, nur das mit dem Wert 
auslesen klappt nicht ganz. Ich seh den Fehler gerade nicht vll. sieht 
jeamdn von euch den auf die schnelle, oder kann mir sagen wie ich das 
ganze inteligenter oder elleganter lösen kann.
//******************************************************************************
//ADC WANDLUNG MIT 8192Hz um RMS zu bilden
//******************************************************************************

#include  <msp430x14x.h>
#include  <math.h>

void ADC_Init(void);
void ADC_Disable(void);

void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
  P4DIR |= 0x0F;                            // P4.0 output
  P4OUT=0;                                  //Reset Outputs
  CCTL0 = CCIE;                             // CCR0 interrupt enabled
  CCR0 = 3;                                 //32768/4 =8192Hz
  TACTL = TASSEL_1 + MC_1;                  // ACLK, upmode

  _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0 w/ interrupt
}

// Timer A0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
  P4OUT ^= 0x0F;                            // Toggle P1.0
  ADC_Init();
  ADC_Disable();
}

void ADC_Init(void)
{
  P6SEL |= 0x01;                            // select A0 input
  ADC12CTL0 = ADC12ON+SHT0_0+ENC+ADC12SC;   // Setup ADC12; 4 Cycles Sample Time; Enable Conversion;Start conversion
  ADC12CTL1 = CSTARTADD0+SHP+ADC12DIV0+ADC12SSEL_3+CONSEQ_0+SHS_0;  // ADC12MEM0;Triggerd sampling Timer;Clock Divider=0;SMCLK=3Mhz;Single conversion;Conversion active;Source=ADC12SC
  ADC12MCTL0 = EOS+INCH_0+SREF_0;           //Enable_end of Sample; Source A0;Source AVCC AVSS; 
  ADC12IE = 0x0001;                         // Enable ADC12IFG.0
  _BIS_SR(LPM0_bits + GIE);                 // Wait for delay, Enable interrupts

}

void ADC_Disable(void){
  P6SEL |= 0x00;                            // diselect A0 input
  ADC12CTL0 = ADC12ON+SHT0_0;               // Setup ADC12; 4 Cycles Sample Time; Enable Conversion;Start conversion
  _BIS_SR(LPM0_bits + GIE);                 //Nur ACLK active
  ADC12CTL0 &= ~ENC;
}

#pragma vector=ADC12_VECTOR
__interrupt void ADC12ISR (void)
{
 //aus MEM0 lesen 1 mal und RMS bilden nach 8192 aufrufen
}



Autor: Werner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
meine Glaskugel hat mir noch nicht verraten, welchen Controller Du 
überhaupt benutzt.
Ich poliere sie noch mal ein wenig, vielleicht klappt es dann....

Autor: Werner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#include  <msp430x14x.h>

I'm sorry.

Wer lesen kann ist klar im Vorteil

Autor: Fabian Hof (Firma: keine) (eimer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
MSP430F149 :)

Hab ich vergessen.

Das Problem hab ich allerdings immernoch.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich kenn zwar den MSP überhaupt nicht.
Aber das hier klingt für mich ziemlich abenteuerlich
  ADC_Init();
  ADC_Disable();
}

void ADC_Init(void)
{
  P6SEL |= 0x01;                            // select A0 input
  ADC12CTL0 = ADC12ON+SHT0_0+ENC+ADC12SC;   // Setup ADC12; 4 Cycles Sample Time; Enable Conversion;Start conversion
  ADC12CTL1 = CSTARTADD0+SHP+ADC12DIV0+ADC12SSEL_3+CONSEQ_0+SHS_0;  // ADC12MEM0;Triggerd sampling Timer;Clock Divider=0;SMCLK=3Mhz;Single conversion;Conversion active;Source=ADC12SC
  ADC12MCTL0 = EOS+INCH_0+SREF_0;           //Enable_end of Sample; Source A0;Source AVCC AVSS; 
  ADC12IE = 0x0001;                         // Enable ADC12IFG.0
  _BIS_SR(LPM0_bits + GIE);                 // Wait for delay, Enable interrupts

}

void ADC_Disable(void){
  P6SEL |= 0x00;                            // diselect A0 input
  ADC12CTL0 = ADC12ON+SHT0_0;               // Setup ADC12; 4 Cycles Sample Time; Enable Conversion;Start conversion
  _BIS_SR(LPM0_bits + GIE);                 //Nur ACLK active
  ADC12CTL0 &= ~ENC;
}

Da wird in der Timer ISR der ADC eingeschaltet um gleich darauf wieder 
ausgeschaltet zu werden. Wie gesagt: ICh kenn den MSP nicht. Kann 
natürlich gut sein, dass sich der ADC ums Ausschalten nicht kümmert, 
solange eine Wandlung im Gange ist. Was er allerdings dazu sagt wenn du 
ihm mitten unter der Wandlung den A0 wegschaltest, wage ich nicht zu 
erraten.

Wie gesagt: Ich kenn den MSP überhaupt nicht. Aber das was du da hast 
ist nicht logisch.
Die Erwartungshaltung wäre gewesen:
In der Timer ISR wird der ADC gestartet. Dar macht sein Ding. Wenn er 
fertig ist, wird die ADC-ISR aufgerufen und erst dort wird der ADC 
wieder abgeschaltet.

Autor: Frank K. (fchk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fabian Hof schrieb:

> #pragma vector=TIMERA0_VECTOR
> __interrupt void Timer_A (void)
> {
>   P4OUT ^= 0x0F;                            // Toggle P1.0
>   ADC_Init();
>   ADC_Disable();
> }

> 
> void ADC_Init(void)
> {
[...]
>   _BIS_SR(LPM0_bits + GIE);                 // Wait for delay, Enable
> interrupts
> 
> }
> 
> void ADC_Disable(void){
[...]
>   _BIS_SR(LPM0_bits + GIE);                 //Nur ACLK active
>   ADC12CTL0 &= ~ENC;
> }
> 

Du schickst den Prozessor mitten in einer ISR wieder in den LPM. Das 
heißt, der Timer-Interrupt wird nie beendet. Ein _BIS_SR solltest Du 
niemals in einer Interrupt-Routine machen, allerhöchstens ein 
_BIS_SR_on_exit. Am Ende eines Interrupts wird ohnehin das SR wieder 
zurückgeladen, und der Prozessor geht wieder in den LPM-Modus, in dem er 
vorher war.

fchk

Autor: Fabian Hof (Firma: keine) (eimer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, lassen wir mal die LPM weg.

Seh ich gerade ein Problem, in der Zeile
ADC12CTL1 = CSTARTADD0+SHP+ADC12DIV0+ADC12SSEL_3+CONSEQ_0+SHS_0;
Schreibt er mir nichts in das Register auch wenn ich ADC12CTL1 = 0x0218; 
mach schreibt er überhaupt nichts rein.

Ich seh gereade nicht was ich falsch mache.

Noch eine Frage im Timer_A interrupt soll er ja solange bleiben bis der 
ADC Interrupt kommt, muss ich da eine Schleife rein machen? Wenn ja 
bleib ich da nach dem ADC_Interrupt nicht hängen?




#include  <msp430x14x.h>
#include  <math.h>

void ADC_Init(void);
void ADC_Disable(void);

double sum;
unsigned int i=0;
double RMS;

void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
  P4DIR |= 0x0F;                            // P4.0 output
  P4OUT=0;                                  //Reset Outputs
  CCTL0 = CCIE;                             // CCR0 interrupt enabled
  CCR0 = 3;                                 //32768/4 =8192
  TACTL = TASSEL_1 + MC_1;                  // ACLK, upmode
  //Test
  ADC12IE = 0x0001;                         // Enable ADC12IFG.0
  _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0 w/ interrupt
}

// Timer A0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
  P4OUT ^= 0x0F;                            // Toggle P1.0
  ADC_Init();
}

void ADC_Init(void)
{
  P6SEL |= 0x01;                            // select A0 input
  ADC12CTL0 = ADC12ON+SHT0_0+ENC+ADC12SC;   // Setup ADC12; 4 Cycles Sample Time; Enable Conversion;Start conversion
  ADC12CTL1 = CSTARTADD0+SHP+ADC12DIV0+ADC12SSEL_3+CONSEQ_0+SHS_0;  // ADC12MEM0;Triggerd sampling Timer;Clock Divider=0;SMCLK=3Mhz;Single conversion;Conversion active;Source=ADC12SC
  ADC12MCTL0 = EOS+INCH_0+SREF_0;           //Enable_end of Sample; Source A0;Source AVCC AVSS; 
  ADC12IE = 0x0001;                         // Enable ADC12IFG.0

}

void ADC_Disable(void){
  P6SEL |= 0x00;                            // diselect A0 input
  ADC12CTL0 = ADC12ON+SHT0_0;               // Setup ADC12; 4 Cycles Sample Time; Enable Conversion;Start conversion
  ADC12CTL0 &= ~ENC;
}

#pragma vector=ADC12_VECTOR
__interrupt void ADC12ISR (void)
{
 double temp=0.0;
  if(i<8192.0){
    
    temp=((ADC12MEM0)*732.421875E-6);
    sum=sum+temp*temp;
    i++;
  }else{
    RMS=sqrt(sum/8192.0);
    i=0;
    sum=0;
  }
  static double test;
  test=(ADC12MEM0*732.421875E-6);
 ADC_Disable();
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fabian Hof schrieb:

> Noch eine Frage im Timer_A interrupt soll er ja solange bleiben bis der
> ADC Interrupt kommt

Warum?

Genau das willst du normalerweise eben nicht. Ansonsten würdest du nicht 
mit Interrupts arbeiten sondern alles in der Hauptschleife in main() 
machen.

Autor: Fabian Hof (Firma: keine) (eimer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok. Keine Schleife.
Die Zeile _BIS_SR(LPM0_bits + GIE); im main auch raus?

Bzw. was ist das Problem warum er mir ADC12CTL1 nicht initiiert?

Autor: Frank K. (fchk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fabian Hof schrieb:
> Ok. Keine Schleife.
> Die Zeile _BIS_SR(LPM0_bits + GIE); im main auch raus?

nein, die nicht. Der soll ja außerhalb der Interrupts im LPM0 sein, 
oder?

Und kein Floating-Point im Interrupt. Das ist (a) sehr langsam und 
könnte (b) auch zu Problemen führen.

> Bzw. was ist das Problem warum er mir ADC12CTL1 nicht initiiert?

Lies das MSP430x1xx Family User's Guide. Da stehts drin. Tip: Unter 
Abschnitt 17.3 schauen.

Und es gibt auch ein Paket mit Beispielcode von TI. Das ist auch sehr 
hilfreich.

fchk

Autor: Fabian Hof (Firma: keine) (eimer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok. ENC muss 0 sein wenn ich das setzen will, fehler von mir.

Ich brauch ein double für die sqrt funktion sonst wird das zu ungenau.

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.