STM Урок 189. LL. STM32F1. ADC. Regular Once. DMA

 

 

 

Продолжаем работать с АЦП (ADC) контроллера STM32F1 с использованием библиотеки LL. Также работать мы пока будем с регулярным каналом.

Только теперь мы, используя регулярный канал с однократным преобразованием, попробуем привлечь к процедуре опроса АЦП и конверсии периферию DMA, что позволит нам делать очень интересные вещи.

Также теперь мы будем использовать режим SCAN, который сканирует сразу несколько каналов в заданной последовательности. Где именно задаётся последовательность эта, мы уже говорили. Тем не менее мы в процедуре инициализации всё это увидим.

Схема наша немного теперь изменится, потому что использовать мы будем сразу 4 канала, поэтому мы повесим 4 резистора, регулируемые ножки которых мы соединим с входами наших каналов, получив тем самым 4 примитивных независимых регулируемых источника напряжения.

Я образно набросал фрагмент нашей схемы, выбрав не совсем такой, но подобный контроллер

 

 

А живьём наша схема имеет следующий вид:

 

 

Проект нашего урока мы сделаем из проекта урока 185 с именем LL_ADC_REG_ONCE и назовём его LL_ADC_REG_DMA.

Откроем наш проект в Cube MX и в свойствах ADC1 включим ещё 3 канала

 

 

Соответственно, у нас включатся также и 3 ножки порта

 

 

Включаем также последовательное преобразование. Только его просто так не включишь, для этого нужно выставить число преобразований – 4 и Scan Conversion Mode включится сам

 

 

Добавим времени на преобразование и выберем соответствующие каналы в последовательность

 

 

Включим также в соответствующей закладке настроек ADC1 канал DMA, в настройках которого оставляем всё по умолчанию

 

 

Также не забываем в настройках проекта задействовать на периферию DMA библиотеку LL

 

 

Сгенерируем проект, откроем его в Keil, настроим программатор на автоперезагрузку, отключим оптимизацию и добавим к дереву проектов файлы lcd.c и i2c_user.c.

В файле main.c в функции MX_ADC1_Init посмотрим, какие изменения теперь у нас произошли теперь в инициализации ADC. Причём практически все настройки DMA у нас находятся здесь. В функции инициализации DMA у нас будут только включение тактирования периферии DMA, включение глобальных прерываний и настройка приоритета. Мало того, в функции инициализации ADC всё начинается с настройки именно DMA после настройки ножке, а уж затем настраивается непосредственно ADC.

Настройки DMA тут, в принципе, стандартные, мы не будем их подробно рассматривать

 

 

Причём настройки здесь не все, часть инициализации DMA (изменение приоритета, включение другого режима, настройку адресов) нам придётся проделать затем отдельно.

Далее нам интересна вот эта настройка, с помощью которой включится бит SCAN в регистре CR1

 

 

Изменения нас ждут также здесь

 

 

Здесь включатся биты L1 и L0 в регистре SQR1, которые будут означать, что сканироваться будут именно 4 канала ADC.

При помощи следующей строки кода инициализации у нас включится бит DMA в регистре CR2

 

 

А далее стандартная настройка четырёх каналов ADC

 

 

В результате данной настройки в битовых полях SMP3:SMP0 регистра SMPR2 выставятся биты 1.

Вот и все изменения.

Добавим глобальный 4-элементный массив для хранения данных, считанных из ADC, а также заведём флаг

 

 

 

В функции main() удалим, соответственно теперь вот эту локальную переменную

 

__IO uint16_t ADC_Data;

 

Другую переменную того же типа превратим теперь в массив, а в символьный массив добавим ещё элементов

 

__IO uint16_t ADC_mVolt[4];

char str01[20];

 

Удалим инициализацию переменной

 

ADC_Data = 0;

 

Внесём изменения в настройки DMA, а также настроим там адреса приёмника и источника

 

 

Здесь возникает резонный вопрос, а почему бы данные настройки сразу не включить в Cube? Оказывается, не получится. Ничего не будет работать и всё повиснет, видимо, здесь важен какой-то порядок и слишком высокий приоритет не даст настроить ADC.

Настроим также длину пакета DMA, включим локальные прерывания по событию окончания приёма-передачи и по событию ошибки и включим канал

 

 

Здесь немного допишем

 

LCD_String("Regular Once DMA");

 

Выведем ещё одну строку на дисплей

 

 

Добавим также функцию для обработки прерывания от DMA, в которой взведём наш пользовательский флаг

 

 

В файле stm32f1xx_it.c добавим прототип на данную функцию

 

 

Затем в обработчике прерываний от DMA DMA1_Channel1_IRQHandler в случае установленного флага окончания передачи вызовем нашу функцию, а в случае ошибки только сбросим флаг

 

 

Вернёмся в функцию main() файла main.c и в бесконечном цикле удалим ожидание и сброс флага окончания преобразования, а также считывание показаний

 

while (!LL_ADC_IsActiveFlag_EOS(ADC1)) {}

LL_ADC_ClearFlag_EOS(ADC1);

ADC_Data = LL_ADC_REG_ReadConversionData12(ADC1);

 

Дождёмся здесь установки своего флага и сбросим его

 

 

Удалим следующую строку

 

ADC_mVolt = __LL_ADC_CALC_DATA_TO_VOLTAGE((uint32_t)3275, ADC_Data, LL_ADC_RESOLUTION_12B);

 

Вместо этого считаем и преобразуем в вольты весь наш массив

 

 

Удалим следующую строку

 

sprintf(str01,"%.2fv",(float)ADC_mVolt/1000.);

 

А вместо этого выведем на дисплей показатели всех наших каналов ADC

 

 

Проверим работу нашего кода на практической схеме, собрав код и прошив контроллер, а также изменяя положения движков наших подстроечных резисторов

 

 

 

Всё работает отлично!

Таким образом, на данном уроке мы научились пользоваться режимом последовательного преобразования каналов с применением периферии DMA, что позволило нам получить четыре независимых измерителя напряжения сигнала на одном ADC. Практически, можно и больше, но для урока, думаю, и этого достаточно.

Всем спасибо за внимание!

 

Предыдущий урок Программирование МК STM32 Следующий урок

 

Исходный код

 

 

Отладочную плату STM32F103C8T6 можно приобрести здесь STM32F103C8T6

Программатор недорогой можно купить здесь ST-Link V2

Дисплей LCD 16×2

Переходник I2C to LCD можно приобрести здесьI2C to LCD1602 2004

Логический анализатор 16 каналов можно приобрести здесь

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

STM LL. STM32F1. ADC. Regular Once. DMA

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*