Урок 19
HAL. ADC Injected Channel
Проект создаём из ADC_REGULAR_DMA, называем его ADC_INJECTED.
Запускаем Cube. Заходим в Configuration. Отключим там везде DMA.
Также отключим прерывания от АЦП, если таковые включены. Они нам пока не нужны. Это тема следующего урока.
Настраиваем там вот так
Генерируем и запускаем проект.
Как всегда настроим программатор и подключим файл lcd.h
Удалим все счётчики cnt отовсюду, включая SysTick
volatile uint32_t cnt1, cnt2;
/* USER CODE END PV */
/* USER CODE BEGIN 2 */
cnt1=0;cnt2=0;
sprintf(str,»%10u»,cnt1);//преобразуем результат в строку
LCD_SetPos(6,0);//покажем результат на ЖКИ-дисплее
LCD_String(str);
sprintf(str,»%10u»,cnt2);
LCD_SetPos(6,1);//покажем результат на ЖКИ-дисплее
LCD_String(str);
cnt1++;
// ADC_Data[0] = HAL_ADC_GetValue(hadc1);
/* USER CODE BEGIN 0 */
extern volatile uint32_t cnt2;
/* USER CODE END 0 */
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
cnt2++;
/* USER CODE END SysTick_IRQn 0 */
Уберем также старт АЦП с DMA
LCD_Clear();
HAL_ADC_Start_DMA(&hadc1,(uint32_t*) &ADC_Data,4);
/* USER CODE END 2 */
Уберем также цикл for из бесконечного цикла, содержимое цикла оставим
Все инжектоные функции теперь не на 108 странице, а на 126
Напишем в бесконечный цикл
while (1)
{
HAL_ADCEx_InjectedStart(&hadc1);//запустим аналого-цифровое преобразование
HAL_ADC_PollForConversion(&hadc1,100);//дождёмся окончания преобразований
u[0]=((float)HAL_ADCEx_InjectedGetValue(&hadc1,ADC_INJECTED_RANK_1))*3/4096;//занесём результат преобразований в переменную
u[1]=((float)HAL_ADCEx_InjectedGetValue(&hadc1,ADC_INJECTED_RANK_2))*3/4096;//занесём результат преобразований в переменную
u[2]=((float)HAL_ADCEx_InjectedGetValue(&hadc1,ADC_INJECTED_RANK_3))*3/4096;//занесём результат преобразований в переменную
u[3]=((float)HAL_ADCEx_InjectedGetValue(&hadc1,ADC_INJECTED_RANK_4))*3/4096;//занесём результат преобразований в переменную
Добавим в main() еще переменную для строки. А существующую немного увеличим. Счётчик-переменную i можно убрать
/* USER CODE BEGIN 1 */
float u[4];
char str[21];
char str1[9];
/* USER CODE END 1 */
Допишем в бесконечный цикл следующий код
u[2]=((float)HAL_ADCEx_InjectedGetValue(&hadc1,ADC_INJECTED_RANK_3))*3/4096;//занесём результат преобразований в переменную
u[3]=((float)HAL_ADCEx_InjectedGetValue(&hadc1,ADC_INJECTED_RANK_4))*3/4096;//занесём результат преобразований в переменную
sprintf(str,»%.2fv»,u[0]);//преобразуем результат в строку
sprintf(str1,»%.2fv»,u[1]);//преобразуем результат в строку
strcat(str,str1);
sprintf(str1,»%.2fv»,u[2]);//преобразуем результат в строку
strcat(str,str1);
sprintf(str1,»%.2fv»,u[3]);//преобразуем результат в строку
strcat(str,str1);
LCD_SetPos(0,3);//покажем результат на ЖКИ-дисплее
LCD_String(str);
HAL_ADCEx_InjectedStop(&hadc1);//остановим преобразования
HAL_Delay(200);//задержка перед следующим циклом
/* USER CODE END WHILE */
Но чтобы нам использовать функцию strcat, подключим библиотеку
/* USER CODE BEGIN Includes */
#include «main.h»
#include <string.h><string.h»></string.h»>
/* USER CODE END Includes */
Предыдущий урок Программирование МК STM32 Следующий урок
Отладочную плату можно приобрести здесь STM32F4-DISCOVERY
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)
Владимир, извините!
Во вложении не тот пример у ВАС, проверьте пожалуйста исходный код!
Да вроде ADC_INJECTED.
А где расхождения?
Да! И ещё во многих случаях SWD выключен, народ будет мучаться как я…
А я его принудительно и не включаю. Вроде всё прошивается и отлаживаетя. Вы имеете в виду в Cube в разделе SYS выбирать Serial Wire?
Да, именно это. Как то нарвался на то что камень не откликался после прошивки, вот и решил поделиться.
Спасибо!
У меня вообще обычно всегда откликается, но учту. Для Workbench обычно всегда включаю, а для Keil как-то нет.
Я сталкивался с таким на F103c8t6, если не включить его, то МК будет шиться сначало по SWD, но потом будет ждать и шиться только по JTAG. В таком случае его нужно вводить в BOOT mode и затерать. Хорошо, что это можно сделать через SWD.
Добрый вечер.
У меня отладочная плата Open746I-C.
Все Ваши уроки по работе с ADC работают, кроме двух:
STM Урок 20. HAL. ADC. Injected Channel.
STM Урок 20. HAL. ADC. Injected Channel. Interrupt.
ADC выдаёт не верные данные. Не могу понять в чём дело.
Периферия на разных версиях контроллеров может различаться, поэтому изучите внимательно ref manual на свой контроллер, а затем уже HAL and LL User Manual.
Хочу заметить, что вы используете HAL_ADC_PollForConversion(), что не есть корректно. Наверно правильней будет HAL_ADCEx_InjectedPollForConversion(). Хотя оба вроде работают.
Столкнулся вот с другим. Использую 2 канала, PA2, PA3. Соответственно 2 банка. Делаю как у Вас в уроке, и оно как бы работает, но как бы и нет. РА2 канал выводит данные, но не корректно, а РА3 вообще нули.
Работаю на дискаверки STM32L100rct6.
В той же документации к STM32L1_HAL_Driver, пишут мол функция по завершению преобразования не очищает флаг, и рекомендуют очищать его. 101я страница мануала. Если есть какие-то мысли по этому поводу, готов выслушать =)
Когда генерируете проект в кубе, проверяйте функцию MX_ADC_Init(), что там куб сгенерировал.
У меня к примеру не было вот такой строчки. Хотя в самом кубе количество диалогов АЦП выставлено 2. sConfigInjected.InjectedNbrOfConversion = 2;
Еще момент. Когда параллельно еще работаете с таймерами то, повторно вызывайте MX_ADC_Init(). Пока еще не нашел какой именно флаг он не включает, но в дебаге заметил, что данные в последнем бите этой функции, отличается.
Тестировал все на STM32L100RCT6, плата Discovery.