STM32 з нуля

Настав час розібратися, що являє собою модуль АЦП в мікроконтролерах STM32. Давайте за звичною схемою, насамперед теорія, під кінець невелика програма для роботи з аналого-цифровим перетворювачем.

Почнемо з…Ось деякі характеристики аналого-цифрового перетворювача в STM32f10x:

  • АЦП є 12-ти бітним
  • Можлива генерація переривання після закінчення перетворення, після закінчення перетворення з інжектованого каналу, а також можливе переривання від Analog Watchdog (що це таке розповім трохи нижче)
  • Можливе одиночне перетворення та перетворення в безперервному режимі
  • Самокалібрування
  • Запуск перетворення від зовнішньої події
  • Робота з ПДП (DMA, прямий доступ до пам'яті)

Ось структурна схема з даташиту, помилуйтесь)

Поки не забув про Analog Watchdog, напишу його роботу. Він потрібен для того, щоб стежити, що напруга потрапляє у певні межі. Причому може сканувати як конкретний канал, і групу каналів. У регістри ADC_HTR і ADC_LTR заносимо значення верхнього та нижнього порогу відповідно. І у випадку, якщо напруга, що перевіряється, виходить за ці межі, генерується переривання. Найкорисніша річ!

Канали АЦП поділяються на регулярні та інжектовані. Причому якщо запустити вимірювання інжектованих каналів, то вимірювання регулярних буде призупинено. У деяких ситуаціях теж дуже корисна фіча.

Як і в мікроконтролерах AVR можливе вирівнювання результату з правого або лівого краю. Тут справді результат 12-ти бітний. Але суть та сама. Ось як це виглядає в регістрах:

Цікава штука – переривання від зовнішньої події. Забігаючи наперед скажу, що таке неподобство ми влаштуємо внашій програмі, тож на практиці і розберемося, навіщо це потрібно і як працює.

Регістр ADC_SR. Статусний регістр. Тут зберігаються прапори – наприклад, прапор, який сигналізує про закінчення перетворення.

Регістр ADC_CR1. Контрольний регістр. Тут усілякі біти, що дозволяють або забороняють ті чи інші події. Наприклад, включення Analog Watchdog для регулярних каналів, аналогічно інжектованих, включення різних переривань – усе це сидить тут, у цьому регістрі.

Регістр ADC_CR2. Ще один контрольний регістр. А що ви хотіли? Багато режимів, потрібно більше контролю) Тут сховалися біти, відповідальні використання АЦП разом із 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. От і все! Мозковий штурм закінчено =) Переходимо до реалізації прикладу.

Не буду наводити повний код, includ'и та defin'и всякі, тільки суть:

Чудово! Програма готова. Але що ми взагалі вимірювати щось зібралися?! Звідки брати сигнал? А в цьому нам знову допоможе мова сценаріїв Keil'а. Створюємо в папці проекту(!) файл adc.ini та пишемо в нього:

Тобто емулюємо змінний з часом, але не безперервно, вхідний сигнал на нульовому каналі АЦП1.

Запускаємо відладчик. Заходимо до View -> Serial Windows -> ADC і вибираємо ADC1. Знаходимо регістр Data у вікні, тут ми і будемо відстежувати результат перетворення. Пишемо у командному рядку:

Запускаємо програму та після цього запускаємо функцію adc(). Докладніше про мову сценаріїв – у статті налагодження програми у Keil

Бачимо, як змінюються дані у регістрі даних. Програма працює правильно, тому можемо переходити до подальшого вивчення STM32. Далі буде…