STM32(意法半导体推出的32位微控制器)通过HC-05主从机一体蓝牙模块实现对舵机(SG90)的控制(含源码)

目录

概要

整体架构流程

HC-05和SG90的介绍

HC-05蓝牙模块

SG90舵机模块

技术名词解释

技术细节

小结

概要

本文主要讲述了利用意法半导体推出的 STM32 微控制器,通过 HC-05 主从机一体蓝牙模块来实现对舵机的控制。

整体架构流程

通过意法半导体(STMicroelectronics)的 STM32F103C8T6 微控制器,将其与 HC-05 主从机一体蓝牙模块进行连接。利用手机 APP 作为控制终端,用户可以在手机上发送指定的命令,这些命令通过蓝牙模块传输到 STM32F103C8T6 微控制器。微控制器接收到这些命令后,对舵机进行精确的控制,使其按照用户指定的要求进行动作,从而实现对舵机的灵活、准确的指定命令控制。

HC-05和SG90的介绍

HC-05蓝牙模块

基于蓝牙 2.0 协议标准的蓝牙串口模块,工作频率为 2.4GHz。通过蓝牙通信协议和串口通信协议实现数据传输,内部硬件结构支持这些协议的运行。所谓透传,即蓝牙接收到信息后,直接不加任何附加内容地原文转发出去,极大提高了其兼容性。常用于与单片机(如 Arduino、STM32 等)进行无线通信,例如智能家居应用、远程控制、数据记录应用、机器人、监控系统等领域。它可以将蓝牙模块与其他设备进行配对连接后,忽视蓝牙内部的通信协议,直接将其当做串口使用,实现设备之间的数据交换和通信。
引脚:KEY、VCC、GND、RXD、TXD、STATE,STATE是蓝牙状态引出 脚,未连接时输出低电平,连接时输出高电平。KEY为AT指令设置脚,和按键功能相同。
输入电压为3.2~6V,电源自带防反接,但反接不工作。
状态指示:主机未记录从机地址时,快闪;记录从机地址时,慢闪。从机未连接时以及连接后,主从机都是LED两闪一停。
接口说明 :接口电平为3.2~6V,可以连接各种单片机(ARDUION、51、AVR、 PIC、ARM、MSP430等),5V单片机可以直接连接。直接连接单片机串口,不能经过MAX232芯片。
通信距离 空旷环境下有效距离为10米,超过10米也是有可能的,但超10米不能保证通信质量。
通信方式:配对成功后,可以作为全双工串口使用,无需了解任何蓝牙协议。
默认常用通讯格式:9600,1,N(AT指令可设置停止位为2,奇或偶校验)
主从机设置:模块为主从一体:出厂默认为从机,可以通过AT指令切换成主机。 AT+RLOE=0/1/2,0为从机,1为主机,2为回环角色,设置时需置高34脚或者是按下模块上的按键。默认值 从机:波特率9600、蓝牙名HC-05、配对密码1234

SG90舵机模块

SG90 是一种微型舵机,也被称为伺服电机。以下是关于 SG90 的一些详细信息:

外观与接线:SG90 舵机通常有三根线,颜色分别为红色、棕色和橙黄色(或黄色)。其中,红色线连接电源正极(VCC),一般为 4.8V 至 7.2V;棕色线连接电源负极(GND);橙黄色线为脉冲信号线。

尺寸与重量:其尺寸相对较小,例如,常见的尺寸约为 23mm×12.2mm×29mm,重量约为 9 克。

工作原理:SG90 舵机的工作原理基于控制信号的脉冲宽度调制(PWM)。舵机内部有一个基准电路,产生周期为 20ms、宽度为 1.5ms 的基准信号。控制信号(也是 PWM 信号)的高电平部分宽度在 0.5ms 至 2.5ms 范围内变化,与基准信号相比较,从而决定舵机的转动角度。例如,1.5 毫秒脉冲(控制信号,周期 20ms)将使电机转到 90 度位置(通常称为中性位置);如果脉冲短于 0.5 毫秒,则电机将轴转到更接近-90 度;如果脉冲为 2.5 毫秒,则轴转接近+90 度。

应用场景:SG90 舵机体积小、重量轻、响应快,常用于各种需要角度控制的小型机械设备中,如模型控制(遥控汽车、飞机、船只等的转向、加速和刹车等控制)、机器人控制(机器人头部旋转、臂部移动等)、相机云台(控制相机的运动,实现左右旋转和上下移动)以及一些自动化系统等。

控制方式:要控制 SG90 舵机,一般需要给它提供特定占空比的 PWM 信号。可以使用单片机(如 STM32)的定时器来产生 PWM 信号,通过调整 PWM 信号的占空比来控制舵机的转动角度。在实际使用中,需要根据舵机的具体型号和应用场景进行参数调整,以达到期望的控制效果。

技术名词解释

RXD:接收数据(Receive Data)的缩写,是串口接收数据的信号线。

TXD:发送数据(Transmit Data)的缩写,是串口发送数据的信号线。

蓝牙主从一体:指设备既可以作为蓝牙主设备,也可以作为蓝牙从设备。

PWM:脉冲宽度调制(Pulse Width Modulation),是一种通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量的技术。

全双工串口:允许数据同时在两个方向上传输的串口通信模式。

工作频率为 2.4GHz:这是蓝牙工作的常用频段。

波特率:衡量数据传输速率的单位,表示每秒钟传输的二进制位数。

