[C] 纯文本查看 复制代码
/*
*********************************************************************************************************
* 函 数 名: bsp_SetTIMOutPWM
* 功能说明: 设置引脚输出的PWM信号的频率和占空比. 当频率为0,并且占空为0时,关闭定时器,GPIO输出0;
* 当频率为0,占空比为100%时,GPIO输出1.
* 形 参: GPIOx : GPIOA - GPIOK
* GPIO_Pin : GPIO_PIN_0 - GPIO__PIN_15
* TIMx : TIM1 - TIM17
* _ucChannel:使用的定时器通道,范围1 - 4
* _ulFreq : PWM信号频率,单位Hz (实际测试,可以输出100MHz),0 表示禁止输出
* _ulDutyCycle : PWM信号占空比,单位: 万分之一。如5000,表示50.00%的占空比
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_SetTIMOutPWM(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, TIM_TypeDef* TIMx, uint8_t _ucChannel,
uint32_t _ulFreq, uint32_t _ulDutyCycle)
{
TIM_HandleTypeDef TimHandle = {0};
TIM_OC_InitTypeDef sConfig = {0};
uint16_t usPeriod;
uint16_t usPrescaler;
uint32_t pulse;
uint32_t uiTIMxCLK;
const uint16_t TimChannel[6+1] = {0, TIM_CHANNEL_1, TIM_CHANNEL_2, TIM_CHANNEL_3, TIM_CHANNEL_4, TIM_CHANNEL_5, TIM_CHANNEL_6};
if (_ucChannel > 6)
{
Error_Handler(__FILE__, __LINE__);
}
if (_ulDutyCycle == 0)
{
//bsp_RCC_TIM_Disable(TIMx); /* 关闭TIM时钟, 可能影响其他通道 */
bsp_ConfigGpioOut(GPIOx, GPIO_Pin); /* 配置GPIO为推挽输出 */
HAL_GPIO_WritePin(GPIOx, GPIO_Pin, GPIO_PIN_RESET); /* PWM = 0 */
return;
}
else if (_ulDutyCycle == 10000)
{
//bsp_RCC_TIM_Disable(TIMx); /* 关闭TIM时钟, 可能影响其他通道 */
bsp_ConfigGpioOut(GPIOx, GPIO_Pin); /* 配置GPIO为推挽输出 */
HAL_GPIO_WritePin(GPIOx, GPIO_Pin, GPIO_PIN_SET); /* PWM = 1 */
return;
}
/* 下面是PWM输出 */
bsp_ConfigTimGpio(GPIOx, GPIO_Pin, TIMx); /* 使能GPIO和TIM时钟,并连接TIM通道到GPIO */
/*-----------------------------------------------------------------------
bsp.c 文件中 void SystemClock_Config(void) 函数对时钟的配置如下:
System Clock source = PLL (HSE)
SYSCLK(Hz) = 400000000 (CPU Clock)
HCLK(Hz) = 200000000 (AXI and AHBs Clock)
AHB Prescaler = 2
D1 APB3 Prescaler = 2 (APB3 Clock 100MHz)
D2 APB1 Prescaler = 2 (APB1 Clock 100MHz)
D2 APB2 Prescaler = 2 (APB2 Clock 100MHz)
D3 APB4 Prescaler = 2 (APB4 Clock 100MHz)
因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = APB1 x 2 = 200MHz;
因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = APB2 x 2 = 200MHz;
APB4上面的TIMxCLK没有分频,所以就是100MHz;
APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14,LPTIM1
APB2 定时器有 TIM1, TIM8 , TIM15, TIM16,TIM17
APB4 定时器有 LPTIM2,LPTIM3,LPTIM4,LPTIM5
----------------------------------------------------------------------- */
if ((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM15) || (TIMx == TIM16) || (TIMx == TIM17))
{
/* APB2 定时器时钟 = 200M */
uiTIMxCLK = SystemCoreClock / 2;
}
else
{
/* APB1 定时器 = 200M */
uiTIMxCLK = SystemCoreClock / 2;
}
if (_ulFreq < 100)
{
usPrescaler = 10000 - 1; /* 分频比 = 10000 */
usPeriod = (uiTIMxCLK / 10000) / _ulFreq - 1; /* 自动重装的值 */
}
else if (_ulFreq < 3000)
{
usPrescaler = 100 - 1; /* 分频比 = 100 */
usPeriod = (uiTIMxCLK / 100) / _ulFreq - 1; /* 自动重装的值 */
}
else /* 大于4K的频率,无需分频 */
{
usPrescaler = 0; /* 分频比 = 1 */
usPeriod = uiTIMxCLK / _ulFreq - 1; /* 自动重装的值 */
}
pulse = (_ulDutyCycle * usPeriod) / 10000;
HAL_TIM_PWM_DeInit(&TimHandle);
/* PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/
TimHandle.Instance = TIMx;
TimHandle.Init.Prescaler = usPrescaler;
TimHandle.Init.Period = usPeriod;
TimHandle.Init.ClockDivision = 0;
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle.Init.RepetitionCounter = 0;
TimHandle.Init.AutoReloadPreload = 0;
if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
/* 配置定时器PWM输出通道 */
sConfig.OCMode = TIM_OCMODE_PWM1;
sConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfig.OCFastMode = TIM_OCFAST_DISABLE;
sConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
sConfig.OCIdleState = TIM_OCIDLESTATE_RESET;
/* 占空比 */
sConfig.Pulse = pulse;
if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TimChannel[_ucChannel]) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
/* 启动PWM输出 */
if (HAL_TIM_PWM_Start(&TimHandle, TimChannel[_ucChannel]) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
}