|

楼主 |
发表于 2018-4-8 21:31:24
|
显示全部楼层
本帖最后由 龙之谷 于 2018-4-8 21:39 编辑
007
bsp_tim_pwm
最终主要实现、常用的有两个函数
1.配置中断函数
/*
*********************************************************************************************************
* 函 数 名: bsp_SetTIMforInt
* 功能说明: 配置TIM和NVIC,用于简单的定时中断. 开启定时中断。 中断服务程序由应用程序实现。
* 形 参: TIMx : 定时器
* _ulFreq : 定时频率 (Hz)。 0 表示关闭。
* _PreemptionPriority : 中断优先级分组
* _SubPriority : 子优先级
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_SetTIMforInt(TIM_TypeDef* TIMx, uint32_t _ulFreq, uint8_t _PreemptionPriority, uint8_t _SubPriority)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
uint16_t usPeriod;
uint16_t usPrescaler;
uint32_t uiTIMxCLK;
/* 使能TIM时钟 */
if ((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM9) || (TIMx == TIM10) || (TIMx == TIM11))
{
RCC_APB2PeriphClockCmd(bsp_GetRCCofTIM(TIMx), ENABLE);
}
else
{
RCC_APB1PeriphClockCmd(bsp_GetRCCofTIM(TIMx), ENABLE);
}
if (_ulFreq == 0)
{
TIM_Cmd(TIMx, DISABLE); /* 关闭定时输出 */
return;
}
/*-----------------------------------------------------------------------
system_stm32f4xx.c 文件中 void SetSysClock(void) 函数对时钟的配置如下:
HCLK = SYSCLK / 1 (AHB1Periph)
PCLK2 = HCLK / 2 (APB2Periph)
PCLK1 = HCLK / 4 (APB1Periph)
因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 = SystemCoreClock / 2;
因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = PCLK2 x 2 = SystemCoreClock;
APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13,TIM14
APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11
----------------------------------------------------------------------- */
if ((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM9) || (TIMx == TIM10) || (TIMx == TIM11))
{
/* APB2 定时器 */
uiTIMxCLK = SystemCoreClock;
}
else /* APB1 定时器 */
{
uiTIMxCLK = SystemCoreClock / 2;
}
if (_ulFreq < 100)
{
usPrescaler = 10000 - 1; /* 分频比 = 1000 */
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; /* 自动重装的值 */
}
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = usPeriod;
TIM_TimeBaseStructure.TIM_Prescaler = usPrescaler;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0000; /* TIM1 和 TIM8 必须设置 */
TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure);
TIM_ARRPreloadConfig(TIMx, ENABLE);
/* TIM Interrupts enable */
TIM_ITConfig(TIMx, TIM_IT_Update, ENABLE);
/* TIMx enable counter */
TIM_Cmd(TIMx, ENABLE);
/* 配置TIM定时更新中断 (Update) */
{
NVIC_InitTypeDef NVIC_InitStructure; /* 中断结构体在 misc.h 中定义 */
uint8_t irq = 0; /* 中断号, 定义在 stm32f4xx.h */
if ((TIMx == TIM1) || (TIMx == TIM10))
irq = TIM1_UP_TIM10_IRQn;
else if (TIMx == TIM2)
irq = TIM2_IRQn;
else if (TIMx == TIM3)
irq = TIM3_IRQn;
else if (TIMx == TIM4)
irq = TIM4_IRQn;
else if (TIMx == TIM5)
irq = TIM5_IRQn;
else if (TIMx == TIM6)
irq = TIM6_DAC_IRQn;
else if (TIMx == TIM7)
irq = TIM7_IRQn;
else if (TIMx == TIM7)
irq = TIM7_IRQn;
else if (TIMx == TIM7)
irq = TIM7_IRQn;
else if ((TIMx == TIM8) || (TIMx == TIM13))
irq = TIM8_UP_TIM13_IRQn;
else if (TIMx == TIM9)
irq = TIM1_BRK_TIM9_IRQn;
else if (TIMx == TIM11)
irq = TIM1_TRG_COM_TIM11_IRQn;
else if (TIMx == TIM12)
irq = TIM8_BRK_TIM12_IRQn;
else if (TIMx == TIM12)
irq = TIM8_TRG_COM_TIM14_IRQn;
NVIC_InitStructure.NVIC_IRQChannel = irq;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = _PreemptionPriority;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = _SubPriority;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
}
2.设置引脚PWM输出函数
/*
*********************************************************************************************************
* 函 数 名: bsp_SetTIMOutPWM
* 功能说明: 设置引脚输出的PWM信号的频率和占空比. 当频率为0,并且占空为0时,关闭定时器,GPIO输出0;
* 当频率为0,占空比为100%时,GPIO输出1.
* 形 参: _ulFreq : PWM信号频率,单位Hz (实际测试,最大输出频率为 168M / 4 = 42M). 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_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
uint16_t usPeriod;
uint16_t usPrescaler;
uint32_t uiTIMxCLK;
if (_ulDutyCycle == 0)
{
TIM_Cmd(TIMx, DISABLE); /* 关闭PWM输出 */
bsp_ConfigGpioOut(GPIOx, GPIO_Pin); /* 配置GPIO为推挽输出 */
GPIO_WriteBit(GPIOx, GPIO_Pin, Bit_RESET); /* PWM = 0 */
return;
}
else if (_ulDutyCycle == 10000)
{
TIM_Cmd(TIMx, DISABLE); /* 关闭PWM输出 */
bsp_ConfigGpioOut(GPIOx, GPIO_Pin); /* 配置GPIO为推挽输出 */
GPIO_WriteBit(GPIOx, GPIO_Pin, Bit_SET); /* PWM = 1 */
return;
}
bsp_ConfigTimGpio(GPIOx, GPIO_Pin, TIMx, _ucChannel); /* 使能GPIO和TIM时钟,并连接TIM通道到GPIO */
/*-----------------------------------------------------------------------
system_stm32f4xx.c 文件中 void SetSysClock(void) 函数对时钟的配置如下:
HCLK = SYSCLK / 1 (AHB1Periph)
PCLK2 = HCLK / 2 (APB2Periph)
PCLK1 = HCLK / 4 (APB1Periph)
因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 = SystemCoreClock / 2;
因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = PCLK2 x 2 = SystemCoreClock;
APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM6, TIM12, TIM13,TIM14
APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11
----------------------------------------------------------------------- */
if ((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM9) || (TIMx == TIM10) || (TIMx == TIM11))
{
/* APB2 定时器 */
uiTIMxCLK = SystemCoreClock;
}
else /* APB1 定时器 */
{
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; /* 自动重装的值 */
}
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = usPeriod;
TIM_TimeBaseStructure.TIM_Prescaler = usPrescaler;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0000; /* TIM1 和 TIM8 必须设置 */
TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = (_ulDutyCycle * usPeriod) / 10000;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable; /* only for TIM1 and TIM8. */
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; /* only for TIM1 and TIM8. */
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; /* only for TIM1 and TIM8. */
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; /* only for TIM1 and TIM8. */
if (_ucChannel == 1)
{
TIM_OC1Init(TIMx, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIMx, TIM_OCPreload_Enable);
}
else if (_ucChannel == 2)
{
TIM_OC2Init(TIMx, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIMx, TIM_OCPreload_Enable);
}
else if (_ucChannel == 3)
{
TIM_OC3Init(TIMx, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIMx, TIM_OCPreload_Enable);
}
else if (_ucChannel == 4)
{
TIM_OC4Init(TIMx, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(TIMx, TIM_OCPreload_Enable);
}
TIM_ARRPreloadConfig(TIMx, ENABLE);
/* TIMx enable counter */
TIM_Cmd(TIMx, ENABLE);
/* 下面这句话对于TIM1和TIM8是必须的,对于TIM2-TIM6则不必要 */
if ((TIMx == TIM1) || (TIMx == TIM8))
{
TIM_CtrlPWMOutputs(TIMx, ENABLE);
}
}
函数中略有瑕疵, /* 配置TIM定时更新中断 (Update) */后的处理有问题,一个是重复处理,这个不影响,一个是定时器与定时器中断没有对应上。
通过将不同定时器同一类别参数进行封装,在这两个函数中进行调用,使不同定时器的配置融合在同一个函数中,整齐统一而又互不干扰。
|
|