Top.Mail.Ru

Часть 7. STM32 и С++. Библиотека SButton.

В своё время я наткнулся на сайт Гайвера, и мне подарили Arduino NANO. Я почитал его статьи. Поморгал диодом и бросил всё это дело. Тогда я программировал на ASM под PIC контроллеры и для меня было мучением найти или разработать простейшие библиотеки. Работа с кнопками, дисплеями и т. д. Купил несколько Ардуин и быстро наваял проекты, мне понравилось, насколько просто и логично можно пользоваться библиотеками. Зарегистрировался на сайте и стал мониторить форум. Немного выполнил заказов и на одном сильно споткнулся. Не тянет Ардуинка, да и сама логика этих МК мне не нравилась. Тут мне подогнали STM32F050, и я поразился, какая мощь в этом невзрачном квадратике, после чего начал изучать STM. Но под HAL мне не хватало того, что можно было сделать на Ардуине - классов. Сначала я скрестил HAL и классы. Но HAL жрёт очень много и очень медлителен, поэтому я решил полностью перейти на CMSIS и классы. Но из-за сложности периферии пока не получается это сделать. Я списался с Гайвером и предложил создать ветку про STM, где я буду выкладывать его библиотеки переделанные под STM. Но эта тема там не встретила понимания. Правда у меня осталось согласие Гайвера на использование его кода, чем я и воспользуюсь, так что выкладываю одну из своих первых переделок.

Библиотека GyverButton, переделанная под STM и названная SButton.

Эта библиотека им больше не поддерживается, но она должна быть вылизана до упора. Он продолжил работу над этой библиотекой, но она называется по-другому и работает также с энкодерами. Но при этом она умеет работать только с кнопками и энкодерами, которые замыкаются на землю. Но есть задачи, которые требуют, чтобы кнопка изначально подключалась к питанию и работала с МК подачей питания на управляемый вход.

Небольшое отступление: в самом МК есть подтяжка входов к земле и к питанию. Данная возможность очень хороша для отладки на макетке, но в конечном устройстве лучше использовать внешнюю схему подтяжки и подавления дребезга. Так как наводки в промышленном использовании не дремлют и могут неплохо попортить нервы. Схема подтяжки с подавлением дребезга весьма проста:

    

Переименовываем оба файла в SButton. Внутри заголовочного файла и файла с кодом исправляем GButton на SButton, в описании структуры GyverButtonFlags правим на SButtonFlags. Все переменные boolean исправляем на bool.

Теперь из библиотеки Гайвера нам нужно убрать элементы, относящиеся к Ардуино, и добавить или переделать некоторые функции под STM:

#ifndef GyverButton_h
#define GyverButton_h
#include <Arduino.h>

#if defined(__AVR__)
#define _buttonRead() bool(*_pin_reg & _bit_mask)
#else
#define _buttonRead() digitalRead(_PIN)
#endif

Убираем этот кусок вообще и вместо него пишем:

#ifndef _SBUTTON_H
#define _SBUTTON_H

#include "STM32.h"
#include <gpio_main.h>

В файле заголовка переписываем конструктор:

GButton(int8_t pin = BTN_NO_PIN, bool type = HIGH_PULL, bool dir = NORM_OPEN);

Делаем его таким:

SButton(GPIO_TypeDef *GPIOx, uint16_t GPIO_PIN, bool type, bool dir);

И в разделе private добавляем пару своих переменных:

private:
    GPIO_TypeDef *_GPIOx_IN;
    uint16_t      _GPIO_Pin_IN;

Теперь берёмся за файл, содержащий сами функции работы с кнопками. Заменяем include и конструктор:

#include "GyverButton.h"

// ==================== CONSTRUCTOR ====================
GButton::GButton(int8_t pin, bool type, bool dir)
{
  if(pin != BTN_NO_PIN)
  {
    _PIN = (uint8_t) pin;
    flags.noPin = false;
  }
  else
  {
    flags.noPin = true;
  }
  setType(type);
  flags.mode = false;
  flags.tickMode = false;
  flags.inv_state = dir;
}

на наш конструктор:

