STM32自学笔记(八)输入捕获

原理讲解

输入捕获模式可以用来测量脉冲宽度或者测量频率。

STM32的定时器,除了TIM6和TIM7, 其他定时器都有输入捕获功能。STM32 的输入捕获,简单的说就是通过检测 TIMx_CHx上的 边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器计数器的值(TIMx_CNT) 存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。同时还可以配置 捕获时是否触发中断/DMA 等。

脉宽计算方法

本章我们用到 TIM5_CH1 来捕获高电平脉宽,也就是要先设置输入捕获为上升沿检测,记 录发生上升沿的时候 TIM5_CNT 的值。然后配置捕获信号为下降沿捕获,当下降沿到来时,发 生捕获,并记录此时的 TIM5_CNT 值。这样,前后两次 TIM5_CNT 之差,就是高电平的脉宽, 同时 TIM5 的计数频率我们是知道的,从而可以计算出高电平脉宽的准确时间。

配置步骤

通过输入捕获,来获取TIM5_CH1(PA)上的高电平脉冲宽度

1)使能时钟

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //使能 TIM5 时钟  
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //使能 GPIOA 时钟 

2)GPIO初始化

(和前几篇博客省略)

3)初始化TIM5,设置ARR和PSC

在开启了 TIM5 的时钟之后,我们要设置 ARR 和 PSC 两个寄存器的值来设置输入捕获的自动重装载值和计数频率。通过库函数 TIM_TimeBaseInit 实现,不再赘述看代码。

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure; 
TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值  
TIM_TimeBaseStructure.TIM_Prescaler =psc;  //设置预分频值      
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // TDTS = Tck_tim 
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM 向上计数模式 
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根据指定的参数初始化 Tim5 

4)配置输入捕获模式

TIM_ICInitTypeDef  TIM5_ICInitStructure;  
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择输入端 IC1 映射到 TI1 上 
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获 
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到 TI1 上 
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;  //配置输入分频,不分频,还有2,4,8分														 //频可选  
TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波 
TIM_ICInit(TIM5, &TIM5_ICInitStructure); 

5)使能捕获和更新中断

因为我们要捕获的是高电平信号的脉宽,所以,第一次捕获是上升沿,第二次捕获时下降 沿,必须在捕获上升沿之后,设置捕获边沿为下降沿,同时,如果脉宽比较长,那么定时器就 会溢出,对溢出必须做处理,否则结果就不准了。这两件事,我们都在中断里面做,所以必须开启捕获中断和更新中断。

这里我们使用定时器的开中断函数 TIM_ITConfig 即可使能捕获和更新中断:

TIM_ITConfig( TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断和捕获中断 

6)设置中断分组,编写中断服务函数 (函数里怎么写很重要,放在下面单独讲解)

设置中断分组的方法前面多次提到这里我们不做讲解,主要是通过函数 NVIC_Init()来完成。分组完成后,我们还需要在中断函数里面完成数据处理和捕获设置等关键操作,从而实现高电平脉宽统计。在中断服务函数里面,跟以前的外部中断和定时器中断实验中一样,我们在中断开始的时候要进行中断类型判断,在中断结束的时候要清除中断标志位。

使用到的函数在上面的实验已经讲解过,分别为 TIM_GetITStatus()函数和 TIM_ClearITPendingBit()函数。

if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET){}//判断是否为更新中断 
if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET){}//判断是否发生捕获事件 
TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update);//清除中断和捕获标志位 

7)使能定时器(设置 TIM5 的 CR1 寄存器)

最后,必须打开定时器的计数器开关, 启动 TIM5 的计数器,开始输入捕获。

TIM_Cmd(TIM5,ENABLE );  //使能定时器 5 

通过以上 6 步设置,定时器 5 的通道 1 就可以开始输入捕获了。

中断服务函数

