赞
踩
提示:小编也是初学者,本文适用于想完成一个基础智能四轮车的初学者,大佬还请勿喷,欢迎各位指出错误的地方
暑假在家无聊,刚好也在学习STM32的HAL库,就想着做个小车巩固自己学到的知识,顺便记录自己所遇到的错误
小编也是现学现写,准备做一个蓝牙遥控红外寻迹超声波避障小车
注意:这篇文章需要用到定时器输出比较和输入捕获,没有基础可能看不懂。
这篇博客讲述的就是如何去制作超声波避障小车
注意:没有基础的是无法完成的
舵机sg90模块
舵机SG90模块是一种小型舵机,适用于各种机器人和电子设备。它由一个直流电机、减速装置和位置反馈电路组成。该模块可以通过PWM信号来控制舵机的角度,典型的工作范围为0到180度。它具有快速响应、精准定位和稳定性好的特点,能够提供可靠的转动效果。
需要用到的知识: 定时器输出比较----pwm输出
使用原理:在PWM周期20MS以内控制有效电平的时间即可控制舵机的转动角度

超声波传感器
工作原理: HC-SR04传感器的工作原理与一般超声波传感器相似,包括发射超声波脉冲和接收反射波。它由超声波发射器和接收器组成,通过测量发射和接收之间的时间差来计算距离。
距离测量范围: HC-SR04传感器的有效测量距离通常在2厘米到4.5米之间,取决于环境条件和具体实现。使用接口: HC-SR04传感器通常通过GPIO口与单片机或其他控制器连接。它需要两个引脚进行数据传输,一个引脚用于发射超声波脉冲,另一个引脚用于接收反射波。
需要使用的知识:定时器输入捕获
使用原理:描述起来比较麻烦,建议看下面的博客

舵机SG90模块
VCC 5V供电
GND
信号线(橙色) PA8 对应TIM1_CH1
超声波HC_04(新版)
VCC 3.3v-5v供电
GND
TRIG引脚 选用普通IO引脚即可 选用PA12
ECHO引脚 选用定时器引脚 PB5的TIM3_CH2重映射
这里是在上一篇----蓝牙小车的基础上完成的
相信大家学到这里了,基本的设置都会配置了
舵机的配置
选用的是PA8 TIM1_CH1 高级定时器具有通用定时器的全部功能
选择定时器1的通道一的PWM输出模式
设置PSC预分频系数为72-1 ARR的值为20000-1
PWM频率=72MHZ/(72-1+1)*(20000-1+1)=50hz
PWM周期=1/50hz=20ms
注意: ARR的值与下面设置转动角度的有关,不懂的建议和我设置的一样

超声波传感器的配置
开启定时器3通道2的输入捕获模式
将PSC预分频系数的值设置为72-1
ARR的值设置的65535

开启定时器3的全局中断,这里不开启的话会导致获取到的超声波避障函数的值为0

4.代码展示部分
舵机部分
duoji.c
- #include "duoji.h"
- void SG90_GetAngle(float value)
- {/* 舵机转向函数*/
- /*
- PSC:20000-1 ARR:72-1
- 0 500
- 180 2500
- 角度 CCR的值
- */
- value=value/180*2000+500;
- __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,value);
- /*value=50相当于一个周期内(20ms)有0.5ms高脉冲*/
- }
- void SG90_Init()
- {
- SG90_GetAngle(90);
- }
- void SG90_TurnL()
- {
- SG90_GetAngle(135);
- }
- void SG90_TurnR()
- {
- SG90_GetAngle(45);
- }