// ==================== CONSTRUCTOR ====================
SButton::SButton(GPIO_TypeDef *GPIOx, uint16_t GPIO_PIN, bool type, bool dir)
{
  _GPIOx_IN = GPIOx;
  _GPIO_Pin_IN = GPIO_PIN;
  flags.noPin = false;

  if(type)
    _SetPin(_GPIOx_IN, _GPIO_Pin_IN, Input, Pull_Down);
  else
    _SetPin(_GPIOx_IN, _GPIO_Pin_IN, Input, Pull_Up);

  flags.type = type;
  flags.mode = false;
  flags.tickMode = true; //false;
  flags.inv_state = dir;
}

Здесь мы инициализируем ранее введённые нами переменные и вызываем ранее написанные функции инициализации порта. Обратите внимание на flags.tickMode = true, в отличие от оригинала, мы устанавливаем флаг в другое значение. Мне показалось, что так будет удобнее пользоваться инициализацией. Эта переменная заставляет опрашивать клавиатуру автоматически, при любом обращении к классу. Если это будет не нужно, можно будет уже в самой функции main() отключить эту возможность и инициировать опрос вручную.

Нам осталось только заменить в функции чтения порта void GButton::tick() одну строчку на свою:

// читаем пин
if(!flags.mode && !flags.noPin) btn_state = !_buttonRead() ^ (flags.inv_state ^ flags.type);

Изменяем на:

// читаем пин
if(!flags.mode && !flags.noPin)
  btn_state = !_DigitalReadBit(_GPIOx_IN, _GPIO_Pin_IN) ^ (flags.inv_state ^ flags.type);

Вот и всё, библиотека готова, можно пользоваться. Пример в каталоге WorkDevel\Developer\Tests MK\F407\F407VExx_Button. Как всегда исходники на Яндекс диске и архивом WorkDevel. Кроме этого добавлены исходники библиотеки Гайвера в каталог WorkDevel\Developer\Source.

Особая благодарность владельцу ресурса https://alexgyver.ru!

Подписаться
Уведомить о
guest

9 комментариев
Старые
Новые
Межтекстовые Отзывы
Посмотреть все комментарии
Дмитрий
Дмитрий
6 месяцев назад

Привет, подскажи как добавить эту библиотеку в hal ? вечер убил так и не удалось(((

Дмитрий
Дмитрий
Ответ на комментарий  Эдуард
5 месяцев назад

Вроде получилось перевести в С++
на классы не ругается
Заменил millis на HAL_GetTick
Библиотеки подключаю следующие
вместо stm32.h - stm32f1xx_hal.h
вместо gpio_main.h - main.h
при попытки компиляции ругается вот на эти строки

  if(type)
    _SetPin(_GPIOx_IN, _GPIO_Pin_IN, Input, Pull_Down);
  else
    _SetPin(_GPIOx_IN, _GPIO_Pin_IN, Input, Pull_Up);
Дмитрий
Дмитрий
Ответ на комментарий  Эдуард
5 месяцев назад

Ну вроде бы заработало)
взгляни пожалуйста не чего лишнего я туда не прикрутил?

Чудо

#include "SButton.h"
#include "stm32f1xx_hal.h"


// ==================== CONSTRUCTOR ====================
SButton::SButton(GPIO_TypeDef *GPIOx, uint16_t GPIO_PIN, bool type, bool dir)
{
	flags.noPin = false;


	_GPIOx_IN = GPIOx;
	_GPIO_Pin_IN = GPIO_PIN;


	GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = _GPIO_Pin_IN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;


    if(type)
  	    GPIO_InitStruct.Pull = GPIO_PULLUP;
    else
  	  GPIO_InitStruct.Pull = GPIO_PULLDOWN;


    HAL_GPIO_Init(_GPIOx_IN, &GPIO_InitStruct);




  flags.type = type;
  flags.mode = false;
  flags.tickMode = false; //false;
  flags.inv_state = dir;
}


Aleksey_Baydin
Aleksey_Baydin
Ответ на комментарий  Дмитрий
5 месяцев назад

Дмитрий привет! Я знаком лично с Эдуардом. Мы с ним созванивались, у него сейчас проблемы с интернетом и он велел передать, что смотрел твой код, и вроде как всё в порядке там у тебя. Пару недель пока у него связи почти не будет с форумом.

Дмитрий
Дмитрий
Ответ на комментарий  Эдуард
5 месяцев назад

Спасибо большое за ваши уроки и подсказки.
Именно подсказки а не готовое решение. Это заставляет извилины шевелится)

9
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x