Продолжаем работать с АЦП (ADC) контроллера STM32F1 с использованием библиотеки LL. Также работать мы пока будем с однократным преобразованием и с регулярным каналом, только отследить окончание процесса преобразования мы попробуем при помощи механизма прерываний от АЦП.
Думаю, что сделать это будет не сложно, в чём нам поможет библиотека LL.
Схему мы используем ту же самую, что и в прошлом уроке
Проект наш также сделан из проекта прошлого урока с именем LL_ADC_REG_ONCE и получил новое имя LL_ADC_REG_ONCE_INT.
Откроем наш проект в Cube MX и включим для ADC1 глобальные прерывания
Сгенерируем проект для Keil, откроем его, настроим автоперезагрузку после прошивки, отключим оптимизацию, подключим к дереву проекта файлы lcd.c и i2c_user.c, откроем main.c и посмотрим, что у нас изменилось в инициализации АЦП в результате разрешения глобальных прерываний. Для этого зайдём в тело функции MX_ADC1_Init и посмотрим изменения.
Мы видим вот такие строки, говорящие нам о том, что глобальные прерывания от ADC1 и ADC2 разрешены и им назначен самый высокий приоритет
1 2 3 |
/* ADC1 interrupt Init */ NVIC_SetPriority(ADC1_2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0)); NVIC_EnableIRQ(ADC1_2_IRQn); |
Больше в инициализации ничего не добавилось и не изменилось, поэтому вывод такой: локальные прерывания нам придётся настраивать самим и управлять их обработкой тоже самим.
Сначала добавим глобальную переменную для пользовательского флага, чтобы нам основную часть реакции на событие не организовывать в его обработчике
1 2 |
/* USER CODE BEGIN PV */ __IO uint8_t fl_adc; |
В main() перед включением ADC разрешим локальные прерывания по событию окончания преобразования
1 2 |
LCD_ini(); LL_ADC_EnableIT_EOS(ADC1); |
Если после этого мы попытаемся собрать код и прошить контроллер, то у нас в бесконечном цикле не выполнится ни одна итерация, так как мы обязаны флаг окончания преобразования ещё и сбросить.
Добавим свой обработчик прерывания, в котором установим наш пользовательский флаг
1 2 3 4 5 |
/* USER CODE BEGIN 4 */ void ADC_ConvCpltCallback(void) { fl_adc = 1; } |
В файле stm32f1xx_it.c добавим на данный обработчик прототип
1 2 |
/* USER CODE BEGIN PFP */ void ADC_ConvCpltCallback(void); |
А уже в обработчике, добавленным LL, ADC1_2_IRQHandler мы сбрасываем флаг EOS и вызываем наш пользовательский обработчик
1 2 3 4 5 6 |
/* USER CODE BEGIN ADC1_2_IRQn 0 */ if(LL_ADC_IsActiveFlag_EOS(ADC1) != 0) { LL_ADC_ClearFlag_EOS(ADC1); ADC_ConvCpltCallback(); } |
И, тем не менее, даже после этого у нас по-прежнему не будет выполняться ни одна итерация в бесконечном цикле, так как мы ждём там установки данного флага, а там мы её никогда не дождёмся.
Вернёмся в функцию main() файла main.c и добавим ещё одну строку на дисплей
1 2 3 |
LCD_String("Regular Once"); LCD_SetPos(0,2); LCD_String("Intrrupt"); |
Удалим вот эти строки в бесконечном цикле
while (!LL_ADC_IsActiveFlag_EOS(ADC1)) {}
LL_ADC_ClearFlag_EOS(ADC1);
а вместо них отследим установку нашего пользовательского флага, после чего его сбросим
1 2 3 |
LL_ADC_REG_StartConversionSWStart(ADC1); while (!fl_adc) {} fl_adc = 0; |
Вот теперь, если мы соберём код и прошьём наш микроконтроллер, у нас всё будет работать, как и прежде
Таким образом, в данном уроке нам удалось, вооружившись накопленными знаниями, запустить механизм обработки прерываний АЦП, в результате чего мы теперь можем отслеживать событие окончания преобразования в отдельном обработчике, не затрагивая ход основной программы. Хотя сейчас это у нас не особо заметно, так как процедуру перерасчёта в вольты сырого значения сигнала и вывод его на дисплей мы проделываем по-прежнему в основном коде, и также висим перед этим, дожидаясь пользовательского флага, ибо мы не можем столь не совсем короткие вещи поручить обработчику прерываний, тем не менее мы знаем, как данный обработчик организовать, что в будущем позволит нам более короткие процедуры обработки окончания преобразования вынести именно туда.
Всем спасибо за внимание!
Предыдущий урок Программирование МК STM32 Следующий урок
Отладочную плату STM32F103C8T6 можно приобрести здесь STM32F103C8T6
Программатор недорогой можно купить здесь ST-Link V2
Переходник I2C to LCD можно приобрести здесьI2C to LCD1602 2004
Логический анализатор 16 каналов можно приобрести здесь
Смотреть ВИДЕОУРОК (нажмите на картинку)
можно без ll
Только я разницы не почувствовал преобразование одиночное и безпрерывное в cmsis