Не могу понять код опроса кнопки STM32

Кто любит RISC в жизни, заходим, не стесняемся.
Аватара пользователя
Jman
Мучитель микросхем
Сообщения: 414
Зарегистрирован: Ср янв 26, 2011 13:43:30
Откуда: С того берега моря
Контактная информация:

Не могу понять код опроса кнопки STM32

Сообщение Jman »

Всем привет. На форуме натолкнулся на статью и в исходниках есть участок кода, который мне не понятен. В https://www.radiokot.ru/forum/viewtopic ... 120написал, но там нет ответа. Создам отдельную тему. Часы, три кнопки: больше, меньше, ок. Кнопки посажены на землю, верх подтянуть резисторами к Uпит. Обработка их была написана следующим образом на все три, кроме управляющих функций, они различаются соответсвенно:

Код: Выделить всё

void read_button(void) {

    static uint8_t count_read_button_ok=0;
    count_read_button_ok++;

    //--------------------------- OK -----------------------------
    static char button, button_old=1;

    button_old=button;
    button=GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
    if (((button_old!=button)&&(button==0))) {
        delay_ms(5);
        button=GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
        if (((button_old!=button)&&(button==0))) {
            delay_ms(5);
            button=GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
            if (((button_old!=button)&&(button==0))) {
                delay_ms(5);
                button=GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
                if (((button_old!=button)&&(button==0))) {
                    delay_ms(5);
                    button=GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
                    if (((button_old!=button)&&(button==0))) {

                        second_systick_ms=0;
                        button_second=0;

                        while (((GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13)==0)&&(button_second<2))); // зачем это???
											
                        if (button_second<2) {
                            button_ok_press(); // управляющая функция.
                        }
                        else {
                            RTC_Counter = RTC_GetCounter();
                            RTC_GetDateTime(RTC_Counter, &RTC_DateTime);
                            RTC_DateTime.RTC_Seconds=0;
                            RTC_SetCounter(RTC_GetRTC_Counter(&RTC_DateTime));
                        }
                    }
                }
            }
        }
    }
Зачем такое количество чтений кнопки каждые 5 мс? Так же в коде не были проинициализированы порты, я добавил в main.

Код: Выделить всё