u8  TIM5CH1_CAPTURE_STA=0; //输入捕获状态           
u16 TIM5CH1_CAPTURE_VAL; //输入捕获值 
//⑤定时器 5 中断服务程序   
void TIM5_IRQHandler(void) 
{   
    if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获(第7位为0)才执行   0x80: 1000 0000
    {      
        if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET) //检测是否发生更新中断  
        {         
            if(TIM5CH1_CAPTURE_STA&0X40)      //已经捕获到高电平了(之前设置的高电平捕获)
            { 										//0x40: 0100 0000
                if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//定时器溢出,计数器(STA低6位)溢出
                {      								//0x3F: 0011 1111
                    TIM5CH1_CAPTURE_STA|=0X80;    //直接标记为成功捕获了一次,STA最高位置1 
                    TIM5CH1_CAPTURE_VAL=0XFFFF;     //16位计数器全部置1(计满数)
                }
                else 								//定时器发生溢出,但计数器未溢出
                    TIM5CH1_CAPTURE_STA++;    		//对溢出次数进行计数(STA低6位)
            }     
        } 
        if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)        //捕获 1 发生捕获事件  
        {   
            if(TIM5CH1_CAPTURE_STA&0X40)        //已经捕获到上升沿,现在捕获到一个下降沿
                								//为什么这里捕获到的是下降沿?看下面else
            {          
                TIM5CH1_CAPTURE_STA|=0X80;      //标记成功捕获到一次上升沿    
                TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);       //读取此时定时器的值
                TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //设置为上升沿捕获   
            }
            else                  				//还未开始,第一次捕获上升沿 (
                	//逻辑是先进入这个else,才会有机会跑上面的if  
            {    
                TIM5CH1_CAPTURE_STA=0;          //清空    
                TIM5CH1_CAPTURE_VAL=0;     
                TIM_SetCounter(TIM5,0);    
                TIM5CH1_CAPTURE_STA|=0X40;      //标记捕获到了上升沿       
                TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //设置为下降沿捕获
            }        
        }                       
    }     
    TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位 
} 

此函数用到了两个全局变量,用于辅助实现 高电平捕获。其中 TIM5CH1_CAPTURE_STA,是用来记录捕获状态,该变量类似我们在 usart.c 里面自行定义的USART_RX_STA寄存器(其实就是个变量,只是我们把它当成一个寄存器那样来使用)。TIM5CH1_CAPTURE_STA 各位描述如表所示

 

另外一个变量TIM5CH1_CAPTURE_VAL,则用来记录捕获到下降沿的时候,TIM5_CNT的值。

捕获高电平脉宽的思路:

首先,设置 TIM5_CH1捕获上升沿,这在 TIM5_Cap_Init函数执行的时候就设置好了,然后等待上升沿中断到来,当捕获到上升沿中断, 此时如果 TIM5CH1_CAPTURE_STA的第 6 位为 0,则表示还没有捕获到新的上升沿,就先把 TIM5CH1_CAPTURE_STATIM5CH1_CAPTURE_VALTIM5_CNT 等清零,然后再设置TIM5CH1_CAPTURE_STA的第 6 位为 1,标记捕获到高电平,最后设置为下降沿捕获,等待下降沿到来。如果等待下降沿到来期间,定时器发生了溢出,就在TIM5CH1_CAPTURE_STA里面对溢出次数进行计数,当最大溢出次数来到的时候,就强制标记捕获完成(虽然此时还没有捕获到下降沿)。当下降沿到来的时候,先设置 TIM5CH1_CAPTURE_STA的第 7 位为 1,标记成功捕获一次高电平,然后读取此时的定时器值到 TIM5CH1_CAPTURE_VAL 里面,最后设置为上升沿捕获,回到初始状态。 这样,我们就完成一次高电平捕获了,只要TIM5CH1_CAPTURE_STA的第 7 位一直为 1, 那么就不会进行第二次捕获,我们在main函数处理完捕获数据后,将TIM5CH1_CAPTURE_STA 置零,就可以开启第二次捕获。 这里我们还使用到一个函数 TIM_OC1PolarityConfig来修改输入捕获通道 1 的极性的。相信这个不难理解:

void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity) 

要设置为上升沿捕获,则为:

  TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //设置为上升沿捕获

还有一个函数用来设置计数器寄存器值,这个同样很好理解:

  TIM_SetCounter(TIM5,0); 

上行代码的意思就是计数值清零。

主函数

extern u8  TIM5CH1_CAPTURE_STA;  //输入捕获状态          
extern u16 TIM5CH1_CAPTURE_VAL;   //输入捕获值   
int main(void)  
{     
    u32 temp=0;   
    delay_init();          //延时函数初始化     
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);    //设置 NVIC 中断分组 2   
    uart_init(115200);        //串口初始化波特率为 115200   
    LED_Init();      //LED 端口初始化   
    TIM3_PWM_Init(899,0);   //不分频。PWM 频率=72000/(899+1)=80Khz   
    TIM5_Cap_Init(0XFFFF,72-1); //以 1Mhz 的频率计数      
    while(1)  
    {    
        delay_ms(10);   
        TIM_SetCompare2(TIM3,TIM_GetCapture2(TIM3)+1);   
        if(TIM_GetCapture2(TIM3)==300) TIM_SetCompare2(TIM3,0);          
        if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿   
        {    
            temp=TIM5CH1_CAPTURE_STA&0X3F;    //溢出次数
            temp*=65536;			  //溢出时间总和    
            temp+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间    
            printf("HIGH:%d us\r\n",temp);    //打印总的高电平时间    
            TIM5CH1_CAPTURE_STA=0;    //开启下一次捕获   
        } 
    }  
}

