Wstęp
W opisywanym mikrokontrolerze zastosowano dwa 12 bitowe przetwoniki ADC. Każdy z tych przetworników wyposażono na wejściu w multiplekser. Pozwala on na odczytywanie danych z 16 linii wejściowych
Przetworniki są 12 bitowe oznacza to, że otrzymana wartość napięcia będzie przetwarzana na jej reprezentację cyfrową z zakresu od 0 do 4096. Obsługiwane są piny od 0 do 15. Do kanału 16 podłączony został wbudowany czujnik temperatury układu. Natomiast do kanału 17 podłączone zostało napięcie referencyjne.
Maksymalny czas przetwarzania wartości przez kanał ADC obliczany jest z nastepującego wzoru:
T = czas próbkowania + 12,5 taktu
Czas próbkowania jest wybierany programowo spośród następujących wartości 1,5, 7,5, 13,5, 28,5, 41,5, 55,5, 71,5, 239,5.
Jeśli częstotliwość wynosi 10MHz i czas próbkowania 252. Wtedy otrzymuje się następujący czas przetwarzania.
Jeśli częstotliwość wynosi 10MHz i czas próbkowania 252. Wtedy otrzymuje się następujący czas przetwarzania.
T = 239,5 + 12,5 = 252 takty
T = 1/10MHz * 252 = 25,2 us
Należy pamiętać, że ADC toleruje napięcia do 3.3V. Z tego powodu nie należy podłączać napięcia wyższego np. 5V ponieważ można bardzo łatwo uszkodzić mikrokontroler.
Inicjalizacja ADC
ADC taktowane jest poprzez APB2. Częstotliwość tej linii przy korzystaniu z PLL wynosi 64MHz. Taką częstotliwością nie można taktować tego przetwornika, ponieważ jego maksymalna częstotliwość pracy wynosi 14MHz, natomiast minimalna 0,6MHz. Informacje te można znaleźć w nocie katalogowej mikrokontrolera na stronie 75.
Częstotliwość taktowana z szyny APB2 może zostać podzielona przez następujące wartości 1, 2, 4, 6, 8. Dzięki temu dostaniemy odpowiednio dobraną wartość częstotliwości, która będzie się mieścić w wymaganym przedziale. Aby częstotliwość była niższa od 14 należy zastosować dzielnik 6 lub 8.
Częstotliwość taktowana z szyny APB2 może zostać podzielona przez następujące wartości 1, 2, 4, 6, 8. Dzięki temu dostaniemy odpowiednio dobraną wartość częstotliwości, która będzie się mieścić w wymaganym przedziale. Aby częstotliwość była niższa od 14 należy zastosować dzielnik 6 lub 8.
Program - Potencjometr
Ten program przedstawia sposób jednokrotnego pomiaru napięcia sygnału analogowego z potencjometru. Oznacza to, że pomiar następuje tylko jeden raz. Wartość zmierzona będzie przechowywana w zmiennej i nie ulegnie zmianie. Nawet jeśli to napięcie będzie zmieniane.
Aby w takim trybie pracy można było dokonać kolejnego pomiaru należy wprowadzić linię ADC_SoftwareStartConvCmd(ADC1, ENABLE) która będzie wykonywana bezpośrednio przed kolejnym pomiarem.
Poniżej przedstawiam pełny program. Wynik jego można oglądać w trybie debugowania.
#include <stdio.h> #include <stdint.h> #include "stm32f10x.h" void Delay(int); void ADCInit(); void GPIOInit(); int main(void) { uint16_t adconv = 0; float wartosc = 0; GPIOInit(); ADCInit(); while (1) { adconv = ADC_GetConversionValue(ADC1); wartosc = (float)adconv * 3.3 / 4096.0; } } void Delay(int time) { int i; for (i = 0; i < time * 5000; i++) { } } void ADCInit(void) { ADC_InitTypeDef ADCInit; //Włączenie sygnału taktującego RCC_ADCCLKConfig(RCC_PCLK2_Div6); //Zmniejszenie częstotliwości z 64MHz na 64MHz/6 = 10,66MHz RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); ADC_StructInit(&ADCInit); //Niezależna praca przetwornika ADCInit.ADC_Mode = ADC_Mode_Independent; //Wylaczone skanowanie kanałów, pomiar tylko na jednym kanale ADCInit.ADC_ScanConvMode = DISABLE; //Dokonywanie pomiarów w trybie jednokrotnym ADCInit.ADC_ContinuousConvMode = DISABLE; //Liczba wykorzystywanych kanałów ADCInit.ADC_NbrOfChannel = 1; //Wyzwalanie zewnętrzne wyłączone ADCInit.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //Inicjalizacja przetwornika ADC_Init(ADC1, &ADCInit); //Ustawienie parametrów ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_71Cycles5); //Włączenie ADC1 ADC_Cmd(ADC1, ENABLE); //Reset rejestrów kalibracyjnych ADC_ResetCalibration(ADC1); //Czekanie na reset while (ADC_GetResetCalibrationStatus(ADC1)); //Kalibracja ADC_StartCalibration(ADC1); //Odczekanie na wykonanie kalibracji while (ADC_GetCalibrationStatus(ADC1)); //Wyzwolenie pojedynczego pomiaru ADC_SoftwareStartConvCmd(ADC1, ENABLE); } void GPIOInit(void) { GPIO_InitTypeDef GPIOInit; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); GPIOInit.GPIO_Pin = GPIO_Pin_0; GPIOInit.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIOInit); }
W celu dokonywania ciągłych konwersji należy zmienić wartość parametru ADC_ContinuousConvMode z Disable na Enable.
ADCInit.ADC_ContinuousConvMode = ENABLE;
Po jego zmianie konwersja jest ciągłą, parametr zmienia się dynamicznie.
ADC_RegularChannelConfig określa parametry przetwarzania. W tym przypadku kanał 0 będzie przetwarzany przez przetwornik ADC1. Ma on zostać przypisany z numerem 1 do grupy podstawowej. Czas próbkowania został określony na 71,5 taktu.
ADC_RegularChannelConfig określa parametry przetwarzania. W tym przypadku kanał 0 będzie przetwarzany przez przetwornik ADC1. Ma on zostać przypisany z numerem 1 do grupy podstawowej. Czas próbkowania został określony na 71,5 taktu.
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_71Cycles5);
Program - Wewnętrzny Termometr
W tym programie zaprezentuje sposób uzyskania dostępu do wewnętrznego termometru podłączonego na stałe do kanału 16 ADC. Dokładność skalibrowanego czujnika wynosi +/- 1,5 st C. Jest on najczęściej wykorzystywany do pomiarów temperatury mikrokontrolera. W celu jego ochrony przed przegrzaniem.
Przetwarzana jest wartość z zakresu napięciowego od 2 do 3.6V.
Poniżej przedstawiam całość programu do obserwacji temperatury.
#include <stdio.h> #include "stm32f10x.h" void Delay(int); void ADCInit(void); int main(void) { uint16_t wartosc = 0; float temperatura = 0; float napiecie = 0; ADCInit(); while (1) { //Odczytanie wartosci z przetwornika uint16_t wartosc = ADC_GetConversionValue(ADC1); //Przetworznie odczytanej wartosci na napiecie napiecie = wartosc * 3.3f / 4096.0f; //Obliczenie temperatury temperatura = (((1430 - (wartosc*0.8067))/4.3) + 25.0); Delay(2000); } } void ADCInit(void) { ADC_InitTypeDef ADCInit; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); ADC_StructInit(&ADCInit); ADCInit.ADC_Mode = ADC_Mode_Independent; ADCInit.ADC_ScanConvMode = DISABLE; ADCInit.ADC_ContinuousConvMode = ENABLE; ADCInit.ADC_NbrOfChannel = 1; ADCInit.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_Init(ADC1, &ADCInit); ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while (ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1)); //Włączenie czujnika temperatury ADC_TempSensorVrefintCmd(ENABLE); ADC_SoftwareStartConvCmd(ADC1, ENABLE); } void Delay(int time) { int i; for (i = 0; i < time * 5000; i++) { } }
Odczytana wartość z przetwornika waha się w granicach od 1693 do 1695. Po skorzystaniu z wzoru otrzymujemy następujące wartości temperatury:
V25 - jest to napięcie w temperaturze 25 st. C. Przyjmuje się ją jako 1,43 V. Oscyluje ona w zakresie od 1,34 do 1,52 V.
Vsense - jest to zmierzone napięcie czujnika
AVG_SLOPE - czułość czujnika. Przyjmuje 4,3mV/st. C
Odczytana temperatura wynosi 39,7 st.C. Należy pamiętać aby czas próbkowania wynosił przynajmniej 17us.