Kursy • Poradniki • Inspirujące DIY • Forum
ADC w naszym STM32
Mikrokontroler STM32F103RB jest wyposażony w dwa, 12-bitowe przetworniki analogowo-cyfrowe. Każdy z przetworników posiada na wejściu multiplekser, dzięki któremu odczytywać dane nawet z 16 różnych linii wejściowych.
Dodatkowo nasz układ posiada wbudowany czujnik temperatury oraz źródło napięcia referencyjnego 1.2V. O ile czujnik temperatury jest mało dokładny i można nim mierzyć tylko zmiany temperatury, o tyle napięcie referencyjne możemy wykorzystać do przetestowania naszego sposobu odczytu napięcia za pomocą ADC.
Jak interpretować wynik?
Najpierw odrobina matematyki. Pomiar wykonywany jest względem napięcia zasilania, czyli 3.3V. Czujnik jest 12-bitowy, więc wynik jest liczbą z zakresu 0 - 4095 (212 = 4096 wartości). Jeśli na wejściu przetwornika pojawi się napięcie Vadc, powinniśmy odczytać wartość, którą możemy obliczyć według wzoru:
ADC = Vadc / 3.3V * 4096
Przykład: wiemy, że napięcie referencyjne to 1.2V, jaki powinniśmy otrzymać odczyt?
ADC = 1.2V / 3.3V * 4096 = 1489
Spróbujmy teraz napisać program, który odczyta wartość napięcia referencyjnego, a wynik wyśle przez złącze szeregowe do komputera PC - nauczyliśmy się, jak to zrobić w poprzedniej części kursu. Dzięki temu sprawdzimy, czy uzyskamy wynik zgodny z naszymi oczekiwaniami.
Gotowe zestawy do kursów Forbota
Komplet elementów Gwarancja pomocy Wysyłka w 24h
Zestaw ponad 120 elementów do przeprowadzenia wszystkich ćwiczeń z kursu można nabyć u naszych dystrybutorów! Dostępne są wersje z płytką Nucleo lub bez niej!
Zamów w Botland.com.pl »STM32 - pomiar napięcia referencyjnego
Jak wiemy, STM32F103 posiada dwa przetworniki A/C. Napięcie referencyjne jest podłączone tylko do pierwszego z nich, oznaczonego jako ADC1. Pierwszy krok, to jak zwykle podłączenie zegara:
1 |
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); |
Przetwornik A/C nie może poprawnie pracować
z zegarem o częstotliwości wyższej od 14MHz.
Ponieważ zegar systemowy ma częstotliwość 64MHz, konieczne jest zmniejszenie częstotliwości za pomocą preskalera, czyli dzielnika częstotliwości. Podzielimy 64MHz przez 6, dzięki temu uzyskamy nieco ponad 10MHz, a więc wartość w dopuszczalnym zakresie.
1 |
RCC_ADCCLKConfig(RCC_PCLK2_Div6); |
Następnie musimy zadeklarować zmienną konfiguracyjną przetwornika i ustawić parametry pracy:
1 2 3 4 5 6 7 |
ADC_InitTypeDef adc; ADC_StructInit(&adc); adc.ADC_ContinuousConvMode = ENABLE; adc.ADC_NbrOfChannel = 1; adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_Init(ADC1, &adc); |
Wybieramy tryb ciągły, nasz przetwornik będzie wykonywał jeden pomiar po drugim. Ustawiamy liczbę kanałów na 1 oraz wyzwalanie na brak – uruchomimy przetwornik programowo.
Następnie musimy ustawić parametry multipleksera. Przetwornik może odczytywać dane z maksymalnie 16 wejść zewnętrznych (numerowanych od 0 do 15), termistora (kanał 16) lub napięcia referencyjnego (kanał 17). Właśnie kanał 17 jest tym który nas interesuje:
1 |
ADC_RegularChannelConfig(ADC1, ADC_Channel_17, 1, ADC_SampleTime_71Cycles5); |
Ostatni parametr to liczba cykli przeznaczonych na próbkowanie wartości wejściowej. Ponieważ nie potrzebujemy wyników bardzo szybko wybieramy wartość 71.5 cyklu na pomiar (możliwe są wartości od 1.5 cyklu do 239.5).
Więcej informacji o działaniu modułu znajdziemy w dokumentacji
(Reference Manual, rozdział 11). Szczegóły o dokumentacji w 3 części kursu.
Włączenie przetwornika ADC i kalibracja
Nasz przetwornik jest już skonfigurowany. Pozostaje go włączyć:
1 |
ADC_Cmd(ADC1, ENABLE); |
Aby poprawić dokładność pomiarów powinniśmy wykonać autokalibrację przetwornika. Jest to czynność zalecana, chociaż niewymagana. Należy ją wykonać po uruchomieniu przetwornika, czyli dokładnie teraz. Kod wygląda następująco:
1 2 3 4 5 |
ADC_ResetCalibration(ADC1); while (ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1)); |
Nasz przetwornik jest już gotowy do pracy, włączmy więc napięcie referencyjne (1.2V) i możemy zaczynać pomiar:
1 2 |
ADC_TempSensorVrefintCmd(ENABLE); ADC_SoftwareStartConvCmd(ADC1, ENABLE); |
Przetwornik działa w trybie ciągłym, nie musimy więc ponownie startować pomiaru, ani czekać na jego zakończenie. Wystarczy odczytać wartość za pomocą funkcji: ADC_GetConversionValue.
Ponieważ chcemy sprawdzić, jakie otrzymujemy rezultaty, to nasz wynik wyślemy przez UART. W poprzednich częściach kursu omówiliśmy jak przekierować wyjście funkcji printf. Dzięki temu kod jest bardzo prosty:
1 2 |
uint16_t adc = ADC_GetConversionValue(ADC1); printf("Adc = %d (%.3fV)\n", adc, adc * 3.3f / 4096.0f); |
Cały program wygląda jak poniżej:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
#include <stdio.h> #include "stm32f10x.h" void send_char(char c) { while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); USART_SendData(USART2, c); } int __io_putchar(int c) { if (c=='\n') send_char('\r'); send_char(c); return c; } int main(void) { GPIO_InitTypeDef gpio; USART_InitTypeDef uart; ADC_InitTypeDef adc; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); GPIO_StructInit(&gpio); gpio.GPIO_Pin = GPIO_Pin_2; gpio.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &gpio); gpio.GPIO_Pin = GPIO_Pin_3; gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &gpio); USART_StructInit(&uart); uart.USART_BaudRate = 115200; USART_Init(USART2, &uart); USART_Cmd(USART2, ENABLE); ADC_StructInit(&adc); adc.ADC_ContinuousConvMode = ENABLE; adc.ADC_NbrOfChannel = 1; adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_Init(ADC1, &adc); ADC_RegularChannelConfig(ADC1, ADC_Channel_17, 1, ADC_SampleTime_71Cycles5); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while (ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1)); ADC_TempSensorVrefintCmd(ENABLE); ADC_SoftwareStartConvCmd(ADC1, ENABLE); while (1) { uint16_t adc = ADC_GetConversionValue(ADC1); printf("Adc = %d (%.3fV)\n", adc, adc * 3.3f / 4096.0f); } } |
Natomiast wyniki działania programu przedstawia poniższy zrzut ekranu:
Jak widać otrzymaliśmy, prawie, to co wychodziło z naszych obliczeń. Spodziewaliśmy się wyniku 1489, a otrzymaliśmy 1490-1491. Widzimy więc, że nasz program działa poprawnie. Warto zwrócić uwagę, że wynik jest nieco inny niż idealny, a ostatnia cyfra jak widać zmienia się w kolejnych pomiarach.
Zadanie domowe 6.1
Oblicz częstotliwość próbkowania, którą ustawiliśmy w pierwszym przykładzie (czyli częstotliwość z jaką są wykonywane pomiary). Niezbędne informacje są w dokumentacji (Reference Manual) mikrokontrolera.
STM32 - pomiar napięcia zewnętrznego
Pierwszy przykład dał nam możliwość upewnienia się, że umiemy obsługiwać przetwornik A/C. Jednak pomiar znanego napięcia referencyjnego nie jest zbyt pasjonujący. Spróbujmy więc zmierzyć napięcie podłączone z zewnątrz.
Elementy, wykorzystane w dalszej części artykułu:
Bez specjalnych zabezpieczeń możemy do wejścia przetwornika podłączyć tylko napięcia z zakresu Vss do Vdd, czyli od 0V do 3.3V. Każde napięcie spoza tego zakresu może uszkodzić mikrokontroler.
Do wejścia przetwornika analogowo-cyfrowego można podłączyć napięcie z zakresu 0V - 3.3V. Wyjście poza ten zakres może spowodować nieodwracalne uszkodzenie mikrokontrolera. Szczególnie należy uważać, jeśli w układzie wykorzystujemy dwa napięcia zasilania: 3.3V oraz 5V.
Aby temu zapobiec podłączymy potencjometr między masę, a zasilanie 3.3V – w takim układzie, kręcąc potencjometrem będziemy mogli regulować napięcie w pełnym, bezpiecznym zakresie.
Używając multimetru będziemy mogli również zweryfikować nasze wyniki. Podłączmy napięcie z potencjometru do pinu PA0. Jest to jednocześnie wejście kanału 0 przetwornika ADC1.
Zdjęcie złożonego układu:
Program będzie bardzo podobny do poprzedniego, omówmy więc tylko różnice. Pierwsza zmiana, to konieczność skonfigurowania pinu PA0 jako wejścia analogowego. W tym celu piszemy:
1 2 3 |
gpio.GPIO_Pin = GPIO_Pin_0; gpio.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &gpio); |
Jak widać poznaliśmy nowy tryb pracy pinu – wejście analogowe (Analog In). Poprzednio odczytywaliśmy dane z kanału 17, teraz interesuje nas kanał 0. Wybieramy go instrukcją:
1 |
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_71Cycles5); |
W tym przykładzie nie używamy już napięcia referencyjnego, nie musimy więc go podłączać (programowo). Jeśli jednak podłączymy, nic złego się nie stanie, ale zawsze możemy zaoszczędzić odrobinę prądu rezygnując z nieużywanego elementu.
Pozostały kod wygląda dokładnie tak samo jak w poprzednim przykładzie. Czas uruchomić program i obserwować odbierane dane zmieniając nastawy potencjometru. Warto również porównać wyniki ze zmierzonymi za pomocą multimetru.
Uwaga!
Na czas pomiaru multimetrem najlepiej jest odłączyć mikrokontroler - inaczej wyniki mogą być obarczone znacznym błędem.
Cały kod wygląda więc następująco:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
#include <stdio.h> #include <stdint.h> #include "stm32f10x.h" void send_char(char c) { while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); USART_SendData(USART2, c); } int __io_putchar(int c) { if (c=='\n') send_char('\r'); send_char(c); return c; } int main(void) { GPIO_InitTypeDef gpio; USART_InitTypeDef uart; ADC_InitTypeDef adc; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); GPIO_StructInit(&gpio); gpio.GPIO_Pin = GPIO_Pin_2; gpio.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &gpio); gpio.GPIO_Pin = GPIO_Pin_3; gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &gpio); USART_StructInit(&uart); uart.USART_BaudRate = 115200; USART_Init(USART2, &uart); USART_Cmd(USART2, ENABLE); gpio.GPIO_Pin = GPIO_Pin_0; gpio.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &gpio); ADC_StructInit(&adc); adc.ADC_ContinuousConvMode = ENABLE; adc.ADC_NbrOfChannel = 1; adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_Init(ADC1, &adc); ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_71Cycles5); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while (ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1)); ADC_SoftwareStartConvCmd(ADC1, ENABLE); while (1) { uint16_t adc = ADC_GetConversionValue(ADC1); float v = (float)adc * 3.3f / 4096.0f; printf("ADC = %d (%.3fV)\n", adc, v); } } |
Uruchomiony program prezentował następujące dane:
Pomiar uzyskany multimetrem w moim przypadku wynosił: 1.460 V, więc jak widać wskazania przesyłane z STM32 do komputera były zbliżone.
Czujnik oświetlenia
Czas na bardziej robotyczny przykład. Odłączmy potencjometr, a w jego miejsce podłączmy fotorezystor oraz rezystor tworząc dzielnik napięcia. Schemat montażowy widoczny jest poniżej:
Układ złożony w praktyce:
Teraz możemy zobaczyć jak zmieniają się odczyty naszego układu, w zależności od poziomu oświetlenia. Dokładnie w ten sposób możemy zbudować światłoluba, czyli prostego robota szukającego silniejszego źródła światła. Podobnie działają również czujniki odbiciowe, używane w robotach typu linefollower, czy micromouse.
Niestety jeden czujnik nie wystarczy do sterowania robota, potrzebujemy więc odczytu napięcia z większej ilości kanałów ADC.
Zadanie domowe 6.2
Napisz program do automatycznej lampki, która będzie zapalała diody święcące w zależności od poziomu zewnętrznego oświetlenia.
Zadanie domowe 6.3
Za pomocą funkcji ADC_RegularChannelConfig ustalamy czas pobierania próbek przez przetwornik. Spróbuj zmieniać ten czas, porównaj stabilność i wynik odczytów. Przeprowadź testy dla wartości z zakresu od ADC_SampleTime_1Cycles5 do ADC_SampleTime_239Cycles5.
STM32 - pomiar napięcia z kilku kanałów
Spróbujmy odczytać dane z więcej niż jednego czujnika. Na początek zmieniamy konfigurację naszego układu. Do pinów PA0 i PA1 podłączymy potencjometry, a w programie spróbujemy odczytywać wartości z obu wejść.
Układ złożony w praktyce:
Poprzednio uruchomiliśmy przetwornik w trybie ciągłym, a funkcją ADC_GetConversionValue pobieraliśmy odczytaną wartość. Takie działanie było wystarczające w przypadku jednego wejścia.
Jednak gdyby przetwornik ciągle odczytywał np. dwa wejścia, jak moglibyśmy pobrać dwie wartości? ADC_GetConversionValue zwraca wynik ostatniego pomiaru, jednak nie pozwala na wybór, które wejście chcemy odczytać.
Moglibyśmy wykorzystać tryb ciągły i np. w przerwaniach pobierać dane – jest to popularna metoda w przypadku mikrokontrolerów 8-bitowych, np. AVR. Wywołujemy ADC_GetConversionValue zaraz po zakończeniu konwersji i zapisujemy wynik w buforze. Ponieważ przerwanie jest zgłaszane zaraz po otrzymaniu kolejnego wyniku, możemy pobrać dane z obu czujników.
Takie rozwiązanie jest jednak bardzo nieefektywne - procesor "co chwilę" musi obsługiwać przerwania tylko po to, żeby buforować wyniki pomiarów.
W dalszej części kursu poznamy znacznie lepsze rozwiązanie z użyciem DMA.
Teraz wykorzystajmy jednak tryb pojedynczego odczytu - będziemy uruchamiać przetwornik i czekać na wynik. Ponieważ wykorzystujemy 2 wejścia, to musimy je odpowiednio skonfigurować:
1 2 3 |
gpio.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; gpio.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &gpio); |
Wyłączamy tryb ciągły, nie chcemy żeby przetwornik ciągle odczytywał dane:
1 |
adc.ADC_ContinuousConvMode = DISABLE; |
Ponieważ będziemy odczytywać dwa kanały, napiszemy funkcję, która skonfiguruje multiplekser wejściowy przetwornika, uruchomi pomiar, poczeka na zakończynie i odczyta wyniki. Oto jej treść:
1 2 3 4 5 6 7 8 9 |
int adc_read(int channel) { ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_71Cycles5); ADC_SoftwareStartConvCmd(ADC1, ENABLE); while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); return ADC_GetConversionValue(ADC1); } |
Pierwsza linia, to wybór kanału, a następna, to uruchomienie konwersji. W pętli while czekamy na koniec przetwarzania (EOC – End Of Conversion). Gdy dane są gotowe, odczytujemy je za pomocą ADC_GetConversionValue.
Mając tą funkcję możemy w pętli głównej programu odczytywać oba wejścia przetwornika:
1 2 3 4 5 6 7 |
uint16_t adc = adc_read(ADC_Channel_0); float v = (float)adc * 3.3f / 4096.0f; printf("ADC0 = %d (%.3fV) ", adc, v); adc = adc_read(ADC_Channel_1); v = (float)adc * 3.3f / 4096.0f; printf("ADC1 = %d (%.3fV)\n", adc, v); |
Cały kod programu wygląda następująco:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
#include <stdio.h> #include <stdint.h> #include "stm32f10x.h" void send_char(char c) { while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); USART_SendData(USART2, c); } int __io_putchar(int c) { if (c=='\n') send_char('\r'); send_char(c); return c; } int adc_read(int channel) { ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_13Cycles5); ADC_SoftwareStartConvCmd(ADC1, ENABLE); while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) != SET); return ADC_GetConversionValue(ADC1); } int main(void) { GPIO_InitTypeDef gpio; USART_InitTypeDef uart; ADC_InitTypeDef adc; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); GPIO_StructInit(&gpio); gpio.GPIO_Pin = GPIO_Pin_2; gpio.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &gpio); gpio.GPIO_Pin = GPIO_Pin_3; gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &gpio); USART_StructInit(&uart); uart.USART_BaudRate = 115200; USART_Init(USART2, &uart); USART_Cmd(USART2, ENABLE); gpio.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; gpio.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &gpio); ADC_StructInit(&adc); adc.ADC_ContinuousConvMode = DISABLE; adc.ADC_NbrOfChannel = 1; adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_Init(ADC1, &adc); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while (ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1)); while (1) { uint16_t adc = adc_read(ADC_Channel_0); float v = (float)adc * 3.3f / 4096.0f; printf("ADC0 = %d (%.3fV) ", adc, v); adc = adc_read(ADC_Channel_1); v = (float)adc * 3.3f / 4096.0f; printf("ADC1 = %d (%.3fV)\n", adc, v); } } |
Wynik działania programu widoczny jest na poniższym zrzucie ekranu. Przy okazji widać tutaj w praktyce, dlaczego programiści tak bardzo lubią printf:
Zadanie domowe 6.4
Podłącz więcej czujników i potencjometrów, np. dwa fotorezystory i dwa potencjometry. Napisz program, który wysyła wszystkie dane do komputera za pomocą UARTa.
Prawie światłolub
Czas zastąpić potencjometry fotorezystorami. Poprzednio wykorzystywaliśmy jeden, teraz możemy podłączyć dwa czujniki.
Układ złożony w praktyce:
Na początek wystarczy nam program który już mamy - za jego pomocą możemy sprawdzić jak nasz światłlub reaguje na zmiany oświetlenia. Jeśli odpowiednio ustawimy czujniki, będziemy mogli obserwować zmiany odczytów w zależności od kierunku, z którego oświetlimy nasz układ.
Napisanie programu, który na podstawie wartości odczytanych z czujników podejmie decyzję w którą stronę ma się poruszać robot jest już dosyć łatwe - i będzie to świetna praca domowa.
Zadanie domowe 6.5
Napisz program do sterowania światłolubem. Zamiast sterowania silnikami, wysyłaj na złącze szeregowe, co robot powinien robić, np. komendy "prosto", "w lewo", "w prawo".
Podsumowanie
Tym razem omówiliśmy podstawy wykorzystywania przetwornika ADC dostępnego w układach STM32. Na ten moment widoczne są dwie główne zalety (względem AVR) - duża liczba dostępnych kanałów oraz stosunkowo niski czas wykonania pomiaru. Jednak prawdziwa rewolucja dopiero przed nami, mowa oczywiście o DMA, które odmieni sposób korzystania z ADC!
Nawigacja kursu
W następnej części zajmiemy się jednym z trudniejszych tematów, czyli licznikami (timerami). Jeśli nie chcesz przeoczyć kolejnego odcinka, to skorzystaj z poniższego formularza i zapisz się na powiadomienia o nowych publikacjach!
Autor kursu: Piotr (Elvis) Bugalski
Redakcja: Damian (Treker) Szymański
Trwa ładowanie komentarzy...