Продолжаем работать с АЦП (ADC) контроллера STM32F1 с использованием библиотеки LL. Также работать мы продолжим с инжектированной группой каналов и использовать будем режим сканирования последовательности каналов инжектированной группы. Запускать мы будем также наш АЦП на данном уроке автоматически, хотя вернёмся мы в режим однократного преобразования. Как же такое возможно и для чего это нужно?
В режиме кольцевого запуска (continuous) АЦП не может запускаться реже чем через 252 цикла (12,5 + 239,5). Порой бывает нужно запускать АЦП автоматически гораздо реже. Для этого существует у контроллера STM32F1 а АЦП запуск от таймера. Причём запустить наш АЦП мы можем, используя различные события таймера, такие как захват, сравнение и переполнение счётчика.
По таймеру мы ADC уже запускали в других уроках, поэтому справимся и сейчас.
Схема также осталась прежней
Проект был сделан из проекта урока 196 с именем LL_ADC_INJ_ONCE_SCAN и назван LL_ADC_INJ_ONCE_SCAN_TIM.
Откроем проект в Cobe MX и включим глобальные прерывания в ADC1
Включим таймер 4
Настроим его на период в 1 милисекунду и выберем событие обновления
В свойствах ADC1 выберем срабатывание от данного таймера
Также не забываем выбрать библиотеку LL здесь
Сгенерируем проект и откроем его в Keil, настроим автоперезагрузку после прошивки, отключим оптимизацию, подключим к дереву проекта файлы lcd.c и i2c_user.c, откроем main.c и добавим глобальный массив для хранения сырых значений регистров каналов АЦП
1 2 |
/* USER CODE BEGIN PV */ __IO uint16_t ADC_Data[4]; |
В функции main() объявление подобного массива удалим
__IO uint32_t wait_loop_index = 0;
__IO uint16_t ADC_Data[4];
Здесь изменим триггер на таймерный
LL_ADC_INJ_SetTriggerSource(ADC1, LL_ADC_INJ_TRIG_EXT_TIM4_TRGO);
Включим локальные прерывания по событию окончания преобразования
1 2 |
LCD_ini(); LL_ADC_EnableIT_JEOS(ADC1); |
Включим бит JEXTTRIG в регистре CR2 при помощи специальной функции
1 2 |
LL_ADC_EnableIT_JEOS(ADC1); LL_ADC_INJ_StartConversionExtTrig(ADC1,LL_ADC_INJ_TRIG_EXT_RISING); |
Надпись в нижнюю строку на дисплее перенесём в верхнюю
LCD_String("Jnjected Once Scan");
А нижняя строка теперь будет с такой надписью
LCD_String("Timer Ext Trigger");
Запустим таймер и немного подождём
1 2 3 |
LCD_String("Timer Ext Trigger"); LL_TIM_EnableCounter(TIM4); LL_mDelay(100); |
Добавим функцию, которую будем вызвать из обработчика прерываний от АЦП, в которой считаем значения из регистров каналов АЦП в элементы массива
1 2 3 4 5 6 7 8 |
/* USER CODE BEGIN 4 */ void ADC_ConvCpltCallback(void) { ADC_Data[0] = LL_ADC_INJ_ReadConversionData12(ADC1, LL_ADC_INJ_RANK_1); ADC_Data[1] = LL_ADC_INJ_ReadConversionData12(ADC1, LL_ADC_INJ_RANK_2); ADC_Data[2] = LL_ADC_INJ_ReadConversionData12(ADC1, LL_ADC_INJ_RANK_3); ADC_Data[3] = LL_ADC_INJ_ReadConversionData12(ADC1, LL_ADC_INJ_RANK_4); } |
В файле stm32f1xx_it.c добавим для данной функции прототип
1 2 |
/* USER CODE BEGIN PFP */ void ADC_ConvCpltCallback(void); |
Вызовем данную функцию и сбросим флаг в функции-обработчике ADC1_2_IRQHandler
1 2 3 4 5 6 7 8 |
void ADC1_2_IRQHandler(void) { /* USER CODE BEGIN ADC1_2_IRQn 0 */ if(LL_ADC_IsActiveFlag_JEOS(ADC1) != 0) { LL_ADC_ClearFlag_JEOS(ADC1); ADC_ConvCpltCallback(); } |
В функции main() файла main.c в бесконечном цикле вот это всё мы можем вполне удалить
LL_ADC_INJ_StartConversionSWStart(ADC1);
while (!LL_ADC_IsActiveFlag_JEOS(ADC1)) {}
LL_ADC_ClearFlag_JEOS(ADC1);
ADC_Data[0] = LL_ADC_INJ_ReadConversionData12(ADC1, LL_ADC_INJ_RANK_1);
ADC_Data[1] = LL_ADC_INJ_ReadConversionData12(ADC1, LL_ADC_INJ_RANK_2);
ADC_Data[2] = LL_ADC_INJ_ReadConversionData12(ADC1, LL_ADC_INJ_RANK_3);
ADC_Data[3] = LL_ADC_INJ_ReadConversionData12(ADC1, LL_ADC_INJ_RANK_4);
Соберём код, прошьём контроллер и посмотрим, как работает наш код
Всё отлично работает!
Таким образом, на данном занятии мы научились запускать преобразование инжектированной группы каналов АЦП контроллера STM32F1 от таймера, что позволило нам теперь более гибко и более в широких пределах настраивать период автоматического запуска преобразования.
Всем спасибо за внимание!
Предыдущий урок Программирование МК STM32 Следующий урок
Отладочную плату STM32F103C8T6 можно приобрести здесь STM32F103C8T6
Программатор недорогой можно купить здесь ST-Link V2
Переходник I2C to LCD можно приобрести здесьI2C to LCD1602 2004
Логический анализатор 16 каналов можно приобрести здесь
Смотреть ВИДЕОУРОК (нажмите на картинку)
Добавить комментарий