天天看點

嵌入式stm32基本超音波測距序列槽_STM32超音波測距

在單片機程式設計中需要與其他子產品進行通信時會經常用到IIC協定和SPI協定,對于新人來說,這兩個協定了解起來簡單但實際自己寫底層協定的時候卻很麻煩,參照着時序圖問題還是很多,撸代碼撸不下去索性就拿來直接用。

要寫IIC和SPI協定的話主要還是要對時序圖熟悉,而這裡我覺得超音波測距(HC-SR04)這個小項目用來練習對時序圖代碼實作非常合适,本身這個底層協定并不難,很友善檢查bug的所在,然後這個測距這個功能也非常實用,我覺得也會比較有興趣吧。話不多說,這裡我從思路到思路的實作來講述超音波測距的實作過程。

本文排布如下

超音波測距子產品硬體介紹

主要思路

實作過程

一、超音波測距子產品的硬體介紹

嵌入式stm32基本超音波測距序列槽_STM32超音波測距

四個引腳,VCC和GND供電和接地,接下來是觸發信号輸入引腳Trig和回響信号輸出引腳Echo。

Trig:針對這個子產品來說Trig腳是輸入,而我們在單片機上需要在這個引腳中輸出一個10us以上的高電平,這時候就會驅動這個超音波子產品發出聲波。

Echo: 針對這個子產品Echo是輸出,接下來它會自動接收超音波,并且接收完後在Echo這個輸出腳上輸出一段高電平,這個高電平的時間就是聲波發出并且反射回來所用的時間,是以我們在單片機中就需要讀取這個引腳。

二、主要思路

嵌入式stm32基本超音波測距序列槽_STM32超音波測距

了解了Trig和Echo,對這個子產品的工作原理基本上可以了解了,那麼接下來就需要在單片機上完成Trig的觸發信号、Echo接收信号。

初始化GPIO,使能總線和端口,由于Trig用作輸出電平,而Echo用作讀取電平,是以将Trig腳設定為推挽輸出,Echo腳設定成浮空輸入。初始化定時器,需要定時器來計時。

将Trig置為1高電平,再延時10us,之後将Trig複原為0低電平。這樣就會讓超音波子產品内部發送觸發信号然後發出超音波。

等待Echo變為1高電平,然後重載并開啟定時器,等待Echo變為0低電平,最後定時器停止計數,讀取TIM->CNT這個寄存器也就是計數次數。

計算可得距離,距離=高電平時間*聲速(340m/s)/2,或者us/58=厘米。

通過序列槽發送或者液晶屏顯示,擷取到這個計算結果。

三、實作過程

此部分為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 cmrn",lenth);
			else
				printf("超出距離!!!rn");	
			PEout(5)=0;
			delay_ms(300);
			PEout(5)=1;
		}
	}
}
           
嵌入式stm32基本超音波測距序列槽_STM32超音波測距