保留了PWM章节的内容,TIM3用于PWM输出控制LED由暗变亮。

通过设置TIM5_Cap_Init(0XFFFF,72-1,将 TIM5_CH1 的捕获计数器设计为 1us 计数一次,并设置重装 载值为最大,所以我们的捕获时间精度为 1us

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《STM32自学笔记第3版》是一本关于STM32微控制器的自学教程。该书深入介绍了STM32微控制器的原理、应用和编程方法。 本书第3版增加了最新的STM32系列微控制器的内容,包括了更多实际应用的案例和项目。读者通过该书可以学习到如何使用STM32微控制器进行各种应用开发,如控制系统、嵌入式系统、通讯系统等。 本书首先对STM32微控制器的硬件结构进行了详细的介绍,包括了芯片的内部结构、引脚的功能和特性。然后,通过具体的实验项目,教授了STM32的基本编程方法和技巧。读者可以通过这些实验,了解STM32的各种功能模块的使用方法,如ADC、USART、SPI等。同时,还介绍了如何使用STM32CubeMX和Keil MDK等常用的开发工具进行项目开发。 此外,本书还对STM32的外设扩展进行了介绍,如通过I2C总线连接外部设备,通过CAN总线实现通讯等。读者可以学习到如何通过外设扩展,实现更复杂的应用系统。 总的来说,《STM32自学笔记第3版》是一本系统、全面的STM32自学教程。通过学习该书,读者可以深入了解STM32微控制器,并掌握其在各种应用领域的开发方法。无论是初学者还是有一定STM32开发经验的人都可以从中获益。 ### 回答2: 《STM32自学笔记 第3版》是一本适合自学STM32开发板的参考书籍。本书以STM32微控制器为基础,详细介绍了STM32的硬件结构和软件开发环境。作者结合自身经验和实际案例,将复杂的知识点以简洁明了的方式呈现,使读者能够快速入门。 第3版的内容相比前两版有所扩充和更新。首先,在硬件方面,本书详细介绍了STM32的引脚布局和外设接口,包括GPIO、USART、I2C、SPI等,使读者能够充分了解STM32的基本硬件结构和功能。 其次,在软件方面,本书提供了详细的开发环境配置和编程指南。包括了Keil MDK开发环境的安装和使用、编译、调试和下载等操作步骤,并且给出了一些常见问题的解决方法。同时,作者还介绍了如何使用STM32的标准外设库进行编程,包括GPIO控制、中断处理、定时器、串口通信等。 除此之外,本书还介绍了一些实际应用案例,以帮助读者更好地理解和应用所学知识。例如,如何使用STM32控制LED灯、驱动液晶显示屏、读取温度传感器数据等。 总体而言,本书是一本系统全面的STM32自学教程。通过学习本书,读者可以了解STM32的基本原理和应用,掌握STM32的硬件配置和软件开发,从而能够独立完成STM32的项目开发。无论是初学者还是有一定基础的开发者都可以从本书中获得很大的收益。 ### 回答3: 《STM32自学笔记第3版》是一本专门介绍如何自学STM32开发的书籍。本书主要针对初学者,通过详细的讲解和实践项目的演示,帮助读者快速上手STM32开发。 书中首先介绍了STM32系列微控制器的基本知识,包括硬件架构、外设功能和寄存器的使用等。对于没有接触过STM32的读者来说,这一部分对于理解后面的内容非常重要。 接着,书中从简单的LED控制开始,逐步引导读者学习各种外设的使用,如GPIO、定时器、UART等。同时,每个外设的使用都配有具体的实例代码和详细的注解,方便读者理解和实践。 书中还介绍了STM32开发中常用的开发工具和环境配置方法。从芯片选择、开发板选购到软件安装和项目配置,都有详细的指导。同时,书中还提供了一些调试技巧和常见问题的解答,帮助读者避开一些容易遇到的坑。 最后,书中还介绍了一些常用的外设应用案例,如按键控制、LCD显示、温湿度传感器等。通过这些案例,读者可以更好地理解STM32的应用场景和开发思路,提升自己的技能水平。 总的来说,《STM32自学笔记第3版》是一本适合学习STM32开发的入门书籍。通过系统完整的内容和实例演示,读者可以快速掌握STM32的基本知识和开发技巧。无论是初学者还是有一定经验的开发者,都可以从中获得实际的帮助和启示。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值