//PinB 13 - Ok, PinB  14 - Down, PinB  15 - Up
static void button_init(void){
   
   GPIO_InitTypeDef button_ok =
    {.GPIO_Pin = GPIO_Pin_13, .GPIO_Speed = GPIO_Speed_2MHz, .GPIO_Mode = GPIO_Mode_IPU};
    GPIO_InitTypeDef button_down =
    {.GPIO_Pin = GPIO_Pin_14, .GPIO_Speed = GPIO_Speed_2MHz, .GPIO_Mode = GPIO_Mode_IPU};
    GPIO_InitTypeDef button_up =
    {.GPIO_Pin = GPIO_Pin_15, .GPIO_Speed = GPIO_Speed_2MHz, .GPIO_Mode = GPIO_Mode_IPU};

    GPIO_Init(GPIOB, &button_up);
    GPIO_Init(GPIOB, &button_down);
    GPIO_Init(GPIOB, &button_ok);
}
[color=#4080FF]- Бежит этот подлец-электрон, а вокруг его масса (аж 10 в 23й) штук ионов кремния и 10 в 15й ионов примеси и он, подлец, взаимодействует![/color]
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

Re: Не могу понять код опроса кнопки STM32

Сообщение Eddy_Em »

Код: Выделить всё

delay_ms(5);
Дальше не читал. Выкинуть это говно в помойку и написать по-человечески!
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Аватара пользователя
Jman
Мучитель микросхем
Сообщения: 414
Зарегистрирован: Ср янв 26, 2011 13:43:30
Откуда: С того берега моря
Контактная информация:

Re: Не могу понять код опроса кнопки STM32

Сообщение Jman »

[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4218311#p4218311"]

Код: Выделить всё

delay_ms(5);
Дальше не читал. Выкинуть это говно в помойку[/uquote]
Я просто хочу понять, что это? Типо антидребезг ? =)) Несколько вложенностей с чтением через задержку.
и написать по-человечески!
Я не спец в этом типе МК, только разбираюсь. Что значит по-человечески? В таймере задержку организовать?
[color=#4080FF]- Бежит этот подлец-электрон, а вокруг его масса (аж 10 в 23й) штук ионов кремния и 10 в 15й ионов примеси и он, подлец, взаимодействует![/color]
Аватара пользователя
НовыйДень
Потрогал лапой паяльник
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

Re: Не могу понять код опроса кнопки STM32

Сообщение НовыйДень »

Ох, же-па, как говорят французы :) Задержки - они в принципе там не нужны. Можно считать весь порт за один раз:
port = GPIOB->IDR;
затем методом наложения маски определить, нажата ли кнопка:
if((port & (1 << BTN0_Pin) == 0) { /* кнопка нажата */ };
затем надо сравнить с предыдущим состоянием кнопки в статической переменной и если предыд.состояние было "не нажата", значит выставить флаг "есть нажатие кнопки".
Если в предыдущем сравнении выяснится, что сейчас кнопка не нажата, значит, сбросить предыдущее состояние в "не нажата".
Защита от дребезга выполняется либо установкой интервала считывания кнопок в диапазоне от 5 до 20 мс, либо введением интегрирующего счетчика, инкрементирующегося/декрементирующегося каждый цикл при определении нажатия/отпускания. Но доп.счетчик усложняет функцию и не всегда нужен.

То есть, в простейшем случае будет выглядеть вот так:

Код: Выделить всё

void ReadButtons(void)
{
   static uint16_t old = (1 << BTN0_Pin) | (1 << BTN1_Pin) | (1 << BTN2_Pin); 
   uint16_t port = GPIOB->IDR; // однократное чтение порта

   if((port & (1 << BTN0_Pin) == 0)  
   {      /* если состояние кнопки = нажата */
       if((old & (1 << BTN0_Pin) != 0)  
       {  /* если предыдущ.сост.кнопки = не нажата*/
           btn0_flag = 1;        // выставить флаг события нажатой кнопки
           old &= ~(1 << BTN0_Pin); // и обновить предыдущ.состояние кнопки
        }    
   } else
  {  /* если кнопка не нажата, то просто обновить предыдущ.сост.кноп. */
      old |= 1 << BTN0_Pin; 
   }

   /* повторить то же самое для BTN1 и BTN2 */

}
вышеприведенный код можно оптимизировать по записи или добавить плюшек, я привел просто для наглядности.
Типо антидребезг ?
Да, попытка сделать повторные чтения состояния кнопки. Хотя дребезг (генерация случайных импульсов) может проявляться до 1-2 мс после первого срабатывания, в зависимости от типа кнопки и её состояния.
И если по уму, то антидребезг надо делать не просто повторными считываниями, а именно интегрирующим счетчиком, фиксирующим степень стабильности логического уровня на входе. Потому что длительность и интервалы импульсов в дребезге - вещь случайная.
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

Re: Не могу понять код опроса кнопки STM32

Сообщение Eddy_Em »

Jman, при чем здесь тип МК? Сам код написан убогим абдуринщиком, который в конечные автоматы вообще никак не умеет! И даже вместо цикла запилил копипасту. За такое руки отрывать и в жопу засовывать - чтобы видно было, откуда растут!!!11
Вот - пример простой функции опроса кнопок. Вызывать из суперлупа.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Аватара пользователя
Jman
Мучитель микросхем
Сообщения: 414
Зарегистрирован: Ср янв 26, 2011 13:43:30
Откуда: С того берега моря
Контактная информация:

Re: Не могу понять код опроса кнопки STM32

Сообщение Jman »

[uquote="НовыйДень",url="/forum/viewtopic.php?p=4218346#p4218346"]Ох, же-па, как говорят французы :)[/uquote]
Спасибо большое! Вот теперь вроде все понятно.

Добавлено after 4 minutes 24 seconds:
[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4218377#p4218377"]Jman, при чем здесь тип МК? Сам код написан убогим абдуринщиком, который в конечные автоматы вообще никак не умеет![/uquote]

Я бы не стал так говорить, ибо каждый могет в силу своих знаний. Я типо тоже такой же по вашим словам ) Но я пытаюсь уловить суть и смысл. Лирика...
По делу. У вас hardware.c в репе реализован на CMSIS на сколько я понимаю?
[color=#4080FF]- Бежит этот подлец-электрон, а вокруг его масса (аж 10 в 23й) штук ионов кремния и 10 в 15й ионов примеси и он, подлец, взаимодействует![/color]
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

Re: Не могу понять код опроса кнопки STM32

Сообщение Eddy_Em »

[uquote="Jman",url="/forum/viewtopic.php?p=4218388#p4218388"]У вас hardware.c в репе реализован на CMSIS, насколько я понимаю?[/uquote]
Конечно, я не пользуюсь калокубами всякими. Да и никакой разработчик, если ему, конечно, не пофиг на свое время, не будет ни этой, ни другой подобной дрянью пользоваться.
На CMSIS все прозрачно, никакого лишнего кода... Конечно, еще лучше было бы на С++ написать на шаблонах всю "подноготную", как некоторые форумчане, но у меня к С++ не очень-то отношение (хотя, конечно, намного лучше, чем к змеюке).
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Аватара пользователя
НовыйДень
Потрогал лапой паяльник
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

Re: Не могу понять код опроса кнопки STM32

Сообщение НовыйДень »

Тут в принципе то не важно, как написана хардварная часть. От нее нужно лишь один раз прочитать состояние входов всех распознаваемых кнопок. Дальше - чисто софтовая часть. Причем, сложность и объемность реализации зависит от того, какие события кнопок нужно распознавать - простое нажатие, нажатие с удержанием, отпускание, фильтрация случайных импульсов. Лишнего без нужды наворачивать не следует.
Ну и в самой ф-ции распознавания кнопок не следует выполнять код функционала кнопки, если это только не простой короткий функционал. Как правило, выставляется флаг события кнопки (и/или код события), а по этому флагу извне уже выполняются действия кнопок.
Функция считывания состояния кнопок вызывается с некоторой периодичностью по таймеру, с интервалом 5 - 20 мс. Такой интервал гарантирует в большинстве случаев уверенную и быструю реакцию кнопок.

А еще бывает вариант срабатывания кнопок по внешнему прерыванию по изменению уровня на входах, он используется в основном для вывода микроконтроллера из режима пониженного потребления. Для этого варианта нужно программное подавление дребезга контактов, особенно когда нет подавительных конденсаторов параллельно кнопкам.
a797945
Мучитель микросхем
Сообщения: 446
Зарегистрирован: Вс ноя 01, 2015 09:15:16
Откуда: 69.Ржев

Re: Не могу понять код опроса кнопки STM32

Сообщение a797945 »

зачем автор так делал? - оставим этот вопрос ему самому (может у него оплата от кол-ва строк кода) :)

ф. read_button, вероятно, вызывается раз в секунду;
если кнопка нажата - опрашивается еще 4раза через 5мс, если "отпустилась" игнорируется;
если еще нажата попадаем на цикл:
"while (((GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13)==0)&&(button_second<2))); // зачем это???"

для выхода из этого цикла - два фактора:
п. button_second, вероятно наращивается в прерывании, когда станет больше 2 - спрыгнем с этого цикла - загрузятся парам. в RTC;
отпустят кнопку раньше - спрыгиваем с цикла - вызываем ф. button_ok_press().
Аватара пользователя
Jman
Мучитель микросхем
Сообщения: 414
Зарегистрирован: Ср янв 26, 2011 13:43:30
Откуда: С того берега моря
Контактная информация:

Re: Не могу понять код опроса кнопки STM32

Сообщение Jman »

Спасибо всем за ответы! У меня еще такой вопрос, у автора задержка реализована следующим образом:

Код: Выделить всё

void delay_ms(uint32_t ms)
{
    volatile uint32_t nCount;
    RCC_ClocksTypeDef RCC_Clocks;
    RCC_GetClocksFreq (&RCC_Clocks);
    nCount=(RCC_Clocks.HCLK_Frequency/10000)*ms;
    for (; nCount!=0; nCount--);
}
Это по вашим словам лучше заменить, и сделать опрос кнопок в таймере. Подойдет для этого SysTick?

Код: Выделить всё

static void init_sys_counter(void) {
    system_counter_init(1000);
    counter = system_counter_ticks();
    SysTick_Config(SystemCoreClock / 1000);
}

volatile uint16_t button_delay;
volatile uint8_t flag = 0; 

 void SysTick_Handler(void) {
    
    button_delay ++;

    if (button_delay >=20) {
        button_delay=0;
        flag = 1;
    }
}

И в основном коде типо оперировать флагом. Или опрос прям в SysTick делать, как в примере НовыйДень?

Код: Выделить всё

volatile uint16_t button_delay;

 void SysTick_Handler(void) {
    
    button_delay ++;

    if (button_delay >=20) {
        
        ReadButtons(void);
        button_delay=0;
    }
}

void ReadButtons(void)
{
   static uint16_t old = (1 << BTN0_Pin) | (1 << BTN1_Pin) | (1 << BTN2_Pin);
   uint16_t port = GPIOB->IDR; // однократное чтение порта

   if((port & (1 << BTN0_Pin) == 0) 
   {      /* если состояние кнопки = нажата */
       if((old & (1 << BTN0_Pin) != 0) 
       {  /* если предыдущ.сост.кнопки = не нажата*/
           btn0_flag = 1;        // выставить флаг события нажатой кнопки
           old &= ~(1 << BTN0_Pin); // и обновить предыдущ.состояние кнопки
        }   
   } else
  {  /* если кнопка не нажата, то просто обновить предыдущ.сост.кноп. */
      old |= 1 << BTN0_Pin;
   }

   /* повторить то же самое для BTN1 и BTN2 */

}
Я еще читая просторы инета, вижу применение задержек на основе DWT. Имеет место быть?
[color=#4080FF]- Бежит этот подлец-электрон, а вокруг его масса (аж 10 в 23й) штук ионов кремния и 10 в 15й ионов примеси и он, подлец, взаимодействует![/color]
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

Re: Не могу понять код опроса кнопки STM32

Сообщение Eddy_Em »

Проще завести переменную Tms и в прерывании SysTick, происходящем каждую условную миллисекунду, его инкрементировать. А везде в своих КА сравнивать внутренние счетчики с этим, оттуда и плясать.
Я ж дал пример кода.
Задержки на основе DWT? А смысл? Разве что если нужно микросекунды — но это тоже дико много. Одно дело - поставить блокирующую задержку в инициализации, там и пару секунд пользователь подождать может, пока все железо проинициализируется. И совсем другое - в рантайме. За абдуринские блокирующие delay'и в рантайме надо бить по рукам. В большинстве случаев их можно элементарным конечным автоматом заменить, не блокируя всю программу.
А блокирующие задержки пусть ставят абдуринщики в своих хеллоуворлдах, где ничего, кроме опроса датчика и вывода данных на экран без динамической индикации, не делается. Если какой-то протокол требует от вас постоянных задержек, либо реализуйте его на таймерах с DMA, либо не пользуйтесь таким говнопротоколом!
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Аватара пользователя
НовыйДень
Потрогал лапой паяльник
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

Re: Не могу понять код опроса кнопки STM32

Сообщение НовыйДень »

Автор того "кода" очень любит писать много строчек :) на проф.жаргоне это зовется "индусский код" - когда нужно создать видимость чего-то архисложного и непонятнонавороченного.

Для опроса кнопок лучше делать неблокирующую задержку (которая не блокирует исполнение остального кода) на таймере. Да, SysTick подойдет для этого, можно делать так, как вы написали. Можно выставлять флаг, а потом в основном цикле проверять флаг, а можно и прямо из прерывания вызывать. Но в случае вызова из прерывания систика, опрос кнопок не должен занимать много времени, чтобы не сбить интервалы систика.
А можно и иначе - запустить любой аппаратный таймер типа TIM6, TIM2, TIM1, TIM15, настроив его сразу на нужный интервал счета, например на 10 мс, с генерацией прерывания по событию обновления (Update). И в прерывании вызывать функцию ReadButtons().
Все варианты допустимы, а какой применить - выбирается по конкретной ситуации. Попробовав их все, поймете их плюсы и минусы.

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

Касательно таймеров и задержек. На одном аппаратном таймере (SysTick или TIMx) можно сделать целый набор софтовых таймеров. Эти таймеры представлены в виде массива структур:

Код: Выделить всё

typedef struct{
	uint32_t delay;		///< Интервал счета (в тиках)
	uint32_t cnt;		///< Счетная переменная
	uint8_t mode: 1;	///< Режим однократный/циклический
	uint8_t run: 1;		///< Бит работы таймера
	uint8_t flag: 1;	///< Флаг истечения интервала
}utim_t;
и объявлены в виде глобальной переменной

Код: Выделить всё

#define MAX_UTIMERS	5	///< Максимальное число софтовых таймеров
volatile utim_t utimer[MAX_UTIMERS];
Функция, обеспечивающая счет таймеров выглядит так:

Код: Выделить всё

/** -------------------------------------------------------
 * \brief		Счет таймеров.
 * \details		Функция может вызываться из прерывания аппаратного таймера.
 * 				Производит декременты счетных переменных и выставляет флаги
 * 				окончания счета.
 */
void UserTimer_Count(void)
{
	for(volatile uint8_t n = 0; n < MAX_UTIMERS; n++)
	{
		if(utimer[n].run)
		{
			if(utimer[n].cnt) utimer[n].cnt--;
			else
			{
				utimer[n].flag = 1;

				if(utimer[n].mode == UTIMER_CIRCMODE) utimer[n].cnt = utimer[n].delay;
				else utimer[n].run = 0;
			}
		}
	}
}
она вызывается из прерывания аппаратного таймера, например SysTick.

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

Код: Выделить всё

/** -------------------------------------------------------
 * \brief		Запуск таймера.
 * \details		Задание значений, запуск
 * @param timer номер таймера
 * @param delay интервал счета в тиках
 * @param mode  режим (однократный/циклический)
 */
void UserTimer_Start(uint8_t timer, uint32_t delay, uint8_t mode)
{
	utimer[timer].cnt = delay - 1;
	utimer[timer].delay = delay - 1;
	utimer[timer].mode = mode;
	utimer[timer].run = 1;
}

/** -------------------------------------------------------
 * \brief		Остановка таймера без сброса счетной переменной.
 * @param timer номер таймера
 */
void UserTimer_Stop(uint8_t timer)
{
	utimer[timer].run = 0;
}
Для проверки истечения времени таймера есть ф-ция

Код: Выделить всё

/** -------------------------------------------------------
 * \brief Проверка истечения времени таймера.
 * \param timer - номер таймера
 * \return Да/Нет
 */
uint8_t UserTimer_Check(uint8_t timer)
{
	if(utimer[timer].flag)
	{
		utimer[timer].flag = 0;
		return 1;
	}else
		return 0;
}/
либо можно записывать этот участок напрямую по месту проверки, сэкономив немного тактов на вызове ф-ции.

Блокирующая задержка (то есть та, которая задерживает дальнейшее исполнение до истечения заданного интервала) записывается гораздо короче.
Эта функция, реализующая саму задержку в том месте, где вызывается эта ф-ция:

Код: Выделить всё

/**--------------------------------------------------------
 * \brief		Блокирующая задержка.
 * \details		Функция блокирующей задержки на заданный интервал времени
 * 				в тиках.
 * \param	delay - начальное значение счета
 */
void BlockedDelay(volatile uint32_t delay)
{
	bltimer_cnt = delay;
	while(bltimer_cnt) { }
}
А вот эта ф-ция вызывается из прерывания аппаратного таймера, например систика:

Код: Выделить всё

/** -------------------------------------------------------
 * \brief		Счет блокирующей задержки.
 * \details		Функция может вызываться из прерывания аппаратного таймера
 * 				Производит декременты счетной переменной.
 */
void BlockedDelay_Count(void)
{
	if(bltimer_cnt) bltimer_cnt--;
}
Вот как бы вот так, касательно таймеров и задержек.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Не могу понять код опроса кнопки STM32

Сообщение VladislavS »

Jman, небольшой совет по оптимизации кода.

Код: Выделить всё

volatile uint16_t button_delay;
volatile uint8_t flag = 0;

 void SysTick_Handler(void) {
   
    button_delay ++;

    if (button_delay >=20) {
        button_delay=0;
        flag = 1;
    }
}
volatile, вообще говоря, не бесплатная опция. Для переменной button_delay это влечёт за собой два чтения из и две записи в память внутри прерывания. От части из них легко избавиться

Код: Выделить всё

volatile bool flag = false;

void SysTick_Handler(void)
{
  static uint32_t button_delay=0;
    
  if (++button_delay >=20) 
  {
    button_delay=0;
    flag = true;
  }
}
Мелочь, но 4 * 1000 тактов в секунду экономите просто на ровном месте. А сколько ещё таких мест будет в программе.


Не говоря уже о том, что SysTick (или любой другой таймер) можно настроить на 10-20 мс и выкинуть вообще весь этот код.
Последний раз редактировалось VladislavS Чт апр 21, 2022 09:41:45, всего редактировалось 3 раза.
Аватара пользователя
Jman
Мучитель микросхем
Сообщения: 414
Зарегистрирован: Ср янв 26, 2011 13:43:30
Откуда: С того берега моря
Контактная информация:

Re: Не могу понять код опроса кнопки STM32

Сообщение Jman »

[uquote="НовыйДень",url="/forum/viewtopic.php?p=4218920#p4218920"]Вот как бы вот так, касательно таймеров и задержек.[/uquote]
Спасибо большое за ликбез и ваше время!!!

Добавлено after 1 hour 55 minutes 27 seconds:
Вот я выбрал таймер 4.

Код: Выделить всё

void timer_init() {
    /*------------------Инициализация TIM4------------------*/
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
  /* По умолчанию частота шины 24 МГц при использовании кварца 8 МГц */
    TIM4->PSC = 24000 - 1; /* Настройка делителя на 1000 "тиков" в секунду */
    TIM4->ARR = 20; /* Отработка прерывания раз в 20мс */
    TIM4->DIER |= TIM_DIER_UIE; /* Разрешения прерывание от таймера */
    TIM4->CR1 |= TIM_CR1_CEN; /* Запуск таймера */
    NVIC_EnableIRQ(TIM4_IRQn); /* Разрешение TIM4_IRQn прерывания */
}

В самом прерывании вызываю функцию.

Код: Выделить всё

 void TIM4_IRQHandler(){
 
  ReadButtons();
}
В мейне разрешил прерывания
__enable_irq();
NVIC_SetPriorityGrouping(0x3);
[color=#4080FF]- Бежит этот подлец-электрон, а вокруг его масса (аж 10 в 23й) штук ионов кремния и 10 в 15й ионов примеси и он, подлец, взаимодействует![/color]
Аватара пользователя
НовыйДень
Потрогал лапой паяльник
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

Re: Не могу понять код опроса кнопки STM32

Сообщение НовыйДень »

Перырвания немного не так разрешаются. По умолчанию, глобально предывания разрешены и не нужна строчка __enable_irq(), только если раньше специально не запрещали глобально прерывания.
Только включить конкретный ветор прерывания, отвечающий за таймер, через ф-цию NVIC_EnableIRQ(TIM4_IRQn).
Ф-ция NVIC_SetPriorityGrouping(0x3) - это группы приоритетов прерываний. И если уж идете по пути глобального разрешения прерываний после настройки, то настройку приоритетов нужно сделать ранее.

Вообще, по структуре построения программы, включать векторы прерываний желатетьно уже после инициализации всей периферии, перед переходм в нормальный рабочий режим. Потому как несвоевременный переход в прерывание во время подготовительных процедур может привести к нежелательным сбоям, когда еще не всё готово для работы.
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

Re: Не могу понять код опроса кнопки STM32

Сообщение Eddy_Em »

Незачем опрос кнопок из прерывания делать! Если уж на то пошло, в прерывании выставляете флаг, а в суперлупе его проверяете. И если надо, вызываете опрос... Но таки лучше счетчики заводить, управляемые SysTick'ом - не придется гробить нормальный таймер на такую пустяковую задачу.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Аватара пользователя
НовыйДень
Потрогал лапой паяльник
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

Re: Не могу понять код опроса кнопки STM32

Сообщение НовыйДень »

Нет, ну если прерывания возникают раз в 20 мс, а опрос кнопок занимает сотню-другую микросекунд, то почему бы и нет? Потому как структура программы бывает разной, единого правильного правила нет. Есть просто подходящие и неподходящие для данного случая методы.
Таймеров TIMx может быть с избытком, а систик может использоваться для других задач и считать более быстро.
Чтобы не возникало неопределенностей и ситуации "а может оставить этот таймер на всякий случай?" надо еще на этапе планирования проработать структуру будующей программы. Все многоопытные программисты, прежде чем сесть за кодописательство, продумывают стратегию, распределяют ресурсы. Чтобы потом не переписывать по нескольку раз.
На этапе обучения - тут другое дело, пока сам не попробуешь все варианты, не поймешь. Но когда у тебя есть уже багаж опыта, тогда планируешь работу иначе, вначале на бумаге в виде блок-схем: задаёшься исходными данными, составляешь структуру взаимодействия, определяешь, какие входные и выходные данные нужны в каждом блоке, как блоки взаимодействуют друг с другом и какой результат они дают. И уже после этого приступаешь к кодописательству, создавая вначале заготовки модулей и функций, затем постепенно заполняешь функциональным наполнением, ну и тестишь.
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

Re: Не могу понять код опроса кнопки STM32

Сообщение Eddy_Em »

то почему бы и нет?
А смысл, если кнопку можно опросить даже миллисекунд позже? Всему свое место. В прерываниях нужно выполнять лишь критический код, который "не ждет".
Таймеров TIMx может быть с избытком
Мне, например, их вечно не хватает! Вот, последняя железка — контроллер шаговиков — не может больше трех осей, т.к. у STM32F072CBT6 слишком мало таймеров, а на каждый шаговик нужно два (один для генерирования STEP, второй - для работы с энкодером, т.е. нужны еще и не абы какие таймеры, а с ногами ШИМ/энкодер).
систик может использоваться для других задач и считать более быстро
systick - на то и systick, чтобы "системное время" отсчитывать. Если он тарахтит не миллисекунды, а, скажем, десяток микросекунд - какая разница? Можно не только инкрементировать системный счетчик, но и счетчик миллисекунд каждое сотое срабатывание.
прежде чем сесть за кодописательство, продумывают стратегию, распределяют ресурсы
Окончательно же ресурсы распределяются на стадии трассировки печатной платы. У меня такое неоднократно было. И в том же примере по ссылке выше, скажем, двигатели 0, 1 и 2 контролируются отнюдь не последовательно пронумерованными таймерами! Да и каналы АЦП, концевики и т.п. зачастую вразнобой размещены - потому что так было удобней разводить печатную плату (иначе пришлось бы вместо недорогой двухслойки заказывать дорогущую четырехслойку).
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Аватара пользователя
НовыйДень
Потрогал лапой паяльник
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

Re: Не могу понять код опроса кнопки STM32

Сообщение НовыйДень »

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

Нет никаких запретов или единых правил для чего использовать аппаратные таймеры. Таймер - это универсальный инструмент с некоторым списком дополнительных, кроме отсчета интервала времени, возможностей. Коль не хватает чего-то, то быть может, стоит выбрать более подходящий для этого микроконтроллер? Последнее сказанное в нынешней ситуации имеет неоднозначную окраску в нынешней ситуации. Но я так понимаю, что проблема нехватки таймеров родилась не на прошлой неделе. И когда программист пытается впихнуть невпихуемое в микроконтроллер начального уровня - это уже проблема системного подхода к задаче.
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

Re: Не могу понять код опроса кнопки STM32

Сообщение Eddy_Em »

При задержке между нажатием кнопки и получением отклика более 50-70 мс получается эффект тормознутости.
Это что ж такое нужно в суперлупе делать, чтобы он так медленно выполнялся? Налицо адово рукожопие!!!
Что до нехватки таймеров, то даже не знаю, во сколько обойдется STM32, у которого на борту будут одновременно работающие CAN и USB, при этом с хотя бы шестью таймерами с ШИМ-выходом (кроме движков еще хоть один ШИМ-канал нужен) и пятью таймерами с входом от энкодера... При этом еще могут понадобиться 1-2 таймера (кроме SysTick) для внутренних нужд + 1-2 канала ЦАП…
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Ответить

Вернуться в «ARM»