(1)基本的工作原理:
a、IO口 --TRIG触发测距,最少给10us的高电平
b、模块自己发出8个40KHz的方波,检测是否有信号返回
c、ECHO回向信号输出一个高电平,高电平持续输出的时间就是超声波一个来回的时间
d、距离=(高电平持续时间*340m/s)/2
(2)IO口选择:
由于数据输出使用TTl串口数据输出,所以借用了STM32预留的CAMERA接口,选用了DCMI_D5(TRIG)、DCMI_D7(ECHO),电源5V和地线
(3)时序图解读:
以上时序图表示,需要提供一个持续10us的高电平触发脉冲信号,这样模块会自己检测回波信号,这样根据通过从发射信号到回收到信号的时间间隔可以算出距离;us公式 --》us/58=厘米
us/148=英寸。
(4)部分关键代码:
//开启AHB1 B组ER组时钟 选用CAMERA DCMI_D5 DCMI_D7引脚 对应PB6 PE6这些引脚的初始化便不都写上;
头文件:
#ifndef __HC_SRC_H
#define __HC_SRC_H
//头文件
#include “stm32f4xx.h” //这个头文件一定要留
#include “sysTick.h” //滴答定时器
#define TRIG(a); if(a)
GPIO_SetBits(GPIOB,GPIO_Pin_6);
else
GPIO_ResetBits(GPIOB, GPIO_Pin_6);
#define EHCO GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_6)
//函数声明
void HC_SRC04_Init(void);//GPIO口初始化
uint16_t Get_Dist(void);//获取距离
#endif
获取距离方法:
uint16_t Get_Dist(void)
{
uint16_t dis = 0;
//1、使用TRIG引脚发初始信号
TRIG(1);
Time_us(15);
TRIG(0);
//2、利用EHCO 获取接收回波时间
while(EHCO==0);//等待高电平
TIM3->CNT = 0; //计时器置0
TIM_Cmd(TIM3,ENABLE);//开始计时
while(EHCO==1); //收到回波
TIM_Cmd(TIM3,DISABLE);//关闭计时
//3、计算距离
dis = (count*1000+TIM3->CNT)/58;
count=0;
return dis;
}
串口的初始化:
void UART1_Init(uint32_t BaudRate)
{
GPIO_InitTypeDef GPIO_InitStructrue;
USART_InitTypeDef USART_InitStructrue;
NVIC_InitTypeDef NVIC_InitStructrue;
//1、开启 串口1 相关GPIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//2、将 PA9 PA10 引脚复用为 USART1 的特殊功能引脚
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10, GPIO_AF_USART1);
//3、配置以及初始化 PA9 PA10 为复用模式
GPIO_InitStructrue.GPIO_Mode = GPIO_Mode_AF; //复用模式
GPIO_InitStructrue.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructrue.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructrue.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructrue);
//4、配置以及初始化 串口模式
USART_InitStructrue.USART_BaudRate = BaudRate; //波特率 115200 9600 ...
USART_InitStructrue.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//关闭硬件流控
USART_InitStructrue.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //能够接收 也 能够发送
USART_InitStructrue.USART_Parity = USART_Parity_No; //无校验
USART_InitStructrue.USART_StopBits =USART_StopBits_1; //1位停止位
USART_InitStructrue.USART_WordLength = USART_WordLength_8b; //8位数据位
USART_Init(USART1,&USART_InitStructrue);
//5、开启接收中断 USART_IT_RXNE --->接收数据寄存器不为空时触发中断。表示有数据到来
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
//6、初始化 NVIC
NVIC_InitStructrue.NVIC_IRQChannel = USART1_IRQn; //串口1中断
NVIC_InitStructrue.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructrue.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级
NVIC_InitStructrue.NVIC_IRQChannelSubPriority = 0; //响应优先级
NVIC_Init(&NVIC_InitStructrue);
//7、使能 串口1
USART_Cmd(USART1, ENABLE);
}
!!!当使用printf函库数时,记得添加头文件“string.h”并重写fputc()
int fputc(int ch, FILE *f)
{
//等待当前数据发送完成
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {}
//发送一个字节数据
USART_SendData(USART1, (uint8_t) ch);
return ch;
}
附:
在此项目中实现过程需要用到滴答定时器、TIM计时器等见我其他篇幅的学习笔记,在我博客中可以搜索到。(串口输出使用stc-isp中的串口助手)