引言
HC05是一款低成本、低功耗的蓝牙串口模块,基于CSR8675蓝牙芯片,支持蓝牙4.2规范。它通过UART接口与主控芯片通信,可实现无线串口数据传输,广泛应用于物联网设备、智能家居、远程控制等领域。本文将详解HC05的工作原理,并提供完整的STM32代码实现方案。
一、HC05模块核心特性
1.1 模块参数概览
项目 | 规格 |
---|---|
工作电压 | 3.3V-5V |
通信协议 | Bluetooth 4.2 |
数据速率 | 最大2Mbps |
UART接口波特率 | 可配置(300-115200bps) |
配对方式 | AT指令配对/自动配对 |
有效距离 | 10米(空旷环境) |
1.2 引脚定义
- VCC:5V电源输入
- GND:地线
- TX:蓝牙模块接收端 → 主控发送端
- RX:蓝牙模块发送端 → 主控接收端
- EN:使能引脚(高电平启用)
- STATE:状态指示灯(常亮=配对成功,闪烁=配对中)
二、AT指令配置详解
2.1 基础AT指令表
指令 | 说明 | 示例 |
---|---|---|
AT | 测试指令 | AT → 回显OK |
AT+NAME= | 设置模块名称 | AT+NAME=MyBluetoothModule |
AT+BAUD= | 设置通信波特率 | AT+BAUD=115200 |
AT+MODE= | 设置工作模式(0=透传,1=AT模式) | AT+MODE=0 |
AT+PAIR= | 设置配对密码 | AT+PAIR=1234 |
AT+DISC | 进入配对模式 | 触发配对流程 |
2.2 进入AT模式的两种方法。
方法一:先按住按键不放,再给模块上电。此时LED 2S闪一次,进入AT模式。波特率固定为38400。
方法二:模块直接上电。此时LED灯快闪(1s两次)。再按下按键,模块也会进入AT指令,此时LED还是快闪。这个时候的波特率和自己设置的一样,默认为9600。1位停止位,无奇偶校验。
三、代码模拟(基于STM32)
//CH05.c
#include "stm32f10x.h" // Device header
#include "stdio.h"
#include "stdarg.h"
#include "string.h"
uint8_t HC05_RxData;
uint8_t HC05_RxFlag;
extern uint8_t RxSTA;
void HC05_Init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
// 配置 USART1 Tx (PA9) 为复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
// 配置 USART1 Rx (PA10) 为上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
// 设置串口波特率为9600bps,通信双方需协商一致
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
// 设置数据帧字长为8位,对应一个字节长度
USART_InitStructure.USART_StopBits = USART_StopBits_1;
// 设置停止位为1位,用于标记数据帧结束
USART_InitStructure.USART_Parity = USART_Parity_No;
// 关闭奇偶校验功能,简化通信协议
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
// 禁用硬件流控制(RTS/CTS),适用于无流控需求的场景
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
// 同时使能接收(Rx)和发送(Tx)模式,实现全双工通信
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
// 使能USART1的接收中断(RXNE中断),当接收数据寄存器非空时触发中断请求
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 设置中断优先级分组为2,即2位抢占优先级 + 2位子优先级(共4级抢占、4级子优先级)
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
// 指定中断源为USART1中断通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
// 使能USART1中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
// 设置抢占优先级为1(分组2中最高优先级为3,最低为0)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
// 设置子优先级为1(分组2中子优先级范围0-3,数值越小优先级越高)
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1,ENABLE);
}
void HC05_SendByte(uint8_t Byte)
{
USART_SendData(USART1, Byte);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
void HC05_SendArray(uint8_t *Array, uint16_t Length)
{
uint16_t i;
for (i = 0; i < Length; i ++)
{
HC05_SendByte(Array[i]);
}
}
void HC05_SendString(char *String)
{
uint8_t i;
for(i = 0; String[i] != '\0'; i++)
{
HC05_SendByte(String[i]);
}
}
uint32_t HC05_Pow(uint32_t X,uint32_t Y)
{
uint32_t Result = 1;
while(Y--)
{
Result *= X;
}
return Result;
}
void HC05_SendNumber(uint32_t Number, uint8_t length)
{
uint8_t i;
for(i = 0; i < length; i ++)
{
HC05_SendByte(Number / HC05_Pow(10, length - i - 1) % 10 + '0');
}
}
//int fputc(int ch, FILE *f)
//{
// HC05_SendByte(ch);
// return ch;
//}
//void HC05_Printf(char *format, ...)
//{
// char String[100];
// va_list arg;
// va_start(arg, format);
// vsprintf(String, format, arg);
// va_end(arg);
// HC05_SendString(String);
//}
uint8_t HC05_GetRxFlag()
{
if(HC05_RxFlag == 1)
{
HC05_RxFlag = 0;
return 1;
}
return 0;
}
uint8_t HC05_GetRxData()
{
return HC05_RxData;
}
void USART1_IRQHandler()
{
if(USART_GetFlagStatus(USART1, USART_IT_RXNE) == SET)
{
HC05_RxData = USART_ReceiveData(USART1);
HC05_RxFlag = 1;
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
void HC05_GetData(char *Buf)
{
uint32_t count = 0, a = 0;
memset(Buf, 0, sizeof(Buf));
while(count < 10000)
{
if(HC05_GetRxFlag() == 1)
{
Buf[a] = HC05_GetRxData();
a++;
count = 0;
RxSTA = 0;
}
count++;
}
}
//CH05.h
#ifndef __HC05_H_
#define __HC05_H_
#include <stdio.h>
void HC05_Init();
void HC05_SendByte(uint8_t Byte);
void HC05_SendArray(uint8_t *Array, uint16_t Length);
void HC05_SendString(char *String);
uint32_t HC05_Pow(uint32_t X,uint32_t Y);
void HC05_SendNumber(uint32_t Number, uint8_t length);
//void HC05_Printf(char *format, ...);
uint8_t HC05_GetRxFlag();
uint8_t HC05_GetRxData();
void HC05_GetData(char *Buf);
#endif
//main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "HC05.h"
uint8_t RxSTA = 1;
char RxData[100] = "None";
int main(void)
{
/*模块初始化*/
OLED_Init(); //OLED初始化
HC05_Init();
OLED_ShowString(1,1,"RxData");
while (1)
{
HC05_GetData(RxData);
if(RxSTA == 0)
{
OLED_Clear();
OLED_ShowString(1,1,"RxData");
OLED_ShowString(2,1,RxData);
RxSTA = 1;
}
}
}