Обработка в суперцикле

STM32 и CubeIDE: кнопки и прерывания

Этот способ можно назвать «в лоб». Суперцикл программы микроконтроллера — это цикл while (хотя может быть и другой), который бесконечное число раз выполняет команды в своём теле. Почему плохо детектировать нажатие кнопок или любые другие импульсные сигналы в этом цикле?

Потому что при таком подходе:

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

Гораздо правильнее делать это с помощью прерываний, о чем мы поговорим позже. А пока, ради знакомства с функцией чтения входных GPIO сигналов сделаем таки «в лоб».

Настройка контактов на вход

Так же, как и в предыдущем уроке, откроем среду STM32CubeIDE и создадим новый проект. Выберем для кнопок два контакта: PB0 и PB1. Жмем на них левую кнопку мыши и выбираем режим GPIO_Input.

Обычно, при подключении кнопок следует соединить задействованный контакт микроконтроллера с землёй через резистор (в уроке для Ардуино мы так и делали). Это называется подтяжкой. Без подтяжки, контакт будет находиться в неопределенном состоянии, что приведет к спонтанному ложному срабатыванию кнопок.

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

На вкладке настройки GPIO, в поле GPIO Pull up/Pull down установим значение Pull down (подтяжка к земле). А заодно назначим псевдонимы BTN1 и BTN2 этим контактам.

Настройка встроенного индикатора

Чтобы проверить работу кнопок нам понадобится какой-нибудь индикатор. В отличие от предыдущего урока, мы не будем подключать внешний светодиод, а используем встроенный — на контакте PC13.

Правда, надо учесть, что этот встроенный светодиод включен по обратной схеме. Его катод подключен к PC13, а анод к питанию +3.3В (с резистором, конечно). Учтём это позже, при составлении программы. А пока отметим PC13 в конфигураторе как GPIO_Output.

Плюс, как и прежде назначим псевдоним LED.

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

Программа

Для чтения сигнала на контакте используем функцию из библиотеки HAL:

HAL_GPIO_ReadPin(порт, контакт)

Здесь порт — идентификатор порта, контакт — индекс контакта в порту. Поскольку мы создали псевдонимы для ножек, используем в качестве аргументов соответствующие константы: BTN1_GPIO_PORT и BTN1_Pin. В общем, всё как у известной нам функции HAL_GPIO_WritePin.

Если в момент вызова этой функции на контакте будет высокий уровень сигнала, то функция вернет истину (ну или 1). В противном случае — вернет ложь (эквивалентно нулю).

Программа будет в суперцикле постоянно опрашивать то одну, то другую кнопку и в зависимости от наличия сигнала на соответствующих контактах гасить или зажигать светодиод.

/* USER CODE BEGIN WHILE */
while (1)
{
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
  if( HAL_GPIO_ReadPin(BTN1_GPIO_Port, BTN1_Pin) ){
    // гасим светодиод
    HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
  }
  if( HAL_GPIO_ReadPin(BTN1_GPIO_Port, BTN2_Pin) ){
    // зажигаем светодиод
    HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
  }
}
  /* USER CODE END 3 */

Почему в этом коде GPIO_PIN_SET — гасит, а GPIO_PIN_RESET — зажигает? Как-будто неправильно, в предыдущем уроке было иначе. А потому, что логика светодиода на ножке PC13 инверсная! Помните?

Загружаем программу на плату. Сразу после запуска светодиод будет гореть, так как изначально на ножках микроконтроллера низкий уровень. Нажимаем первую кнопку — светодиод гаснет. Нажимаем вторую — загорается. Работает!


Изменено: