STM32 от нулата

Време е да разберем какъв е ADC модулът в микроконтролерите STM32. Нека следваме обичайната схема, първо теорията, накрая малка програма за работа с аналогово-цифров преобразувател.

Нека започнем с... Ето някои спецификации на A/D преобразувателя в STM32f10x:

  • ADC е 12 бита
  • Възможно е да се генерира прекъсване в края на преобразуването, в края на преобразуването от инжектирания канал, а също така е възможно да се прекъсне от Analog Watchdog (ще ви кажа какво е по-долу)
  • Възможно е единично преобразуване и непрекъснато преобразуване
  • Самокалибриране
  • Задействане на трансформация от външно събитие
  • Работа с DMA (DMA, директен достъп до паметта)

Ето блокова диаграма от листа с данни, възхищавам се)

Докато не забравих за Analog Watchdog, ще опиша работата му. Това е необходимо, за да се гарантира, че напрежението попада в определени граници. Освен това може да сканира както определен канал, така и група от канали. В регистрите ADC_HTR и ADC_LTR въвеждаме съответно стойностите на горния и долния праг. И ако тестваното напрежение надхвърли тези граници, се генерира прекъсване. Най-полезното нещо!

ADC каналите са разделени на обикновени и инжектирани. Освен това, ако започнете измерването на инжектирани канали, тогава измерването на обикновените ще бъде спряно. В някои ситуации това също е изключително полезна функция.

Както при AVR микроконтролерите, възможно е резултатът да се подравни надясно или наляво. Тук резултатът е истински 12-битов. Но същността е същата. Ето как изглежда всичко в регистрите:

Интересно нещо е прекъсване от външно събитие. Гледайки напред, ще кажа какъв позор ще организираменашата програма, така че на практика ще разберем защо е необходима и как работи.

Регистрирайте ADC_SR. регистър на състоянието. Тук се съхраняват флагове - например флаг, който сигнализира края на преобразуването.

Регистрирайте ADC_CR1. Контролен регистър. Има всякакви битове, които позволяват или забраняват определени събития. Например, включване на Analog Watchdog за обикновени канали, подобно на инжектирани, включване на различни прекъсвания - всичко това се намира тук в този регистър.

Регистрирайте ADC_CR2. Още един контролен регистър. Какво искаш? Много режими, необходим е повече контрол) Тук са скрити битове, които са отговорни за използването на ADC във връзка с DMA, както и за стартиране на преобразуването от външен източник. Освен това тук можете да активирате или деактивирате използването на температурния сензор. Важният бит е SWSTART, който стартира преобразуването на обикновените канали.

РегистритеADC_SMPRx отговарят за времето за вземане на проби. В ADC_SQR и ADC_JSQR избираме номерата на нужните ни канали. Регистрите за Analog Watchdog вече бяха споменати по-рано. Повече подробности в листа с данни)

И накрая, регистърът на данните -ADC_DR - там и само там ще вземем нашите ценни резултати, получени с голяма трудност.

Нека се заемем с практиката. Поставихме задачата, между другото, това е най-важното. Понякога е много по-трудно да си поставиш задача, отколкото да я решиш. Ще вземем данни на входа и ще ги прекараме през аналогово-цифров преобразувател. Банално, така че нека усложним малко нещата. Ще започнем трансформацията от външен източник, или по-скоро от таймер, или по-скоро от събитие, причинено от препълване на таймера =) Тук ще направим пример като този.

Отваряме файловете stm32f10x_adc.c и stm32f10x_adc.h и търсим нещо, което може да ни помогне. И много бърза структураADC_InitTypeDef намираме интересно поле uint32_t ADC_ExternalTrigConv. От какво имаш нужда! Но какво трябва да пише там? Продължете и намерете това парче:

Това не е нищо друго освен възможните стойности на полето ADC_ExternalTrigConv. Искаме например прекъсване при препълване на таймер 3, но по дяволите, няма такова нещо. Но има нещо мистериозно, наречено ADC_ExternalTrigConv_T3_TRGO. И това е такава функция - Trigger Output Mode. Тоест можем да изберем каквото ни трябва като външно събитие, но това вече е в настройките на таймера. Въпрос за боклук, нека отидем да изберем файла stm32f10x_tim.c и да намерим функцията TIM_SelectOutputTrigger (TIM_TypeDef * TIMx, uint16_t TIM_TRGOSource) там. В списъка с възможните му аргументи лесно можем да намерим необходимия - TIM_TRGOSource_Update. Това е всичко! Мозъчната атака приключи =) Да преминем към изпълнението на примера.

Няма да давам пълния код, всички видове включвания и дефиниции, само същността:

Страхотен! Програмата е готова. Но какво всъщност ще измерваме? Откъде взимате сигнала? И скриптовият език на Keil отново ще ни помогне с това. Създайте файл adc.ini в папката на проекта (!) и напишете в него:

Тоест, ние емулираме входния сигнал, променящ се във времето, но не непрекъснато, на нулевия канал на ADC1.

Стартираме дебъгера. Отидете на Изглед -> Сериен Windows -> ADC и изберете ADC1. Намираме регистъра на данните в прозореца, който се отваря, тук ще проследим резултата от преобразуването. Пишем на командния ред:

Стартирайте програмата и след това стартирайте функцията adc(). Прочетете повече за скриптовия език в статията за отстраняване на грешки в програма в Keil

Виждаме как се променят данните в регистъра на данните. Програмата работи правилно, така че можем да преминем към по-нататъшно изучаване на STM32. Следва продължение…