duoji.h
- #ifndef __DUOJI_H_
- #define __DUOJI_H_
-
- #include "main.h"
- #include "tim.h"
- void SG90_GetAngle(float value);
- void SG90_Init(void); //舵机头初始化,摆正
- void SG90_TurnL(void); //舵机头左转
- void SG90_TurnR(void); //舵机头右转
- #endif
-
-
超声波部分
这部分代码我引用了这个博主的,大家有不懂的点这里
将下面代码添加到tim.c中,复制粘粘到最下面
- //[7]:0,没有成功的捕获;1,成功捕获到一次.
- //[6]:0,还没捕获到低电平;1,已经捕获到低电平了.
- //[5:0]:捕获低电平后溢出的次数
- uint8_t TIM3CH2_CAPTURE_STA; // 输入捕获状态
- uint16_t TIM3CH2_CAPTURE_VAL; //输入捕获值
- //溢出回调函数和捕获回调函数
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
- {
- if ((TIM3CH2_CAPTURE_STA & 0x80) == 0) // 还未捕获成功
- {
- if (TIM3CH2_CAPTURE_STA & 0x40) // 捕获到一个下降沿
- {
- if ((TIM3CH2_CAPTURE_STA & 0x3F) == 0x3F) // 高电平的时间太长
- {
- TIM3CH2_CAPTURE_STA |= 0X80; // 标记为成功捕获一次
- TIM3CH2_CAPTURE_VAL = 0XFFFF;
- }
- else
- TIM3CH2_CAPTURE_STA++; // 否则标记溢出数加1
- }
- }
- }
-
- // 捕获中断发生时执行 上升沿复位开始计时,下降沿获取捕获值计算
- void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
- {
- if ((TIM3CH2_CAPTURE_STA & 0X80) == 0) //还未捕获成功 [7]:0,没有成功的捕获;1,成功捕获到一次.
- {
- if (TIM3CH2_CAPTURE_STA & 0X40) // 成功率捕获到1个下降沿 [6]:0,还没捕获到低电平;1,已经捕获到低电平了.
- {
- // usart_printf("get down\r\n");
- TIM3CH2_CAPTURE_STA |= 0X80; // 标记成功,捕获到1次高电平完成
- TIM3CH2_CAPTURE_VAL = HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_2); // 捕获当前设置捕获值
- TIM_RESET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_2); // 清除原来设置
- TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_2, TIM_ICPOLARITY_RISING); // 捕获到下降沿之后,将捕获到复位为上升沿
- }
- else // 捕获到一个上升沿
- {
- // usart_printf("get up\r\n");
- TIM3CH2_CAPTURE_STA = 0;
- TIM3CH2_CAPTURE_VAL = 0;
- TIM3CH2_CAPTURE_STA |= 0X40; //将STA置为0x40 当下一次触发中断时,会进入上面的if语句
- __HAL_TIM_DISABLE(&htim3);
- __HAL_TIM_SET_COUNTER(&htim3, 0);
- TIM_RESET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_2);
- TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_2, TIM_ICPOLARITY_FALLING);
- __HAL_TIM_ENABLE(&htim3);
- }
- }
- }

将下面的代码添加到main.h中
- extern uint8_t TIM3CH2_CAPTURE_STA; // 输入捕获状态
- extern uint16_t TIM3CH2_CAPTURE_VAL; //输入捕获值
- extern uint8_t unit_change; //单位变换

HCSR04.C
- /**
- * @file HCSR04.c
- * @author Zhong Zepeng (1935595312@qq.com)
- * @brief
- * @version 0.1
- * @date 2022-11-25
- *
- * @copyright Copyright (c) 2022
- *
- */
- #include "HCSR04.h"
- #include "gpio.h"
- #include "tim.h"
- #include "usart.h"
- #include "User_Debug.h"
- /**
- * @brief 激活超声波定时器
- *
- */
- void HCSR_04()
- {
- uint32_t i;
- HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET);
- for (i = 0; i < 72 * 40; i++)
- __NOP();
- HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);
- }
- /**
- * @brief 关闭超声波定时器
- *
- */
- void Stop_HCSR_04()
- {
- HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);
- }
- /**
- * @brief 计算超声波检测的距离
- *
- * @return float
- */
- //uint8_t TIM3CH2_CAPTURE_STA; // 输入捕获状态
- //uint16_t TIM3CH2_CAPTURE_VAL; //输入捕获值
- uint8_t unit_change;
- float getSR04Distance()
- {
- float len = 0;
- uint32_t time = 0;
- if (TIM3CH2_CAPTURE_STA & 0X80) // 输入捕获 触发
- {
- time = TIM3CH2_CAPTURE_STA & 0X3f; // 获得溢出次数
- time *= 65535; // 一次溢出为65536 得到溢出的时间
- time += TIM3CH2_CAPTURE_VAL; // 溢出的时间+现在定时器的值 得到总的时间
- if (unit_change == 0)
- {
- len = (time * 342.62 * 100 / 2000000); // 计算得到距离 cm
- }
- // else if (unit_change == 1)
- // {
- // len = time * 342.62 * 100 / 200000000; // 计算得到距离 m
- // usart_printf("m\r\n");
- // }
-
- TIM3CH2_CAPTURE_STA = 0; // 清除溢出
- }
- return len;
- }

