Урок 31. Работа с АЦП через функции библиотеки HAL.

Работа с АЦП STM32

В уроке расскажу об использовании HAL-библиотеки для настройки конфигурации и управления модулем АЦП. В качестве примеров реализуем проекты из предыдущих уроков с применением HAL-функций. Разберемся, как настраивать АЦП с помощью конфигуратора STM32CubeMX.

Предыдущий урок     Список уроков     Следующий урок

В предыдущих уроках мы подробно разобрали все режимы работы АЦП, его функциональные возможности, управляющие регистры. Если вся эта информация уложилась у вас в голове, хотя бы на уровне принципов управления и возможностей АЦП, то работа с ним через HAL-функции не представит ни малейших затруднений. Имена функций и аргументов сами подскажут, как их использовать. А настройка конфигурации с помощью STM32CubeMX сведется к выбору закладок меню.

 

Я все время беспокоюсь, что мои уроки об использовании HAL-библиотеки будут похожи на большинство уроков из Интернета, построенных по принципу – сюда задаем то-то, здесь пишем то-то и “Вуаля!”. Они и получаются похожими, потому что смысл операций с АЦП я объяснял в предыдущих уроках. А в этом показываю более простой способ их реализации. Но этот материал не может быть полноценно воспринят без предыдущих уроков.

Давайте реализуем все проекты уроков 27-30 с использованием библиотеки HAL. Увидите насколько это просто.

Еще. В справочнике библиотеки HAL  появилось описание функций работы с АЦП. Я не буду в уроке описывать их форматы, смотрите в справочнике.

 

Настройка конфигурации АЦП с помощью STM32CubeMX.

Я подробно расскажу о задании конфигурации через CubeMX и одновременно настрою модуль АЦП на первый пример урока 27, а именно режим один канал, однократное преобразование.

Открываем STM32CubeMX.

Разрешаем работу генератора.

Мы будем использовать аналоговые входы IN0 … IN3. Выбираем их в поле Analog -> ADC1 -> Mode.

Настройка АЦП

Переходим в окно настройки тактирования. Задаем основную частоту тактирования 72 мГц.

Предделитель АЦП (ADC Prescaler) устанавливаем на коэффициент деления 6. Частота тактирования АЦП равна 12 мГц.

Настройка тактирования

Возвращаемся к окну конфигурации АЦП Configuration -> Parameter Settings.

В поле Mode выбираем Independent mode – независимый режим работы АЦП.

Настройка АЦП STM32

Поле Data Alignment задает режим выравнивания результата преобразования. Оставляем выравнивание по правому краю (Right alignment).

Следующие 3 поля разрешают или запрещают следующие режимы:

  • Scan Conversion Mode - режим сканирования каналов;
  • Continues Conversion Mode - режим непрерывного преобразования;
  • Discontinuous Conversion Mode - прерывистый режим.

Напомню таблицу основных режимов.

Состояние битов Режим
CONT SCAN
0 0 Один канал, однократное преобразование
0 1 Несколько каналов, однократное преобразование
1 0 Один канал, непрерывное преобразование
1 1 Несколько каналов, непрерывное преобразование

Для однократного преобразования одного канала запрещаем все поля.

Конфигурация АЦП STM32

Ниже две корневые закладки, ADC_Regular_ConversionMode и ADC_Injected_ConversionMode определяют конфигурацию аналоговых входов для регулярных и инжектированных групп.

В этом проекте мы собираемся использовать только один регулярный канал.

Открываем закладку для регулярной группы.

  • Enable Regular Conversions – разрешает преобразование регулярной группы.
  • Number Of Conversion – количество каналов сканирования. Сейчас задаем 1.
  • External Trigger Conversion Source – источник запуска преобразований. Выбираем программный запуск от бита SWSTART.
  • Rank – последовательность преобразования каналов. У нас в параметре Number Of Conversion задан только один кагал. Поэтому только одно поле Rank.

Открываем его и устанавливаем:

  • Channel – номер канала для этого преобразования.
  • Sampling Time – время выборки сигнала.

Настройка АЦП STM32

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

Разрешим работу UART в асинхронном режиме со скоростью 9600 бит/сек.

Конфигурация АЦП STM32

