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


von Fabian H. (Firma: keine) (eimer)


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.
1
//******************************************************************************
2
//ADC WANDLUNG MIT 8192Hz um RMS zu bilden
3
//******************************************************************************
4
5
#include  <msp430x14x.h>
6
#include  <math.h>
7
8
void ADC_Init(void);
9
void ADC_Disable(void);
10
11
void main(void)
12
{
13
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
14
  P4DIR |= 0x0F;                            // P4.0 output
15
  P4OUT=0;                                  //Reset Outputs
16
  CCTL0 = CCIE;                             // CCR0 interrupt enabled
17
  CCR0 = 3;                                 //32768/4 =8192Hz
18
  TACTL = TASSEL_1 + MC_1;                  // ACLK, upmode
19
20
  _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0 w/ interrupt
21
}
22
23
// Timer A0 interrupt service routine
24
#pragma vector=TIMERA0_VECTOR
25
__interrupt void Timer_A (void)
26
{
27
  P4OUT ^= 0x0F;                            // Toggle P1.0
28
  ADC_Init();
29
  ADC_Disable();
30
}
31
32
void ADC_Init(void)
33
{
34
  P6SEL |= 0x01;                            // select A0 input
35
  ADC12CTL0 = ADC12ON+SHT0_0+ENC+ADC12SC;   // Setup ADC12; 4 Cycles Sample Time; Enable Conversion;Start conversion
36
  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
37
  ADC12MCTL0 = EOS+INCH_0+SREF_0;           //Enable_end of Sample; Source A0;Source AVCC AVSS; 
38
  ADC12IE = 0x0001;                         // Enable ADC12IFG.0
39
  _BIS_SR(LPM0_bits + GIE);                 // Wait for delay, Enable interrupts
40
41
}
42
43
void ADC_Disable(void){
44
  P6SEL |= 0x00;                            // diselect A0 input
45
  ADC12CTL0 = ADC12ON+SHT0_0;               // Setup ADC12; 4 Cycles Sample Time; Enable Conversion;Start conversion
46
  _BIS_SR(LPM0_bits + GIE);                 //Nur ACLK active
47
  ADC12CTL0 &= ~ENC;
48
}
49
50
#pragma vector=ADC12_VECTOR
51
__interrupt void ADC12ISR (void)
52
{
53
 //aus MEM0 lesen 1 mal und RMS bilden nach 8192 aufrufen
54
}

von Werner (Gast)


Lesenswert?

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

von Werner (Gast)


Lesenswert?

#include  <msp430x14x.h>

I'm sorry.

Wer lesen kann ist klar im Vorteil

von Fabian H. (Firma: keine) (eimer)


Lesenswert?

MSP430F149 :)

Hab ich vergessen.

Das Problem hab ich allerdings immernoch.

von Karl H. (kbuchegg)


Lesenswert?

Ich kenn zwar den MSP überhaupt nicht.
Aber das hier klingt für mich ziemlich abenteuerlich
1
  ADC_Init();
2
  ADC_Disable();
3
}
4
5
void ADC_Init(void)
6
{
7
  P6SEL |= 0x01;                            // select A0 input
8
  ADC12CTL0 = ADC12ON+SHT0_0+ENC+ADC12SC;   // Setup ADC12; 4 Cycles Sample Time; Enable Conversion;Start conversion
9
  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
10
  ADC12MCTL0 = EOS+INCH_0+SREF_0;           //Enable_end of Sample; Source A0;Source AVCC AVSS; 
11
  ADC12IE = 0x0001;                         // Enable ADC12IFG.0
12
  _BIS_SR(LPM0_bits + GIE);                 // Wait for delay, Enable interrupts
13
14
}
15
16
void ADC_Disable(void){
17
  P6SEL |= 0x00;                            // diselect A0 input
18
  ADC12CTL0 = ADC12ON+SHT0_0;               // Setup ADC12; 4 Cycles Sample Time; Enable Conversion;Start conversion
19
  _BIS_SR(LPM0_bits + GIE);                 //Nur ACLK active
20
  ADC12CTL0 &= ~ENC;
21
}

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.

von Frank K. (fchk)


Lesenswert?

Fabian Hof schrieb:
1
> #pragma vector=TIMERA0_VECTOR
2
> __interrupt void Timer_A (void)
3
> {
4
>   P4OUT ^= 0x0F;                            // Toggle P1.0
5
>   ADC_Init();
6
>   ADC_Disable();
7
> }
8
9
> 
10
> void ADC_Init(void)
11
> {
12
[...]
13
>   _BIS_SR(LPM0_bits + GIE);                 // Wait for delay, Enable
14
> interrupts
15
> 
16
> }
17
> 
18
> void ADC_Disable(void){
19
[...]
20
>   _BIS_SR(LPM0_bits + GIE);                 //Nur ACLK active
21
>   ADC12CTL0 &= ~ENC;
22
> }
23
>

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

von Fabian H. (Firma: keine) (eimer)


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?




1
#include  <msp430x14x.h>
2
#include  <math.h>
3
4
void ADC_Init(void);
5
void ADC_Disable(void);
6
7
double sum;
8
unsigned int i=0;
9
double RMS;
10
11
void main(void)
12
{
13
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
14
  P4DIR |= 0x0F;                            // P4.0 output
15
  P4OUT=0;                                  //Reset Outputs
16
  CCTL0 = CCIE;                             // CCR0 interrupt enabled
17
  CCR0 = 3;                                 //32768/4 =8192
18
  TACTL = TASSEL_1 + MC_1;                  // ACLK, upmode
19
  //Test
20
  ADC12IE = 0x0001;                         // Enable ADC12IFG.0
21
  _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0 w/ interrupt
22
}
23
24
// Timer A0 interrupt service routine
25
#pragma vector=TIMERA0_VECTOR
26
__interrupt void Timer_A (void)
27
{
28
  P4OUT ^= 0x0F;                            // Toggle P1.0
29
  ADC_Init();
30
}
31
32
void ADC_Init(void)
33
{
34
  P6SEL |= 0x01;                            // select A0 input
35
  ADC12CTL0 = ADC12ON+SHT0_0+ENC+ADC12SC;   // Setup ADC12; 4 Cycles Sample Time; Enable Conversion;Start conversion
36
  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
37
  ADC12MCTL0 = EOS+INCH_0+SREF_0;           //Enable_end of Sample; Source A0;Source AVCC AVSS; 
38
  ADC12IE = 0x0001;                         // Enable ADC12IFG.0
39
40
}
41
42
void ADC_Disable(void){
43
  P6SEL |= 0x00;                            // diselect A0 input
44
  ADC12CTL0 = ADC12ON+SHT0_0;               // Setup ADC12; 4 Cycles Sample Time; Enable Conversion;Start conversion
45
  ADC12CTL0 &= ~ENC;
46
}
47
48
#pragma vector=ADC12_VECTOR
49
__interrupt void ADC12ISR (void)
50
{
51
 double temp=0.0;
52
  if(i<8192.0){
53
    
54
    temp=((ADC12MEM0)*732.421875E-6);
55
    sum=sum+temp*temp;
56
    i++;
57
  }else{
58
    RMS=sqrt(sum/8192.0);
59
    i=0;
60
    sum=0;
61
  }
62
  static double test;
63
  test=(ADC12MEM0*732.421875E-6);
64
 ADC_Disable();
65
}

von Karl H. (kbuchegg)


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.

von Fabian H. (Firma: keine) (eimer)


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?

von Frank K. (fchk)


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

von Fabian H. (Firma: keine) (eimer)


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.

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.