Podstawowa obsługa przetwornika ADC
Podobnie jak większość rodzin układów STM32, także mikrokontrolery Megawin z serii MG32F1 są wyposażone w 12-bitowy przetwornik analogowo-cyfrowy (rysunek 1). Zarówno sposób konfiguracji programowej, jak i zakres funkcjonalności tego bloku okazują się bardzo zbliżone w przypadku STM32F1 i MG32F103 – dlatego osoby zaznajomione z użyciem starych bibliotek STM32 Standard Peripheral Library będą pozytywnie zaskoczone podobieństwem kodu źródłowego, zaprezentowanego na listingu 1, do programów obsługujących ADC w procesorach STM32F1.
void ADC_config(void) {
/* wlaczenie sygnalu taktowania ADC i niezbednych zegarow dodatkowych */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_ADC | RCC_APB1Periph_BMX1| RCC_APB1Periph_AFIO, ENABLE);
/* odblokowanie bloku kontrolnego funkcji analogowych w celu zapisu */
PWR_UnlockANA();
/* zezwolenie na prace przetwornika ADC */
ANCTL_SARADCCmd(ENABLE);
/* przywrocenie stanu zablokowanego w celu ochrony waznych rejestrow*/
PWR_LockANA();
/* struktura inicjalizacyjna ADC */
ADC_InitTypeDef init;
/* uzywamy pojedynczej konwersji, wiec nie potrzebujemy trybu ciaglego skanowania */
init.ADC_ScanConvMode = DISABLE;
init.ADC_ContinuousConvMode = DISABLE;
/* nie uzywamy sprzetowego triggera (wyzwalanie programowe) */
init.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
/* wyrownanie danych do prawej (zera po stronie MSB) */
init.ADC_DataAlign = ADC_DataAlign_Right;
/* jeden kanal do konwersji */
init.ADC_NbrOfChannel = 1;
/* inicjalizacja przetwornika */
ADC_Init(&init);
/* uzywamy tylko kanalu nr 14, wybieramy mozliwie dlugi czas probkowania */
ADC_RegularChannelConfig(ADC_Channel_14, 1, ADC_SampleTime_239Cycles5);
/* zezwolenie na wyzwalanie przetwornika */
ADC_ExternalTrigConvCmd(ENABLE);
/* wlaczenie bloku przetwornika */
ADC_Cmd(ENABLE);
/* zerowanie ustawien kalibracyjnych */
ADC_ResetCalibration();
/* oczekiwanie na gotowosc do rozpoczecia kalibracji */
while(ADC_GetResetCalibrationStatus());
/* rozpoczecie kalibracji */
ADC_StartCalibration();
/* oczekiwanie na zakonczenie kalibracji */
while(ADC_GetCalibrationStatus());
}
Listing 1. Funkcja konfigurująca i inicjalizująca przetwornik ADC
Pewne wątpliwości może natomiast budzić blok trzech instrukcji, znajdujących się na początku ciała funkcji void ADC_config():
Sensowne jest zatem zastosowanie blokady przed przypadkowym nadpisaniem wartości rejestrów kontrolujących pracę tych – kluczowych dla bezpieczeństwa – bloków procesora. Dlatego też, aby móc skorzystać z wbudowanego przetwornika analogowo-cyfrowego, musimy najpierw odblokować możliwość zapisu do rejestrów ANCTL, dopiero wtedy zezwolić na działanie ADC, po czym (dla pewności) ponownie zablokować ANCTL.
Następne operacje bazują już wyłącznie na rejestrach samego przetwornika i polegają na przygotowaniu zawartości struktury inicjalizacyjnej typu ADC_InitTypeDef, na drodze sukcesywnego przypisywania nastaw kolejnych parametrów. Potem – przy użyciu funkcji ADC_Init(), przyjmującej jako parametr wskaźnik na ww. strukturę – wystarczy już tylko przekazać odpowiednie ustawienia do bloku rejestrów konfiguracyjnych. Osobnych działań wymaga:
- wybór kanału(-ów) do skanowania przez sekwencer wbudowany w przetwornik ADC – oraz czasu próbkowania,
- zezwolenie na wyzwalanie przetwornika sygnałem zewnętrznym (w naszym przypadku – dla ułatwienia – zastosujemy wyzwalanie programowe),
- właściwe włączenie bloku przetwornika (nie należy mylić tej operacji z odgórnym zezwoleniem, które ustawiliśmy wcześniej w bloku ANCTL),
- przeprowadzenie automatycznej kalibracji ADC, mającej na celu zniwelowanie rozrzutów pojemności próbkujących (producent zaleca wykonanie kalibracji każdorazowo po włączeniu zasilania systemu).
Tak skonfigurowany przetwornik ADC jest całkowicie przygotowany do pracy. Teraz, już w funkcji main() naszego programu, wystarczy rozpocząć konwersję (funkcja ADC_SoftwareStartConvCmd(ENABLE)), odczekać na jej zakończenie (poprzez sprawdzenie flagi EOC funkcją ADC_GetFlagStatus(ADC_FLAG_EOC)), a następnie odczytać zawartość 16-bitowego rejestru ADC->DR. Całość jest wykonywana w pętli for(), mającej na celu uśrednianie zestawu próbek (w naszym przypadku używamy „bufora” o rozmiarze 128), dzięki czemu odczyty prezentowane na wyświetlaczu LED będą znacznie stabilniejsze niż przy pracy z pojedynczymi wynikami konwersji ADC.