STM32超声波测距

在单片机编程中需要与其他模块进行通信时会经常用到IIC协议和SPI协议,对于新人来说,这两个协议理解起来简单但实际自己写底层协议的时候却很麻烦,参照着时序图问题还是很多,撸代码撸不下去索性就拿来直接用。

要写IIC和SPI协议的话主要还是要对时序图熟悉,而这里我觉得超声波测距(HC-SR04)这个小项目用来练习对时序图代码实现非常合适,本身这个底层协议并不难,很方便检查bug的所在,然后这个测距这个功能也非常实用,我觉得也会比较有兴趣吧。话不多说,这里我从思路到思路的实现来讲述超声波测距的实现过程。

本文排布如下

  1. 超声波测距模块硬件介绍
  2. 主要思路
  3. 实现过程

一、超声波测距模块的硬件介绍

STM32超声波测距_第1张图片

四个引脚,VCC和GND供电和接地,接下来是触发信号输入引脚Trig和回响信号输出引脚Echo。

Trig:针对这个模块来说Trig脚是输入,而我们在单片机上需要在这个引脚中输出一个10us以上的高电平,这时候就会驱动这个超声波模块发出声波。

Echo: 针对这个模块Echo是输出,接下来它会自动接收超声波,并且接收完后在Echo这个输出脚上输出一段高电平,这个高电平的时间就是声波发出并且反射回来所用的时间,所以我们在单片机中就需要读取这个引脚。

二、主要思路

STM32超声波测距_第2张图片
了解了Trig和Echo,对这个模块的工作原理基本上可以理解了,那么接下来就需要在单片机上完成Trig的触发信号、Echo接收信号。

  1. 初始化GPIO,使能总线和端口,由于Trig用作输出电平,而Echo用作读取电平,所以将Trig脚设置为推挽输出,Echo脚设置成浮空输入。初始化定时器,需要定时器来计时。
  2. 将Trig置为1高电平,再延时10us,之后将Trig复原为0低电平。这样就会让超声波模块内部发送触发信号然后发出超声波。
  3. 等待Echo变为1高电平,然后重载并开启定时器,等待Echo变为0低电平,最后定时器停止计数,读取TIM->CNT这个寄存器也就是计数次数。
  4. 计算可得距离,距离=高电平时间*声速(340m/s)/2,或者us/58=厘米。
  5. 通过串口发送或者液晶屏显示,获取到这个计算结果。

三、实现过程

此部分为SR04.c文件,实现了触发信号发送,获取回响信号的时间。

#include "SR04.h"
#include "stm32f10x.h"
#include "sys.h"
#include "delay.h"
#include "timer.h"

/*超声波测距模块HC-SR04
使用端口PF13,PF15
规定PF13为TRIG
PF15为ECHO
*/

#define TRIG PFout(13)
#define ECHO PFin(15)

void SR04_Init()
{
	RCC->APB2ENR|=1<<7;//使能F端时钟
	GPIOF->CRH&=0x0F0FFFFF;
	GPIOF->CRH|=0x40300000;//TRIG推挽输出,ECHO浮空输入
	TRIG=0;
}

/*发送一个10us的方波*/
void SR04_Trig()
{
	TRIG=0;
	delay_us(2);
	TRIG=1;
	delay_us(10);
	TRIG=0;
	ECHO=0;
}

/*等待*/
u16 SR04_Echo()
{
	while(ECHO!=1);//等待回响信号到来
	TIM3_Start();
	while(ECHO!=0);//等待回响信号结束
	return TIM3_End();//停止计时并返回计数值
}

此部分为timer.h的部分代码,实现初始化,开启计数,结束计数返回CNT寄存器的值也就是计数值,由于在我的思路中是用不到中断的,这里就注释掉了.

#include "stm32f10x.h"
#include "timer.h"
#include "led.h"
#include "sys.h"
#include "delay.h"


void TIM3_init(u16 arr,u16 psc)
{
	//NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC->APB1ENR|=1<<1;//APB1时钟使能
	
	TIM3->ARR=arr;
	TIM3->PSC=psc;
	
	TIM3->DIER|=1<<0;

	TIM3->CR1=0x00;//Ïȹرն¨Ê±Æ÷
	/*
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//ÏÈÓÅÏȼ¶0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;//´ÓÓÅÏȼ¶3
	NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn;
	
	NVIC_Init(&NVIC_InitStructure);
	*/
}

//开启定时器
void TIM3_Start()
{
	TIM3->CNT=0;//ÖØתÔØ

	TIM3->CR1=0x01;//¿ªÆô¼Æʱ
}

//停止计时器,并返回计数值
u16 TIM3_End()
{	
	TIM3->CR1=0x00;//¹Ø±Õ¼Æʱ
	
	return TIM3->CNT;//0.1msΪһ¸ö¼Æʱµã£¬Ëã³ö½á¹ûΪn¸ö0.1ms

}

最后是main函数,配置定时器分频系数为7200,也就是0.1ms计数一次,溢出的计数次数设置为5000,也就是计时500ms会溢出,意思就是不会启用定时器中断了,这样计时缺点就是精度不高.
总体流程就是按下按键,发送触发信号,获得在回响信号中的计时次数,然后根据公式算出距离,最后经过简单判断,通过串口输出,顺便亮一下灯提示一下.

#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "SR04.h"
#include "usart.h"
#include "timer.h"


int main(void)
{
	u16 cnt_100us=0;
	u16 lenth=0;
	delay_init();
	led_init();
	key_init();
	SR04_Init();
	uart_init(115200);
	TIM3_init(7199,4999);//分频7200,最大计数5000

	while(1)
	{
		if(PEin(4)==0)
		{
			SR04_Trig();
			cnt_100us=SR04_Echo();
			lenth=cnt_100us*1.7;
			if(lenth<1000)
				printf("距离为:%d cm\r\n",lenth);
			else
				printf("超出距离!!!\r\n");	
			PEout(5)=0;
			delay_ms(300);
			PEout(5)=1;
		}
	}
}

你可能感兴趣的:(STM32超声波测距)