【STM32學習】(13)STM32實現超聲波測距(HC-SR04)

經過反覆的研究和調試,終於搞好了,所以說,只要靜下心,肯於研究,問題就會顯得沒那麼複雜。

博文寫之前,先要分析一下硬件的基本構造和樣式以及它的工作原理:

樣式如圖:


工作原理(很重要):

說明一下工作過程:

單片機型號:STM32F103VET

       1.提供一個10us以上的脈衝

       2.模塊會自動發出8個40KHz週期電平,並檢測回波

       3.等待輸出迴響信號,

             要注意這個電平是自動產生的,測試距離遠,這個脈寬就寬,與檢測距離成正比

實現步驟:

     1.用按鍵來調用測距功能,後期可以修改成自動循環測距,但循環測距的週期要在60ms以上,不然會有干擾

              按鍵接在PC0

     2.打開串口1(USART1),爲了在電腦上用串口調試助手看測試的距離值。

     3.打開定時器TIM3,這裏設置了5us中斷一次,讀者也可以用其它定時器完成

     4.開外部中斷1,映射到PA1口外部中斷

這樣就差不多了

接線:

按鍵接在PC0

超聲波測距模塊,trig接在PA0

超聲波測距模塊,Echo接在PA1

超聲波測距模塊,VCC接在5V上

 

下面看代碼,因爲代碼分的文件比較多。只貼出核心代碼:

核心代碼如下:

main.c

#include"stm32f10x.h"
#include "usart.h"
#include "delay.h"
#include "key.h"
#include "time.h"
#include "exti.h"
#include "Ultrasonic.h"



int main(void)
{
	unsigned int rang = 0;
	/*初始化串口*/
	delay_init();
	key_init_wt();	    
    //TIM3_Int_Init(4999,7199);//10Khz的計數頻率,計數到5000爲500ms  
	Ultrasonic_config();
	EXTI_config();  
	TIM3_Int_Init(4,71);		//	5us
	USART1_Config();
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設置NVIC中斷分組2:2位搶佔優先級,2位響應優先級
	
	USART1_printf(USART1,"\r\nHello World\r\n");
	
	while(1)
	{
		if(0 == KEY1)
		{
			delay_ms(10);
			if(0 == KEY1)
			{
				while(0 == KEY1);
				USART1_printf(USART1,"\r\n\r\n");
				Ultrasonic_Ranging(); 
				USART1_printf(USART1,"\r\ntime_count=%d\n",time_count);
				rang = (unsigned int)(((time_count*0.000005*340)/2)*1000); 
				USART1_printf(USART1,"\r\nDistance=%d\n",rang);
				
			}
			while(0 == KEY1);
		}
	}
}

time.c

#include "sys.h"
#include "key.h"

unsigned int cnt=0;

//通用定時器3中斷初始化
//這裏時鐘選擇爲APB1的2倍,而APB1爲36M
//arr:自動重裝值。
//psc:時鐘預分頻數
//這裏使用的是定時器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //時鐘使能

    //定時器TIM3初始化
    TIM_TimeBaseStructure.TIM_Period = arr; //設置在下一個更新事件裝入活動的自動重裝載寄存器週期的值   
    TIM_TimeBaseStructure.TIM_Prescaler =psc; //設置用來作爲TIMx時鐘頻率除數的預分頻值
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //設置時鐘分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上計數模式
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根據指定的參數初始化TIMx的時間基數單位

    TIM_ITConfig(TIM3,TIM_IT_Update,DISABLE ); //失能指定的TIM3中斷,允許更新中斷

    //中斷優先級NVIC設置
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中斷
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先佔優先級0級
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 8;  //從優先級8級
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
    NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器


    TIM_Cmd(TIM3, ENABLE);  //使能TIM3                    
}
//定時器3中斷服務程序
void TIM3_IRQHandler(void)   //TIM3中斷
{
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //檢查TIM3更新中斷髮生與否
    {
		cnt++;
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  	//清除TIM3更新中斷標誌
    }
}



exti.c

#include "stm32f10x.h"                  // Device header
#include "stm32f10x_gpio.h"
#include "Ultrasonic.h"
#include "time.h"
#include "delay.h"



int EXTI_flag=0;
void EXTI_config(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	EXTI_InitTypeDef EXTI_InitStruct;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	//	開啓GPIOA時鐘
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);		//	開啓功能復原IO時鐘

		
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; //GPIO_Mode_IN_FLOATING;	//	浮空輸入
	GPIO_Init(GPIOA,&GPIO_InitStruct);				//	根據GPIO_InitStruct中指定的參數初始化外設GPIOA寄存器
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);	//	選擇GPIOA管腳的1管腳用作外部中斷線
	
	EXTI_InitStruct.EXTI_Line = EXTI_Line1;					//	選中外部中斷線0
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;		//	設置EXTI線路爲中斷請求
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;	//	上升沿,下降沿都觸發
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;	//	使能
	EXTI_Init(&EXTI_InitStruct);		//	根據EXTI_InitStruct中指定的參數初始化外設EXTI寄存器
	
	//選擇中斷向量	下面很重要
    NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
    //搶佔優先級
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    //響應優先級
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 7;
    //使能中斷向量
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    //初始化中斷向量配置
    NVIC_Init(&NVIC_InitStructure);
	
}
void  EXTI1_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line1))				//	檢查指定的EXTI線路觸發請求發生與否
    {
		if(1 == Echo)   
		{
			TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);		//	
			//USART1_printf(USART1,"\r\nwan\r\n");
			//delay_ms(10000);
			//EXTI_flag = 1;
		}				
		else
		{
			TIM_ITConfig(TIM3,TIM_IT_Update,DISABLE);
			//USART1_printf(USART1,"\r\ntin\r\n");
			//EXTI_flag = 0;
		}
		
		EXTI_ClearITPendingBit(EXTI_Line1);			//	清除EXTI線路掛起位
       
    }

}

 

Ultrasonic.c

#include "stm32f10x_gpio.h"
#include "Ultrasonic.h"
#include "delay.h"
#include "time.h"
#include "usart.h"


unsigned int time_count = 0;

void  Ultrasonic_config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	//	使能或者失能APB2外設時鐘
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	//GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_1;
	//GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void Ultrasonic_Ranging(void) 
{
	Trig = 0;
	delay_us(10);	//	10us
	Trig = 1;
	delay_us(20);	//	10us以上的脈衝		
	Trig = 0;

	delay_ms(1000);
	USART1_printf(USART1,"cnt = %d\n",cnt);

	time_count = cnt;
	cnt = 0;
	
}


 

 

精度還是可以的

Demo源碼可下載:https://download.csdn.net/download/XiaoCaiDaYong/12039906

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章