18.10.2013
(8) Mikrokontrolery MSP430: obsługa ADC – przykładowa aplikacja: cyfrowy termometr
Aplikacja
Kod źródłowy programu pokazano na listingu 5.
List. 5. Funkcja main
// "MSP430 z pamięcią FRAM" // konfiguracja "MSP-EXP430FR5739": // Zadanie numer 7.1. Obsługa analogowego wejścia. Termistor. // (ustawienia fabryczne) // // w programie wykorzystano // ACLK nieaktywny // zainstalowany w module // MCLK = SMCLK = DCOCLK ~1MHz // termistor NTC, 100 kOm // // do modułu podłączamy wyświetlacz // MSP430FR5739 // // ----------------- // działanie programu: // | | // raz na sekundę wykonywany jest pomiar // | P1.0 | -> LCD E // napięcia na wyjściu termistora NTC // | P1.1 | -> LCD RS // wynik pomiaru konwertowany jest na // | P2.0 | -> LCD D7 // wartość temperatury w st. Celsjusza // | P2.5 | -> LCD D6 // na ekranie LCD wyświetlane są: // A4 -> | P1.4 P2.6 | -> LCD D5 // wynik pomiaru binarnie i w Voltach // NTC on/off <- | P2.7 P2.1 | -> LCD D4 Ł.K.'13 // oraz temperatura w st. Celsjusza //------------------------------------------------------------------- // // pliki nagłówkowe #include "io430.h" // rejestry procesora #include "intrinsics.h" // instrukcje procesora #include "LCD_2x16.h" // procedury LCD #include "tlv.h" // struktura TLV #include // funkcje wejścia/wyjścia // // zmienne globalne unsigned int wPomiaruB; // wynik pomiaru (binarnie) float wPomiaruV; // wynik pomiaru (Volty) float wPomiaruC; // wynik pomiaru (stopnie Celsjusza) // void main(void) // program główny { // WDTCTL = WDTPW + WDTHOLD; // zatrzymaj układ Watchdog // unsigned char tekst[16 + 1]; // zmienna lokalna // bufor, tekst ekranu LCD // // konfiguracja linii we/wy P1OUT = 0x00; P2OUT = 0x00; P3OUT = 0x00; P4OUT = 0x00; // stan niski na liniach PJOUT = 0x00; // linie w kierunku wyjścia P1DIR = 0xff; P2DIR = 0xff; P3DIR = 0xff; P4DIR = 0xff; // wszystkie linie to: PJDIR = 0xff; // wyjścia w stanie niskim // // konfiguracja LCD LcdPiny(); // linie we/wy LcdSekwencjaStartowa4b3V(); // sekwencja startowa LcdInicjalizacja(); // inicjalizacja LCD // // konfiguracja generatora REF while(REFCTL0 & REFGENBUSY); // czekaj dopóki gen. jest zajęty REFCTL0 = REFVSEL_0 + REFTCOFF; // ustaw napięcie VREF = 1.5V // wyłącz czujnik temperatury // P1SELC |= BIT4; // konfiguracja P1SEL1 |= BIT4; // wejścia analogowego A4 P1SEL0 |= BIT4; // ustaw trzeci funkcyjny tryb pracy // // konfiguracja przetwornika ADC ADC10CTL0 &=~ ADC10ENC; // wyzeruj bit zezwolenia na konwersję // próbkowanie 32 takty ADC10CLK ADC10CTL0 = ADC10SHT_3; // ustaw tryb pojedynczego pomiaru ADC10CTL1 = ADC10SHP + ADC10SHS_0 + ADC10SSEL_0 + ADC10CONSEQ_0; // taktowanie pomiaru z wew. osc. 5MHz ADC10CTL2 = ADC10RES; // rozdzielczość pomiaru 10 bitów ADC10MCTL0 = ADC10SREF_1 + ADC10INCH_4; // potencjały referencyjne: // V(R+) = VREF, V(R-) = AVSS // obsługa zew. kanału pomiarowego nr. 4 // ADC10IFG &=~ ADC10IFG0; // wyzeruj flagę przerwania ADC10IE |= ADC10IE0; // włącz obsługę przerwań // od zakończenia pomiaru napięcia // __bis_SR_register(GIE); // odblokuj obsługę // przerwań maskowalnych // while(1) // pętla główna programu { // while(REFCTL0 & REFGENBUSY); // czekaj dopóki gen. REF jest zajęty REFCTL0 |= REFON; // włącz generator P2OUT |= BIT7; // włącz zasilanie termistora NTC ADC10CTL0 |= ADC10ON; // włącz przetwornik ADC10 // __delay_cycles(100); // czekaj 100us // ADC10CTL0 |= ADC10ENC; // ustaw bit zezwolenia na konwersję ADC10CTL0 |= ADC10SC; // rozpocznij pomiar napięcia // (programowe wyzwalanie pomiaru) // __bis_SR_register(CPUOFF); // przejdź w tryb uśpienia LPM0 // koniec pomiaru, wyjście z uśpienia // P2OUT &=~ BIT7; // wyłącz zasilanie termistora NTC ADC10CTL0 &=~ ADC10ENC; // wyzeruj bit zezwolenia na konwersję ADC10CTL0 &=~ ADC10ON; // wyłącz przetwornik ADC10 while(REFCTL0 & REFGENBUSY); // czekaj dopóki gen. REF jest zajęty REFCTL0 &=~ REFON; // wyłącz generator nap. referencyjnego // // kalibracja binarnej wartości pomiaru wPomiaruB = (unsigned int)(wPomiaruB * (float)(sTlvRef.CAL_ADC_15VREF_FACTOR / 32768)); // (wzór 7.9) wPomiaruB = (unsigned int)(wPomiaruB * (float)(sTlvAdc10.CAL_ADC_GAIN_FACTOR / 32768)) + sTlvAdc10.CAL_ADC_OFFSET; // wPomiaruV = (float)(wPomiaruB * 1.5) / 1023; // obliczenie wartości w Voltach (wzór 7.4) wPomiaruC = (float)(0.4542 - wPomiaruV)/0.0088; // obliczenie wartości w st. Celsjusza (wzór 7.16) // // prezentacja wyniku // LcdWyczyscEkran(); // wyczyść ekran LCD LcdUstawKursorWK(0,0); // ustaw kursor na początku 1 linii snprintf((char*)tekst,17,"B: %.4d A: %.2fV",wPomiaruB,wPomiaruV);// wypisz wynik pomiaru prezentowany LcdPiszTekst(tekst); // binarnej oraz w Voltach // następnie LcdUstawKursorWK(1,0); // ustaw kursor na początku 2 linii snprintf((char*)tekst,17,"Temp: %.1f%cC",wPomiaruC,223); // wypisz wynik pomiaru prezentowany LcdPiszTekst(tekst); // w stopniach Celsjusza // __delay_cycles(1000000); // czekaj 1 sekundę }; // } // // #pragma vector=ADC10_VECTOR // procedura obsługi przerwania __interrupt void ADC10_ISR(void) // przetwornika A/C, moduł ADC10 { // switch(__even_in_range(ADC10IV,12))// odczytaj rejestr ADC10IV { // case 0: break; // brak przerwań case 2: break; // nadpisanie sekwencji pomiarowej case 4: break; // nadpisanie wyniku pomiaru case 6: break; // komparator analogowy, próg w górę case 8: break; // komparator analogowy, próg w dół case 10: break; // komparator analogowy, próg pomiędzy // case 12: // zakończenia pomiaru wPomiaruB = ADC10MEM0; // odczytaj wynik pomiaru __bic_SR_register_on_exit(CPUOFF); // wyjdź z trybu uśpienia break; // default: break; // brak obsługi } // } //
W programie głównym zatrzymywana jest pracy układu Watchdog:
WDTCTL = WDTPW + WDTHOLD;
Następnie konfigurowane są linie wejścia/wyjścia mikrokontrolera. Wszystkie linie wejścia/wyjścia ustawiane są jako wyjścia w stanie niskim. Najpierw ustawiany jest stan niski na liniach, następnie zmieniany jest kierunek linii z wejścia na wyjście:
P1OUT = 0x00; P2OUT = 0x00; P3OUT = 0x00; P4OUT = 0x00; PJOUT = 0x00; P1DIR = 0xff; P2DIR = 0xff; P3DIR = 0xff; P4DIR = 0xff; PJDIR = 0xff;