HC-SR04超声波测距模块可提供2cm-400cm的非接触式距离感测功能,测距精度可高达23mm。模块包括超声波发射器、接收器与控制电路
该模块引出四个接口:
VCC和GND为供电端,VCC接5V,GND必须和单片机共地(很重要,给单片机提供一个低电平参考,否则接下来的通信会错乱而导致读取到的数值无规律)
TRIG和ECHO为通信端,TRIG是触发控制信号输入,ECHO是回响信号输出
时钟配置:
分配trig引脚和按键控制输入,echo引脚我们通过tim计数器的ch1分配
设置定时器2并开启中断,
为了能够进行GPIO中断,我们需要配置PA6引脚
超声波时序图
1.发送大于10us的触发信号。
2.检测超声波发出信号时产生的高电平。
3.检测超声波接收到信号时产生的低电平
显示超声波测出的距离,我这里就直接使用串口助手显示了
为了能够用输入电平控制测距的开启或者关闭,我们这里设置当输入为高电平时中断测距,再次输入高电平时重新测距。
main函数代码
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
int a1=0;
int p1=0;
int time=0;
int con=1;
int resu=0;
int good_en=0;
p=&p1;
timer=&time;
control=&con;
result=&resu;
good=&good_en;
int count=0;
int user_num=1;
/* USER CODE END 2 */
int resu_arr[3];
HAL_Delay(3000);
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{ if(count<3)
{ if(a1<3)
a1++;
else a1=0;
if(*control)
{ GetSR04Range(a1,p,result,good);
if(*result==1)
{ resu_arr[count]=1;
count=count+1;}
else if(*timer>0&&*timer<20009)
*timer=*timer+1;
else{
*timer=0;
if(*good)
*result=3;
else *result=2;
resu_arr[count]=*result;
count=3;
resu_arr[2]=*result;
}
}
HAL_Delay(1200);}
else {//printf("s1=%d,s2=%d,s3=%d\r\n",resu_arr[0],resu_arr[1],resu_arr[2]);
printf("%d,%d%d.00200",resu_arr[2],user_num/10,user_num%10);
count=0;
user_num++;}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
可以看到这里主要调用了GetSR04Range函数,它在驱动文件SR04.C文件中:
进行多次连续测量,直到满足下列两个条件中的一个:
- 检测到障碍物,此时result设为1,记录本次打分结果
- 累计测量时间超过20000毫秒未检测到障碍物。此时:
- 如果good为1(表明前面多次测量距离大,离障碍物远),result设为3,表示通过
- 否则result设为2,表示未通过
uint32_t GetSR04Range(int a,int * sum,int *result,int *good)
{
uint32_t temp=0;
float Distance=0;
TRIG_L();
HAL_Delay(1);
TRIG_H();
HAL_Delay(10);
TRIG_L();//触发信号控制
//计算距离
if(TIM2CH1_CAPTURE_STA&0X80) //成功捕获到了一次高电平
{
temp=TIM2CH1_CAPTURE_STA&0X3F;
temp*=65536; //溢出时间总和
temp+=TIM2CH1_CAPTURE_VAL; //得到总的高电平时间
Distance=(temp/58);
if(a<3)
{
*sum+=Distance;
}
else{
float out=*sum/3;
if(out<4)
{
*result=1;
*good=0;
}
else if(out>30)
*result=1;
else if(out>15)
*good=0;
else *good=1;
*sum=0;
// printf("out:%.3f cm\r\n",out); //打印总的高点平时间
}
TIM2CH1_CAPTURE_STA=0; //开启下一次捕获
return Distance;
}
return 0;
}
通过驱动文件我们便可以实现串口读取经过滤波的距离数据,为了能够用GPIO引脚进行中断控制,我们同时还要修改stm32f1xx_it.c文件:
void EXTI9_5_IRQHandler(void)
{
/* USER CODE BEGIN EXTI9_5_IRQn 0 */
HAL_Delay(3);//??
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6))
{
if(*control){
HAL_TIM_IC_Stop_IT(&htim2, TIM_CHANNEL_1); //停止定时器中断捕获
HAL_TIM_IC_DeInit(&htim2); //停止定时器捕获
}
else //否则开始测距
{
HAL_TIM_IC_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); }
*control=~*control;
}
else
{
}
/* USER CODE END EXTI9_5_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(key_Pin);
/* USER CODE BEGIN EXTI9_5_IRQn 1 */
/* USER CODE END EXTI9_5_IRQn 1 */
}
这样就可以在GPIO6引脚接收到高电平的时候进入中断并且进入判断。