由于之前觉得家里水龙头每次需要自己打开,恰巧最近又突发奇想,想做一个用超声波控制舵机的程序,于是便花了一个下午写了这个代码,尝试用hal库完成代码的编写
所需要的元器件
- stm32单片机
- stlink
- 超声波模块
- 舵机
- ttl串口模块
- 导线若干
整体思路
- 先编写超声波测距的代码,实现距离值通过串口发送出去;
- 配置相关stm32的初始化设置;
- 在keil里编写串口中断接收函数,将串口1用于接收超声波发送来的数据,并编写舵机控制程序;
- 烧录程序实现效果,并改进出现的问题。
接线方式
- stm32通过uart1与TTL连接
- stm32通过sw与stlink连接
- stm32通过GND、VCC、PWM口连接舵机
完成效果
超声波通过距离识别,并把其数值发送给stm32,单片机读取后控制舵机转动,实现水龙头的非接触感应。
Cube配置
- 串口,用于检测超声波距离
2.定时器,用于驱动舵机与产生超声波输入捕获
3.GPIO,作为超声波脉冲产生接口
之后生成keil代码,打开并编辑
代码解析
- 舵机角度转换为占空比代码
void MG996R_Set_Angle(int16_t angle)
{
uint16_t CCR_value = 0;
if ((-90 <= angle) && (angle <= 90))
{
CCR_value = (10. / 9) * angle + 150;
}
else
{
CCR_value = 150;
}
}
- 超声波测距代码
float soner_getdistance(void)
{
uint16_t time_node1;
uint16_t time_node2;
uint16_t measure;
soner_startrange();
while(HAL_GPIO_ReadPin(SONER_PORT,SONER_ECHO_PIN)==RESET);
time_node1=soner_gettime();
while(HAL_GPIO_ReadPin(SONER_PORT,SONER_ECHO_PIN)==SET);
time_node2=soner_gettime();
measure=time_node2-time_node1;
distance_temp = measure * 17.0/100;
if(distance_last==0)
distance_last = distance_temp;
if(distance_last-distance_temp>100 || distance_temp-distance_last>100)
{
distance_result =distance_last;
distance_last=distance_temp;
}
else
{
distance_result=distance_temp;
distance_last=distance_temp;
}
return distance_result;
}
- 超声波距离测算返回值进行舵机操控
distance=soner_getdistance();
if(distance>3&&distance<40){
printf("in \r\n");
MG996R_Set_Angle(70);
}else if(distance>42&&distance<90){
MG996R_Set_Angle(0);
printf("out \r\n");
}else{
MG996R_Set_Angle(0);
}
最终实验结果
将手靠近超声波时,舵机发生转动。将此机构转载在水龙头后,便可实现水龙头非接触式感应出水。
遇到的问题
刚开始超声波返回值容易出现大幅波动,于是通过限定返回值范围,将波动数据进行滤波,使得舵机在干扰时抖动的现象得以克服,并运行平稳。
总结
程序设计时,多结合之前的经验总结很关键,并且顶层至底层的设计相当重要,需要不断地尝试与反思。
坚持成就梦想。