Создаем проект. У меня Lesson31_1.

Думаю, вы уже оценили простоту конфигурирования АЦП таким образом. Мы не просматривали бесконечные битовые поля регистров, боясь установить что-то не так или забыть про что-то.  Мы просто выбрали из того, что нам предложил конфигуратор CubeMX.

В принципе, можно настраивать конфигурацию АЦП с помощью CubeMX, а работать с АЦП через регистры CMSIS.

Давайте посмотрим и осознаем, что сделал конфигуратор. Это необходимо для понимания работы HAL-библиотеки. Возможно, нам в будущем потребуется изменять режимы АЦП динамически или захочется задать его конфигурацию без использования STM32CubeMX.

В файле stm32f1xx_hal_msp.c :

Разрешается тактирование АЦП1 и порта GPIOA.

__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();

Конфигурируются выводы GPIOA 0 … 3 как аналоговые входы.

GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

АЦП конфигурируется с помощью функции

HAL_ADC_Init (ADC_HandleTypeDef * hadc)

Функция имеет один аргумент – структуру параметров конфигурации типа ADC_HandleTypeDef. А  одним из элементов этой структуры является другая структура типа ADC_InitTypeDef. Она определяет основные параметры АЦП. Для конфигурации АЦП необходимо задать значения полей этих структур и вызвать функцию инициализации HAL_ADC_Init.

Разберемся на примере нашего проекта. Все происходит в файле main.c.

Создается экземпляр структуры типа ADC_HandleTypeDef с именем hadc1.

ADC_HandleTypeDef hadc1;

Поле Instance определяет базовый адрес АЦП, т.е. какой именно модуль АЦП будет использоваться.

hadc1.Instance = ADC1;

Дальше заданы поля структуры Init. Это параметры АЦП, которые мы устанавливали в STM32CubeMX.

hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;

И в завершение вызывается функция инициализации.

if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
  Error_Handler();
}

Для установки параметров каналов используется функция

HAL_ADC_ConfigChannel (ADC_HandleTypeDef * hadc, ADC_ChannelConfTypeDef * sConfig).

Создается экземпляр структуры типа ADC_ChannelConfTypeDef.

ADC_ChannelConfTypeDef sConfig = {0};

В нем выбирается канал, параметры которого в данный момент устанавливаются.

sConfig.Channel = ADC_CHANNEL_0;

Задаются параметры канала

sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5;

И вызывается функция конфигурации канала.

if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
  Error_Handler();
}

Если нужно настроить несколько каналов, то функция вызывается для каждого канала.

Добавим еще калибровку АЦП.

/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1);

На этом настройка конфигурации АЦП закончена.

Все эти операции сделал за нас конфигуратор CubeMX, но ничего не мешает выполнить их нам самим или изменить параметры в ходе выполнения программы.

Еще нам потребуется определение опорного напряжения АЦП, которое будем использовать при вычислениях измеренного напряжения.

/* USER CODE BEGIN PD */
#define VREF 3.3065 // напряжение ИОН

Мы собираемся выводить информацию на LCD-дисплей. Добавим в проект библиотеку для работы с ним из урока 25.

Скопируем в проект папку Libraries из проекта предыдущего урока. В ней содержатся библиотеки для работы с LCD-дисплеем.

В Atollic TrueStudio:

  • Подключаем библиотеки.

/* USER CODE BEGIN Includes */
#include "LCD780.h"
#include "DelayDWT.h"
/* USER CODE END Includes */

  • Правой кнопкой мыши нажимаем на папку LCD780 в проекте, Add/Remove Include Path -> OK.
  • Ту же операцию повторяем с папкой DelayDWT.
  • Правой кнопкой по Libraries, Properties -> C/C++ General -> Paths and Symbols -> Source Location -> Add Folder -> Apply.
  • Добавим блок инициализации дисплея.

// инициализация дисплея
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPAEN ;
initDelayDwt();
init_LCD(GPIOA, 1<<12, GPIOA, 1<<15, GPIOB, 1<<14, GPIOB, 1<<15, GPIOA, 1<<8, GPIOA, 1<<11, 16, 2, 1);

Все это мы делали в предыдущих уроках. Теперь можно работать с функциями библиотеки LCD-дисплея.

