学习记录--输入捕获(超声波模块SR04)

一,所用模块HC-SR04C用法

引脚:VCC, GND 供电(+5V)

Trig:触发测距:给至少10us的高电平信号,模块自动发射8个40KHz的方波,自动检测是否有信号返回。(用一个普通输出口加延时即可实现触发)

Echo:返回信号:通过IO口ECHO输出一个高电平,高电平持续时间就是超声波从发射到返回的时间。(可以用定时器端口进行输入捕获,获取高电平的持续时间,以此来算出距离)

二,定时器输入捕获原理(截自正点原子HAL库开发指南)

三,CUBEMX配置

1,配一个IO口output

2,配置定时器输入捕获

3,打开TIM3的全局中断(用来处理溢出次数)

4,打开一个串口接收测距结果 

三,keil中代码

板级支持包:bsp_SR04.c

0,自定义的要用到的变量

float len=0;        //算出的距离
uint32_t time=0;//返回的高电平时间

//自定义记录输入捕获状态变量(在写中断回调时会用来做标记和计算):(8位)
//[7]:0,没有成功的捕获;1,成功捕获到一次.
//[6]:0,还没捕获到高电平;1,已经捕获到高电平了
//[5:0]:捕获低电平后溢出的次数

uint8_t      TIM3CH1_CAPTURE_STA;                            //输入捕获状态    
uint16_t    TIM3CH1_CAPTURE_VAL;                            //输入捕获值(TIM2是16位)

1,触发函数

//给至少10us的高电平信号:用延时函数实现
void my_trig(void)
{
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);
    HAL_Delay(1);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);    
}

2,写更新中断回调函数(每次定时器计数溢出时调用,记录溢出次数)

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if((TIM3CH1_CAPTURE_STA&0X80)==0)            //还未成功捕获完一次高电平脉宽(若完成捕获了就不用管计数的溢出了)
    {
        if(TIM3CH1_CAPTURE_STA&0X40)                //已经捕获到上升沿了(正处于脉冲中)
        {
            if((TIM3CH1_CAPTURE_STA&0X3F)==0X3F)    //高电平太长了(已经超过能统计的次数了)
            {                    
                TIM3CH1_CAPTURE_STA|=0X80;            //标记为成功捕获完一次高电平脉宽一次
                TIM3CH1_CAPTURE_VAL=10000;            //因为这一次STA没有++且保持和正常情况一致,故将VAL设置为装载值(max)
            }
            else TIM3CH1_CAPTURE_STA++;    //没有超过能统计的max的正常情况:记录脉冲过程溢出的次数
        }     
    }        
}

3,写捕获中断回调函数(每次捕获到输入沿时调用,函数中进行设置与置位)

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if((TIM3CH1_CAPTURE_STA&0X80)==0)				//还未捕获完
	//捕获完一次之后TIM3CH1_CAPTURE_STA会|=0X80
	//故若想重新开始捕获要自己在外面TIM2CH2_CAPTURE_STA=0开启下一次捕获
	{
		if(TIM3CH1_CAPTURE_STA&0X40)				//在捕获上升沿(else)里TIM3CH1_CAPTURE_STA|=0X40
																				//故此处表示捕获到一个下降沿 		
		{	  			
			TIM3CH1_CAPTURE_STA|=0X80;				//标记成功捕获到一次高电平脉宽
      TIM3CH1_CAPTURE_VAL=HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1);//获取当前的捕获值.
			TIM_RESET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1);   //一定要先清除原来的捕获极性设置
      TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//配置为上升沿捕获
		}
		else  										//还未开始,捕获上升沿
		{
			TIM3CH1_CAPTURE_STA=0;					//清空
			TIM3CH1_CAPTURE_VAL=0;
			TIM3CH1_CAPTURE_STA|=0X40;				//标记捕获到了上升沿
			__HAL_TIM_DISABLE(&htim3);      	//关闭定时器3
			__HAL_TIM_SET_COUNTER(&htim3,0);	//清除原来定时器的计数(定时器一开始就不断计数,从这里开始要重新计数才能算模块输出的高电平总时间)
			TIM_RESET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1);   //一定要先清除原来的设置
			TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);//定时器3通道1设置为下降沿捕获
			__HAL_TIM_ENABLE(&htim3);		//重新开启定时器3开始计数
		}		    
	}		
}

4,开启定时器捕获中断和更新中断

    HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);  
    __HAL_TIM_ENABLE_IT(&htim3,TIM_IT_UPDATE);  

5,printf重定向

6,main函数

  while (1)
  {
		HAL_Delay(1000);
		my_trig();
		
		if(TIM3CH1_CAPTURE_STA&0X80)           //成功捕获到了一次高电平
		{
			time=TIM3CH1_CAPTURE_STA&0X3F; 				//得到溢出次数
			time*=10000;		 	    	        			//溢出的计数次数总和
			time+=TIM3CH1_CAPTURE_VAL; 						//加上最后一次的计数值得到总的计数次数
			len=time*0.017;												//距离=计数次数*计数周期(1us)*声速(340*100cm/s)/2 
			TIM3CH1_CAPTURE_STA=0;          			//开启下一次捕获
			printf("get\r\n");
		}
		printf("LENGHT:%f CM\r\n",len);  //打印平均距离
							

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

测试效果:(还是比较准的)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值