今天的定时器也是我们常用的一个32外设,PWM更不用说,电机的转速调节,家里的电灯亮度调节基本上用到的就是通过PWM。
一、定时器
1.定义
设置等待时间,到达后则执行指定操作的硬件。
2.STM32F407的定时器有以下特征
具有基本的定时功能,也有PWM输出(灯光亮度控制、电机的转速)、脉冲捕获功能(红外捕捉)。
2个高级控制定时器、10个通用定时器和2个基本定时器
a.高级控制定时器(TIM1和TIM8)
具有16位定时器功能,也具有PWM输出高级控制功能,一个定时器支持多路的PWM输出。
b.通用定时器(TIM2到TIM5)具有16位定时功能,也具有PWM输出控制功能,一个定时器支持1路的PWM输出。
c.通用定时器(TIM9到TIM14)具有16位定时功能,也具有PWM输出控制功能,一个定时器支持1路的PWM输出。
d.基本定时器(TIM6和TIM7)注:TIM是TIMER英文的缩写。
二、定时器初始化
1.选择时钟源,并初始化定时器分频值与定时时间
/* TIM3 clock enable ,定时器3时钟使能*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/* Time base configuration ,定时器基本配置*/
TIM_TimeBaseStructure.TIM_Period = (10000/1000)-1; //定时时间的设置[非常重要],中断频率为1000Hz,也就是定时时间为1ms
TIM_TimeBaseStructure.TIM_Prescaler = 8400-1; //预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,也称之为二次分频,当前是1分频,说白了不分频,不降低频率
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数的方法
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //初始化
2. 中断的配置
/* TIM Interrupts enable,使能定时器3更新中断事件,也代表说定时已经到达的事件 */
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
/* TIM3 enable counter,使能定时器3工作 */
TIM_Cmd(TIM3, ENABLE);
3. 中断服务函数的编写
void TIM3_IRQHandler(void)
{
static uint32_t cnt=0;
//是否已经有更新中断事件
if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)
{
//添加用户代码
cnt++;
if(cnt>=500)
{
cnt =0;
PFout(9)^=1;
}
//清空标志位,告诉CPU我已经完成中断处理
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
三、PWM概述
1、定义频率要大于25Hz,灯光的亮度的变化是跟着占空比而变化,占空比越大,灯光越暗;占空比越小,灯光越亮。
四、程序设计
1.原理图
不同的定时器,输出通道的数目都有所不一样。在高级定时器输出多路的PWM,输出频率是一样的,但是占空比可以是不一样的,能够由TIM_SetComparex[1-3]来进行设置不同的通道占空比!2.配置频率
/* TIM14 clock enable ,定时器14时钟使能*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE);
/* Time base configuration ,定时器基本配置,TIM_Period是计数值*/
TIM_TimeBaseStructure.TIM_Period = (10000/100)-1; //输出频率为100Hz,(10000/100)-1得到的结果就是计数值。
TIM_TimeBaseStructure.TIM_Prescaler = 8400-1; //预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,也称之为二次分频,当前是1分频,说白了不分频,不降低频率
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数的方法
TIM_TimeBaseInit(TIM14, &TIM_TimeBaseStructure); //初始化
/* PWM1 Mode configuration: Channel1 ,让PWM的通道1工作在模式1*/
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //PWM模式1,在递增模式下,只要 TIMx_CNT < TIMx_CCR1,通道 1 便为有效状态(高电平),否则为无效状态(低电平)。
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //允许输出
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //有效的时候,输出高电平
TIM_OC1Init(TIM14, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable); //自动重载初值,不断输出PWM脉冲
TIM_ARRPreloadConfig(TIM14, ENABLE); //自动重载初值使能
/* TIM14 enable counter,使能定时器14工作 */
TIM_Cmd(TIM14, ENABLE);
4.配置引脚的复用功能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
/* 配置PF9引脚为输出模式 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //第9根引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能模式,使用引脚的第二功能
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽模式,增加驱动电流
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //设置IO的速度为100MHz,频率越高性能越好,频率越低,功耗越低
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //不需要上拉电阻
GPIO_Init(GPIOF, &GPIO_InitStructure);
//将PF9引脚连接到定时器14
GPIO_PinAFConfig(GPIOF, GPIO_PinSource9, GPIO_AF_TIM14);
2. 计数值与比较值之间的关系
void tim14_init(void)
{
/* TIM14 clock enable ,定时器14的时钟使能*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE);
/* Time base configuration ,定时器的基本配置,用于配置定时器14输出方波的频率为100Hz*/
TIM_TimeBaseStructure.TIM_Period = (10000/100)-1; //10000是10KHz,是定时器3的时钟源,100就是定时器14输出方波的频率
TIM_TimeBaseStructure.TIM_Prescaler = 8400-1; //预分频,也就是说第一次分频,降低频率
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //第二次分频,当前是实现1分频,也就是不降低频率
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数方法,从0开始计算
TIM_TimeBaseInit(TIM14, &TIM_TimeBaseStructure);
/* Output Compare Timing Mode configuration: Channel1 ,让PWM工作是模式1*/
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //PWM1模式1:只要 TIMx_CNT < TIMx_CCR1,通道 1 便为有效状态,否则为无效状态。
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //允许输出PWM
//TIM_OCInitStructure.TIM_Pulse = CCR1_Val; //待会有专门的函数用于设置比较值,说白就是设置占空比
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //通道1有效的状态为高电平
TIM_OC1Init(TIM14, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable); //定时器14自动重装载初值,那个初值指的是TIM_TimeBaseStructure.TIM_Period,当计数值加到99的时候,又重新从0加到99.
TIM_ARRPreloadConfig(TIM14, ENABLE); //自动重装载初值使能
/* TIM14 enable counter,使能定时器14工作,开始计数 */
TIM_Cmd(TIM14, ENABLE);
}
int main(void)
{
uint32_t pwm_cmp=0;
/* GPIOA GPIOE GPIOF硬件时钟使能,就是让GPIOA GPIOE GPIOF工作 */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* 配置PF9 为复用功能模式 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //第9 引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,增强驱动能力,引脚的输出电流更大
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //引脚的速度最大为100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //没有使用内部上拉电阻
GPIO_Init(GPIOF, &GPIO_InitStructure);
/* Connect TIM14 pins to AF9 */
GPIO_PinAFConfig(GPIOF, GPIO_PinSource9, GPIO_AF_TIM14);//PF9引脚连接到TIM14
//配置系统定时器基于168MHz进行8分频,得到21MHz
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
//设置中断优先级的分组为2,那么支持设置4个中断抢占优先级、4个中断响应优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
tim14_init();
while(1)
{
//不断增加比较值,渐亮还是渐灭?答案:这是渐灭过程
for(pwm_cmp=0; pwm_cmp<=100; pwm_cmp++)
{
TIM_SetCompare1(TIM14,pwm_cmp);
delay_ms(20);
}
}
}