STM32智能小车--测距模块(舵机+HC_SR04超声波)

大家好哇!我是湫湫,一个正在摸索嵌入式的普通大学生。

进入正题,最近在做智能小车,想通过文章记录学习过程。

本次文章主要使用 stm32F1C8T6 实现小车测距

非常感谢大家的阅读,如果有不对的地方欢迎指正。


目录

一.实物图

1.舵机

2.HC_SR04:

二.基本工作原理

1.舵机工作原理

2.HC_SR04时序图

三.相关代码

1.Servo.c

2.PWM.c

3.HCSR04.c

四.总结


一.实物图

1.舵机

本人接触的舵机线序颜色为:

中间红色线:电源极,棕色线:电源极,黄色线:控制信号线,具体如下图所示。

(特别说明:不同的厂商制作的舵机的输入线颜色可能会存在不一致,但一般中间的线为红色正极,信号线可能为白色,负极可能为黑色,具体还是要参考舵机的数据手册。)

2.HC_SR04:

可提供 2cm-400cm 的非接触式距离感测功能,

测距精度可达高到的非接触式距离感测功能,测距精度可达高到 3mm ;

模块包括超声波发射器、接收器与控制电路。

VCC:5v供电

Triger引脚:单片机某个引脚--->输入一个信号。

Echo引脚:输出一个信号--->单片机的某个引脚。

GND:接地。


二.基本工作原理

1.舵机工作原理

       舵机转动的角度与脉宽在0.5ms~2.5ms的区间内呈线性关系。舵机有90°、180°、270°、360°最大转角,这里以180°舵机为例来说明脉冲宽度和角度的关系,其他角度舵机参考具体参数,180°舵机周期为20ms时的脉宽和转角关系如下图:

舵机的死区,扭矩等相关参数在此我就不多解释了,想多了解的更深入的话,看我文末附上的链接进行深入学习。

2.HC_SR04时序图

1.如单片机某一个引脚输出一个10微秒的高电平,输入到Triger

2.HC_SR04的上面网状小孔就发出8个4K Hz,

3.再发出来之后,Echo置高电平

4.如若发出去的波遇到障碍物,就会被反射回来,反射回来的波被小孔接收到后,Echo置低电平

5.Echo持续置高电平的时间,是超声波往返的距离,除于2,就是超声波到障碍物的距离

6.即:测试距离=(高电平时间*音速)/2;音速=340m/s=0.034cm/us

三.相关代码

1.Servo.c

//舵机
#include "stm32f10x.h"                  // Device header
#include "PWM.h"
#include "Servo.h"
/**
  * 函    数:舵机初始化
  * 参    数:无
  * 返 回 值:无
  */
void Servo_Init(void)
{
	PWM_Init();									//初始化舵机的底层PWM
}

/**
  * 函    数:舵机设置角度
  * 参    数:Angle 要设置的舵机角度,范围:0~180
  * 返 回 值:无
  */
void Servo_SetAngle(float Angle)
{
	PWM_SetCompare2(Angle / 180 * 2000 + 500);	//设置占空比
												//将角度线性变换,对应到舵机要求的占空比范围上
}

2.PWM.c

#include "stm32f10x.h"  
#include "myMOTOR.h"
#include "track.h"

void PWM_Init(void)
{
	MOTOR_GPIO_Init();
	Track_Init();
	
	 //开启TIM2的时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2;  
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	//选择时基准单元的时钟(内部时钟)
	TIM_InternalClockConfig(TIM2);
	
		//配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//不分屏
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period=799;  //arr 计数周期
	TIM_TimeBaseInitStructure.TIM_Prescaler=0; //psc 预分频器
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
	
    //初始化,输出比较单元(OC)
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM2;
	TIM_OCInitStructure.TIM_OCPolarity=TIM_CounterMode_Up;
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
	
	TIM_OC2Init(TIM2,&TIM_OCInitStructure);
	TIM_OC3Init(TIM2,&TIM_OCInitStructure);
	
	 //启动定时器
	TIM_Cmd(TIM2,ENABLE);
	
}
/**
  * 函    数:PWM设置CCR
  * 参    数:Compare 要写入的CCR的值,范围:0~100
  * 返 回 值:无
  * 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比
  *           占空比Duty = CCR / (ARR + 1)
  */
void PWM_SetCompare2(uint16_t Compare)
{
	TIM_SetCompare2(TIM2, Compare);		//设置CCR2的值
}

3.HCSR04.c

#include "stm32f10x.h"
#include "Delay.h"
#include "TIME.H"

void HC_SR04_Init(void) {
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 使能GPIO时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 使能TIMx时钟

    // GPIO初始化 Trig(STM32发送触发信号给HC-SR04)
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // GPIO初始化 Echo(STM32接受回波特率,计算距离)
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // 定时中断配置
    TIM_InternalClockConfig(TIM2);

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; // 定时时间0.1ms
    TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; // 1MHz
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);

    TIM_ClearFlag(TIM2, TIM_FLAG_Update);
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_Init(&NVIC_InitStructure);

    TIM_Cmd(TIM2, DISABLE);
}

float HCSR04_MeasureOnce(void) {
    // 触发信号
    GPIO_SetBits(GPIOB, GPIO_Pin_11);
    Delay_us(15);
    GPIO_ResetBits(GPIOB, GPIO_Pin_11);

    // 等待Echo引脚变为高电平,超时保护
    uint32_t timeout = 0;
    while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10) == 0 && timeout < 10000) {
        timeout++;
    }
    if(timeout >= 10000) {
        return -1.0f; // 超时返回错误值
    }

    // 开始计时
    Time_On();

    // 等待Echo引脚变为低电平,超时保护
    timeout = 0;
    while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10) == 1 && timeout < 10000) {
        timeout++;
    }
    if(timeout >= 10000) {
        return -1.0f; // 超时返回错误值
    }

    // 停止计时
    Time_Off();

    unsigned int t = Time_Get_Counter();
    float Length = ((float)t / 58.0); // 计算距离
    return Length;
}

float HCSR04_GetLength(void) {
    float Sum = 0.0f;
    for(int i = 0; i < 3; i++) {
        float Length = HCSR04_MeasureOnce();
        if(Length < 0) {
            return -1.0f; // 如果测量失败,返回错误值
        }
        Sum += Length;
    }
    return Sum / 3.0; // 返回平均值
}

四.总结

本篇文章主要是记录小车的部分模块,

具体器件的工作和控制原理介绍的不是很全,

要了解舵机和HC-SR04工作原理和控制原理,参考下面链接和视频

欢迎大家指错,看到了就会修改,希望大家一起共同进步!!!

参考链接: 

舵机的相关原理

参考视频:

STM32驱动HC-SR04超声波测距模块测距_哔哩哔哩_bilibili

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值