最近买了一个大夏龙雀家的蓝牙模块DX-BT311-10C02S,这个蓝牙是一款基于BLE 5.4规范的串口透传模块,支持AT指令配置、主从模式切换,非常适合与单片机搭配实现无线数据传输。
如果是第一次买还是很便宜的,他家的模块有一说一是真的不错

本文将分享如何使用STM32F103C6T6(HAL库)驱动该模块,完成基础功能验证。
一、模块简介
DX-BT311-10C02S具有以下特点(拷贝手册的):
-
支持BLE 5.4协议,主从模式可切换
-
默认串口参数:9600bps/8/n/1
-
提供UART接口,支持AT指令配置
-
默认从模式,UUID:SERVICE UUID: 0xFFE0,NOTIFY/WRITE UUID: 0xFFE1,WRITE UUID: 0xFFE2
-
支持数据透传,连接后自动进入透传模式
-
具有LINK-STATUS引脚,高电平表示蓝牙已连接
手册中AT指令格式说明:
-
所有指令以
AT开头,以\r\n结尾 -
响应以
+开头,成功时以OK结束,失败返回ERROR=<code> -
例如修改名称:发送
AT+NAME1234,返回+NAME=1234后跟OK
二、硬件连接
| STM32F103C6T6 | DX-BT311模块 |
|---|---|
| PB10 (USART3_TX) | RX |
| PB11 (USART3_RX) | TX |
| 3.3V | VCC |
| GND | GND |
| PA0(可选) | LINK-STATUS |
三、驱动设计思路
为了高效处理不定长数据,我们采用DMA + 空闲中断 + 环形缓冲区的方案:
-
DMA接收:开启USART3的DMA循环接收,无需CPU干预。
-
空闲中断:当模块发送一帧数据(以空闲状态结束)时,触发中断,在中断中将DMA缓冲区数据拷贝到环形缓冲区。
-
环形缓冲区:用于暂存接收数据,供主循环取用。
-
AT命令同步:发送AT命令后,清空环形缓冲区,然后循环调用行读取函数,直到收到"OK"或"ERROR"或超时。这样既能与透传数据隔离,又避免阻塞。
关键点:
-
接收统一由环形缓冲区管理,AT命令和透传数据共用缓冲区,但通过状态标志区分。
-
连接状态通过PA0引脚轮询检测,并提供回调。
-
支持GBK编码,方便设置中文蓝牙名称。
四、关键代码实现
4.1 初始化与DMA启动
void bt311_init(UART_HandleTypeDef *huart, DMA_HandleTypeDef *hdma_rx) {
g_bt311.huart = huart;
g_bt311.hdma_rx = hdma_rx;
ring_buffer_clear();
// 启动DMA空闲中断接收
HAL_UARTEx_ReceiveToIdle_DMA(huart, g_bt311.rx_dma_buf, BT311_RX_DMA_BUF_SIZE);
}
4.2 空闲中断回调
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {
if (huart != g_bt311.huart) return;
for (uint16_t i = 0; i < Size; i++) {
// 存入环形缓冲区
uint16_t next_head = (g_bt311.rx_ring_head + 1) % BT311_RX_RING_SIZE;
if (next_head != g_bt311.rx_ring_tail) {
g_bt311.rx_ring_buf[g_bt311.rx_ring_head] = g_bt311.rx_dma_buf[i];
g_bt311.rx_ring_head = next_head;
}
}
g_bt311.rx_ready = 1;
HAL_UARTEx_ReceiveToIdle_DMA(huart, g_bt311.rx_dma_buf, BT311_RX_DMA_BUF_SIZE);
}
4.3 AT命令发送与同步
bool bt311_send_cmd(const char *cmd, char *response, uint16_t resp_size, uint32_t timeout_ms) {
// 发送命令(添加\r\n)
char full_cmd[128];
snprintf(full_cmd, sizeof(full_cmd), "%s\r\n", cmd);
HAL_UART_Transmit(g_bt311.huart, (uint8_t*)full_cmd, strlen(full_cmd), 100);
// 清空环形缓冲区
ring_buffer_clear();
uint32_t start = HAL_GetTick();
char line[128];
while (HAL_GetTick() - start < timeout_ms) {
if (ring_buffer_read_line(line, sizeof(line))) {
if (strstr(line, "OK") != NULL) return true;
if (strstr(line, "ERROR") != NULL) return false;
}
bt311_process(); // 处理环形缓冲区(从DMA搬运)
HAL_Delay(1);
}
return false;
}
4.4 主循环处理
void bt311_process(void) {
// 处理透传数据(用户回调)
if (g_bt311.rx_ready && g_bt311.user_rx_callback) {
// 从环形缓冲区取数据,调用回调
// ...
}
// 处理连接状态变化
if (g_bt311.link_status_port) {
uint8_t cur = HAL_GPIO_ReadPin(...);
if (cur != g_bt311.link_status) {
g_bt311.link_status = cur;
if (g_bt311.link_status_callback) g_bt311.link_status_callback(cur);
}
}
}
4.5 测试函数
提供全功能测试函数,自动完成初始化、AT测试、版本查询、MAC读取、名称设置、连接状态检测、数据收发打印,方便快速验证。
void bt311_run_full_test(UART_HandleTypeDef *huart, DMA_HandleTypeDef *hdma_rx) {
bt311_init(huart, hdma_rx);
bt311_register_rx_callback(print_received_data);
bt311_set_link_status_pin(GPIOA, GPIO_PIN_0);
bt311_register_link_callback(print_link_status);
// 执行AT测试
if (bt311_test()) printf("AT OK\r\n");
char version[32]; bt311_get_version(version);
char mac[18]; bt311_get_mac(mac);
bt311_set_name("HealthMonitor");
bt311_reset();
while (1) {
bt311_process();
// 连接后每5秒发送模拟数据
if (bt311_get_link_status()) {
static uint32_t last = 0;
if (HAL_GetTick() - last > 5000) {
bt311_send_data((uint8_t*)"HR:75,SPO2:98\r\n", 14);
last = HAL_GetTick();
}
}
HAL_Delay(10);
}
}
五、测试验证
在STM32F103C6T6上运行后,串口调试助手输出:

手机连接后,发送的数据被正确打印,同时模块每隔5秒自动发送模拟心率血氧数据。连接状态引脚PA0电平变化触发回调,工作稳定。
六、总结
本文介绍了DX-BT311-10C02S蓝牙模块的驱动设计思路与关键实现。通过DMA+空闲中断+环形缓冲区的组合,实现了高效、非阻塞的数据接收,并统一处理AT命令响应与透传数据。该驱动已成功应用于健康监测项目,可方便地扩展其他传感器。代码结构清晰,移植方便,可作为STM32与BLE模块通信的参考模板。