Мы создали шаблон проекта для урока. Дальше будем разрабатывать конкретные проекты.

 

Режим один канал, однократное преобразование.

Конфигурацию АЦП для режима однократного преобразования одного канала мы уже установили.

В основном цикле:

  • запускаем АЦП;
  • ждем окончания преобразования;
  • считываем результат;
  • пересчитываем его в напряжение;
  • выводим на LCD-дисплей;
  • передаем на компьютер через UART.
 Зарегистрируйтесь и оплатите. Всего 40 руб. в месяц за доступ ко всем ресурсам сайта! 
  • Для разрешения работы АЦП и запуска преобразования используется функция HAL_ADC_Start.
  • Функция HAL_ADC_PollForConversion ожидает окончание преобразования. Программа в ней "подвисает". Второй аргумент – время тайм-аута в мс.
  • Чтение результата преобразования регулярных каналов происходит с помощью функции HAL_ADC_GetValue.

Остальные операции цикла аналогичны действиям из проектов предыдущих уроков.

Проект можно загрузить по ссылке.

  Зарегистрируйтесь и оплатите. Всего 40 руб. в месяц за доступ ко всем ресурсам сайта!  

 

Один канал, однократное преобразование инжектированного канала.

Сделаем тоже самое для инжектированного канала. В этом случае используются другие HAL-функции.

Я копировал проект с именем Lesson31_2 и открыл в нем файл Lesson31_1.ioc.

Изменяем конфигурацию АЦП через CubeMX.

Запрещаем работу регулярной группы, устанавливаем параметры для инжектированной.

  • Число преобразований -1.
  • Запуск – программный.
  • Автозапуск – запрещен.
  • Очередь каналов – 1.
  • Канал – 0.
  • Время выборки – 28,5 циклов.
  • Смещение нуля – 0.

Настройка АЦП STM32

Создаем проект.

Добавился блок конфигурации инжектированных каналов.

sConfigInjected.InjectedChannel = ADC_CHANNEL_0;
sConfigInjected.InjectedRank = ADC_INJECTED_RANK_1;
sConfigInjected.InjectedNbrOfConversion = 1;
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_28CYCLES_5;
sConfigInjected.ExternalTrigInjecConv = ADC_INJECTED_SOFTWARE_START;
sConfigInjected.AutoInjectedConv = DISABLE;
sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
sConfigInjected.InjectedOffset = 0;
if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
{
  Error_Handler();
}

Для определения параметров используется структура sConfigInjected типа ADC_InjectionConfTypeDef.

Параметры расписаны в справочнике, хотя и без него все понятно.

Сама установка производится функцией HAL_ADCEx_InjectedConfigChannel.

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

У функции HAL_ADCEx_InjectedGetValue добавился еще один аргумент – номер инжектированного канала.

Основной цикл программы выглядит так.

 Зарегистрируйтесь и оплатите. Всего 40 руб. в месяц за доступ ко всем ресурсам сайта! 

Полностью проект можно загрузить по ссылке.

  Зарегистрируйтесь и оплатите. Всего 40 руб. в месяц за доступ ко всем ресурсам сайта!  

В обоих последних примерах функции ожидания завершения преобразования блокируют выполнение программы.

 

Один канал, непрерывное преобразование.

Вернемся к проекту Lesson31_1.

Единственное изменение, которое мы сделаем – разрешим непрерывное преобразование.

Это можно сделать в строке

hadc1.Init.ContinuousConvMode = ENABLE;

или с помощью CubeMX.

Конфигурация АЦП STM32

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

 Зарегистрируйтесь и оплатите. Всего 40 руб. в месяц за доступ ко всем ресурсам сайта! 

Здесь окончательный проект.

  Зарегистрируйтесь и оплатите. Всего 40 руб. в месяц за доступ ко всем ресурсам сайта!  

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

 

Непрерывное преобразование одного регулярного и одного инжектированного каналов.

Можно запустить непрерывное преобразование для регулярного и инжектированного канала одновременно. Тогда получим два регистра с постоянно обновляемыми значениями сигналов на двух аналоговых входах.

Напомню, что у инжектированных каналов нет режима непрерывных преобразований, но есть возможность установить режим их автоматического запуска после конверсии регулярной группы.

