/** ************************************************************************** * @file general_gpio.c * @brief Модуль для инициализации портов и работы с ними. ************************************************************************** * @details Реализация функций для работы с GPIO: - Включение тактирования портов - Инициализация светодиодов и кнопок - Управление светодиодами: включение, выключение, моргание, плавное затухание - Чтение состояния кнопок с фильтром от дребезга ***************************************************************************/ #include "general_gpio.h" //------------------------------------------------------------------- //------------------------GPIO INIT FUNCTIONS------------------------ /** * @brief Включить тактирование порта GPIO */ HAL_StatusTypeDef GPIO_Clock_Enable(GPIO_TypeDef *GPIOx) { if(check_null_ptr_1(GPIOx)) return HAL_ERROR; HAL_StatusTypeDef status = HAL_OK; // choose port for enable clock if (GPIOx==GPIOA) __HAL_RCC_GPIOA_CLK_ENABLE(); else if (GPIOx==GPIOB) __HAL_RCC_GPIOB_CLK_ENABLE(); #ifdef GPIOC else if (GPIOx==GPIOC) __HAL_RCC_GPIOC_CLK_ENABLE(); #endif #ifdef GPIOD else if (GPIOx==GPIOD) __HAL_RCC_GPIOD_CLK_ENABLE(); #endif #ifdef GPIOE else if (GPIOx==GPIOE) __HAL_RCC_GPIOE_CLK_ENABLE(); #endif #ifdef GPIOF else if (GPIOx==GPIOF) __HAL_RCC_GPIOF_CLK_ENABLE(); #endif #ifdef GPIOH else if (GPIOx==GPIOF) __HAL_RCC_GPIOH_CLK_ENABLE(); #endif else status = HAL_ERROR; return status; } //------------------------GPIO INIT FUNCTIONS------------------------ //------------------------------------------------------------------- //------------------------------------------------------------------- //------------------------GPIO LED FUNCTIONS------------------------- /** * @brief Инициализировать светодиод (структуру светодиода) * @param led Указатель на структуру светодиода * @param GPIOx Указатель на структуру порта для светодиода * @param GPIO_PIN_X Пин для светодиода * @param LED_ActiveLevel Состояния пина, при котором светодиод будет включен */ HAL_StatusTypeDef GPIO_LED_Init(GPIO_LEDTypeDef *led, GPIO_TypeDef *GPIOx, uint32_t GPIO_PIN_X, uint8_t LED_ActiveLevel) { if(check_null_ptr_3(led, GPIOx, GPIO_PIN_X)) return HAL_ERROR; led->LED_Port = GPIOx; led->LED_Pin = GPIO_PIN_X; led->LED_ActiveLvl = LED_ActiveLevel; GPIO_LED_Off(led); return HAL_OK; } /** * @brief Включить светодиод * @param led Указатель на структуру светодиода * @return HAL Status */ HAL_StatusTypeDef GPIO_LED_On(GPIO_LEDTypeDef *led) { if(check_null_ptr_3(led, led->LED_Port, led->LED_Pin)) return HAL_ERROR; led->state = LED_IS_ON; HAL_GPIO_WritePin(led->LED_Port, led->LED_Pin, led->LED_ActiveLvl); return HAL_OK; } /** * @brief Выключить светодиод * @param led Указатель на структуру светодиода * @return HAL Status */ HAL_StatusTypeDef GPIO_LED_Off(GPIO_LEDTypeDef *led) { if(check_null_ptr_3(led, led->LED_Port, led->LED_Pin)) return HAL_ERROR; led->state = LED_IS_OFF; HAL_GPIO_WritePin(led->LED_Port, led->LED_Pin, !led->LED_ActiveLvl); return HAL_OK; } /** * @brief Выставить светодиод по переменной * @param led Указатель на структуру светодиода * @param led_state Состояние светодиода * @return HAL Status */ HAL_StatusTypeDef GPIO_LED_Set(GPIO_LEDTypeDef *led, uint8_t led_state) { if(check_null_ptr_3(led, led->LED_Port, led->LED_Pin)) return HAL_ERROR; if(led_state) { return GPIO_LED_On(led); } else { return GPIO_LED_Off(led); } } /** * @brief Активировать моргание светодиодом * @param led Указатель на структуру светодиода * @param period Период плавного моргания светодиода * @return HAL Status * @details Функция ставит режим моргания, который после управляется в @ref GPIO_LED_Dynamic_Handle */ HAL_StatusTypeDef GPIO_LED_Blink_Start(GPIO_LEDTypeDef *led, uint32_t period) { if(check_null_ptr_3(led, led->LED_Port, led->LED_Pin)) return HAL_ERROR; led->state = LED_IS_BLINKING; led->LED_Period = period; return HAL_OK; } /** * @brief Активировать моргание светодиодом * @param led Указатель на структуру светодиода * @param period Период плавного моргания светодиода * @return HAL Status * @details Функция ставит режим моргания, который после управляется в @ref GPIO_LED_Dynamic_Handle */ HAL_StatusTypeDef GPIO_LED_Fading_Start(GPIO_LEDTypeDef *led, uint32_t period) { if(check_null_ptr_3(led, led->LED_Port, led->LED_Pin)) return HAL_ERROR; led->state = LED_IS_FADING; led->LED_Period = period; return HAL_OK; } //uint8_t LED_PWM_FADING_DUTYS[LED_PWM_TICKS] = {0 1 2 3 4 5 6 7 8 9 10 11 12 } /** * @brief Управление динамическими режимами свечения светодиода * @param Указатель на структуру светодиода * @details Функция моргает/плавно моргает светодиодом в неблокирующем режиме * Т.е. функцию надо вызывать постоянно, чтобы она мониторила тики * и в нужный момент переключала светодиод */ void GPIO_LED_Dynamic_Handle(GPIO_LEDTypeDef *led) { if(check_null_ptr_3(led, led->LED_Port, led->LED_Pin)) return; /* Режим моргания светодиода */ if(led->state == LED_IS_BLINKING) { uint32_t tickcurrent = local_time(); /* Ожидание истечения периода моргания */ if((tickcurrent - led->tickprev) > led->LED_Period) { /* Моргание */ HAL_GPIO_TogglePin(led->LED_Port, led->LED_Pin); led->tickprev = tickcurrent; } } /* Режим плавного моргания светодиода */ else if(led->state == LED_IS_FADING) { static unsigned direction = 0; static int duty = 0; uint32_t tickcurrent = local_time(); /* Ожидание момента изменения яркости */ /* Период ШИМ 20 мс, поэтому менять яроксть надо 40 раз за период (туда обратно) */ if((tickcurrent - led->tickprev) > led->LED_Period/(LED_PWM_TICKS*2)) { /* Формирование разтухания */ if(direction == 0) { if(++duty >= LED_PWM_TICKS) { direction = 1; duty = LED_PWM_TICKS; } } /* Формирование затухания */ else { if(--duty <= 0) { direction = 0; duty = 0; } } led->tickprev = tickcurrent; } /* Формирование ШИМ для изменения яркости */ int duty_crt = (duty*duty/LED_PWM_TICKS); if(tickcurrent%LED_PWM_TICKS < duty_crt) { HAL_GPIO_WritePin(led->LED_Port, led->LED_Pin, led->LED_ActiveLvl); } else { HAL_GPIO_WritePin(led->LED_Port, led->LED_Pin, !led->LED_ActiveLvl); } } } //------------------------GPIO LED FUNCTIONS------------------------- //------------------------------------------------------------------- //------------------------------------------------------------------- //------------------------GPIO SW FUNCTIONS------------------------- /** * @brief Инициализировать кнопку (структуру кнопки) * @param sw Указатель на структуру кнопки * @param GPIOx Указатель на структуру порта для кнопки * @param GPIO_PIN_X Пин для кнопки * @param SW_ActiveLevel Состояния пина, когда кнопка нажата * @return HAL Status */ HAL_StatusTypeDef GPIO_Switch_Init(GPIO_SwitchTypeDef *sw, GPIO_TypeDef *GPIOx, uint32_t GPIO_PIN_X, uint8_t SW_ActiveLevel) { if(check_null_ptr_3(sw, GPIOx, GPIO_PIN_X)) return HAL_ERROR; sw->Sw_Port = GPIOx; sw->Sw_Pin = GPIO_PIN_X; sw->Sw_ActiveLvl = SW_ActiveLevel; return HAL_OK; } /** * @brief Считать состоянии кнопки * @param sw Указатель на структуру кнопки * @return 1 - если кнопка нажата, * 0 - если отжата, * -1 - если ошибка * @details Функция включает в себя неблокирующую проверку на дребезг * Т.е. функцию надо вызывать постоянно, чтобы она мониторила состояние кнопки */ int GPIO_Read_Switch(GPIO_SwitchTypeDef *sw) { if(check_null_ptr_3(sw, sw->Sw_Port, sw->Sw_Pin)) return -1; if(HAL_GPIO_ReadPin(sw->Sw_Port, sw->Sw_Pin) == sw->Sw_ActiveLvl) { sw->Sw_PrevState = 1; if(sw->Sw_FilterDelay) // если включена защита от дребезга { if(sw->tickprev == 0) sw->tickprev = local_time(); if((local_time() - sw->tickprev) >= sw->Sw_FilterDelay) { if(HAL_GPIO_ReadPin(sw->Sw_Port, sw->Sw_Pin) == sw->Sw_ActiveLvl) { return 1; } else { sw->tickprev = 0; return 0; } } } else // если нет защиты от дребезга { if(HAL_GPIO_ReadPin(sw->Sw_Port, sw->Sw_Pin) == sw->Sw_ActiveLvl) { return 1; } else { sw->tickprev = 0; return 0; } } } else { sw->Sw_PrevState = 0; } return 0; } //------------------------GPIO SW FUNCTIONS------------------------- //-------------------------------------------------------------------