【STM32学习】(13)STM32实现超声波测距(HC-SR04)

经过反复的研究和调试,终于搞好了,所以说,只要静下心,肯于研究,问题就会显得没那么复杂。

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

样式如图:

【STM32学习】(13)STM32实现超声波测距(HC-SR04)_第1张图片

【STM32学习】(13)STM32实现超声波测距(HC-SR04)_第2张图片
工作原理(很重要):

【STM32学习】(13)STM32实现超声波测距(HC-SR04)_第3张图片

【STM32学习】(13)STM32实现超声波测距(HC-SR04)_第4张图片

说明一下工作过程:

单片机型号:STM32F103VET

       1.提供一个10us以上的脉冲

       2.模块会自动发出8个40KHz周期电平,并检测回波

       3.等待输出回响信号,【STM32学习】(13)STM32实现超声波测距(HC-SR04)_第5张图片

             要注意这个电平是自动产生的,测试距离远,这个脉宽就宽,与检测距离成正比

实现步骤:

     1.用按键来调用测距功能,后期可以修改成自动循环测距,但循环测距的周期要在60ms以上,不然会有干扰

              按键接在PC0

     2.打开串口1(USART1),为了在电脑上用串口调试助手看测试的距离值。

     3.打开定时器TIM3,这里设置了5us中断一次,读者也可以用其它定时器完成

     4.开外部中断1,映射到PA1口外部中断

这样就差不多了

接线:

按键接在PC0

超声波测距模块,trig接在PA0

超声波测距模块,Echo接在PA1

超声波测距模块,VCC接在5V上

 

下面看代码,因为代码分的文件比较多。只贴出核心代码:

【STM32学习】(13)STM32实现超声波测距(HC-SR04)_第6张图片

核心代码如下:

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;
	
}


 

 

【STM32学习】(13)STM32实现超声波测距(HC-SR04)_第7张图片

精度还是可以的

Demo源码可下载:https://download.csdn.net/download/XiaoCaiDaYong/12039906

你可能感兴趣的:(单片机c语言,HC-SR04,串口,定时器,外部中断,超声波)