STM32F4一共有三种14个定时器。(12个16位的,2个32位的),STM32F1系列只有8个16位的。
高级定时器:TIM1、TIM8。通常用于特定领域和专业需求用户使用的精密计时工具,通常适用于需要精度更高的领域。通常可以精确到毫秒或更小的时间单位,并具有更复杂的逻辑和算法。
通用定时器:TIM2、TIM5、TIM3、TIM4,TIM9~TIM14。
基本定时器:TIM6、TIM7,没有捕获等通道,用作简单定时。
STM32通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)等。
定时器的计数模式:
(看的正点原子视频以这几个通用定时器为例讲解的,这里笔记就记了这几个通用定时器特点。)
自动装载计数器(TIMx_CNT)。
16 位可编程(可以实时修改)预分频器(TIMx_PSC):计数器时钟频率的分频系数 为 1~65535 之间的任意数值。
使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几微秒到几毫秒间调整。STM32的每个通用定时器都是完全独立的,没有互相共享的资源。
输入捕获;输出比较;PWM生成;可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。(应用较少)
输入捕获:输入捕获功能可以用来接收外部的数字信号,用于测量脉冲宽度、频率或周期。以下是在STM32F4上实现输入捕获的步骤:
1. 初始化定时器:在使用输入捕获前,需要先初始化使用的定时器。对于输入捕获来说,一般选择适合的定时器模式和对应的输入模式。比如可以选择TIM_IC_Mode_TI1来启用输入捕获功能。
2. 配置定时器输入:外部数字信号需要连接到定时器的输入端口上。在STM32F4上,定时器的输入端口有很多,例如PA0、PA1、PA2等,可以根据需要选择合适的端口进行连接。连接后,需要将输入端口配置为“捕获输入模式”来启用输入捕获。另外,还需要对输入信号的上升沿或下降沿进行配置,以便在捕获时获取正确的时间戳。
3. 开始输入捕获:在完成上述配置后,可以开始启用输入捕获功能。通过使用STM32F4的输入捕获库函数,可以捕获输入信号的上升沿或下降沿,并获取相应的时间戳。
4. 计算时间差:捕获到时间戳后,就可以计算时间差了。时间差等于两个时间戳之间的差值,可以用来测量脉冲宽度、频率或周期等。
输出比较:该功能可以用于产生PWM信号、输出脉冲或者触发其他的事件。可以实现精确的PWM波形产生和高速脉冲输出等应用。以下是在STM32F4上实现输出比较的步骤:
1. 初始化定时器:在使用输出比较前,需要先初始化使用的定时器。对于输出比较,一般选择适合的定时器模式和对应的输出模式。比如可以选择TIM_OCMode_PWM1或TIM_OCMode_PWM2模式来启用输出比较功能。
2. 配置输出通道:STM32F4的定时器一般有多个输出通道,每个输出通道都可以单独控制。 在输出比较之前,需要对输出通道进行相应的配置。在每个输出通道上,可以配置输出模式、极性、预分频器和周期数等。
3. 设置比较值:在开始使用输出比较功能之前,需要先设置比较值。比较值可以是固定的值,也可以是动态变化的值。设置比较值的方式包括直接设置、加载缓存器或者使用DMA进行传输等。
4. 启动定时器:在完成上述配置和设置后,就可以启动定时器和输出比较功能了。在输出比较期间,定时器会根据设定的输出模式、极性和比较值等参数,动态输出相应的电平和波形。
PWM生成:PWM生成采用定时器的输出比较模式实现。可以选择边缘对齐模式或中间对齐模式来控制PWM的产生,同时可以通过定时器的单脉冲模式来输出单个脉冲。以下是在STM32F4上实现PWM生成的步骤:
1. 初始化定时器:在使用PWM生成前,需要先初始化使用的定时器。通常情况下,选择定时器模式和输出模式,并配置相应的时钟和分频等参数。
2. 配置输出通道:STM32F4的定时器一般有多个输出通道,每个输出通道都可以单独控制。 在PWM生成之前,需要对输出通道进行相应的配置。比如,在边缘对齐模式下,需要选择PWM1模式或PWM2模式,并配置输出通道的极性和预分频等参数。
3. 设置占空比:在完成输出通道的配置后,需要设置PWM的占空比。占空比一般是一个介于0到1之间的值。可以通过直接设置寄存器的方式或者使用库函数来完成占空比的设置。
4. 启动定时器:在完成上述配置和设置后,就可以启动定时器并开始产生PWM信号。如果需要产生单个脉冲,可以在单脉冲模式下启动定时器,然后停止定时器。
外部信号(TIMx_ETR)控制外部信号控制定时器或者定时器之间同步:使用外部信号控制定时器可以实现根据外部事件来触发定时器中断或者定时器计数,而使用定时器之间的同步电路可以实现多个定时器运行频率的同步。使用外部信号控制定时器和定时器之间的同步电路是STM32F4上比较少用的功能。
外部信号控制定时器:在STM32F4中,定时器的ETR输入端口可以用于接收外部信号来控制定时器。当外部信号到达时,定时器的计数器会根据设定的极性和模式来触发更新或者捕获事件。通过配置外部信号的极性和模式,可以实现对定时器中断和计数的控制,例如计数的启动、停止、复位等操作。
定时器之间的同步电路:STM32F4系列的定时器具有复杂的同步电路结构,可实现多个定时器之间的同步。在同步电路中,可以选择一个定时器作为同步源,然后将其他定时器的时钟信号与同步源进行同步。同步源可以是外部信号或另一个定时器的输出信号等。通过使用同步电路,可以实现多个定时器之间时钟频率的同步和相位控制等功能。
更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发);
触发事件(计数器启动、停止、初始化或者由内部/外部触发计数);
输入捕获和输出比较;
支持针对定位的增量(正交)编码器和霍尔传感电路
触发输入作为外部时钟或者按周期的电流管理。
时钟源部分:产生一个CK_PSC时钟来源供定时器使用。(有以下四种时钟源选择)
CK_PSC可以来自RCC的内部时钟(CK_INT)分频。(RCC内部时钟是APB1倍频得到的)
CK_PSC可以来自定时器的外部引脚:TIMx_ETR引脚(外部触发ETR)。
CK_PSC可以来自ITR0~4 内部触发 输入口:是由其他定时器通过TRGO输出,定时器级联得到。(定时器级联:一个定时器的输出可以作为另外一个定时器的输入)
CK_PSC可以来自TIMx_CH1,2,3,4等外部通道引脚外部产生TI1FP1、TI2FP2以及TI1F_ED。
时基单元部分:
CK_PSC经过一个PSC预分频器产生一个CK_CNT时钟作为CNT计数器的时钟,CNT计数器的计数属性(向上/下,递增/递减计数等)在触发控制器设置。
定时器的影子寄存器:用于保存定时器计数器当前计数值的寄存器,通常和定时器计数器一起使用,用于处理定时器中断。为避免在计数器更新的过程中产生中断,通常使用影子寄存器来保存当前计数值,中断处理程序在完成后再将寄存器值恢复到原先的值,这样就可避免在中断处理期间对原计数器造成干扰,确保定时器的精度和稳定性。需要确保中断处理程序能够正确地读取和恢复定时器的计数值。
在定时器运行中修改寄存器:如果上次ARR的值是200,通道1的比较寄存器CCR1值是100,产生占空比50%的PWM。此时若要改变PWM的频率,把ARR的值改为100,但CCR1的值还没来得及更改,那么占空比肯定会出问题,所以需要让他们同步修改。之前的ARR=200,CCR1=100,提高频率后ARR=100,CCR1=50,需要这两个寄存器值同步修改,最好还是让他们计数完一个周期后再修改,那么进入下一个周期ARR、CCR1同步修改过去,对PWM的占空比就没有一点影响了。为达此目的,先用一个寄存器把修改的值保存好(ARR_A=100,CCR1_A=50),一旦上一个周期结束,给一个信号,立即就把寄存器A的值赋值过去,立即生效,这样就完成了最理想的在定时器运行中修改寄存器的过程。
定时器框图中,有阴影的小方框,代表该功能对应的寄存器有其影子寄存器,也就是:PSC预分频器、自动重装载寄存器和4个通道的捕获/比较寄存器。有影子寄存器的寄存器实际上对应了两个寄存器:一个是用户可写入或读出数据的寄存器,称为preload register(预装载寄存器),另一个是用户看不见、但在操作中真正起作用的寄存器称为shadow register(影子寄存器)。我们修改的定时器周期、预分频系数、通道的比较值等都是修改的表面那个预装载寄存器,要让这个修改起作用,还要把预装载寄存器的值赋给影子寄存器才行。
从ARR预装载寄存器传送到影子寄存器,有两种方式,一种是立刻更新,一种是等触发事件之后更新;这两种方式主要取决于寄存器TIMx->CR1中的“APRE”位:APRE=0,当ARR值被修改时,同时马上更新影子寄存器的值;APRE=1,当ARR值被修改时,必须在下一次事件UEV发生后才能更新影子寄存器的值。
输入捕获部分:经过TIMx_CH1等引脚触发一定的功能,比如:信号从TIMx_CH1输入(被捕获),经过输入滤波器和边沿检测器,再经过一个预分频器(设定:触发几个边沿检测一次),每次捕获到之后,与CNT计数器中的值进行比较(比如:捕获到上升沿之后,记录下CNT计数器的值,当捕获到下降沿再记录一次CNT计数器的值,做差就可以得出一个高电平持续时间是多少。)
IC1、2、3、4可以分别通过软件设置将其映射到TI1、2、3、4;
4个16位捕捉比较寄存器可以编程用于存放检测到对应的每一次输入捕捉时计数器的值;
当产生一次捕捉,相应的CCxIF标志位被置1;同时若中断或DMA请求使能,则产生中断或DMA请求。
如果当CCxIF标志位已经为1,当又产生一个捕捉,则捕捉溢出标志位CCxOF将被置1。
输出比较部分:通过TIMx_CH1等通道引脚输出PWM波等。CNT计数器值(CNT计数器一直在计数)和捕获比较寄存器值进行比较可产生脉冲,脉冲的占空比是可调的(调节捕获/比较寄存器值)。
频率和占空比可以进行如下设定:一个自动重载寄存器用于设定PWM的周期;每个PWM通道有一个捕获/比较寄存器用于设定占空时间。
APB1时钟经过一个倍频得到CK_INT时钟也就是CK_PSC时钟。
X1:APB1分频系数是1,通用定时器的时钟CK_INT等于APB1时钟。(CK_INT=APB1 x1)
X2:APB1分频系数不是1,通用定时器的时钟CK_INT等于APB1时钟的2倍。(CK_INT=APB1 x2)
APB1的时钟是AHB时钟经过一个分频系数 x 产生的:AHB / x=APB1。
例如:在调用SystemInit()情况下:SYSCLK=168M,AHB=168M,分频系数是4,因此APB1时钟=AHB / 4=42M。因为APB1分频系数不是1,因此CK_INT的时钟是APB1时钟的2倍,因此CK_INT = APB1*2=84M。
最终:CK_INT经过 ÷ N的一个分频产生时钟CK_CNT。
设置计数到重装载值36会有计数器溢出,产生更新事件或者更新中断。CNT_EN使能。
向下计数到0会有计数器溢出,然后重装载到36。
时钟分频因子=1,ARR=6,向下计数到0会有一更新事件,从0再计数到6也会产生一更新事件。
计数器当前值寄存器TIMx_CNT:时基单元里的CNT计数器。
预分频寄存器TIMx_PSC:设置PSC预分频器分频的值。
自动重装载寄存器TIMx_ARR:配置时基单元里的自动重装载寄存器
控制寄存器1:TIMx_CR1,控制计数器计数方向、计数器使能。
DMA中断使能寄存器:TIMx_DIER。
void TIM_TimeBaseInit(TIM_TypeDef* TIMx,TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
结构体TIM_TimeBaseInitStruct组成:
typedef struct
{
uint16_t TIM_Prescaler; 预分频器,指定PSC值
uint16_t TIM_CounterMode; 设置计数模式(向上,向下)
uint16_t TIM_Period; 自动重装载寄存器,设置自动重装载值
uint16_t TIM_ClockDivision; 时钟分频因子
uint8_t TIM_RepetitionCounter; 高级定时器才有的控制重复计数器,指定重复计数次数
} TIM_TimeBaseInitTypeDef;
ARR-自动重装载值 PSC-预分频值 Tclk即CK_INT,一般为84M。
溢出时间公式:Tout=。
是计时频率,频率的倒数就是时间,也就是计1个数的时长。(ARR+1)是计数次数。
例如:设置向上计数,使用72MHz的主时钟,TIM_Prescaler = 7199,重装载值ARR = 4999。
计一个数的计数时间为:(7199+1)/72,000,000=0.0001s=0.1ms。
则定时器溢出时间为:(4999 + 1)*(7199 + 1) / 72,000,000 = 0.5s=500ms,即定时器计数器计满5000所需要的时长为500ms。
TIM_TimeBaseStructure.TIM_Period = 4999;
TIM_TimeBaseStructure.TIM_Prescaler =7199;
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);
使能定时器时钟: RCC_APB1PeriphClockCmd();
初始化定时器,配置ARR,PSC: TIM_TimeBaseInit();
开启定时器中断,配置NVIC: void TIM_ITConfig(); NVIC_Init();
使能定时器: TIM_Cmd();
编写中断服务函数: TIMx_IRQHandler();
PWM-脉冲宽度调制:是利用微处理器(单片机)的数字输出来对模拟电路进行控制的技术。简单说就是对脉冲宽度的控制。用到定时器的输出比较部分(定时器框图右下角部分)。PWM的功能有很多种,比如控制呼吸灯、控制直流电机或者舵机等驱动原件等。(比如呼吸灯即通过循环调整占空比来控制灯的由逐渐变亮和逐渐熄灭)
除了两个基本定时器TIM6、7以外,其他的定时器都可以用来产生 PWM 输出。高级定时器 TIM1 和 TIM8 可以同时产生7路的 PWM 输出。通用定时器也能同时产生4路的 PWM 输出。
如上:一个简单的 PWM 原理示意图。图中,我们假定定时器工作在向上计数 PWM模式。当 CNT
占空比:就是指在一个周期内,信号处于高电平的时间占据整个信号周期的百分比,例如方波的占空比就是50%。
定时器作为PWM输出时候,内部实现过程(以通道1为例):
从最左边 CNT 计数器的值与定时器的CCR1寄存器的值进行比较,进入输出模式控制器,通过TIMx_CCMR1寄存器的OC1M[2:0]位来配置PWM模式,之后进入一个选择器,由TIMx_CCER寄存器的CC1P位来设置输出极性,最后由TIMx_CCER寄存器的CC1E位来使能输出,然后通过OC1来输出PWM波。输出到通道引脚OC1。
CCR1:捕获比较(值)寄存器(x=1,2,3,4):设置比较值。
TIMx_CCMR1寄存器的 位6:4 OC1M[2:0]位:对于PWM方式下,用于设置PWM模式1【110】或者PWM模式2【111】
TIMx_CCER:CC1P位:输入/捕获1输出极性。0:高电平有效,1:低电平有效。
TIMx_CCER:CC1E位:输入/捕获1输出使能。0:关闭,1:打开。
PWM模式1的情况下,当前值小于比较值为有效电平。TIMx_CCER:CC1P位为0时,有效电平为高电平,输出1。
PWM模式2的情况下,当前值大于比较值为有效电平。TIMx_CCER:CC1P位为1时,有效电平为低电平,输出0。
例:PWM模式1,向上计数配置:
定时器PWM实验,初始化时基单元之后,还需要对输出通道进行初始化:
void TIM_OCxInit(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
typedef struct
{
uint16_t TIM_OCMode; //选择PWM模式(模式1或2)
uint16_t TIM_OutputState; //输出使能 OR失能
uint16_t TIM_OutputNState;//互补输出使能(使用较少)
uint16_t TIM_Pulse; //比较值,写CCRx
uint16_t TIM_OCPolarity; //比较输出极性
uint16_t TIM_OCNPolarity; //(使用较少)
uint16_t TIM_OCIdleState; //(使用较少)
uint16_t TIM_OCNIdleState; //(使用较少)
} TIM_OCInitTypeDef;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //PWM模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure. TIM_Pulse=100;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性 高
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据指定的参数初始化外设TIM3 OC2
void TIM_SetCompareX(TIM_TypeDef* TIMx, uint16_t Compare2);
TIM_SetCompareX,修改X的值选择不同通道
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
① 使能定时器14和相关IO口时钟:RCC_APB1PeriphClockCmd();
使能GPIOF时钟:RCC_AHB1PeriphClockCmd();
② 初始化IO口为复用功能输出。函数:GPIO_Init();
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能
③ GPIOF9复用映射到定时器14,把PF9用作定时器的PWM输出引脚,所以要重映射配置,
GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14);
④ 初始化定时器:ARR,PSC等:TIM_TimeBaseInit();
⑤ 初始化输出比较参数:TIM_OC1Iint();
⑥ 使能预装载寄存器: TIM_OC2PreloadConfig(TIM14,TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM14,TIM_OCPreload_Enable);
⑦ 使能定时器。TIM_Cmd();
⑧ 不断改变比较值CCRx,达到不同的占空比效果:TIM_SetCompare1();
通过检测TIMx_CHx(输入引脚)上的边沿信号,在边沿信号发生跳变(上升沿 / 下降沿)时,将当前定时器的值(TIM_CNT)存放到对应的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。
输入捕获单通道内部细节工作过程:
第一部分(滤波部分):设置输入捕获滤波器(通道1为例)
输入捕获1滤波器 ICIF[3:0],这个用来设置输入采样频率和数字滤波器长度。其中,内部时钟是定时器的输入频率(TIMxCLK),一般为 72Mhz,而 则是恨据TIMx_CR1寄存器的 CKD[1:0]的设置来确定的,如果 CKD[1:0]设置为 00,那么 = 。N 值就是滤波长度。举个简单例子:假设TIMx_CCMR1的 IC1F[3:0]=0011,并设置IC1 映射到通道1上,且为上升沿触发,那么在捕获到上升沿的时候,再以的频率,连续采样到8次通道1的电平,如果都是高电平,则说明确实是一个有效的触发,就会触发输入捕获中断(如果开启了的话)。这样可以滤除那些高电平脉宽低于 8个采样周期的脉冲信号,从而达到滤波的效果。我们不做滤波处理,所以设置 IC1F[3:0]=0000,只要采集到上升沿,就触发捕获。
第二部分:设置输入捕获极性(通道1为例)
TIMx_CCER的CC1P位设置是捕获上升沿还是捕获下降沿。
第三部分:设置捕获映射通道
第四部分:设置输入捕获分频器
TIMx_CCER的ICPS位设置每N个事件触发一次捕捉。比如:可设置成,每4次上升沿事件触发一次捕捉。
TIMx_CCER的CC1E位控制捕获/比较通道的使能 / 失能。
第五部分(中断部分):捕获到有效信号可以开启中断
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
typedef struct
{
uint16_t TIM_Channel; //通道
uint16_t TIM_ICPolarity; //输入捕获的极性
uint16_t TIM_ICSelection; //选择TI1映射到IC1~IC4
uint16_t TIM_ICPrescaler; //预分频
uint16_t TIM_ICFilter; //滤波
} TIM_ICInitTypeDef;
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM5_ICInitStructure.TIM_ICFilter = 0x00; //IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM5, &TIM5_ICInitStructure);
在四个通道中选择一个,设置通道极性。通常在初始化函数中已经设置了通道极性,此函数用于除初始化之外的修改。
void TIM_OCxPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
在四个通道中选择一个,确定上一次输入捕捉事件传输的计数值。
uint16_t TIM_GetCapturex(TIM_TypeDef* TIMx);
1.初始化定时器和通道对应IO的时钟;
2.初始化IO口,模式为复用; 调用函数: GPIO_Init(); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
3.设置引脚复用映射GPIO_PinAFConfig();
4.初始化定时器ARR,PSC。调用函数:TIM_TimeBaseInit();
5.初始化输入捕获通道。调用函数:TIM_ICInit();
6.如果要开启捕获中断。调用函数:TIM_ITConfig(); NVIC_Init();
7.使能定时器。调用函数:TIM_Cmd();
8.编写中断服务函数。调用函数:TIMx_IRQHandler()。
输入捕获用于测量脉冲宽度实验(以一个简单的脉冲输入为例):
先设置输入捕获为下降沿检测,记录发生下降沿时TIMx_CNT的值。然后配置捕获信号为上升沿捕获,当上升沿到来的时候发生捕获,并记录此时的TIMx_CNT的值。这样,前后两次TIMx_CNT的值之差就是低电平的脉宽。同时根据TIM的计数频率,我们就能知道低电平脉宽的准确时间。(同理可以测的高电平脉宽)
我们进行输入捕获,一旦捕捉到了上升沿,就设置计数器当前值为0,让它从0开始重新计数。但是如果脉冲的长度过于宽时。也就是,从0开始计数到自动重加载值一个循环结束了,脉冲还是没有结束。这种情况下,显然不能只记录一下最后的计数器当前值。
定义一个8位变量TIM5CH1_CAPTURE_STA。
bit5-0为捕捉高电平后定时器溢出的次数。每溢出一次,TIM5CH1_CAPTURE_STA加1。
捕获具体逻辑:TIM5_Cap_Init 函数执行的时候就设置好了,然后等待上升沿中断到来,当捕获到上升沿中断,此时如果 TIM5CH1_CAPTURE_STA 的第6位为0,则表示还没有捕获到新的上升沿,就先把TIM5CH1_CAPTURE_STA、TIM5CH1_CAPTURE_VAL 和 TIM5->CNT 等清零,然后再设置TIM5CH1_CAPTURE_STA 的第 6位为1,标记捕获到高电平,最后设置为下降沿捕获,等待下降沿到来。如果等待下降沿到来期间,定时器发生了溢出,就在TIM5CH1_CAPTURE_STA里面对溢出次数进行计数。当下降沿到来的时候,先设置 TIM5CH1_CAPTURE_STA 的第7位为1,标记成功捕获一次高电平,然后读取此时的定时器值到 TIM5CH1_CAPTURE_VAL 里面,最后设置为上升沿捕获,回到初始状态。
计算脉冲持续时间
计数溢出次数 × 计数器从0计数满的时间(0~ARR) + 计数器当前值(TIM5CH1_CAPTURE_VAL )
这样,就完成一次高电平捕获了,只要 TIMSCH1_CAPTURE_STA 的第7位一直为 1,那么就不会进行第二次捕获,我们在main 两数处理完捕获数据后,将TIM5CH1_CAPTURE_STA置零,就可以开启第二次捕获。