一.所需材料:
1任何一种型号的stm32f10x的微控制器
2.HC-SR04模块
3.安装串口驱动与串口助手(这里用的火哥的串口调试助手)
4.ST-link或者串口等下载方式都可以
二。超声波原理
网上一大堆,这里我就大体说一下:单片机先给TRIG一个大于10us的高电平,然后模块ECHO引脚会发出一个高电平,检测高电平的时间乘声速便可算出距离。这里ECHO发出也接收,所以检测的时间,假设按秒算,然后乘170便是以m为单位的距离。
三.源代码分析
1.接口定义:
//由于只是用的定时器的基本计时功能,所以IO口随便找两个便可以
#define HCSR04_PORT GPIOB
#define HCSR04_PORTC_CLK_FUN RCC_APB2PeriphClockCmd
#define HCSR04_CLK RCC_APB2Periph_GPIOB
#define HCSR04_TRIG GPIO_Pin_11
#define HCSR04_ECHO GPIO_Pin_10
2.驱动函数分析
//超声波计数,记录有几个更新中断,由于在.c文件中定义,中断函数中测试其值,故加个extern
extern u16 msHcCount = 0;
//IO口初始化 TRIG为普通推挽输出,ECHO为浮空输入,
//配置时基结构体
void Hcsr04Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
GPIO_InitTypeDef GPIO_InitStructure;
HCSR04_PORTC_CLK_FUN(HCSR04_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin =HCSR04_TRIG;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(HCSR04_PORT, &GPIO_InitStructure);
GPIO_ResetBits(HCSR04_PORT,HCSR04_TRIG);
GPIO_InitStructure.GPIO_Pin = HCSR04_ECHO;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(HCSR04_PORT, &GPIO_InitStructure);
GPIO_ResetBits(HCSR04_PORT,HCSR04_ECHO);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
TIM_DeInit(TIM2);
TIM_TimeBaseStructure.TIM_Period = (1000-1); //定时器时钟1MHZ,自动重装载寄存器的值为1000, 也就是说满一次为1MS
TIM_TimeBaseStructure.TIM_Prescaler =(72-1);
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
TIM_ClearFlag(TIM4, TIM_FLAG_Update);
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
hcsr04_NVIC();
TIM_Cmd(TIM4,DISABLE);
}
//中断配置,这里只用了一个中断,不用考虑中断嵌套等等,所以中断优先级以及次优先级可以随便配置,只用到了定时器update中断
void hcsr04_NVIC(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//关闭定时器4
static void CloseTimerForHc(void)
{
TIM_Cmd(TIM4, DISABLE);
}
//打开定时器4
static void OpenTimerForHc(void)
{
TIM_SetCounter(TIM4,0);
msHcCount = 0;
TIM_Cmd(TIM4, ENABLE);
}
//获取定时器4计数器值,此值为更新中断的次数*1000+计数器的值
u32 GetEchoTimer(void)
{
u32 t = 0;
t = msHcCount*1000;
t += TIM_GetCounter(TIM4);
TIM4->CNT = 0;
Systick_DelayMs(50);
return t;
}
//通过定时器4计数器值推算距离,单位厘米,假设测试值为x,距离y=x/1M*17000
//这里每测出5此求个平均值输出
float Hcsr04GetLength(void )
{
u32 t = 0;
int i = 0;
float lengthTemp = 0;
float sum = 0;
while(i!=5)
{
GPIO_SetBits(HCSR04_PORT,HCSR04_TRIG);
Systick_DelayUs(20);
GPIO_ResetBits(HCSR04_PORT,HCSR04_TRIG);
while(GPIO_ReadInputDataBit(HCSR04_PORT,HCSR04_ECHO)==RESET);
OpenTimerForHc();
i = i + 1;
while(GPIO_ReadInputDataBit(HCSR04_PORT,HCSR04_ECHO)==SET);
CloseTimerForHc();
t = GetEchoTimer();
lengthTemp = ((float)t*0.017);//cm
sum = lengthTemp + sum ;
}
lengthTemp = sum/5.0;
return lengthTemp;
}
3.主函数测试程序:
float length;
//延时函数初始化
Systick_DelayMs(10); //这里用的系统滴答定时器延时
hcsr04_NVIC(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
USART_Config();//串口服务程序,这里我用的火哥的串口一
Hcsr04Init();
while(1)
{
length = Hcsr04GetLength();
printf("距离为:%.3fcm\n",length);
Systick_DelayMs(1000);
}
四.效果图