在单片机编程中需要与其他模块进行通信时会经常用到IIC协议和SPI协议,对于新人来说,这两个协议理解起来简单但实际自己写底层协议的时候却很麻烦,参照着时序图问题还是很多,撸代码撸不下去索性就拿来直接用。
要写IIC和SPI协议的话主要还是要对时序图熟悉,而这里我觉得超声波测距(HC-SR04)这个小项目用来练习对时序图代码实现非常合适,本身这个底层协议并不难,很方便检查bug的所在,然后这个测距这个功能也非常实用,我觉得也会比较有兴趣吧。话不多说,这里我从思路到思路的实现来讲述超声波测距的实现过程。
本文排布如下
四个引脚,VCC和GND供电和接地,接下来是触发信号输入引脚Trig和回响信号输出引脚Echo。
Trig:针对这个模块来说Trig脚是输入,而我们在单片机上需要在这个引脚中输出一个10us以上的高电平,这时候就会驱动这个超声波模块发出声波。
Echo: 针对这个模块Echo是输出,接下来它会自动接收超声波,并且接收完后在Echo这个输出脚上输出一段高电平,这个高电平的时间就是声波发出并且反射回来所用的时间,所以我们在单片机中就需要读取这个引脚。
了解了Trig和Echo,对这个模块的工作原理基本上可以理解了,那么接下来就需要在单片机上完成Trig的触发信号、Echo接收信号。
此部分为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;
}
}
}