(8) Mikrokontrolery MSP430: obsługa ADC – przykładowa aplikacja: cyfrowy termometr
W kolejnych instrukcjach konfigurowane są parametry pracy wyświetlacza LCD. Konfigurowane są linie sterujące pracą wyświetlacza. Realizowane jest sekwencja startowa (interfejs 4 bitowy, znaki 5×8, obsługa dwóch linii po 16 znaków każda). Inicjowane jest praca wyświetlacza. Procedury do obsługi alfanumerycznego wyświetlacza LCD ze sterownikiem Hitachi HD44780 umieszczono w pliku „LCD_2x16.c”:
LcdPiny(); LcdSekwencjaStartowa4b3V(); LcdInicjalizacja();
W prezentowanym przykładzie podczas pomiarów analogowych będziemy używać wewnętrznego napięcia referencyjnego wytwarzanego przez moduł REF. Dlatego też w następnych instrukcjach programu konfigurujemy parametry pracy modułu REF. Przed rozpoczęciem pracy z rejestrem konfiguracyjnym REFCTL0 sprawdzany jest stan modułu. Jeśli moduł jest zajęty, to należy czekać do czasu aż nie będzie używany.
while(REFCTL0 & REFGENBUSY);
Kiedy moduł REF nie wykonuje żadnych zadań, można rozpocząć konfigurację modułu. Podczas konfiguracji wartość napięcia referencyjnego VREF ustawiana jest na 1,5 V (bit REFVSEL_0). Wyłączany jest wewnętrzny czujnik temperatury (bit REFVSEL_0), a moduł generatora napięcia jest wyłączony (instrukcja przypisania wartości do rejestru REFCTL0 zeruje bit REFON).
REFCTL0 = REFVSEL_0 + REFTCOFF;
Następnie konfigurowane są parametry pracy modułu przetwornika ADC10_B. Najpierw konfigurowane jest wejście pomiarowe (linia P1.4 mikrokontrolera, wejście analogowe A4). Żeby linia P1.4 zaczęła pracować jako wejście analogowe należy linie ustawić w trzeci funkcyjny tryb pracy. Konfigurację linii realizują poniższe instrukcje.
P1SELC |= BIT4; P1SEL1 |= BIT4; P1SEL0 |= BIT4;
Następnie konfigurowane są rejestry sterujące pracą przetwornika ADC10. Ustawiany jest tryb pracy przetwornika, rozdzielczość pomiarów, potencjały referencyjne, źródło i częstotliwość sygnału taktującego pomiary. Konfigurowany jest sposób wyzwalania pomiarów, czas oraz tryb próbkowania sygnału. Włączana jest obsługę przerwań. Przed rozpoczęciem konfiguracji zerowany jest bit zezwolenia na konwersję.
ADC10CTL0 &=~ ADC10ENC;
Następnie ustawiany jest czas próbkowania sygnału analogowego na 32 takty zegara ADC10CLK (bit ADC10SHT_3), oraz włączana jest obsługa przetwornika (wyzerowany bit ADC10ON).
ADC10CTL0 = ADC10SHT_3;
W ramce poniżejpokazano w jakiś sposób obliczyć czas próbkowania sygnału.
Czas próbkowania sygnału analogowego – obliczenia Sygnał ADC10CLK taktowany jest z wewnętrznego oscylatora MODOSC. Częstotliwość sygnału ADC10CLK wynosi około 5 MHz. Czas próbkowania sygnału t Sample obliczamy ze wzoru 7.2 t Sample = 7,62 · (RE + RI) * CI Rezystancja wewnętrzna RI = 1 k?. Pojemność wewnętrzna CI = 6 pF. Pojemność zewnętrzną RE musimy obliczyć. Przy rozmieszczeniu elementów jak na rysunku 7, rezystancja RE = (100*470 / 100+470) = 82.46 k? Podstawiając obliczone wartości do wzoru 7.2 otrzymujemy. t Sample = 7,62 · (82,46 k? + 1 k?) · 6 pF = 7,62 · 500 ns = 3,8 us Liczbę taktów sygnału ADC10CLK o czasie trwania t Sample obliczamy ze wzoru 7.3 x Sample = t Sample · fADC10CLK = 3,8 us · 5 MHz = 19 Bit ADC10SHTx pozwala na ustawienie wybranych wartości w zakresie 4…1024 takty sygnału ADC10CLK. Wybieramy pierwszą wyższą wartość od obliczonej. Wartość bitu którą należy ustawić to: ADC10SHT_3 = 32 · ADC10CLK |
W kolejnych instrukcjach ustawiany jest tryb pracy przetwornika (bit ADC10CONSEQ_0 pojedynczy pomiar jednego kanału). Włączane jest programowe wyzwalanie pomiarów (bit ADC10SHS_0). Ustawiany jest tryb próbkowania sygnału (bit ADC10SHP). W prezentowanym przykładzie włączane jest próbkowanie sygnału w trybie wyzwalania w którym sygnał próbkowany jest przez czas zdefiniowany za pomocą bitu ADC10SHT z rejestru ADC10CTL0. Następnie definiowane jest źródło sygnału ADC10CLK taktującego konwersję (bit ADC10SSEL_0). W prezentowanym przykładzie sygnał ADC10CLK taktowany jest z wewnętrznego oscylatora MODOSC wytwarzającego sygnał zegarowy o częstotliwości 5 MHz:
ADC10CTL1 = ADC10SHP + ADC10SHS_0 + ADC10SSEL_0 + ADC10CONSEQ_0;
W kolejnym rejestrze konfiguracyjnym ustawiana jest rozdzielczość pomiarów na10 bitów (bit ADC10RES), włączana jest prezentację wyniku pomiaru w formie binarnej (wyzerowany bit ADC10DF) oraz ustawiany jest tryb szybkiej konwersji (wyzerowany bit ADC10SR):
ADC10CTL2 = ADC10RES;
Następnie konfigurowane są potencjały referencyjne V(R+), V(R-) (bit ADC10SREF_1). Źródłem potencjału V(R+) jest napięcie referencyjne VREF o wartości 1,5 V (napięcie generowane przez wewnętrzny moduł REF). Źródłem potencjału V(R–) jest masa analogowa AVSS mikrokontrolera o wartości 0 Volta. Multiplekser analogowy ustawiany jest na obsługę czwartego kanału pomiarowego (bit ADC10INCH_4, kanał A4):
ADC10MCTL0 = ADC10SREF_1 + ADC10INCH_4;
Na zakończenie konfigurowana jest obsługa przerwań. Zerowana jest flaga przerwania ADC10IFG0, oraz włączana jest obsługa przerwań od zakończenia pomiaru (flaga ustawiana w momencie zakończenia pomiaru i wypisania wyniku pomiaru do rejestru ADC10MEM0):
ADC10IFG &=~ ADC10IFG0; ADC10IE |= ADC10IE0;
Dodatkowo odblokowywana jest obsługa przerwań maskowalnych:
__bis_SR_register(GIE);
Podsumowując: moduł przetwornika ADC10_B pracuje w trybie pojedynczego pomiaru jednego kanału. Pomiary realizowane są na zewnętrznym czwartym kanale pomiarowy. Rozdzielczość pomiarów to 10 bitów. Potencjałem referencyjnym V(R+) jest wewnętrzne napięcie VREF o wartości 1,5 V. Czas próbkowania sygnału został ustawiony na 32 takty zegara ADC10CLK. Pomiary wyzwalane są w sposób programowy przy pomocy bitu ADC10SC. Sygnał taktujący konwersję ADC10CLK taktowany jest w zewnętrznego oscylatora MODOSC. Częstotliwość sygnału wynosi 5 MHz (brak podziału częstotliwości sygnału, preskalery częstotliwości sygnału są ustawione na wartość 1, wyzerowane bity ADC10DIVx, ADC10PDIVx). Włączona jest obsługa przerwań od zakończenia pomiaru.
W pętli głównej programu włączany jest generator napięcia referencyjnego (bit REFON):
while(REFCTL0 & REFGENBUSY); REFCTL0 |= REFON;
Włączane jest zasilanie termistora NTC (stan wysoki na wyjściu P2.7):
P2OUT |= BIT7;
Włączany jest przetwornik ADC10 (bit ADC10ON):
ADC10CTL0 |= ADC10ON;
Ponieważ od włączenia generatora REF do pojawienia się napięcia VREF musi minąć co najmniej 30 ms, to wprowadzane jest programowe opóźnienie. Czas opóźnienia to 100 ms:
__delay_cycles(100);
Następnie ustawiany jest bit zezwolenia na konwersję (bit ADC10ENC) i uruchamiany jest pomiar napięcia (bit ADC10SC, programowe wyzwalanie pomiaru):
ADC10CTL0 |= ADC10ENC; ADC10CTL0 |= ADC10SC;
Mikrokontroler wprowadzany jest w tryb uśpienia LPM0 (w trybie tym wyłączona jest CPU mikrokontrolera):
__bis_SR_register(CPUOFF);
Ustawienie bitu ADC10SC w rejestrze ADC10CTL0 rozpoczyna pomiar napięcia na wejściu analogowym A4. Uruchamiany jest proces próbkowania sygnału analogowego, który trwa 32 takty zegara ADC10CLK. Następnie rozpoczyna się konwersja wyniku z postaci analogowej na cyfrową. Wynik pomiaru w formie binarnej o rozdzielczości10 bitów zapisywany jest w rejestrze wyniku ADC10MEM0. Wpisanie wyniku do rejestru ADC10MEM0 powoduje ustawienie w rejestrze ADCD10IFG flagi przerwania ADCD10IFG0. Mikrokontroler jest budzony z uśpienia i rozpoczyna się wykonanie procedury obsługi przerwania:
#pragma vector=ADC10_VECTOR __interrupt void ADC10_ISR(void) { switch(__even_in_range(ADC10IV,12)) { case 0: break; case 2: break; case 4: break; case 6: break; case 8: break; case 10: break; case 12: wPomiaruB = ADC10MEM0; __bic_SR_register_on_exit(CPUOFF); break; default: break; } }
W procedurze obsługi przerwania odczytujemy wartość rejestru ADC10IV (instrukcja switch). W naszym przykładzie obsługiwane są wyłącznie przerwania od zakończenia pomiaru (blok case 12). Z rejestru ADC10MEM0 odczytujemy wynik pomiaru i zapisujemy w zmiennej globalnej wPomiaruB. Odczyt rejestru ADC10MEM0 powoduje wyzerowanie flagi przerwania ADC10IFG0. Na zakończenie procedury obsługi przerwania wykonywana jest instrukcja procesora która modyfikuje sposób powrotu z procedury obsługi przerwania:
__bic_SR_register_on_exit(CPUOFF);
Po powrocie z procedury obsługi przerwania wykonanie programu powraca w miejsce w którym zostało przerwane przez przerwanie. W naszym przypadku jest to tryb uśpienia LPM0. Wywołanie instrukcji __bic_SR_register_on_exit z parametrem CPUOFF powoduje, że po powrocie z procedury obsługi przerwania mikrokontroler nie wróci do trybu uśpienia LPM0. Mikrokontroler zostanie obudzony z uśpienia, a wykonanie pętli głównej programu będzie kontynuowane.
Po powrocie do wykonania pętli głównej programu wyłączane jest zasilanie termistora NTC (stan niski na wyjściu P2.7):
P2OUT &=~ BIT7;
Wyłączany jest przetwornik ADC10 (zerowanie bitu ADC10ON):
ADC10CTL0 &=~ ADC10ENC; ADC10CTL0 &=~ ADC10ON;
Wyłączany jest moduł napięć referencyjnych (zerowanie bitu REFON):
while(REFCTL0 & REFGENBUSY); REFCTL0 &=~ REFON;
Następnie rozpoczyna się obróbka wyniku pomiaru. Wynik pomiaru w formie binarnej jest kalibrowany. Do kalibracji używane są współczynniki zapisane w strukturze TLV mikrokontrolera. Kalibrowana jest wartość napięcia referencyjnego REF oraz przetwornik ADC10 (wzór 7.9):
wPomiaruB = (unsigned int)(wPomiaruB * (float) (sTlvRef.CAL_ADC_15VREF_FACTOR / 32768)); wPomiaruB = (unsigned int)(wPomiaruB * (float) (sTlvAdc10.CAL_ADC_GAIN_FACTOR / 32768)) + sTlvAdc10.CAL_ADC_OFFSET;
Binarny skalibrowany wynik pomiaru konwertowany jest na wartość w Voltach (wzór 7.4):
wPomiaruV = (float)(wPomiaruB * 1.5) / 1023;
Na podstawie zmierzonego napięcia, obliczana jest wartość temperatury (wzór 7.16)
wPomiaruC = (float)(0.4542 - wPomiaruV)/0.0088;
W zmiennych globalnych wPomiaruB, wPomiaruV, wPomiaruC, są zapisane: skalibrowany wynik pomiaru w formie binarnej, wartość napięcia na wyjściu termistora NTC w Voltach, oraz temperatura w stopniach Celsjusza.
W kolejnych liniach programu wartości te prezentowane są na ekranie wyświetlacza LCD. W pierwszej linii ekranu wyświetlane są wynik pomiaru binarnie oraz w Voltach:
LcdWyczyscEkran(); LcdUstawKursorWK(0,0); snprintf((char*)tekst,17,"B: %.4d A: %.2fV",wPomiaruB,wPomiaruV); LcdPiszTekst(tekst);
W drugiej linii ekranu wyświetlana jest temperatura
LcdUstawKursorWK(1,0); snprintf((char*)tekst,17,"Temp: %.1f%cC",wPomiaruC,223); LcdPiszTekst(tekst);
Do konwersji zmiennych na napisy użyta została funkcja języka „C” snprintf(). Po wypisaniu wyników pomiarów na ekranie wyświetlacza LCD. Wprowadzane jest programowe opóźnienie o czasie trwania jednej sekundy:
__delay_cycles(1000000);
Następnie pętla główna programu wykonuje się ponownie. Cykl pomiaru napięcia na wyjściu termistora NTC powtarza się.