Продолжаем работать с АЦП (ADC) контроллера STM32F1 с использованием библиотеки LL. Также работать мы продолжим с инжектированной группой.
Только теперь мы можем уверенно сказать, что именно с группой, так как работать мы будем не с одним каналом, а с четырьмя, что является максимально возможным количеством каналов для инжектированной группы.
Чтобы работать с количеством каналов более одного в инжектированной группе, необходимо использовать режим SCAN, который сканирует сразу несколько каналов в заданной последовательности. Где именно задаётся последовательность эта, мы уже говорили. Также режим SCAN мы уже использовали с регулярной группой в уроках 189-191.
Использовать мы будем также однократное преобразование, то есть запускать мы будем каждый раз сканирование наших каналов принудительно.
Схема урока остаётся прежней, причём использовать мы теперь, как вы поняли, её будем полностью — все 4 делителя
Проект для нашего урока мы сделаем из проекта урока 192 с именем LL_ADC_INJ_ONCE и присвоим ему теперь имя LL_ADC_INJ_ONCE_SCAN.
Запустим наш проект в Cube MX и включим следующие 3 канала ADC1
Мы видим, что теперь у нас для ADC задействованы ещё 3 ножки порта
Настроим также количество сканируемых каналов
Засчёт этого у нас включился автоматически режим сканирования последовательности каналов
Также настроим добавившиеся 3 позиции последовательности каналов, выбрав для них требуемый интервал между выборками и нужный канал
Хотя, в принципе, все наши настройки ничего нам сейчас не дадут, так как мы не пользуемся сгенерированной автоматически инициализации. Но будем всё же надеяться на то, что когда-то это недоразумение поправят и мы впоследствии всё же воспользуемся автоматикой и удалим из функции main() нашу самостоятельную инициализацию.
Сгенерируем проект, откроем его в Keil, настроим программатор на автоперезагрузку, отключим оптимизацию и добавим к дереву проектов файлы lcd.c и i2c_user.c. и в функции main() файла main.c сделаем наши локальные переменные четырёхэлементными массивами, а строковый массив немного увеличим
__IO uint16_t ADC_Data[4];
__IO uint16_t ADC_mVolt[4];
char str01[20];
Установим длину последовательности для сканирования
1 2 3 |
LL_ADC_INJ_SetTriggerSource(ADC1, LL_ADC_INJ_TRIG_SOFTWARE); //Set ADC group injected sequencer length and scan direction LL_ADC_INJ_SetSequencerLength(ADC1, LL_ADC_INJ_SEQ_SCAN_ENABLE_4RANKS); |
Тем самым мы в битовом поле JL регистра JSQR установим оба бита.
Включим режим SCAN. Эта настройка работает как для регулярной, так и для инжекторной групп
1 2 3 |
LL_ADC_INJ_SetSequencerLength(ADC1, LL_ADC_INJ_SEQ_SCAN_ENABLE_4RANKS); //Set ADC sequencers scan mode, for all ADC groups LL_ADC_SetSequencersScanMode(ADC1, LL_ADC_SEQ_SCAN_ENABLE); |
Аналогично первому, настроим остальные три канала
1 2 3 4 5 6 7 8 9 10 |
LL_ADC_INJ_SetOffset(ADC1, LL_ADC_INJ_RANK_1, 0); LL_ADC_INJ_SetSequencerRanks(ADC1, LL_ADC_INJ_RANK_2, LL_ADC_CHANNEL_2); LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_2, LL_ADC_SAMPLINGTIME_7CYCLES_5); LL_ADC_INJ_SetOffset(ADC1, LL_ADC_INJ_RANK_2, 0); LL_ADC_INJ_SetSequencerRanks(ADC1, LL_ADC_INJ_RANK_3, LL_ADC_CHANNEL_3); LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_3, LL_ADC_SAMPLINGTIME_7CYCLES_5); LL_ADC_INJ_SetOffset(ADC1, LL_ADC_INJ_RANK_3, 0); LL_ADC_INJ_SetSequencerRanks(ADC1, LL_ADC_INJ_RANK_4, LL_ADC_CHANNEL_4); LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_4, LL_ADC_SAMPLINGTIME_7CYCLES_5); LL_ADC_INJ_SetOffset(ADC1, LL_ADC_INJ_RANK_4, 0); |
Выведем ещё одну строку на дисплей
1 2 3 |
LCD_String("Jnjected Once"); LCD_SetPos(0,2); LCD_String("Scan"); |
В бесконечном цикле вместо переменной используем нулевой элемент массива для считывания данных из регистра первого канала
ADC_Data[0] = LL_ADC_INJ_ReadConversionData12(ADC1, LL_ADC_INJ_RANK_1);
Считаем остальные регистры в соответствующие элементы массива
1 2 3 4 |
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); |
Преобразование и вывод в вольты наших показателей пока удалим
ADC_mVolt = __LL_ADC_CALC_DATA_TO_VOLTAGE((uint32_t)3275, ADC_Data, LL_ADC_RESOLUTION_12B);
sprintf(str01,«%.2fv»,(float)ADC_mVolt/1000.);
Вместо этого применим цикл, в котором преобразуем показания сигнала всех каналов и затем выведем их на дисплей
1 2 3 4 5 6 7 |
ADC_Data[3] = LL_ADC_INJ_ReadConversionData12(ADC1, LL_ADC_INJ_RANK_4); for(uint8_t i=0; i<4; i++) { ADC_mVolt[i] = __LL_ADC_CALC_DATA_TO_VOLTAGE((uint32_t)3275, ADC_Data[i], LL_ADC_RESOLUTION_12B); } sprintf(str01,"%.2f %.2f %.2f %.2f ", (float)ADC_mVolt[0]/1000., (float)ADC_mVolt[1]/1000., (float)ADC_mVolt[2]/1000., (float)ADC_mVolt[3]/1000.); |
Соберём код, прошьём контроллер и посмотрим, как у нас теперь всё будет работать
Всё работает отлично, показания оперативно снимаются со всех каналов.
Итак, на данном уроке мы научились работать с режимом последовательного сканирования каналов инжекторной группы, применяя при этом также режим однократного преобразования сигнала.
Всем спасибо за внимание!
Предыдущий урок Программирование МК STM32 Следующий урок
Отладочную плату STM32F103C8T6 можно приобрести здесь STM32F103C8T6
Программатор недорогой можно купить здесь ST-Link V2
Переходник I2C to LCD можно приобрести здесьI2C to LCD1602 2004
Логический анализатор 16 каналов можно приобрести здесь
Смотреть ВИДЕОУРОК (нажмите на картинку)
На исходный код ссылка битая!
Исправьте?
Николай:
Поправил, спасибо!