- максимально убрана зависимость от HAL - можно использовать и без него, чисто на cmsis - документирован uart - документирован spi - добавлены примеры использования в general_periph - всякие фиксы документации
		
			
				
	
	
		
			326 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			326 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** 
 | 
						||
**************************************************************************
 | 
						||
* @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-------------------------
 | 
						||
//-------------------------------------------------------------------
 |