Forum: Mikrocontroller und Digitale Elektronik Nochmal AD-Wandler MSP430


von Peter Mueller (Gast)


Lesenswert?

Hallo zusammen,

ich habe folgendes Problem: Der MSP wartet im LP-Mode bis ein WD-Irq 
auftritt. Nach einer best. Anzahl irqs wird die Batteriespannung mit dem 
ADC10 gesampelt. Da klappt auch sehr gut. Aber es gibt sporadisch 
Fehlmessungen. Ich habe keine Idee woher das kommen kann.

Wo fange ich an zu suchen? Anbei eine Datei die die Messungen zeigen. Es 
gibt an zwei Stellen Ausreisser. Ansonsten immer gute Messungen über 
Stunden.

Danke und Gruß,
Peter

von Joe (Gast)


Lesenswert?

Bildest du einen Mittelwert ? Wo ist der Anhang ?

von Jörg S. (Gast)


Lesenswert?

Der Source Code wäre interessanter als die Messwerte.

Messung mit MSP Ref.Spg?
Wird gewartet bis Ref.Spg korrekt anliegt?

von Peter (Gast)


Lesenswert?

Hallo,

>Messung mit MSP Ref.Spg?

Ja

>Wird gewartet bis Ref.Spg korrekt anliegt?

Nein. Gerade im Manual gelesen:

" The total settling time when REFON becomes set is  30 us."

Werde vor dem Setzen von ENC 30us warten und prüfen ob es
weiterhin diese Ausreisser gibt.

Danke für den Tip. Anbei mein Code. Habt ihr sonst noch Hinweise?

Peter

von Peter (Gast)


Lesenswert?

Hier der Code (war in der ersten Mail mit Formatierung drin, ist aber 
irgendwie verschwunden. Jetzt nochmal ohne Formatierung.


unsigned short read_ubatt(void){
  unsigned long calc;

  ADC10CTL1 = ADC10DIV_3 + INCH_0;
  ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE + ENC + 
ADC10SC;
  _BIS_SR(CPUOFF + GIE);                  // LPM0 with interrupts 
enabled

  calc = ((unsigned long)ADC10MEM*(unsigned long)1500);

  return calc/1023;

}

// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR (void)
{
    ADC10CTL0 &= ~(ENC + ADC10SC);
    _BIC_SR_IRQ(CPUOFF);                    // Clear CPUOFF bit from 
0(SR)
}

von Stefan (Gast)


Lesenswert?

Bist Du Dir auch sicher, dass Deine Batteriespannung konstant bleibt 
während der Messung? Ich meine, wenn Du einen Impuls-artigen Verbraucher 
dranhängen hast, dann wirst Du auch Spannungseinbrüche mit dem ADC 
messen. Die Chance diese Einbrüche zu "treffen" ist gering, deshalb 
vielleicht auch nur die sporadischen "Fehlmessungen"!

Was noch fehlt ist der Code für den WDT-IRQ.

Gruß Stefan

von Jörg S. (Gast)


Lesenswert?

> Werde vor dem Setzen von ENC 30us warten und prüfen ob es
> weiterhin diese Ausreisser gibt.
Die Zeit ist stark abhängig vom Kondensator der am Vref Pin hängt (den 
du hoffentlich verwendest). Am besten mit den Oszi messen wie schnell 
der sich läd und das Delay entsprechend anpassen.

von Stefan (Gast)


Lesenswert?

>Die Zeit ist stark abhängig vom Kondensator der am Vref Pin hängt (den
>du hoffentlich verwendest)

Ich weiß jetzt nicht auswendig wie das bei anderen MSP430 Typen ist, 
aber bei den MSP430x1xx braucht man an Vref keinen Kondensator, vorallem 
nicht, wenn man die interne Referenzspannung benutzt (was ja aus dem 
Code-Schnipsel hervorgeht). Zum Entkoppeln reicht laut User-Guide 10uF 
parallel mit 100nF zwischen Vcc und Vss!

von Jörg S. (Gast)


Lesenswert?

Bei den anderen MSPs könnte man sich das auch sparen, ist halt die Frage 
wie genau der AD Wandler betrieben werden soll.

von Christian R. (supachris)


Lesenswert?

Den Kondensator (100nf || 10µF) an Vref braucht man bei den F1xx Typen 
genauso. Steht im Datenblatt. Ich habs auch mehrfach ohne probiert, da 
kommen keine reproduzierbare Ergebnisse raus.

Gabs nicht auch irgendwo ein Bit, das man setzen kann, damit während der 
eigentlichen Messung die CPU abgeschaltet wird, um Störungen zu 
vermeiden?

von Jörg S. (Gast)


Lesenswert?

Man kann in Low Power Mode gehen, macht er ja auch schon :
1
_BIS_SR(CPUOFF + GIE);    // LPM0 with interrupts

von Stefan (Gast)


Lesenswert?

Also um Missverständnisse zu vermeiden:
Für den ADC10, um den es sich in dieser Frage handelt, braucht man an 
Vref KEINEN Kondensator. Denn an Vref liegt überhaupt keine Ref-Spannung 
an, solangen man nicht explizit REFOUT in ADC10CTL0 setzt (was aber für 
eine Messung nicht notwendig ist)!

von Stefan (Gast)


Lesenswert?

@Peter:

Dein Code-Bsp. ist meiner Meinung nach nicht ganz optimal ;-)

In 'read_ubatt(void)' startest Du eine conversion und legst die CPU 
danach schlafen. Sobald der ADC10 fertig ist, weckst Du die CPU in 
'ADC10_ISR (void)' wieder auf, um dann in 'read_ubatt(void)' die 
Berechnung durchzuführen. D.h. die CPU ist nur für ein paar µs aus... 
lohnt sich das?

Ich würde den ADC einmalig nach µC-Reset initialisieren, etwa so:

<init>:
...
ADC10CTL0 &= ~ENC;
ADC10CTL0  = SREF_1 + ADC10SHT_3 + REFON + ADC10ON;
ADC10CTL1  = ADC10DIV_3 + INCH_0;
ADC10AE    = ADC10AE0;             // enable analog input A0
ADC10CTL0 |= ENC;
...

In deiner Funktion dann Batteriespannung messen und danach LPM:
<read_ubatt>:
ADC10CTL0 |= ADC10SC;            // Start conversion
while(!ADC10CTL0 & ADC10IFG);    // warten bis conversion fertig
...
Berechnung
...
_BIS_SR(CPUOFF + GIE);           // LPM0

Aufwecken der CPU über WDT-ISR:
#pragma vector=WDT_VECTOR
__interrupt void WDT_ISR (void)
{
  _BIC_SR_IRQ(CPUOFF);
}

So in etwa zumindest als Anregung!

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.