STM32控制SG90舵机与超声波HC_SR04测距模块

article/2025/8/19 0:04:01

目录

前言

1、项目简介

项目相关内容

2、模块

1、系统定时器SysTick

2、舵机模块SG90

3、 超声波模块 HC-SR04 

4、Main.c

5、总结


前言

这篇文章主要是对自己学习STM32做的一个总结,利用超声波模块加舵机模块进行的小项目,为了方便知识的回顾,有错误还望指正谢谢。

1、项目简介

项目是利用超声波模块(HC_SR04)来进行测距,由此来进行操纵舵机(SG90)进行运动反馈。这也是可以做成一个小小的开盖垃圾桶。

项目相关内容

本项实验的硬件组成有STM32F103C8T6开发板、USB转TTL串口模块(CH340)、超声波模块(HC-SR04)、舵机模块(SG90 180度),系统定时器SysTick,由此来进行一个各个模块的编写。

2、模块

1、系统定时器SysTick

系统定时器的延时函数参考我的上一篇文章,有详细解释。

STM32的SysTick系统定时器_努力学习的多云的博客-CSDN博客

void ms_delay(uint32_t ms)
{uint32_t i;SysTick_Config( 72000);for(i=0;i<ms;i++)//一个循环相当于1ms{while(  !((SysTick->CTRL)&(1<<16))  );//一次计时结束}SysTick->CTRL	&=~	SysTick_CTRL_ENABLE_Msk;//使之使能,置O}void us_delay(uint32_t us)
{uint32_t i;SysTick_Config(72);for(i=0;i<us;i++){while(  !((SysTick->CTRL)&(1<<16)) );}SysTick->CTRL	&=~	SysTick_CTRL_ENABLE_Msk;}

2、舵机模块SG90

我是选择图中这款的SG90舵机支持0到180度,可以看到有三根线,红色线(VCC)、棕色线(GND)、还有一根黄橙色的信号线。舵机的控制一般需要一个20ms的时基脉冲,。

SG90舵机的控制需要一个20ms的时基脉冲,定时器的时钟周期计算公式是, T = (arr+1) * (psc+1) / 72M。对TIM_TimeBaseInit结构体的成员TIM_Period 与TIM_Prescaler进行赋值即可。 当设置arr= 199,psc = 7199,T = 200*7200/72000000 = 0.02s = 20ms。

脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分,所以是利用一个占空比来控制舵机转动的角度。PWM占空比是指在一个周期内,信号处于高电平的时间占据整个信号周期的百分比。占空比 = t / T 相关参数如下:
t = 0.5ms——————-舵机会转动 0 °
t = 1.0ms——————-舵机会转动 45°
t = 1.5ms——————-舵机会转动 90°
t = 2.0ms——————-舵机会转动 135°
t = 2.5ms——————-舵机会转动180°

当你需要转动135°时,他的占空比就是2.0ms/20ms=10%,所以 TIMx 捕获比较寄存器值就为200-200*10% = 180。

#include "motor.h"
#include "stm32f10x.h"void motor_config(void)
{GPIO_InitTypeDef	GPIO_Motorinit;TIM_TimeBaseInitTypeDef	TIM_Motorinit;TIM_OCInitTypeDef		TIMPWM_Motorinit;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, 	ENABLE);//根据参考手册可知道他们各自挂在APB2还是APB1RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,		ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,  ENABLE);GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3 ,  ENABLE);//部分重映射GPIO_Motorinit.GPIO_Mode		=	GPIO_Mode_AF_PP;//根据参考手册查找,可以看图选择复用推挽GPIO_Motorinit.GPIO_Pin			=	GPIO_Pin_5;GPIO_Motorinit.GPIO_Speed		=	GPIO_Speed_50MHz;GPIO_Init( GPIOB,  &GPIO_Motorinit);TIM_Motorinit.TIM_ClockDivision		=	TIM_CKD_DIV1;				//设置时钟分割TIM_Motorinit.TIM_CounterMode			=	TIM_CounterMode_Up;	//TIM向上计数模式TIM_Motorinit.TIM_Period					=	200-1;							//设置在下一个更新事件装入活动的自动重装载值TIM_Motorinit.TIM_Prescaler				=	7200-1;							//TIMx时钟频率预分频值TIM_TimeBaseInit( TIM3, &TIM_Motorinit);TIMPWM_Motorinit.TIM_OCMode				=	TIM_OCMode_PWM1;				//选择定时器模式,低于比较值为有效电平TIMPWM_Motorinit.TIM_OutputState	=	TIM_OutputState_Enable;	//比较输出使能TIMPWM_Motorinit.TIM_OCPolarity		=	TIM_OCPolarity_Low;			//选择有效输出极性,为低电平TIM_OC2Init( TIM3, &TIMPWM_Motorinit);//使能通道的的TIM3TIM_OC2PreloadConfig( TIM3, TIM_OCPreload_Enable );TIM_Cmd( TIM3, ENABLE);}

 在选择向上计数模式,讲述PWM原理:
①在PWM输出模式下除了CNT(计数器当前值) ARR(自动重装载值),CCRx(捕获/比较寄存器值)。

②当CNT小于CCRx时,TIMxCHx通道输出低电平,根据定时器模式和选择有效输出极性来做判断

③当CNT等于或大于CCRx时,TIMxCHx通道输出高电平

由此在上面的占空比图中就可以看到调整占空比就可以控制舵机转的角度了。

其中的引脚配置由参考手册可以查找到

STM32F1xx中文参考手册-->8.1.11 外设的GPIO配置-->表20 通用定时器TIM2/3/4/5

   STM32F1xx中文参考手册-->8.3.7 定时器复用功能重映射-->表42 TIM3复用功能重映像

 

3、 超声波模块 HC-SR04 

HC-SR04是一款尺寸完全兼容老版本增加UART和IIC功能的开放式超声波测距模块,可以通过电阻设置成UART或IIC模式。2CM盲区,4.5M典型最远测距,2.2mA作电流。工作电压宽(3-5.5V)。

外部MCU给模块Trig脚一个大于10uS的高电平脉冲;模块会给出一个与距离等比的高电平脉冲信号,可根据脉宽时间“T”算出:
距离=T*C/2 (C为声速)

 

图中时VCC为供电电源,Trig触发端口配置了PB11,Echo为接受端口配置了PB10,GND为地。

在此次程序中做了IO配置,定时器配置,和中断配置,因为要计数高电平的持续时间,在高电平的时候开始计数,下降沿的时候关闭定时器。

其中输入输出模式可以从参考手册找到

 

#include"HC_SR04.h"
#include"stm32f10x.h"
#include"SysTick.h"extern uint16_t mscount	= 0;//超声波计数,加了extern后,在Main里也可以使用了void HC_SR04Config(void)
{GPIO_InitTypeDef GPIO_HCSR04init;//io配置TIM_TimeBaseInitTypeDef	TIM_HCSR04init;//定时器配置NVIC_InitTypeDef NVIC_HCSR04init;//中断配置RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE );RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4 ,  ENABLE);//在rcc.h寻找,出TIM1外的定时器都是挂在APB1总线上的/*所以要使能定时器时钟就要使能APB1外设时钟寄存器*/NVIC_PriorityGroupConfig( NVIC_PriorityGroup_1);//优先级分组//Trig触发  PB11GPIO_HCSR04init.GPIO_Mode		=	GPIO_Mode_Out_PP;GPIO_HCSR04init.GPIO_Pin		=	GPIO_Pin_11;GPIO_HCSR04init.GPIO_Speed	=	GPIO_Speed_50MHz;GPIO_Init( GPIOB,  &GPIO_HCSR04init);//初始化//Echo接受引脚 PB10  接收电平不需要配置速度GPIO_HCSR04init.GPIO_Mode		=	GPIO_Mode_IN_FLOATING;GPIO_HCSR04init.GPIO_Pin		=	GPIO_Pin_10;GPIO_Init( GPIOB,  &GPIO_HCSR04init);TIM_HCSR04init.TIM_ClockDivision=	TIM_CKD_DIV1;//时钟分割    在内核misc.h寻找TIM_HCSR04init.TIM_CounterMode	=	TIM_CounterMode_Up;//计数模式TIM_HCSR04init.TIM_Period		=	1000-1;//自动重装载数值TIM_HCSR04init.TIM_Prescaler	= 72-1;//分频系数TIM_TimeBaseInit( TIM4, &TIM_HCSR04init);TIM_ITConfig( TIM4,  TIM_IT_Update, ENABLE );//定时器中断TIM_Cmd( TIM4, DISABLE );//使能定时器,因为要计算高电平时间,所以先关闭,等检测时再打开NVIC_HCSR04init.NVIC_IRQChannel		= TIM4_IRQn;//中断通道  在stm32f10x.h寻找NVIC_HCSR04init.NVIC_IRQChannelPreemptionPriority	=0;//抢占优先级,最高级NVIC_HCSR04init.NVIC_IRQChannelSubPriority			=0;//响应优先级NVIC_HCSR04init.NVIC_IRQChannelCmd					=ENABLE;//通道使能NVIC_Init( &NVIC_HCSR04init);}

超声波测距步骤

1.配置GPIO引脚结构体(Trig,Echo)。
2.配置定时器结构体
3.配置定时器中断结构体
4.开启时钟(定时器,GPIO)
5.Trig引脚输出高电平(10us以上),然后关闭
6.等待Echo引脚输入高电平开始,定时器打开--->开启计数器计数
7.等待Echo引脚输入高电平结束,定时器关闭-..>停止计数器计数
8.通过计数器的值计算得出超声波测量距离

程序中配置了周期为1us的TIM4,再编写中断服务函数TIM4_IRQHandler(void),进入一次中断 mscount加1,

//打开定时器4
void Open_TIM4(void)
{TIM_SetCounter( TIM4, 0);//设置寄存器的计数值mscount =0 ;TIM_Cmd( TIM4, ENABLE );}//关闭定时器4
void Close_TIM4(void)
{TIM_Cmd( TIM4, DISABLE );}//中断服务函数
void TIM4_IRQHandler(void)
{if (TIM_GetITStatus( TIM4, TIM_IT_Update ) != RESET)//判断是否发生中断,意思是不等于0时{TIM_ClearITPendingBit( TIM4, TIM_IT_Update );mscount++;}}
/*获取定时器计数的值,计算高电平的时间*/
int GetEcho_time(void)
{uint32_t t = 0;t = mscount*1000;//换算成以us做单位t += TIM_GetCounter( TIM4);//获取定时器的值TIM4->CNT = 0;//清零从头开始计数us_delay(50);return t;
}

距离公式:高电平持续时间*声速(340m/s)/2。

34300 除于 1000 00 换算成cm/us,也就是0.0343cm/us,在换算一个角度,1/(0.0343)cm/us,即29.15 us/cm,意味着 291.5us表示10cm的距离,1cm就是29.15us,发送后接收,声音走过两倍距离,实际距离就是1cm,对应58.3us,程序中的 length 实际上是 us,换算成距离,除以 58.358.3 会更具体一点,但是我们除以58就可以了。

代码中运用5次计算求出平均,使得结果会更准确。其中TRIG_Send(), ECHO_Reci(),是我在.h文件中宏定义了出来,方便查看。

#define ECHO_Reci	     GPIO_ReadInputDataBit( GPIOB,  GPIO_Pin_10)/* 注意 这里 第二行 不要分号结尾   */
#define TRIG_Send(a)     if(a) \GPIO_SetBits( GPIOB,  GPIO_Pin_11);\else \GPIO_ResetBits( GPIOB,  GPIO_Pin_11) // 就是这里 
//通过定时器4计数器值推算距离
float GetLength(void)
{int i = 0;uint32_t t = 0;float length	=	0;float sum = 0;while(i !=5){TRIG_Send(1);us_delay(20);//TRIG引脚发送20us高电平TRIG_Send(0);while (ECHO_Reci == 0);//while (ECHO_Reci == 0); 相当于是 while(0); 就是一直在0那里循环   //到了这里相当于跳出0了 到了1Open_TIM4();        //也就是高电平的时候 开启 TIM4  i = i+1;while (ECHO_Reci == 1);//这里的意思 和上面的相反Close_TIM4();          t = GetEcho_time();length = ((float)t /58.0);sum = sum + length;}length = sum/5.0;return length;}

4、Main.c

其中作为一个超声波距离判断来进行一个舵机的转动,距离可以通过串口打印出来。在讲到PWM波控制占空比大小来进行一个舵机的转动角度,要让舵机转180度,那么就让pwmval的值为200*(1-(2.5/20)) = 175。我选择的是选择135度,所以pwmval设置为180。

int main()
{int pwmval ;float Length = 0;HC_SR04Config();usart_init();motor_config();while(1){Length = GetLength();printf("%.3f\r\n",Length);ms_delay(500);if (Length < 10){pwmval = 180;TIM_SetCompare2( TIM3,  pwmval);ms_delay(500);}else if (Length >20){pwmval =195;TIM_SetCompare2( TIM3,  pwmval );}}
}

5、总结

在这个学习过程中,也是从不明白到渐渐进入状态,也看了很多小伙伴的文章,终于把第一篇搞了出来,在这里有错误的还望大家指正,这次的就是一个简单的小项目,内容就是要学会查资料,看参考手册,整个弄懂之后会发现一个新的感觉,内容相对简单,但对于新手的我就是极大的一个收获,后续可以通过更多的模块来实现更多好玩的东西。

参考链接:

STM32驱动SG90舵机与HC_SR04超声波模块_嵌入式的自我修养的博客-CSDN博客_stm32驱动sg90


http://chatgpt.dhexx.cn/article/aXpZx8Zw.shtml

相关文章

STM32F103单片机控制SG90舵机

前言 在智能衣柜系统中&#xff0c;试用SG90旋转0-180&#xff0c;模拟衣柜的开关门&#xff0c;舵机正转开门&#xff0c;180-0反转模拟一个关门的现象。 一&#xff0c;SG90舵机 1.1SG90链接&#xff1a; 【淘宝】https://m.tb.cn/h.UjfPasG?tk10CNdeeB4Il CZ0001 「SG9…

Arduino与SG90舵机握手

Arduino教程传送门&#x1f9ed;&#x1f3d4;&#x1f30b;&#x1f6e4;&#x1f3de;&#x1f3dc; Arduino与SG90舵机握手 1.0 简介2.0 实验材料3.0 实验步骤3.1 根据原理图搭建电路3.2 新建sketch&#xff0c;拷贝如下代码并进行保存编译上传3.3 实验现象 4.0 总结 1.0 简…

C51单片机定时器2实现SG90舵机控制

谈起舵机最初的了解应用于航模&#xff0c;偶然的机会在网上看到有牛人使用多个舵机做人形机器人的关节&#xff0c;感觉这小东西很有趣&#xff0c;蒙发了买来学习学习的想法&#xff0c;这已经是多年前的事了&#xff0c;后来由于某些原因&#xff0c;这个想法直到今年才落地…

智能垃圾桶(七)——SG90舵机的介绍与使用(树莓派pico实现)

文章目录 一、SG90舵机的引脚介绍二、与pico引脚的对接三、舵机的使用原理四、Thonny程序五、效果展示一、SG90舵机的引脚介绍 舵机上会引出三根线:分别是GND(棕色线)、VCC(红色线)和SIG(黄色线),就是地线、电源线(5V)和信号线。千万不能接错! 二、与pico引脚的对接…

FPGA实现360°SG90舵机

SG90 SG90舵机需要注意区分90、180和360&#xff0c;今天要用的舵机是360的。 舵机是通过输入信号来控制转动的&#xff0c;360舵机不同于180舵机&#xff0c;它只有顺时针旋转、逆时针选择和停止&#xff0c;无法通过特定的信号来达到转动的角度。所以需要通过时间和转动速度…

PWM开发SG90

文章目录 2. PWM开发SG90 2.1 简介 2.3 控制舵机 2.4 遇见潇潇遇见你&#xff0c;不负代码不负卿 前言 2. PWM开发SG90 2.1 简介 PWM &#xff0c;英文名 Pulse Width Modulation &#xff0c;是脉冲宽度调制缩写&#xff0c;它是通过对一系列脉冲的宽度进 行调制&#xff0…

学习笔记12-SG90舵机

目录 一、简介接线 二、原理3、代码段3.1、sg90.c3.2、main.c 一、简介 舵机是一种位置&#xff08;角度&#xff09;伺服的驱动器&#xff0c;适用于需要角度不断变化并可以保持的控制系统&#xff0c;可以根据控制信号来输出指定的角度&#xff08;常见的有0-90、0-180、0-3…

PWM驱动sg90电机

关于PWM驱动sg90电机&#xff0c;不管是180还是360舵机都满足左侧的条件关系。 PWM周期为20ms&#xff0c;频率为50Hz 重装载值arr 1999 预分频值psc 7199 stm32f103主频72MHz TIM3_Int_Init(1999,7199);//Tout (arr1)(psc1)/TCLK;72000000/2000/720050PWM周期 (主频 / […

51单片机控制sg90舵机

2.1 简介 PWM&#xff0c;英文名Pulse Width Modulation&#xff0c;是脉冲宽度调制缩写&#xff0c;它是通过对一系列脉冲的宽度进 行调制&#xff0c;等效出所需要的波形&#xff08;包含形状以及幅值&#xff09;&#xff0c;对模拟信号电平进行数字编码&#xff0c;也就是说…

SG90舵机使用介绍

舵机控制 型号&#xff1a;SG90 接线 黄线&#xff1a;信号线 红线&#xff1a;电源线 棕线&#xff1a;地线 PWM周期 需要通过信号线往舵机输入PWM波&#xff0c;才能驱动舵机转动 PWM波的频率不能太高&#xff0c;大约50HZ&#xff0c;即周期1/频率1/500.02s&#xff…

51单片机sg90舵机

51单片机按键控制舵机旋转 一、舵机工作原理 1、这里介绍的sg90的可旋转角度为 0~180 2、sg90有三条线&#xff0c;橙色&#xff08;PWM&#xff09;红色&#xff08;5V&#xff09;棕色&#xff08;GND&#xff09; 3、PMW的范围为0.5ms2.5ms&#xff0c;相应的旋转角度为…

PWM开发SG90舵机

1. 简介 PWM,全称&#xff1a;Pulse Width Modulation,脉冲宽度调制缩写&#xff0c;它是通过宽度对一系列脉冲的宽度进行调制&#xff0c;等效出所需要的波形&#xff08;包含形状以及幅值&#xff09;&#xff0c;对模拟信号电平进行数字编码&#xff0c;也就是说通过调节占空…

控制SG90舵机

1. 什么是舵机 如下图所示&#xff0c;最便宜的舵机sg90&#xff0c;常用三根或者四根接线&#xff0c;黄色为PWM信号控制 用处&#xff1a;垃圾桶项目开盖用、智能小车的全比例转向、摄像头云台、机械臂等 常见的有0-90、0-180、0-360 VCC:接电压端 GND:接地端 PWM信号&#…

STM32控制SG90舵机

简介 通过使用STM32控制SG90舵机进行转动 PWM输出&#xff1a;PC6 定时器&#xff1a;TM3&#xff0c;通道1 接线如下&#xff1a; 控制原理及PWM配置 舵机的控制一般需要一个20ms的时基脉冲&#xff0c;该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分 PWM周…

【mcuclub】舵机-SG90

一、实物图&#xff08;SG90&#xff09; 二、原理图 编号名称功能1GND电源地&#xff08;棕色线&#xff09;2VCC电源正&#xff08;红色线&#xff09;3I/O信号线&#xff08;黄色线&#xff09; 三、简介 舵机&#xff08;英文叫Servo&#xff09;&#xff0c;是伺服电机的…

STM32外设系列—sg90(舵机)

文章目录 一、sg90简介二、引脚连接三、控制方法四、程序设计4.1 配置定时器4.2 编写控制程序 五、360舵机 一、sg90简介 首先介绍说一下什么是舵机。舵机是一种位置&#xff08;角度&#xff09;伺服的驱动器。适用于一些需要角度不断变化的&#xff0c;可以保持的控制系统。…

java基本类型与包装类型

基本数据类型&#xff1a;byte&#xff0c;int&#xff0c; short&#xff0c; long&#xff0c; boolean&#xff0c;char&#xff0c; float&#xff0c;double等 包装类型 &#xff1a; Byte&#xff0c;Integer&#xff0c;Short&#xff0c;Long&#xff…

java基本类型与包装类型区别

java基本类型与包装类型区别 Java中基本类型都有固定的存储空间&#xff0c;不像其他大多数语言那样随机器硬件架构的变化而变化&#xff0c;这种占存储空间大小的不变性是java程序比其他大多数语言编写的程序更具可移植性的原因之一。 java中基本类型和包装类的区别&#xff1…

【包装类型】

文章目录 包装类八种基本类型及其包装类手动装箱/拆箱自动装箱/拆箱整数型常量池 Integer方法 包装类 我们已经知道&#xff0c;Java的数据类型分两种&#xff1a; 基本类型&#xff1a;byte&#xff0c;short&#xff0c;int&#xff0c;long&#xff0c;boolean&#xff0c;…

Java为什么要有基本数据类型和包装类型

作为面向对象语言为代表的Java, 在很多任务场景中经常看到它的身影。那么&#xff0c;Java为什么要有基本数据类型和包装类型&#xff1f; 这个问题看似简单&#xff0c;其实也不好回答。毕竟这个问题不仅你我感觉到困惑&#xff0c;许多大佬也感觉到困惑&#xff0c;一些人希望…