STM32F103五分钟入门系列(十五)输入捕获(精雕细琢-.-)
Posted 自信且爱笑‘
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32F103五分钟入门系列(十五)输入捕获(精雕细琢-.-)相关的知识,希望对你有一定的参考价值。
学习板:STM32F103ZET6
参考:
STM32F103五分钟入门系列(十五)输出比较(PWM输出)+各类测试
STM32F103五分钟入门系列(五)按键实验(库函数+寄存器)
一、输入捕获简介
接触过Arduino的朋友应该知道,在Arduino中pulseIn()可以返回高电平、低电平持续时间,如以下代码:
int pin = 7;
unsigned long duration;
void setup()
{
pinMode(pin, INPUT);
}
void loop()
{
duration = pulseIn(pin, HIGH);;
}
本博通过输入捕获同样可以获取到输入脉冲的高低电平持续时间。那怎么来实现呢?
在STM32F1中,除了基本定时器TIM6和TIM7,其它定时器都具有输入捕获功能。通过检测对应通道TIMx_CHx 上的边沿信号,来获取电平跳变。如获取到上升沿后,记录下此时定时器的值(TIMx_CNT),再一次捕获到下降沿(TIM1~5、TIM8需要算法,不支持双边沿检测,本博(六)5中有说明)后记录下此时定时器的值,两者之间的差为定时器在一个高电平持续时间内计数的次数,这个次数除以定时器的时钟频率就得到了高电平持续时间。
检测到本次下降沿后记录定时器的值,到下次上升沿到来之时再次记录定时器的值,两者之差除以定时器时钟频率得到输入脉冲的低电平持续时间。
需要注意的是:当低电平、高电平持续时间很长,定时器多次重装载后才得到下一次电平跳变,此时就需要记录定时器重装载次数,否则会到导致计算结果出错。
基于上述思想,接下来从寄存器、库函数及举例测试来深入了解输入捕获的相关内容
二、输入捕获相关寄存器
1、自动重装载寄存器(TIMx_ARR)
该寄存器是16位寄存器,用来重装载计数器的初值,最大为0xffff。
2、 预分频器(TIMx_PSC)
该寄存器为16位寄存器,用来设置定时器时钟的。我们知道定时器2~7搭载在APB1外设上,初始状态下(系统时钟72MHZ、AHB预分频系数1、APB1预分频系数2、APB2预分频系数1),APB1时钟为36MHZ、APB2时钟为72MHZ。通过该寄存器设置预分频系数后得到定时器的时钟频率(默认状态TIM1 ~TIM8输入时钟都为72MHZ)。
该寄存器16位有效,即预分频系数为0~0xffff,即预分频系数可以为0 ~65535。如将该寄存器赋值为7199,则定时器的时钟频率为72MHZ/7200=10KHZ。
需要注意的是,当该寄存器为0时表示不分频,即分频因子为1,所以真正的分频因子是:该寄存器的值+1
3、捕获/比较模式寄存器 1、2(TIMx_CCMR1、TIMx_CCMR2)(滤波重点说明)
以捕获/比较模式寄存器 1(TIMx_CCMR1)为例说明,TIMx_CCMR2类似。
这个寄存器上一博客STM32F103五分钟入门系列(十五)输出比较(PWM输出)+各类测试中涉及到了,所以输入捕获的内容也比较好理解。
位1:0
①位1:0=01,CC1通道被配置为输入,IC1映射在TI1上,如下图所示:
②位1:0=10,CC1通道被配置为输入,IC1映射在TI2上,如下图所示:
③位1:0=11,CC1通道被配置为输入,IC1映射在TRC上,如下图所示:
可见该寄存器用来设置IC1通道来源的,同理CCMR1高8位的位9:8设置IC2的通道来源、CCMR2的位1:0设置IC3的通道来源、CCMR2的位9:8设置IC4的通道来源。
位3:2
这两位是设置检测频率的。当CC1E=’0’(TIMx_CCER寄存器中),即关闭了OC1输入,这两位就会复位。
位3:2=00:无预分频器,捕获输入口上检测到的每一个边沿都触发一次捕获;
位3:2=01:每2个事件触发一次捕获;
位3:2=10:每4个事件触发一次捕获;
位3:2=11:每8个事件触发一次捕获。
我们知道,当在对应通道识别到上升沿或下降沿时就会发生一次更新事件。如果这两位被设置为00,则每一次更新事件都捕获一次,记录定时器此时的值,同01、10、11。
位7:4
理解IC1F[3:0]之前,先明白各时钟关系:
默认状态下TIM1~ 8输入时钟为72MHZ。再经过预分频寄存器PSC设置分频作为定时器时钟:72MHZ/(1 ~65536)
这个时钟是用来计数,也只用来计数,与滤波、采样没有直接关系。
接下来就是滤波器(采样)频率=fDTS和采样频率fSAMPLING。
滤波(采样)频率=fDTS在CR1寄存器位9:8定义
可以看到:
①当CKD[1:0]=00时,滤波器(采样)频率=定时器时钟=72MHZ/(1 ~65536)
②当CKD[1:0]=01时,滤波器(采样)频率=定时器时钟×2=72MHZ/(1 ~65536)×2
③当CKD[1:0]=10时,滤波器(采样)频率=定时器时钟×4=72MHZ/(1 ~65536)×4
再回到CCMR1寄存器:
再强调一下,采样跟计数是两个线程,没有关联!
可以看到当IC1F[3:0]取不同值时,对输入信号的采样频率为滤波器(采样)频率/n。(注意是n,不是N)。而这个N也非常关键,表示采样几个周期。
为了方便理解,我们仔细的再写一遍:
1)位7:4=0000,无滤波器,以fDTS采样。
①若CR1寄存器位9:8—>CKD[1:0]=00,即fDTS = fCK_INT,则通道1以定时器时钟×1的频率捕获输入。
②若CR1寄存器位9:8—>CKD[1:0]=01,即fDTS = fCK_INT×2,则通道1以定时器时钟×2的频率捕获输入。
③若CR1寄存器位9:8—>CKD[1:0]=10,即fDTS = fCK_INT×4,则通道1以定时器时钟×4的频率捕获输入。
2)位7:4=0001,采样频率fSAMPLING=fCK_INT,N=2
①若CR1寄存器位9:8—>CKD[1:0]=00,即fDTS = fCK_INT×1,则通道1以定时器时钟fCK_INT的频率捕获输入。但是当捕获到上升沿后,还要以这个采用频率(fCK_INT)捕获2次,若都为高电平,才表示上升沿捕获。当捕获到下降沿后,还要以这个采样频率(fCK_INT)捕获2次,若都为低电平,才表示下降沿捕获。
②若CR1寄存器位9:8—>CKD[1:0]=01,即fDTS = fCK_INT×2,则通道1以定时器时钟fCK_INT的频率捕获输入。但是当捕获到上升沿后,还要以这个采用频率(fCK_INT)捕获2次,若都为高电平,才表示上升沿捕获。当捕获到下降沿后,还要以这个采样频率(fCK_INT)捕获2次,若都为低电平,才表示下降沿捕获。
③若CR1寄存器位9:8—>CKD[1:0]=10,即fDTS = fCK_INT×4,则通道1以定时器时钟fCK_INT的频率捕获输入。但是当捕获到上升沿后,还要以这个采用频率(fCK_INT)捕获2次,若都为高电平,才表示上升沿捕获。当捕获到下降沿后,还要以这个采样频率(fCK_INT)捕获2次,若都为低电平,才表示下降沿捕获。
…
…
…
3)位7:4=0111,采样频率fSAMPLING=fDTS/4,N=8
①若CR1寄存器位9:8—>CKD[1:0]=00,即fDTS = fCK_INT×1,则通道1以定时器时钟/4的频率捕获输入。但是当捕获到上升沿后,还要以这个采样频率(fDTS/4=tCK_INT/4)捕获8次,若都为高电平,才表示上升沿捕获。当捕获到下降沿后,还要以这个采用频率(fDTS/4=fCK_INT/4)捕获8次,若都为低电平,才表示下降沿捕获。
②若CR1寄存器位9:8—>CKD[1:0]=01,即fDTS = fCK_INT×2,则通道1以定时器时钟/2的频率捕获输入。但是当捕获到上升沿后,还要以这个采用频率(fDTS/4=tCK_INT/2)捕获8次,若都为高电平,才表示上升沿捕获。当捕获到下降沿后,还要以这个采用频率(fDTS/4=tCK_INT/2)捕获8次,若都为低电平,才表示下降沿捕获。
③若CR1寄存器位9:8—>CKD[1:0]=10,即fDTS = fCK_INT×4,则通道1以定时器时钟×1的频率捕获输入。但是当捕获到上升沿后,还要以这个采用频率(fDTS/4=fCK_INT)捕获8次,若都为高电平,才表示上升沿捕获。当捕获到下降沿后,还要以这个采用频率(fDTS/4=fCK_INT)捕获8次,若都为低电平,才表示下降沿捕获。
…
…
…
4)位7:4=1110,采样频率fSAMPLING=fDTS/32,N=6
①若CR1寄存器位9:8—>CKD[1:0]=00,即fDTS = fCK_INT×1,则通道1以定时器时钟/32的频率捕获输入。但是当捕获到上升沿后,还要以这个采样频率(fDTS/32=tCK_INT/32)捕获6次,若都为高电平,才表示上升沿捕获。当捕获到下降沿后,还要以这个采用频率(fDTS/32=fCK_INT/32)捕获6次,若都为低电平,才表示下降沿捕获。
②若CR1寄存器位9:8—>CKD[1:0]=01,即fDTS = fCK_INT×2,则通道1以定时器时钟/16的频率捕获输入。但是当捕获到上升沿后,还要以这个采用频率(fDTS/32=tCK_INT/16)捕获6次,若都为高电平,才表示上升沿捕获。当捕获到下降沿后,还要以这个采用频率(fDTS/32=tCK_INT/16)捕获6次,若都为低电平,才表示下降沿捕获。
③若CR1寄存器位9:8—>CKD[1:0]=10,即fDTS = fCK_INT×4,则通道1以定时器时钟/8的频率捕获输入。但是当捕获到上升沿后,还要以这个采用频率(fDTS/32=fCK_INT/8)捕获6次,若都为高电平,才表示上升沿捕获。当捕获到下降沿后,还要以这个采用频率(fDTS/32=fCK_INT/8)捕获6次,若都为低电平,才表示下降沿捕获。
…
…
…
滤波的目的:在接收到外部脉冲输入后,可能会因为噪声使得某一时刻有一个冲激,如果不多次检测,这个冲激就会被检测为上升沿,造成干扰。
剩下的位15:8位设置通道2,CCMR2寄存器位7:0设置通道3、位15:8设置通道4,与通道1设置一样,不在赘述。
4、捕获/比较使能寄存器(TIMx_CCER)
位0
使能通道1,该位置1后(文档错误)使能通道1捕获。
位1
该位很重要,设置捕获事件发生在上升沿还是下降沿
当位1=0,捕获发生在上升沿
当位1=1,捕获发生在下降沿
剩下的位5:4、位9:8、位13:12分别设置通道2、通道3、通道4,与通道1设置一样,不在赘述。
5、DMA/中断使能寄存器(TIMx_DIER)
该寄存器使能各类请求
上图位4:0从低位到高位分别:使能定时器更新中断、使能CH1中断、使能CH2中断、使能CH3中断、使能CH4中断。
位6使能定时器触发中断(更新中断、触发中断区分),剩下的就是对DMA请求的使能,之后博客会专门总结DMA,这里先不总结了。
6、控制寄存器 1(TIMx_CR1)
该寄存器上一博客STM32F103五分钟入门系列(十五)输出比较(PWM输出)+各类测试,主要是对定时器的配置,这里也不在赘述。
7、 捕获/比较寄存器 1~4(TIMx_CCR1 ~4)
这个寄存器上一博客也总结过,不过只总结了输出比较的部分,现总结一下输入捕获。
若将通道设置为输入模式,则该寄存器存储上一次事件(上升沿或下降沿)时计数器的值。
CCR2、CCR3、CCR4分别对应CH2、CH3、CH4,不再赘述。
三、输入捕获相关库函数
1、输入捕获设置函数TIM_ICInit()
参数:
第一个参数:TIM_TypeDef* TIMx,选择哪个定时器
第二个参数:TIM_ICInitTypeDef* TIM_ICInitStruct
①TIM_Channel
选择通道,四个通道:
②TIM_ICPolarity
选择是上升沿捕获、下降沿捕获还是上升沿、下降沿都捕获(TIM1~5、TIM8不支持双边沿检测)
③TIM_ICSelection
选择通道来源,第一个参数已经选定了通道,TIM_ICSelection选择通道的来源,如下图通道1的三种来源:
若选择参数:TIM_ICSelection_DirectTI,则由TI1作为IC1来源。
若选择参数:TIM_ICSelection_IndirectTI,则由TI2作为IC1来源。
若选择参数:TIM_ICSelection_TRC,则由TRC作为IC1来源。
当然若第一个参数选择通道2,则:
若选择参数:TIM_ICSelection_DirectTI,则由TI2作为IC1来源。
若选择参数:TIM_ICSelection_IndirectTI,则由TI1作为IC1来源。
若选择参数:TIM_ICSelection_TRC,则由TRC作为IC1来源。
④TIM_ICPrescaler
设置捕获次数,是对CCMR寄存器位3:2的操作。
参数对于关系一目了然,表示每X个事件触发一次捕获。
⑤TIM_ICFilter
选择滤波器,是对CCMR寄存器位7:4的设置
这个参数自己写就行,0~0xf之间的数。需要注意的是这个值不能随便写,比如捕获上升沿时,高电平持续时间很短,大概2个计数器时钟周期,此时就不能N>1了,毕竟还没采样完,高电平持续时间就结束了。
2、设置捕获通道极性函数TIM_OC1PolarityConfig()
参数:
第一个参数:TIM_TypeDef* TIMx,选择哪个定时器
第二个参数 uint16_t TIM_OCPolarity
设置极性,即设置捕获发生在上升沿还是下降沿,是对CCER寄存器位1的操作。
位1为0时捕获发生在上升沿
位1位1时捕获发生在下降沿
3、使能捕获和更新中断函数TIM_ITConfig()
参数:
第一个参数: TIM_TypeDef* TIMx,选择哪个定时器
第二个参数: uint16_t TIM_IT,选择通道x中断、更新中断,是对DIER寄存器的位0和为4:1、位6(触发中断这里不用)操作。
第三个参数:FunctionalState NewState,使能ENABLE
4、获取中断和捕获状态标志函数TIM_GetITStatus()、TIM_GetFlagStatus()
这个函数在STM32F103五分钟入门系列(十二)定时器中断
中总结过,而且在那篇博客中还强调了相比于TIM_GetITStatus(),TIM_GetFlagStatus()函数多了是否重复捕获。不过TIM_GetITStatus()更加严谨。
函数体这里就不再总结了。主要总结一下捕获相关的用法:
判断是否为更新中断:
if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET){}//判断是否为更新中断
判断是否发生捕获事件:
if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET){}//判断是否发生捕获事件
5、清除中断和捕获标志位函数TIM_ClearITPendingBit()、TIM_ClearFlag()
这个函数在STM32F103五分钟入门系列(十二)定时器中断
中也总结过,且强调过,重复捕获标记只有TIM_ClearFlag()函数拥有这个功能。其它东西两个函数都一样。
主要看一下用法:
清除中断标志位:
TIM_ClearITPendingBit(TIM5, TIM_IT_Update);//清除中断标志位
清除捕获标志位:
IM_ClearITPendingBit(TIM5, TIM_IT_CC1);//清除捕获标志位
四、输入捕获编程顺序
1、使能定时器时钟RCC_APB1PeriphClockCmd()、RCC_APB2PeriphClockCmd()
定时器2~7挂载在APB1上,定时器1和8挂载在APB2上。如使能定时器5:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //使能 TIM5 时钟
2、使能GPIO时钟RCC_APB2PeriphClockCmd()
如使能GPIOA:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能 GPIOA 时钟
3、使能复用时钟
4、重映射设置(如需要)
5、初始化定时器TIM_TimeBaseInit()
用TIM_TimeBaseInit()设置重装载、预分频系数、向上、相信计数模式
6、输入捕获参数设置 TIM_ICInit()
使用 TIM_ICInit()设置输入捕获通道、输入捕获极性、通道来源、分频系数、滤波器
7、使能捕获中断、更新中断TIM_ITConfig()
通过TIM_ITConfig()来使能定时器更新中断、通道捕获中断
8、设置中断分组NVIC_Init()
通过NVIC_Init()函数设置中断优先级、初始化中断。
9、使能定时器TIM_Cmd()
10、编写中断服务函数TIMx_IRQHandler()
五、例1+测试
1、题
使用定时器5通道2(PA1复用)检测PA1引脚输入PWM在1s内上升沿次数。其中输入的PWM为定时器4通道2输出500HZ、占空比为70%的PWM信号。(PB7复用)
硬件连接:将PA1与PB7引脚用飞线连接起来。
2、分析
定时器4通道2输出500HZ、占空比为50%的PWM信号参考上一博客,这里不再分析。
检测1s内上升沿次数,则可把定时器设置为1s。定时器5通道1为PA1的复用功能引脚。定时器5输入时钟为72MHZ,若将预分频系数设置为7199,则定时器5时钟为10kHZ,计数一次的时间为0.1ms,则可将重装载值设置为1s/0.1ms-1=9999。
设置定时器5通道1为捕获通道,且每个上升沿都触发。输入信号500HZ,则一个周期2ms,占空比为70%的话,每个高电平持续时间为1.4ms,为定时器时钟的14倍,即在一个高电平持续时间定时器计数14、一个低电平持续时间定时器计数6,次。所以可以用定时器时钟的大小作为采样频率,且采样2次作为滤波。
定时器每1s进入一次中断服务函数,则可在中断服务函数中输出1s内上升沿次数,采用串口输出,利用串口调试助手检测串口输出。
3、输出比较代码
输出比较代码上一篇博客都总结过,现直接附代码:
pwm.h代码:
//pwm.h
#ifndef _PWM_
#define _PWM_
void PWM_Init(void);
#endif
pwm.c代码:
//pwm.c
//pwm.c
#include "pwm.h"
#include "stm32f10x.h"
void PWM_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_TimeBaseInitStructure.TIM_Period=19;
TIM_TimeBaseInitStructure.TIM_Prescaler=7199;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure);
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OC2Init(TIM4,&TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);
TIM_Cmd(TIM4, ENABLE);
}
4、输入捕获代码
(1)cap.h代码编写
cap.h固定格式:
//cap.h
#ifndef _CAP_
#define _CAP_
void CAP_Iint(void);
#endif
(2)cap.c代码编写
经查资料,发现定时器5通道2为PA1复用引脚,所以需设置PA1时钟和复用。
使能定时器5时钟、PA1时钟和复用时钟:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
设置PA1,为浮空输入:
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
初始化定时器5:
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period=9999;
TIM_TimeBaseInitStructure.TIM_Prescaler=7199;
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure);
输入捕获参数设置:
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;
TIM_ICInitStructure.TIM_ICFilter=0x0001; //采样频率=定时器频率,N=2
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_BothEdge;
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;
TIM_ICInit(TIM5,&TIM_ICInitStructure);
使能捕获输入中断、更新中断:
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC2, ENABLE);
设置中断分组:
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//主函数
NVIC_InitStructure.NVIC_IRQChannel=TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
使能定时器:
TIM_Cmd(TIM5,ENABLE);
(3)中断服务函数
void TIM5_IRQHandler(void)
{
if(TIM_GetITStatus(TIM5, TIM_IT_CC2)!=RESET)//捕获到上升沿
{
Rise_count++;
}
TIM5->SR&=~TIM_IT_CC2;//注意清零,当捕获事件发生时该位由硬件置’1’,它由软件清’0’或通过读TIMx_CCR1清’0’
//这里没有读CCR1寄存器,所以需要手动清零
if(TIM_GetITStatus(TIM5, TIM_IT_Update)!=RESET)//发生了更新中断
{
printf("Rise_count:%d \\r\\n",Rise_count);
Rise_count=0;
}
TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
}
}
解释一下:
定时器5进行输入捕获,因为使能了通道2的中断,所以每次捕获后后发生中断,进入中断服务函数,并且对Rise_count++,需要注意的是:由于没有对CCR1寄存器进行读操作,所以捕获中断标志不能自动清零,需要手动去清零,所以才有以下代码:
TIM5->SR&=~TIM_IT_CC2;
同时由于使能了更新中断,所以每计数1s需要自动重装载初值,发生更新事件,进入中断服务函数,所以当发生更新事件后,说明1s计数结束,输出上升沿次数Rise_count并重新归零。
无论是捕获事件中断还是更新事件中断,进入中断服务函数后都需要清除中断标志。
(4)完整代码
//cap.c
#include "cap.h"
#include "stm32f10x.h"
#include "usart.h"
u16 Rise_count=0;
void CAP_Iint()
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period=9999;
TIM_TimeBaseInitStructure.TIM_Prescaler=7199;
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure);
TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter=0x0001;//2次检测
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;
TIM_ICInit(TIM5,&TIM_ICInitStructure);
NVIC_InitStructure.NVIC_IRQChannel=TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC2, ENABLE);
TIM_Cmd(TIM5,ENABLE);
}
void TIM5_IRQHandler(void)
{
if(TIM_GetITStatus(TIM5, TIM_IT_CC2)!=RESET)//捕获到下降沿
{
Rise_count++;
}
TIM5->SR&=~TIM_IT_CC2;//注意清零,当捕获事件发生时该位由硬件置’1’,它由软件清’0’或通过读TIMx_CCR1清’0’
//这里没有读CCR1寄存器,所以需要手动清零
if(TIM_GetITStatus(TIM5, TIM_IT_Update)!=RESET)//发生了更新中断
{
printf("Rise_count:%d \\r\\n",Rise_count);
Rise_count=0;
}
TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
}
5、主函数代码
主函数中直接初始化各类函数即可
//main.c
#include "stm32f10x.h"
#include "pwm.h"
#include "cap.h"
#include "usart.h"
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2)STM32F103五分钟入门系列(十五)输出比较(PWM输出)+各类测试
STM32F103(二十五)完美解决USART发送接收floatu16u32数据