HCSR04.h
- #ifndef __HCSR04_H
- #define __HCSR04_H
-
- #include "stdint.h"
-
-
- void HCSR_04(void);
- void Stop_HCSR_04(void);
- float getSR04Distance(void);
-
- #endif
-
main.c
这里我是用函数封装了起来,大家使用的时候在while(1)里调用这个函数就行
因为超声波数据获取的时候有视野盲区,小编在代码方法添加了2个红外传感器防止撞墙
- void ultrasonic_waves()
- {
- //★舵机指向90° 正中间
- SG90_Init();
- Change_speed(70);
- HAL_Delay(700); //延时,不做延时的话,会超过采样频率
- HCSR_04(); //激活超声波模块
- distance_res[0] = getSR04Distance();
- HAL_Delay(10);
-
-
- if(LR1==0 || LR2==0)
- {
- HAL_Delay(10);
- if(LR1==0)
- {
- Backward();
- HAL_Delay(300);
- Turn_Right();
- HAL_Delay(200);
- }
- if(LR2==0)
- {
- Backward();
- HAL_Delay(300);
- Turn_Left();
- HAL_Delay(200);
- }
- }
- else if(distance_res[0]>35.00)
- {
- Forward();
- }
-
- else if(LR2==1&&LR2==1)//如果前方距离小于30厘米 停车测左右距离
- {
-
- Stopward();
- SG90_TurnL();//舵机左转45度测距
- HAL_Delay(1200);
- HCSR_04(); //激活超声波模块
- distance_res[1]=getSR04Distance();
- HAL_Delay(10);
-
- SG90_TurnR();//舵机右转45度测距
- HAL_Delay(1200);
- HCSR_04(); //激活超声波模块
- distance_res[4]=getSR04Distance();
- HAL_Delay(10);
- SG90_Init();
-
-
- if(distance_res[1]>distance_res[4]) //如果左边的距离大于右边的距离
- {
- SG90_Init(); //舵机摆正
- HAL_Delay(700);
- HCSR_04(); //激活超声波模块
- distance_res[0] =getSR04Distance(); //重复测前方的距离同时左转
- HAL_Delay(100);
- Turn_Left();
- if(distance_res[0]>30.0000)
- {
- Forward();
- }
-
- if(distance_res[1]<distance_res[4]) //如果右边的距离大于左边的距离
- {
- SG90_Init();
- HAL_Delay(700);
- HCSR_04(); //激活超声波模块
- distance_res[0] =getSR04Distance(); //重复测前方的距离同时右转
- HAL_Delay(10);
- Turn_Right();
- {
- Forward();
- HCSR_04(); //激活超声波模块
- distance_res[0] = getSR04Distance();
- HAL_Delay(10);
- Turn_Right();
- if(distance_res[0]>30.0000)
- {
- Forward();
- }
- }
- }
- }
- }
-
- }

1.舵机信号线使用的定时器不能和超声波传感器使用的一致,不然会导致超声波函数接收到的数据不准确,导致经常撞墙。
2.在获取超声波测距的数据的时候,可以使用USB转TTL转换器,用串口获取准确的数据,数据一定要稳定。
3.供电问题,一定要保证要稳定供电,供电不足会导致传感器无法正常工作
这个功能我调试了很久,相比于前2个功能比较复杂,关于代码,不推荐大家照搬,要根据自己的需求来改,大家有什么疑惑可以发评论区里,看到了我会回复
关于代码部位我已上传,分别关于舵机部分,超声波部分,避障小车部分
基于stm32的HAL库开发的超声波避障小车
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。