Открываем CubeMx.

  • Разрешаем работу и регулярной, и инжектированной групп на преобразование одного канала.
  • Для регулярной группы выбираем канал 0, для инжектированной - канал 1.
  • Разрешаем режим непрерывных преобразований (Continues Converson Mode).
  • Разрешаем режим автозапуска инжектированной группы (Injected Conversion Mode).

Настройка АЦП STM32

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

Вот, как выглядит основной цикл.

 Зарегистрируйтесь и оплатите. Всего 40 руб. в месяц за доступ ко всем ресурсам сайта! 

Здесь можно загрузить весь проект.

  Зарегистрируйтесь и оплатите. Всего 40 руб. в месяц за доступ ко всем ресурсам сайта!  

Чтение результатов также происходит в неблокирующем режиме.

 

Несколько каналов, однократное преобразование.

В этом примере по программному запуску будут происходить 5 преобразований: для одного регулярного канала и четырех инжектированных.

Настраиваем АЦП с помощью STM32CubeMX.

  • Разрешаем режим сканирования и настраиваем регулярную группу на 1 преобразование канала IN4.
  • Непрерывный режим запрещаем.

Настройка АЦП STM32

Для инжектированной группы устанавливаем 4 преобразования, разрешаем автозапуск и заполняем параметры очереди сканирования каналы 0…3.

Настройка АЦП STM32

В основном цикле:

  • Запускаем преобразование регулярной группы.

HAL_ADC_Start(&hadc1); // запуск преобразования

  • Ожиданием окончания сканирования всех каналов.

HAL_ADCEx_InjectedPollForConversion(&hadc1, 10); // ожидание окончания преобразования

  • Считываем результаты преобразований, вычисляем напряжение и выводим на дисплей.

Вот этот проект.

  Зарегистрируйтесь и оплатите. Всего 40 руб. в месяц за доступ ко всем ресурсам сайта!  

Работа с АЦП происходит в блокирующем режиме. При ожидании окончания преобразований программа зависает.

 

Несколько каналов, непрерывное преобразование.

Модифицируем предыдущий проект таким образом, что преобразования будут происходить в непрерывном режиме. В результате в пяти регистрах будут всегда храниться “свежие” значения сигналов на входах пяти каналов IN0 …  IN4.

В настройках АЦП одно изменение - разрешим непрерывный режим.

Конфигурация АЦП STM32

В программе:

  • Размещаем функцию запуска до основного цикла.
  • Функцию ожидания окончания преобразования убираем.
  • В цикле считываем значения измерений из регистров результатов и выводим данные на дисплей.
 Зарегистрируйтесь и оплатите. Всего 40 руб. в месяц за доступ ко всем ресурсам сайта! 

Полный проект можно загрузить по ссылке.

  Зарегистрируйтесь и оплатите. Всего 40 руб. в месяц за доступ ко всем ресурсам сайта!  

Еще раз подчеркну, что простота работы с АЦП через HAL-функции основана на понимании всех режимов и управляющих параметров АЦП, которым были посвящены предыдущие уроки.

 

В следующем уроке продолжим работу с АЦП через функции библиотеки HAL.

Предыдущий урок     Список уроков     Следующий урок

0

Автор публикации

не в сети 2 дня

Эдуард

201
Комментарии: 1687Публикации: 173Регистрация: 13-12-2015

2 комментария на «Урок 31. Работа с АЦП через функции библиотеки HAL.»

  1. Нашёл у Вас в 21-м уроке функцию HAL_TIM_PeriodElapsedCallback(). Подскажите, а в чём преимущества перед обычным обработчиком прерывания? И как определять какой таймер вызвал данную колбэк функцию, сравнивать в данной функции указатели?

    0
    • Здравствуйте!
      Вызов функции инициируется прерыванием. Преимущество — системный подход к программированию.
      Определить таймер можно так:
      if(htim1->Instance == TIM1)
      {
      // таймер 1

      }

      0

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

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

Нажимая кнопку "Отправить" Вы даёте свое согласие на обработку введенной персональной информации в соответствии с Федеральным Законом №152-ФЗ от 27.07.2006 "О персональных данных".