赞
踩
定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
16位计数器,预分频器,自动重装寄存器的时基本单元可以实现最大的59.65s的定时
定时器不仅具备中断功能,而且还包含内外时钟源选择,输入捕获,输出比较,编码器口
定时器主要分为3大类,高级定时器(TIM1,TIM8) 通用定时器(TIM2~TIM5) 基本定时(TIM6,TIM7)
不同芯片所带的资源不同,因此具体所带资源应该查看所对应的芯片手册。
高级定时器:拥有通用定时器的全部功能,并额外拥有重复计数器,死区生成,互补输出,刹车输入等功能
通用定时器:拥有基本定时器的所有功能,并且额外具有内外时钟源选择,输入捕获,输出比较,编码器接口,主从触发模式等功能
基本定时器:定时中断,主模式触发DAC的功能
定时器中断:定时中断是在受到时钟源的影响下,实现CNT计数器的增长,在增长的同时与自动重装寄器(ARR)相比较,当计数器达到自动重装寄存器的值时,会使CNT计数器清0,并且发出一个中断信号,以实现定时器中断的目标。
在定时器中断时,我们通常需要打开定时器的内部时钟,并且为定时器选择时钟源(选择内部时钟源)。使其在内部模式的状态下工作,此时我们也需要初始化时基单元。将时基单元的参数配置成我们实现功能所需要的参数。然后就时配置配置中断实现功能了。
对于定时器时基单元的参数选择:
计数器溢出频率:也就是计数器计完一个过程的频率,换句话说也就是计数器达到ARR触发中断的频率,通过这样也就可以得到他的周期,也就是定时器定的时间。CK_PSC也就是定时器时钟源的时钟频率。
//定时器初始化函数 void TIM_Init() { // 1.第一步打开定时器的时钟,使用RCC_APB1PeriphClockCmd函数打开TIM2资源 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //2.第二步将时钟资源设为内部时钟源 TIM_InternalClockConfig(TIM2); //3.第三步配置时基单元,设置一个结构体来对其赋值 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; // TIM_CKD_DIV1:不分频,即输入时钟不分频。这意味着定时器的时钟频率等于输入时钟的频率。例如,如果输入时钟是72MHz,那么定时器的时钟频率也是72MHz。这样可以保持最高的定时器分辨率,但也意味着定时器的计数速度较快。 //TIM_CKD_DIV2:除以2分频。定时器的时钟频率为输入时钟的一半。这可以减慢定时器的计数速度,使得定时器的周期变长。 //TIM_CKD_DIV4:除以4分频。定时器的时钟频率为输入时钟的四分之一。这进一步减慢了定时器的计数速度,使得定时器的周期更长。 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1 ; TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up ; TIM_TimeBaseInitStructure.TIM_Period=(10000-1); TIM_TimeBaseInitStructure.TIM_Prescaler=(7200-1); TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0; TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure); /*中断输出配置*/ TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除定时器更新标志位 //TIM_TimeBaseInit函数末尾,手动产生了更新事件 //若不清除此标志位,则开启中断后,会立刻进入一次中断 //如果不介意此问题,则不清除此标志位也可 TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //开启TIM2的更新中断 /*NVIC中断分组*/ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2 //即抢占优先级范围:0~3,响应优先级范围:0~3 //此分组配置在整个工程中仅需调用一次 //若有多个中断,可以把此代码放在main函数内,while循环之前 //若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置 /*NVIC配置*/ NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量 NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //选择配置NVIC的TIM2线 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC线路使能 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //指定NVIC线路的抢占优先级为2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC线路的响应优先级为1 NVIC_Init(&NVIC_InitStructure); //将结构体变量交给NVIC_Init,配置NVIC外设 /*TIM使能*/ TIM_Cmd(TIM2, ENABLE); //使能TIM2,定时器开始运行 } 定时器中断函数 //打开定时器二的中断函数 void TIM2_IRQHandler(void) { //判断定时器中断的标志位是否就绪,判断是否为更新中断 if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET) { num++; //清楚中断定时标志 TIM_ClearITPendingBit(TIM2, TIM_IT_Update); } } 在这段代码中设置了ARR为(10000-1),PCS为(7200-1)这样的配置也就达到了实现1s定时发生中断的功能
定时器的外部中断如定时器的基本结构图可知,定时器的外部中断需要选择一个外部时钟源,同时需要搭配GPIO口来使用,实现定时器外部中断的功能。
//定时器初始化函数 void TIM_Init() { // 1.第一步打开定时器的时钟,使用RCC_APB1PeriphClockCmd函数打开TIM2资源,并且打开GPIOA的时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //2.第二步将时钟资源设为内部时钟源,选着不分频外部时钟,选择上升有效 TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0); /*GPIO初始化*/ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0引脚初始化为上拉输入 //3.第三步配置时基单元,设置一个结构体来对其赋值 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; // TIM_CKD_DIV1:不分频,即输入时钟不分频。这意味着定时器的时钟频率等于输入时钟的频率。例如,如果输入时钟是72MHz,那么定时器的时钟频率也是72MHz。这样可以保持最高的定时器分辨率,但也意味着定时器的计数速度较快。 //TIM_CKD_DIV2:除以2分频。定时器的时钟频率为输入时钟的一半。这可以减慢定时器的计数速度,使得定时器的周期变长。 //TIM_CKD_DIV4:除以4分频。定时器的时钟频率为输入时钟的四分之一。这进一步减慢了定时器的计数速度,使得定时器的周期更长。 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1 ; TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up ; TIM_TimeBaseInitStructure.TIM_Period=9; TIM_TimeBaseInitStructure.TIM_Prescaler=0; TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0; TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure); /*中断输出配置*/ TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除定时器更新标志位 //TIM_TimeBaseInit函数末尾,手动产生了更新事件 //若不清除此标志位,则开启中断后,会立刻进入一次中断 //如果不介意此问题,则不清除此标志位也可 TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //开启TIM2的更新中断 /*NVIC中断分组*/ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2 //即抢占优先级范围:0~3,响应优先级范围:0~3 //此分组配置在整个工程中仅需调用一次 //若有多个中断,可以把此代码放在main函数内,while循环之前 //若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置 /*NVIC配置*/ NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量 NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //选择配置NVIC的TIM2线 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC线路使能 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //指定NVIC线路的抢占优先级为2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC线路的响应优先级为1 NVIC_Init(&NVIC_InitStructure); //将结构体变量交给NVIC_Init,配置NVIC外设 /*TIM使能*/ TIM_Cmd(TIM2, ENABLE); //使能TIM2,定时器开始运行 }
OC(Output Compare)输出比较 输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形 每个高级定时器和通用定时器都拥有4个输出比较通道 高级定时器的前3个通道额外拥有死区生成和互补输出的功能。
PWM波
1. 什么是PWM:PWM简称脉冲宽度调制,即在一个周期内存在不同极性的电平状态。
2. PWM频率:是指一秒钟内从高电平时间在到低电平时间,再从低电平跳到高电平的瞬间次数,也就是一秒钟内有多少个PWM的周期。f = T / 1(HZ)。
\3. PWM周期:是指一秒钟内从高电平时间在到低电平时间,T = f / 1(s)。
4. PWM占空比:是指一个周期内高电平时间和总时间的比值。
例如:PWM的周期为1ms,高电平时间为0.5ms,低电平时间为0.5ms,则频率就为1kHz,占空比就为百分之五十。
void Init_PWM(void) { //第一步打开定时器TIM2时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //打开GPIO时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //配置GPIO口结构体 GPIO_InitTypeDef GPIO_InitStructure; //设置GPIO结构体对象的各个参数,选着复用推挽输出PWM波 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); //第二步选择时钟源 TIM_InternalClockConfig(TIM2); //第三步配置定时器参数 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //参数选择不分屏 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1 ; //计数模式选着向上计数 TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_Period=100-1; //arr TIM_TimeBaseInitStructure.TIM_Prescaler=720-1; //psc TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0; //初始化定时器参数 TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure); //第四步配置输出比较参数 TIM_OCInitTypeDef TIM_OCInitStruct; TIM_OCStructInit(&TIM_OCInitStruct); //选着模式为PWm1模式 TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1; //表示在PWM波1模式下小于比较值时输出高电平,高于这个时输出低电平 TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High; TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable; TIM_OCInitStruct.TIM_Pulse=50;//ccr //初始化 TIM_OC1Init(TIM2,&TIM_OCInitStruct); }
此时更改cnt的值就可以修改占空了
IC(Input Capture)输入捕获 输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数 每个高级定时器和通用定时器都拥有4个输入捕获通道 可配置为PWMI模式,同时测量频率和占空比 可配合主从触发模式,实现硬件全自动测量
#include "stm32f10x.h" // Device header //本驱动程序是实现输入捕获的功能,实现输入捕获测算频率 void IC_Init(void) { //打开GPIO RCC时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //打开定时器三 RCC时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //配置GPIO口结构体 GPIO_InitTypeDef GPIO_InitStructure; //设置GPIO结构体对象的各个参数,选着复用推挽输出PWM波 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); TIM_InternalClockConfig(TIM3); //选择TIM3为内部时钟,若不调用此函数,TIM默认也为内部时钟 //设置时机单元 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInitStruct.TIM_Period=65536 - 1; TIM_TimeBaseInitStruct.TIM_Prescaler=(72-1); TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct); /*输入捕获初始化*/ TIM_ICInitTypeDef TIM_ICInitStructure; //定义结构体变量 TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择配置定时器通道1 TIM_ICInitStructure.TIM_ICFilter = 0xF; //输入滤波器参数,可以过滤信号抖动 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //极性,选择为上升沿触发捕获 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //捕获预分频,选择不分频,每次信号都触发捕获 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //输入信号交叉,选择直通,不交叉 TIM_ICInit(TIM3, &TIM_ICInitStructure); //将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道 /*选择触发源及从模式*/ TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); //触发源选择TI1FP1 TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); //从模式选择复位 //即TI1产生上升沿时,会触发CNT归零 /*TIM使能*/ TIM_Cmd(TIM3, ENABLE); } /** * 函 数:获取输入捕获的频率 * 参 数:无 * 返 回 值:捕获得到的频率 */ uint32_t IC_GetFreq(void) { return 1000000 / (TIM_GetCapture1(TIM3) + 1); //测周法得到频率fx = fc / N,这里不执行+1的操作也可 }
#include "stm32f10x.h" // Device header //本驱动程序是实现输入捕获的功能,实现输入捕获测算频率 void IC_Init(void) { //打开GPIO RCC时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //打开定时器三 RCC时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //配置GPIO口结构体 GPIO_InitTypeDef GPIO_InitStructure; //设置GPIO结构体对象的各个参数,选着复用推挽输出PWM波 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); //设置时机单元 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInitStruct.TIM_Period=65536 - 1; TIM_TimeBaseInitStruct.TIM_Prescaler=0; TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct); /*输入捕获初始化*/ TIM_ICInitTypeDef TIM_ICInitStructure; //定义结构体变量 //初始化输入捕获结构体,因为输入捕获的结构不是每一个都有用,因此将输入捕获结构体需要使用函数初始化一下 TIM_ICStructInit(&TIM_ICInitStructure); TIM_ICInitStructure.TIM_Channel=TIM_Channel_1 ; TIM_ICInitStructure.TIM_ICFilter=0xF; TIM_ICInit(TIM3,&TIM_ICInitStructure); TIM_ICInitStructure.TIM_Channel=TIM_Channel_2 ; TIM_ICInitStructure.TIM_ICFilter=0xF; TIM_ICInit(TIM3,&TIM_ICInitStructure); TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); //配置编码器模式以及两个输入通道是否反相 //注意此时参数的Rising和Falling已经不代表上升沿和下降沿了,而是代表是否反相 //此函数必须在输入捕获初始化之后进行,否则输入捕获的配置会覆盖此函数的部分配置 //设置编码器喊数有直接的函数调用 /*TIM使能*/ TIM_Cmd(TIM3, ENABLE); } /** * 函 数:获取输入捕获的频率 * 参 数:无 * 返 回 值:捕获得到的频率 */ uint32_t IC_GetFreq(void) { return 1000000 / (TIM_GetCapture1(TIM3) + 1); //测周法得到频率fx = fc / N,这里不执行+1的操作也可 } //测量占空比的计算 uint32_t PWM_zhankongbi(void) { return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1); //占空比Duty = CCR2 / CCR1 * 100,这里不执行+1的操作也可 } int16_t En_Get(void) { /*使用Temp变量作为中继,目的是返回CNT后将其清零*/ int16_t Temp; Temp = TIM_GetCounter(TIM3); TIM_SetCounter(TIM3, 0); return Temp; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。