Кнопки в STM32

Рассмотрим как работают кнопки в STM32 расположенных на отладочной плате STM32F407VET6. На плате находится три кнопки WK_UP, KEY0, KEY1.

Кнопки в STM32

Подключение кнопки к STM32

Подключение кнопки к STM32 можно реализовать 2 способами:

  • Кнопка подключается через резистор к питанию на 3.3В.
  • При втором способе подключения, кнопка соединяется с землей. Это значит, что при нажатии на кнопку на порту, к которому кнопка подключена, будет низкий уровень сигнала.

Нажатие кнопки STM32

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

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

Обработка кнопок STM32

Вся настройка выводов и прерываний микроконтроллера будет производится с помощью CubeMX. Так же будем использовать библиотеку HAL для обработки нажатия кнопок.

Обработать нажатие кнопки в STM32 можно несколькими способами:

  • Просто проверять в бесконечном цикле состояние порта, на котором подключена кнопка. Данный способ самый примитивный и на мой взгляд годится для того что бы продемонстрировать работу кнопок. При таком способе не обрабатывается дребезг кнопки (многократное срабатывание при нажатии за короткий промежуток времени). Так же можно пропустить нажатие, так как исполняемая программа обычно не мальнькая, и в момент нажатия кнопки может выполнятся другое действие.
  • Второй способ это использовать прерывания от кнопки.
  • Третий способ включает второй, это использовать проверенную библиотеку для работы с кнопками в STM32.

Обработка кнопок проверкой состояния порта

Этот способ прост в применении. Нам необходимо только проверить состояние порта на 0 или 1 (смотря как подключена кнопка).

Для начала настроим порт с кнопкой на нужный режим работы:

Настройка порта A0

Так же добавим порт PE4 и порт PA6 на котором светодиод. В CubeMx настраиваем порты согласно рисунку ниже.

Настройка кнопок в STM32

Если кнопка подключена через резистор к питанию, то на порту необходимо установить внутреннюю подтяжку Pull-down. Если кнопка подключена к земле, то устанавливаем подтяжку Pull-Up. Таким образом мы установим значение порта, если кнопка не нажата. Пример кода смотрите ниже:

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdbool.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
bool btnClick = false;      // глобальная переменная, флаг нажатия кнопки
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define ReadKey HAL_GPIO_ReadPin(GPIOE, Button_Pin)
#define ReadKey_WK_UP HAL_GPIO_ReadPin(GPIOA, WK_UP_Pin)
/* USER CODE END PD */

void main()
{
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
while (1)
    {
      if  (ReadKey == 0)
      {
          btnClick = true;  // отмечаем что кнопка нажата
      }
      if (ReadKey_WK_UP == 1)
      {
          btnClick = true;  // отмечаем что кнопка нажата
      }
         // если кнопка была нажата, меняем ее состояние на противоположное и сбрасываем флаг нажатия
      if (btnClick)
      {
          HAL_GPIO_TogglePin(GPIOA, Led_Pin);
          btnClick = false;
      }
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
}

Обработка кнопок с помощью прерываний

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

В CubeMX открываем Clock Configuration и сморим какая частота тактирования у таймеров.

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

В нашем случае это 84 МГц. Настроим 6 таймер на 1 мс, для этого в Prescaler запишем число 8399, а в Counter Period запишем число 10. Эти значения вытекают из формулы:

F = 84 МГц / (8399 + 1) = 10 кГц,

10 кГц это 100 мкс, по этому в счетчик периода мы записываем 10, 100 мкс*10=1000 мкс или 1 мс.

Настройка таймера STM32

Поставьте галочку в разделе NVIC Settings. Это действие разрешит использование прерывания от таймера.

Так же необходим в разделе Project Manager -> Advenced Settings, разрешить использование функции Callback от таймеров:

Теперь в функции Callback от таймера делаем что нам нужно:

/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if (htim->Instance == htim6.Instance)
  {
     if  (ReadKey == 0)
      {
          btnClick = true;  // отмечаем что кнопка нажата
      }
      if (ReadKey_WK_UP == 1)
      {
          btnClick = true;  // отмечаем что кнопка нажата
      }
         // если кнопка была нажата, меняем ее состояние на противоположное и сбрасываем флаг нажатия
      if (btnClick)
      {
          HAL_GPIO_TogglePin(GPIOA, Led_Pin);
          btnClick = false;
      }
  }
}
/* USER CODE END 4 */

