【笔记】【STM32】定时器驱动超声波

之前参加比赛,自己写了一些传感器的驱动,不太确定网上是否有雷同的,给大家参考下。

模块用的是HC-SR06,比较普遍,首先看一下驱动原理,如下图:

  1. 将T引脚置高超过10us;
  2. 结束后探头将发送超声波信号并进入检测,同时拉高E引脚;
  3. 接收到反射波后拉低E引脚;

可知E引脚被拉高的时间是超声波的传输时间,根据声速即可计算距离。
在这里插入图片描述

在这里插入图片描述
STM32的实现方式还是有许多种的,如延时查询,获取系统节拍等,本文采用的定时器,以后有机会可以写一下其他方式的。

因为当时参加的项目功能较少,所以用资源比较奢侈,这里用了一个定时器的一个通道驱动T引脚,一个通道捕获E引脚。

思路比较简单,介绍一下代码。
配置是参考正点原子例程的, 用标准库配置的,一股原子味。

首先是定时器配置,具体参数定义可以自己看官方文档,修改成自己的:

void TIM3_Init(u16 arr,u16 psc)
{  
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_ICInitTypeDef  TIM3_ICInitStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	//外设时钟配置
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//使能定时器3时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟
	
	//映射GPIO
	GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);
	
	//E引脚输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_Init(GPIOC, &GPIO_InitStructure);
	GPIO_ResetBits(GPIOC,GPIO_Pin_0);
	
	//T引脚输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOC, &GPIO_InitStructure);
 
 	//定时器配置
  	TIM_TimeBaseStructure.TIM_Period = arr;
	TIM_TimeBaseStructure.TIM_Prescaler =psc;
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
	
	//输入捕获配置
	TIM3_ICInitStructure.TIM_Channel = TIM_Channel_3;
  	TIM3_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  	TIM3_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  	TIM3_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  	TIM3_ICInitStructure.TIM_ICFilter = 0x00;
  	TIM_ICInit(TIM3, &TIM3_ICInitStructure);
	
	//捕获中断配置
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	TIM_ITConfig(TIM3,TIM_IT_Update|TIM_IT_CC3,ENABLE);
	
	//输出比较配置 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
	TIM_OC4Init(TIM3, &TIM_OCInitStructure); 
	TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);

  	TIM_Cmd(TIM3,ENABLE );
}
void DISTANCE_INIT(){
	TIM3_Init(50000-1,72-1);			//重装载频率20HZ
	TIM_SetCompare4(TIM3,20);		//
	g_target_distance = 0;
}

这里解释一下:
首先定时器的频率计算公式是 72M / ((arr+1)*(psc+1))(72M是我的主频率)
然后设置计数器时钟分频到1M Hz,重装载频率20Hz,又设置了输出比较值是20。
这样的结果是定时器的定时精度为1 / 1M s,每秒自动启动超声波模块20次(输出比较每秒20次置20us的高电平)。
这里没必要设置成PWM模式,显然是多余的,而且不需要中断管理,利用输出比较的特性自动控制管脚高低。

接下来是输入捕获部分

void TIM3_IRQHandler(void)
{ 
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET){	    
		if(TIM3CH3_CAPTURE_STA&0X40)//已经捕获到高电平了
		{
				TIM3CH3_CAPTURE_STA = 0;//标记成功捕获了一次
				TIM3CH3_CAPTURE_VAL=0;
				TIM_OC3PolarityConfig(TIM3,TIM_ICPolarity_Rising);
		}	 
	}
	if (TIM_GetITStatus(TIM3, TIM_IT_CC3) != RESET)//发生捕获事件
	{	
		if(TIM3CH3_CAPTURE_STA&0X40)		//捕获到一个下降沿 		
		{	  			
			TIM3CH3_CAPTURE_STA|=0X80;		//标记成功捕获到一次上升沿
			TIM3CH3_CAPTURE_VAL=TIM_GetCapture3(TIM3);
			TIM_OC3PolarityConfig(TIM3,TIM_ICPolarity_Rising); //设置为上升沿捕获
		}
		else  								//还未开始,第一次捕获上升沿
		{
			TIM3CH3_CAPTURE_STA=0;			//清空
			TIM3CH3_CAPTURE_VAL=0;
			TIM_SetCounter(TIM3,0);
			TIM3CH3_CAPTURE_STA|=0X40;		//标记捕获到了上升沿
			TIM_OC3PolarityConfig(TIM3,TIM_ICPolarity_Falling);		//CC1P=1 设置为下降沿捕获
		}		    
	}
	//上面是修改正点原子的
	//下面计算并保存数据
	if(TIM3CH3_CAPTURE_STA & 0X80){
		if(TIM3CH3_CAPTURE_VAL < 1750 && TIM3CH3_CAPTURE_VAL > 50)
		{
			g_target_distance = TIM3CH3_CAPTURE_VAL * 1.72f;//1us 3.44mm 来回
			//printf("target distance :%d mm\r\n",g_target_distance );
		}
		else
		{
			g_target_distance = 0;
		}
		TIM3CH3_CAPTURE_STA = 0;
	}
  TIM_ClearITPendingBit(TIM3, TIM_IT_CC3|TIM_IT_Update); //清除中断标志位
}

接着对外开放一个接口获取g_target_distance,可以自己加滤波之类的。

这里再插两个个知识
为什么STM32会自动调用这个中断函数呢,是因为标准库内其实已经有这个同名函数了,且在中断向量表内指向了这个函数名。但是它被配置成weak函数,所以当我们自己写了同一名称的函数时,就取代了原本的函数入口。具体这里不展开介绍。
还有超声波模块需要较高电压(相对)驱动,但是我们直接接到5v上就能用,这是为什么呢?其实可以用类似MAX232芯片来驱动,可以参考这篇文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值