蓝牙协议:是一系列规范和标准,用于定义蓝牙设备之间如何通信和交互。

技术细节

硬件部分

首先对蓝牙模块进行调试,将USB转TTL与蓝牙模块进行连接(RX接TX,TX接RX,VCC接VCC,GND接GND,其余空接),按下图相连

连接完毕之后,将USB接口插入电脑,打开手机蓝牙调试器APP(注意:只用用安卓手机),连接HC-05蓝牙模块,连接完毕如下图所示

再打开电脑串口工具,扫描串口(注意:要提前安装好串口的驱动),通过手机APP发送指令,蓝牙接受完毕之后,显示到接受面板,如下图(发送数据2024.07.26)

接着对各模块进行连线,如下图

软件部分
PWM
#include "stm32f10x.h"                  // Device header


/**
  * 函    数:PWM初始化
  * 参    数:无
  * 返 回 值:无
  */
void PWM_Init(void)
{
	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);			//开启TIM3的时钟			
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);			//开启GPIOB的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_Init(GPIOB, &GPIO_InitStructure);							//将PB0
																	//受外设控制的引脚,均需要配置为复用模式
	
	/*配置时钟源*/
	TIM_InternalClockConfig(TIM3);		//选择TIM3为内部时钟,若不调用此函数,TIM默认也为内部时钟
	
	/*时基单元初始化*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;				//计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;				//预分频器,即PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM3的时基单元
	
	/*输出比较初始化*/ 
	TIM_OCInitTypeDef TIM_OCInitStructure;							//定义结构体变量
	TIM_OCStructInit(&TIM_OCInitStructure);                         //结构体初始化,若结构体没有完整赋值
	                                                                //则最好执行此函数,给结构体所有成员都赋一个默认值
	                                                                //避免结构体初值不确定的问题
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;               //输出比较模式,选择PWM模式1
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;       //输出极性,选择为高,若选择极性为低,则输出高低电平取反
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   //输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;								//初始的CCR值
	TIM_OC2Init(TIM3, &TIM_OCInitStructure);                        //将结构体变量交给TIM_OC2Init,配置TIM3的输出比较通道2
	TIM_OC3Init(TIM3, &TIM_OCInitStructure);
	TIM_OC1Init(TIM3, &TIM_OCInitStructure); 
	TIM_OC4Init(TIM3, &TIM_OCInitStructure); 
	/*TIM使能*/
	TIM_Cmd(TIM3, ENABLE);			//使能TIM3,定时器开始运行
}

/**
  * 函    数:PWM设置CCR
  * 参    数:Compare 要写入的CCR的值,范围:0~100
  * 返 回 值:无
  * 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比
  *           占空比Duty = CCR / (ARR + 1)
  */

void PWM_SetCompare3(uint16_t Compare)
{
	TIM_SetCompare3(TIM3, Compare);		//设置CCR2的值
}


舵机SG90
#include "stm32f10x.h"                  // Device header
#include "PWM.h"

void Servo_Init(void)
{
	PWM_Init();								
}

/**
  * 函    数:舵机设置角度
  * 参    数:Angle 要设置的舵机角度,范围:0~180
  * 返 回 值:无
  */

void Servo_SetAngle(float Angle)
{
	PWM_SetCompare3(Angle / 180 * 2000 + 500);	//设置占空比
	
}


/**
  * 函    数:舵机读取角度
  * 参    数:无
  * 返 回 值:舵机角度,范围:0~180
  */

uint8_t Servo_GetAngle(void)
{
	return (TIM_GetCapture3(TIM3) - 500) * 180 / 2000;//占空比的反变换
}

蓝牙串口
#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>

void Serial_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//TX
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//RX
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART1, &USART_InitStructure);
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	USART_Cmd(USART1, ENABLE);
}

void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1, Byte);
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}

void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
	uint16_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Array[i]);
	}
}

void Serial_SendString(char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i ++)
	{
		Serial_SendByte(String[i]);
	}
}

uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y --)
	{
		Result *= X;
	}
	return Result;
}

void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
	}
}

int fputc(int ch, FILE *f)
{
	Serial_SendByte(ch);
	return ch;
}

void Serial_Printf(char *format, ...)
{
	char String[100];
	va_list arg;
	va_start(arg, format);
	vsprintf(String, format, arg);
	va_end(arg);
	Serial_SendString(String);
}



主函数部分
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Servo.h"
#include "usart1.h"
#include "PWM.h"

uint8_t move_mode1 ;

int main(void)
{
	/*模块初始化*/
	Servo_Init();		//舵机初始化;
	Serial_Init();
	PWM_Init();
	
	while (1)
	{
			
		
	}
}
void USART1_IRQHandler(void)
{
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		move_mode1 = USART_ReceiveData(USART1);
		if (move_mode1 == '1') { 
			Servo_SetAngle(0);
		} else if (move_mode1 == '2') {
		Servo_SetAngle(60);
		} else if (move_mode1 == '3') { 
			Servo_SetAngle(90);
		} else if (move_mode1 == '4') { 
			Servo_SetAngle(180);
		
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}

}
	}

注意事项

HC-05蓝牙供电最好为5V

舵机供电不能太低,最好外接电源,不然会分压

分步测试可采取用LED等代替舵机,看是否蓝牙能够接受到指令

代码

链接: https://pan.baidu.com/s/1G_e_KDuTXPNE75ByLb5cyQ?pwd=2003 提取码: 2003

  • 42
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值