Не забудьте запустить работу прерывания вызвав функцию: HAL_TIM_Base_Start_IT(&htim6).

Библиотека для работы с кнопками в STM32

Здесь рассмотрим библиотеку банальным названием Button, ссылка на скачивание в конце статьи в разделе «Загрузки». Библиотека содержит два файла: Button.с и Button.h.

Перед использованием библиотеки необходимо настроить таймер на срабатывание один раз в 1 мс по примеру из раздела выше. Также необходимо прописать нашу кнопку в файле библиотеки, для этого В файле button.h зададим в перечисление ButtonID  «названия» наших кнопок. У меня это кнопка «BUTTONS»:

typedef enum {
    BUTTONS_NUM,
} ButtonID;

Следующим шагом настраиваем задержки для длительного и очень длительного нажатия кнопки:

#define BUTTONS_LONG_PRESS_MS                                1500
#define BUTTONS_VERY_LONG_PRESS_MS                           3500

Также необходимо настроить константу GPIO_BUTTON_NOT_PRESSED она отвечает за не нажатое состояние кнопки. Так как кнопка может быть подключена по разному, то здесь устанавливаем GPIO_PIN_SET или GPIO_PIN_RESET.

Последней настройкой будет необходимость указать в файле Button.c к каким ножкам подключены кнопки:

// Configuration

static McuPin buttons[BUTTONS_NUM] = {{GPIOC, GPIO_PIN_13}};

Теперь нам необходимо добавить в проект нашу библиотеку, для этого помещаем в отдельную папку файлы Button.с и Button.h. и прописываем в main вызов библиотеки include «button.h»

Теперь мы можем использовать функции библиотеки.

Для использования библиотеки необходимо в Callback от таймера вызвать функцию BUTTON_TimerProcess():

/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if (htim->Instance == htim6.Instance)
  {
    BUTTON_TimerProcess();
  }
}
/* USER CODE END 4 */

Функция вызывается согласно нашему таймеру раз в 1 мс и проверяет состояние кнопок.

Вся работа с библиотекой сводится к вызову нескольких функций:

while (1)
{
    BUTTON_Process(); // функция с внутренним механизмом библиотеки, для работы с кнопками
    // Work with buttons
    // Button "Up"
    if (BUTTON_GetAction(BUTTON_UP) == BUTTON_SHORT_PRESS)  // функция проверки состояния кнопки по ее имени
    {
      // LED on
      HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
    }
    // Button "Down"
    if (BUTTON_GetAction(BUTTON_DOWN) == BUTTON_SHORT_PRESS)
    {
      // LED off
      HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
    }
    BUTTON_ResetActions(); // функция сбрасывает состояние всех кнопок после обработки. Ее необходимо вызывать каждый раз, так как останется предыдущее состояни.
}

Что бы библиотека заработала необходимо вызвать функцию инициализации и запустить таймер с прерыванием:

/* USER CODE BEGIN 2 */
BUTTON_Init();
HAL_TIM_Base_Start_IT(&htim6);
/* USER CODE END 2 */

Загрузки

5 1 голос
Рейтинг статьи
Подписаться
Уведомить о
guest
6 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Тимур
7 месяцев назад

а почему название buttons? должно же быть buttons_pin?

AII
AII
3 месяцев назад

Здравствуйте! Выложите, пожалуйста, проект целиком, где работаете с библиотекой

Алексей
Алексей
7 дней назад

Вместо таймера может использовать systick? у него тотже периуд 1мс.