/* ---- msp430g2231 ADC10 DemoCode ----------------------------------- #### (c) B. Nollmeyer 04/2012 #### ---- */ /* */ /* ADC Oversampling 12 BIT, Gain, Offset Error Kompensation mittels "Fixed-point Arithmetik". AREF wird auf die interne 2,5V Referenz eingestellt. Die Ausgabe erfolgt an den MSP430 USB Application COM Port, 8N1, 9600 Baud. Messwertberuhigung mittels Tiefpassfilter. ---- IAR C/C++ Compiler for MSP430, Codesize 558 Byte ---- MSP430g2231 ------\/------ +3,5V --|DVCC GND|-- DVSS/AGND rote LED --|P1.0 P2.6|-- TXD --|P1.1 P2.7|-- --|P1.2 TEST|-- TEST/SBWTCK Taster --|P1.3 RESET|-- RST/NMI/SBWTDIO --|P1.4 P1.7|-- ADC+ IN --|P1.5 P1.6|-- grüne LED -------------- */ #include "msp430g2231.h" #include "inttypes.h" // ADC Werte für die Referenzpunkte #define AdcRawHigh 3194 // Stützpunkt 2.00 Volt #define AdcRawLow 626 // Stützpunkt 0.40 Volt #define DeltaRaw (AdcRawHigh - AdcRawLow) // ADC Skalierung für die Ausgabe #define OutValHigh 20000.0 // Ausgabewert für AdcRawHigh #define OutValLow 4000.0 // Ausgabewert für AdcRawLow #define DeltaOut (OutValHigh - OutValLow) // ADC Signalfenster #define AdcWindow 40 // Delta <> 4.0 mV => ADC "immediate" Update // Berechnung der ADC Korrekturwerte mittels Referenzpunkte #define Slope (DeltaOut / DeltaRaw) // ADC Steigung #define zeroPoint (OutValLow - AdcRawLow * Slope) // ADC Offset #define Factor (int32_t) (Slope * (1L << 16)) // ADC Steigung zur Basis 2^16 #define Offset (int32_t) (zeroPoint * (1L << 16)) // ADC Offset zur Basis 2^16 // MSP430g2231 Signale / PINs GPIOs #define LED1 BIT0 // rote Led #define LED2 BIT6 // grüne Led #define TXD BIT1 // TXD an P1.1 #define AdcInput 0x10 // ADC Eingang an P1.5 // Timing serielle Schnittstelle / Software UART #define BitTime 104 // 9600 Baud, SMCLK=1MHz (1MHz/9600)=104 // globale Variablen volatile uint16_t TXByte; // TXByte + Start/Stop BIT's uint16_t AdcVal; // Prototypen void putChar (uint8_t c); void AdcValOut (uint16_t AdcValue); uint16_t getAdcValue (void); void TimerInit (void); void AdcInit (void); void main (void) { WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; // SMCLK = DCO = 1MHz // ---- GPIO's initialisieren ---- P1SEL |= TXD; P1DIR |= LED1 | LED2 | TXD; // LED1, LED2, TXD als Ausgang setzen P1OUT &= ~ (LED1 | LED2); // LED's = AUS TimerInit (); AdcInit (); __bis_SR_register (GIE); // interrupts enabled for (;;) { AdcValOut (getAdcValue ()); // ~ 1x pro Sekunde } } // ---- ADC Oversampling 12 BIT, Linearisierung, Messwertberuhigung, Offset + Gain Kompensation ---- uint16_t getAdcValue (void) { uint16_t AvgCount = 0, measVal = 0; uint32_t AvgSum = 0; for (AvgCount = 0; AvgCount < 1024; AvgCount ++) { ADC10CTL0 &= ~ADC10IFG; ADC10CTL0 |= ENC + ADC10SC; // AD Wandler starten while (!(ADC10CTL0 & ADC10IFG)); // AD Wandlung fertig ? AvgSum += ADC10MEM; // Mittelwert über 1024 Messungen } measVal = ((((AvgSum >> 8) * Factor) + Offset) >> 16); // skaliert auf 12 BIT /*** ---- Messwertberuhigung, ADC Delta < +-4mV ? => interpolieren, > 4mV ? immediate Update ---- ***/ if (measVal > AdcVal) { (measVal - AdcVal > AdcWindow) ? (AdcVal = measVal) : (AdcVal += 1); } else if (measVal < AdcVal) { (AdcVal - measVal > AdcWindow) ? (AdcVal = measVal) : (AdcVal -= 1); } return AdcVal; } // ---- ADC Value integer -> ASCII ---- void AdcValOut (uint16_t AdcValue) { uint8_t AdcValArray [5]; uint8_t m = 4; do { AdcValArray [m] = '0' + AdcValue %10; // Berechnung der einzelnen Stellen sowie AdcValue /= 10; // Wandlung nach ASCII und abspeichern im } while (m--); // Array putChar ('\r'); while (m != 3) { // Anzahl der auszugebenden Stellen = 4 putChar (AdcValArray [++m]); // Integer Wert ausgeben if (m == 0) putChar ('.'); // Dezimalpunkt setzen } } // ---- Soft. UART Timer Setup ---- #pragma inline void TimerInit (void) { CCTL0 = OUT; // TXD Idle as Mark = '1' TACTL = TASSEL_2 | MC_2; // SMCLK, continuous mode } // ---- ADC initialisieren ---- #pragma inline void AdcInit (void) { ADC10CTL1 |= INCH_5 | ADC10SSEL0 | ADC10SSEL1 | ADC10DIV_7; // ADC IN an P1.5, ADC CLK = SMCLK/8 ADC10CTL0 = SREF_1 | ADC10SHT_3 | REF2_5V | REFON | ADC10ON; // SHT 64x ADC10CLKs, VREF 2.5V, ADC ON ADC10AE0 |= AdcInput; // ADC Input Enable an P1.5 } // ---- simple putChar ---- void putChar (uint8_t c) { while (CCTL0 & CCIE); // Warten bis die ISR alle BITs ausgesendet hat TXByte = 0x200 | (c << 1); // Char + Start/Stop BIT in TXByte einfügen CCR0 = TAR + 16; CCTL0 = CCIS0 | OUTMOD0 | CCIE; // re-Enable Interrupts, trigger Transmit ISR } // ---- Timer A0 interrupt service routine, transmit Byte via ISR ---- #pragma vector=TIMERA0_VECTOR __interrupt void Timer_A (void) { if (TXByte) { // Wenn alle BITs ausgesendet sind... (TXByte & 1) ? (CCTL0 &= ~ OUTMOD2) : (CCTL0 |= OUTMOD2); TXByte >>= 1; CCR0 += BitTime; // BIT Zeit aufaddieren } else { CCTL0 &= ~ CCIE; // ...disable interrupt } }