STM32与ATK-HC05蓝牙模块实战:硬件接线、AT命令与串口调试全解析
简介正点原子ATK-HC05蓝牙模块资料面向STM32嵌入式开发者和物联网项目工程师系统梳理了基于Bluetooth V2.0EDR的串口蓝牙模块的完整使用路径。资源以压缩包形式提供约33.2MB文件目录未在下载页展示不过从已有说明看内容涵盖模块硬件设计原理图、AT命令集、STM32串口初始化及收发示例、设备发现/配对/连接流程以及常见问题排查指南兼顾理论讲解与项目实操。已有2058人浏览学习适合需要在中低速无线通信场景下快速集成蓝牙功能的开发者。资料在介绍UART/SPI/I2C接口接法的同时还会指导如何通过AT指令配置工作模式、配对和通信速率帮助读者理解蓝牙底层交互机制从而在智能家居、工业控制、便携设备等项目中完成从硬件连线到无线数据传输的全流程搭建。资料将AT指令配置、串口通信与连接管理串联起来形成从入门到上手的系统参考。1. 为什么STM32项目里还在用正点原子ATK-HC05这类串口蓝牙模块手头有个基于STM32F103的小型数据采集设备当初选无线方案时团队里有人提议直接用BLE模组理由是协议新、功耗低。后来评估了一圈还是把正点原子ATK-HC05放了上去。原因不复杂这类基于Bluetooth 2.0 EDR的串口蓝牙模块走的是SPPSerial Port Profile协议对MCU来说它就是一根无线的串口线没有协议栈移植成本也没有GATT服务开发的负担。正点原子资料里把原理图、AT命令集、STM32标准库示例代码、排错指南都铺全了对要快速交付或做毕设、课程设计的场景来说这是最短路径。适合谁手里有STM32开发板、要接手机蓝牙调试助手做无线透传、又不想碰BLE协议栈的工程师。2. 硬件链路电源、电平与接线——ATK-HC05和STM32的物理层细节ATK-HC05核心是CSR BC417方案Bluetooth 2.0 EDRSPP协议这些参数决定了它的硬件设计思路和接线方式。很多人第一次拿到模块直接按“蓝牙串口”四个字把四根线一连能通但后面调试AT命令、出现乱码、连不上手机时问题往往不在代码而在物理层。2.1 供电与电源噪声资料里的原理图显示模块板载3.3V稳压VCC允许3.6V到6V输入所以可以直接从STM32板的5V引脚取电不要用3.3V引脚去喂它。模块射频发射时电流峰值可以到40mA以上如果稳压前级是从USB口拉的3.3V会把MCU的供电一起拉垮。我一般会在VCC和GND之间并联一个10uF电解电容靠近模块引脚放置避免射频突发电流在长线上造成压降。正点原子ATK-HC05常见是模块加底板的套装底板上有USB转串口和按键这种版本直接用USB供电调试AT命令很方便。但注意接到STM32时不要同时插USB线和接单片机串口两个发送端会在同一根线上打架轻则收不到数据重则烧坏IO口。2.2 电平匹配与引脚定义STM32的IO是3.3V模块的串口逻辑电平也是3.3VTXD和RXD可以直连。但如果手头模块是别人给的、或带电平转换芯片的底板版本要先确认底板上的转换方向。有些二手模块是5V电平版本直连STM32会把IO打坏上电前用万用表量一下模块TXD的空闲电平3.3V是安全的5V就要加电阻分压。典型的接线方式如下我一般挂在USART3上把USART1留给调试打印STM32引脚ATK-HC05引脚说明PB10 (USART3_TX)RXDMCU发、模块收交叉连接PB11 (USART3_RX)TXD模块发、MCU收5VVCC模块输入电源3.6-6VGNDGND必须共地否则逻辑电平无参考PA4KEY拉高进入AT命令模式平时拉低PB1STATE连接状态输出空闲低电平、连接高电平代码里把引脚定义写成宏方便换板子时只动一处#define HC05_USART USART3 #define HC05_USART_CLK RCC_APB1Periph_USART3 #define HC05_GPIO_CLK RCC_APB2Periph_GPIOB #define HC05_TX_PIN GPIO_Pin_10 #define HC05_RX_PIN GPIO_Pin_11 #define HC05_KEY_GPIO_CLK RCC_APB2Periph_GPIOA #define HC05_KEY_PORT GPIOA #define HC05_KEY_PIN GPIO_Pin_4 #define HC05_STATE_GPIO_CLK RCC_APB2Periph_GPIOB #define HC05_STATE_PORT GPIOB #define HC05_STATE_PIN GPIO_Pin_1引脚宏定好后初始化GPIO时把TX配成复用推挽输出、RX配成浮空输入KEY配成推挽输出并默认拉低。这里有个很多人踩过的坑如果之前用底板调试过AT命令模块里可能已经被改成了非默认波特率首次接到STM32时先按模块当前波特率通信或者干脆通过底板恢复出厂设置避免第一轮就怀疑代码有问题。2.3 PCB布线与天线处理洞洞板或PCB布线时天线区域下方不要走长平行线尽量远离晶振、电感和DC-DC电感。模块天线端垂直悬空朝外不要贴在外壳金属面或大块覆铜上否则蓝牙信号会被吸走表现为传输距离骤降、偶尔断连。资料里的PCB布局说明对这些有明确指引实际项目中影响的是连接稳定性和误码率。3. AT命令实操进入AT模式、参数固化与常见失败原因AT命令是控制HC05的主要手段。资料里给了完整的命令集但实际调试时大部分人卡在“发AT没反应”这一步而不是命令本身。先把进入AT模式的条件说清楚。3.1 两种工作模式与进入方法HC05有两个工作状态数据透传状态和AT命令状态。上电后默认是透传状态此时串口收到的数据直接走蓝牙发出去要让模块识别AT命令必须先把KEY引脚拉高再上电或者在上电后、未连接蓝牙时给KEY一个高电平脉冲。正点原子底板上有独立按键按住再上电就是AT模式。判断模式的简单方法是看LED闪法慢闪约2秒一次表示在AT模式等待命令连上手机后变成快闪这个现象可以用来快速确认当前状态。进入AT模式后发一条AT\r\n正常会回OK。如果没有任何回显按这个顺序排查串口波特率是否和模块当前一致模块默认9600老版本常见38400KEY是否确实拉高发送时有没有带回车换行很多串口助手默认不带换行导致命令没有被解析模块是否处于已连接状态连接状态下不会响应AT命令。3.2 高频命令表与参数说明下面这张表是正点原子资料里最常用到的命令按实际使用频率排了序命令参数示例作用AT无测试通信返回OKATNAMEATNAMEHC05-X修改模块名称手机搜索时显示ATROLEATROLE1设置主从角色0从机、1主机ATPSWDATPSWD8888设置配对密码默认1234ATUARTATUART115200,0,0设置串口波特率、停止位、校验位ATCMODEATCMODE0配对模式0指定地址、1任意地址ATBINDATBIND0014,03,050607主机模式下绑定从机地址ATRMAAD无清除配对记录ATRESET无软复位参数生效注意ATROLE和ATBIND这一组。默认模块是从机模式手机直接搜名字就能连这是大多数场景的用法。如果要做两个模块之间的串口透传比如STM32采集端和数据接收端各挂一个HC05就必须一个设主机、一个设从机主机绑定从机地址两边波特率和密码要一致。ATBIND的地址格式和手机蓝牙地址显示格式不一样要把冒号换成分号和逗号地址00:14:03:05:06:07写成0014,03,050607中间两位一组反着写这个格式问题卡住过不少人。3.3 波特率修改与回包解析修改波特率的命令要特别小心ATUART115200,0,0执行完并复位后模块立刻按新波特率工作如果此时调试助手没同步改成115200之后就再也收不到任何响应看起来就像模块变砖了。恢复办法是短接模块上的复位电路或者重新上电并在上电后立刻用旧波特率发AT测试。我一般开发阶段保持9600不动等整个链路调通后再统一改。给一段标准的AT命令发送代码基于第2章的USART3配置void HC05_SendATCmd(char *cmd) { printf(AT %s, cmd); while (*cmd) { while (USART_GetFlagStatus(HC05_USART, USART_FLAG_TXE) RESET); USART_SendData(HC05_USART, (uint8_t)(*cmd)); } // 等待最后一个字节发送完成 while (USART_GetFlagStatus(HC05_USART, USART_FLAG_TC) RESET); } // 使用示例 HC05_SendATCmd(AT\r\n); // 测试通信 HC05_SendATCmd(ATROLE0\r\n); // 设为从机 HC05_SendATCmd(ATPSWD8888\r\n);这段代码只负责发送不处理返回值。实际项目里应该在后面串一个500ms超时等待把回包收下来判断是否包含“OK”再决定下一步执行什么命令。回包解析要按行做HC05一次可能回多个CRLF分隔的字符串不要用简单的strstr去匹配整个缓冲区。另一个容易被忽略的点是ATUART的最后两个参数停止位和校验位。绝大多数情况下填0,0但如果你的STM32串口初始化里配了奇偶校验或2位停止位这里必须和MCU侧完全一致否则会出现“能连上但数据全乱”的现象。这种问题用示波器看串口波形最直观没有示波器就把模块接回底板用USB串口助手验证。提示绝大多数“hc06蓝牙模块at无响应”的问题也适用于这里。HC06和HC05的AT指令集有差异HC06不支持主从切换和绑定如果发HC05的命令给HC06自然不会有响应。4. STM32串口驱动与收发状态机从标准库到中断处理STM32和ATK-HC05之间本质是串口通信核心工作是三件事初始化串口、发送数据、接收数据。正点原子资料里给了标准库的示例工程下面这套逻辑是类似项目里常用的精简写法删掉了调试打印和LED闪烁干扰方便移植。4.1 串口初始化与中断配置USART3挂载在APB1总线上波特率默认96008位数据、无校验、1位停止位和HC05出厂参数对齐void HC05_UART_Init(uint32_t baudrate) { GPIO_InitTypeDef gpio; USART_InitTypeDef usart; NVIC_InitTypeDef nvic; RCC_APB2PeriphClockCmd(HC05_GPIO_CLK, ENABLE); RCC_APB1PeriphClockCmd(HC05_USART_CLK, ENABLE); // TX: PB10 复用推挽输出 gpio.GPIO_Pin HC05_TX_PIN; gpio.GPIO_Mode GPIO_Mode_AF_PP; gpio.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(HC05_GPIO_PORT, gpio); // RX: PB11 浮空输入 gpio.GPIO_Pin HC05_RX_PIN; gpio.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(HC05_GPIO_PORT, gpio); usart.USART_BaudRate baudrate; usart.USART_WordLength USART_WordLength_8b; usart.USART_StopBits USART_StopBits_1; usart.USART_Parity USART_Parity_No; usart.USART_HardwareFlowControl USART_HardwareFlowControl_None; usart.USART_Mode USART_Mode_RX | USART_Mode_TX; USART_Init(HC05_USART, usart); nvic.NVIC_IRQChannel USART3_IRQn; nvic.NVIC_IRQChannelPreemptionPriority 2; nvic.NVIC_IRQChannelSubPriority 0; nvic.NVIC_IRQChannelCmd ENABLE; NVIC_Init(nvic); USART_ITConfig(HC05_USART, USART_IT_RXNE, ENABLE); USART_Cmd(HC05_USART, ENABLE); }这段初始化把TX配成复用推挽、RX配成浮空输入这是STM32串口最常用的GPIO配置。中断优先级设成2给主程序和其他外设留出调整空间。收到AT命令返回时把回包打印出来。4.2 接收中断与环形缓冲接收数据用中断方式不要在main函数里轮询RXNE标志否则蓝牙数据包稍微密集一点就会丢字节。中断服务函数只做一件事把收到的字节放进环形缓冲由主循环取走解析#define RX_BUF_SIZE 256 static uint8_t rx_buf[RX_BUF_SIZE]; static volatile uint16_t rx_head 0; static volatile uint16_t rx_tail 0; void USART3_IRQHandler(void) { if (USART_GetITStatus(HC05_USART, USART_IT_RXNE) ! RESET) { uint8_t byte USART_ReceiveData(HC05_USART); uint16_t next (rx_head 1) % RX_BUF_SIZE; if (next ! rx_tail) { rx_buf[rx_head] byte; rx_head next; } // 如果缓冲区满直接丢弃新字节保留未读数据 } }环形缓冲的好处是中断开销极小主循环可以等空闲时一次性处理完一批数据不会因为处理逻辑太慢导致后续字节丢失。缓冲区大小256字节对HC05的串口速率来说够用如果单包数据超过200字节可以考虑改成1024。4.3 数据发送的两种方式发送数据有两种做法。简单场景用阻塞发送适合小数据量void HC05_SendData(uint8_t *buf, uint16_t len) { for (uint16_t i 0; i len; i) { while (USART_GetFlagStatus(HC05_USART, USART_FLAG_TXE) RESET); USART_SendData(HC05_USART, buf[i]); } while (USART_GetFlagStatus(HC05_USART, USART_FLAG_TC) RESET); }阻塞发送会卡住CPU如果主循环里还有其他实时任务比如PID控制、LED扫描就要改成中断发送或DMA发送。用DMA时把串口TX配置成DMA请求源发送前关掉对应DMA通道的EN位、填充内存地址和长度、再重新打开原子性比中断逐字节发送好。主循环里的处理逻辑一般是先查环形缓冲有没有完整的一行数据有就按AT命令回复格式解析或者打包进应用层协议。HC05透传模式下收到的数据没有边界要自己在协议层定义帧头和长度不要指望蓝牙帮你分包。5. 掉线重连与STATE引脚检测HC05在STM32项目里的可靠性收尾HC05在实验室环境很好用一旦做成设备放到现场最头疼的是“手机离开蓝牙范围再回来连不上了”。这一章讲项目交付前一定要做的处理利用STATE引脚做链路检测配合自动重连机制把模块从“能通”用到“可交付”。5.1 STATE引脚轮询检测连接状态用STATE引脚判断。模块空闲时输出低电平与手机建立连接后拉高断开后恢复低。轮询周期建议100ms到200ms不要在主循环里不加延时地死读uint8_t link_connected 0; uint32_t last_check 0; void HC05_LinkCheckTask(void) { if (millis() - last_check 100) return; last_check millis(); if (GPIO_ReadInputDataBit(HC05_STATE_PORT, HC05_STATE_PIN) Bit_SET) { if (!link_connected) { printf([HC05] link established\r\n); link_connected 1; } } else { if (link_connected) { printf([HC05] link lost\r\n); link_connected 0; } } }把状态变化打印出来方便串口调试时观察连接和断开的准确时间点。注意到一个问题手机蓝牙断开后STATE引脚不会立刻拉低实测有几百毫秒到一秒的延迟所以不要用它做精确的实时链路判断只做状态监测和重连触发。5.2 断线后的自动重连逻辑断线后的处理要分情况。如果模块本身还活着只是蓝牙链路断了HC05在从机模式下会重新进入可发现状态手机再次配对即可。如果是被手机主动取消配对模块会记住旧配对信息此时需要发ATRMAAD清除后重新配对。更稳妥的做法是在主循环里做超时管理uint8_t link_connected 0; uint32_t last_check 0; void HC05_LinkCheckTask(void) { if (millis() - last_check 100) return; last_check millis(); if (GPIO_ReadInputDataBit(HC05_STATE_PORT, HC05_STATE_PIN) Bit_SET) { if (!link_connected) { printf([HC05] link established\r\n); link_connected 1; } } else { if (link_connected) { printf([HC05] link lost\r\n); link_connected 0; } } }这个状态机只做一件事情在无连接状态持续一段时间后触发一次ATRESET。复位后模块重新上电初始化比反复尝试发送数据更干净而且能清掉偶发的内部死锁状态。断线后盲目往串口写数据模块在无连接状态下不会把数据发出去反而可能造成缓冲区堆积。最后一个实用技巧利用STATE引脚做低功耗唤醒。设备平时让HC05处于非连接状态只有手机靠近并连上后STATE拉高MCU才从停止模式唤醒开始采集和发送数据。这样一来蓝牙模块不连的时候MCU不用空转设备整体功耗可以压到毫安级比单纯靠透传数据判断连接状态省电得多。本文还有配套的精品资源点击获取