小智打印机第十节:BLE
// 退出AT模式 else if(g_ble_init_step == BLE_SET_NAME_SUCCESS || g_ble_init_step == BLE_NONEED_SET_NAME || g_ble_init_step == BLE_OUT_AT_MODE){ printf("BLE:正退出AT模式\n");} 第七步:出现问题初始化 else if(g_ble_init_ste
由于STM32是没有蓝牙功能的,而我们需要和手机进行通讯,这里我们使用了蓝牙透传模组,通过串口与STM32进行数据透传。
蓝牙部分我们使用串口2进行数据交互,所以需要重写串口2的处理函数
我们使用的蓝牙模组是RF Crazy/智汉的模组,主要是立创上购买方便,大家也可以根据自己需要选择其它模组。
由于模组启动时,模组的名称是RF-CRAZY, 模组的状态会打印到串口上,所以我们需要使用模组提供的AT指令AT+NAME=Mini-Printer\r\n,设置模组的名称为Mini-Printer,这样我们在手机APP中才能找到这个设备。
另外模组工作时,会打印下方这些设备状态,它会影响我们接收打印数据,所以我们需要使用AT指令AT+STATUS=0\r\n关闭掉。

而在开发过程中,和厂家技术沟通时发现,使用AT+STATUS=0\r\n是无法关闭CONNECTED和DISCONNECTED状态的,所以需要我们在代码中自己处理。
这个蓝牙的通讯和初始化写的很好,用的状态机会处理每一步,第一步:蓝牙初始化发送+++,进入AT模式,第二步:设置状态为0,关闭状态显示,第三步:查询状态是否为0,第四步:查询设备名称,第五步:设置设备名称,第六步:退出AT模式,进入数据透传。
数据类型:
typedef enum{ BLE_INIT_START = 0, // 初始化开始 BLE_IN_AT_MODE, // 进入AT模式 BLE_IN_AT_MODE_SUCCESS, // 进入AT模式成功 BLE_CLOSE_STATUS, // 关闭状态显示 BLE_CLOSE_STATUS_SUCCESS, // 关闭状态显示成功 BLE_QUERY_STATUS, // 查询状态 BLE_QUERY_STATUS0_SUCCESS, // 查询状态为0成功 BLE_QUERY_NAME, // 查询设备名称 BLE_NEED_SET_NAME, // 需要设置名称 BLE_NONEED_SET_NAME, // 不需要设置名称 BLE_SET_NAME, // 设置名称 BLE_SET_NAME_SUCCESS, // 设置名称成功 BLE_OUT_AT_MODE, // 退出AT模式 BLE_INIT_FINISH, // 初始化完成 BLE_RESET, // 重置 } e_ble_init_step;
- 串口数据流解析与协议识别 (Protocol Parsing & Recognition):
-
- 核心机制:uart_cmd_handle() 函数作为串口中断或接收任务的处理核心,维护一个 cmd_buffer 环形缓冲区(实际为线性累加),根据数据特征动态解析。
- 数据类型:
int cmd_index = 0; uint8_t cmd_buffer[100]; bool need_clean_ble_status = false;
-
- 原理:
- 文本状态过滤:在初始化完成后,若接收到 "CONNECTED"、"DISCONNECTED" 等文本字符串,通过 strstr 识别并标记 need_clean_ble_status,在后续任务中清空缓冲区,防止这些非业务数据干扰打印。
- 二进制指令识别:
- 热敏密度控制:检测连续的 0xA5 头部(4字节)+ 1字节参数,根据参数(1, 2, 其他)设置不同的加热密度(30, 60, 100)。
- 读取完成信号:检测连续的 0xA6 头部,置位 read_ble_finish 标志,通知主程序数据接收完毕。
- 打印数据透传:当缓冲区累积达到特定长度(48字节)时,判定为打印图片数据,调用 write_to_printbuffer 将其存入打印队列,并累加 packcount 用于流量统计。
- 原理:
- 设备状态主动上报 (Active Status Reporting):
-
- 核心机制:ble_report() 函数封装了设备状态的结构体数据。
- 原理:将电池电量、温度、缺纸状态、打印状态打包成 4 字节的紧凑数组,通过 HAL_UART_Transmit 发送给蓝牙模组。这通常用于手机端 App 轮询或模组主动上报,让用户实时了解打印机硬件状态。
- AT指令状态机配置 (Finite State Machine Configuration):
-
- 核心机制:init_ble() 函数内部维护一个 while(1) 循环,配合 g_ble_init_step 枚举变量构建状态机。
- 原理:
- 流程控制:系统启动时,状态机按顺序执行:进入AT模式 (+++) -> 关闭状态显示 (AT+STATUS=0) -> 查询并校验名称 -> 设置名称 -> 退出AT模式。
- 容错与重试:如果在某一步骤未收到预期的 "OK\r\n" 回复,状态机会停留在当前状态或重置,配合 vTaskDelay 实现延时重试,确保配置的可靠性。
- 一致性检查:通过查询当前名称并与目标名称比对,仅在名称不一致时才执行写入操作,既保证了配置正确,又减少了不必要的 Flash 擦写(延长模组寿命)。
代码:
void uart_cmd_handle(uint8_t data)
{
cmd_buffer[cmd_index++] = data;
if(g_ble_init_step == BLE_INIT_FINISH){
// 连接状态处理
if(strstr((char*)cmd_buffer, "CONNECTED")){
need_clean_ble_status = true;
run_led(LED_CONNECT);
}
if(strstr((char*)cmd_buffer, "DISCONNECTED")){
need_clean_ble_status = true;
run_led(LED_DISCONNECT);
}
// 错误处理
if(strstr((char*)cmd_buffer, "DEVICE ERROR")){
need_clean_ble_status = true;
run_led(LED_ERROR);
}
// 命令解析
if(cmd_index >= 5){
// 热密度设置命令
if(memcmp(cmd_buffer, "\xA5\xA5\xA5\xA5", 4) == 0){
switch(cmd_buffer[4]){
case 1: set_heat_density(30); break;
case 2: set_heat_density(60); break;
default: set_heat_density(100);
}
clear_cmd_buffer();
return;
}
// 读取完成命令
if(memcmp(cmd_buffer, "\xA6\xA6\xA6\xA6", 4) == 0){
set_read_ble_finish(true);
printf("数据包计数: %d\n", packcount);
clear_cmd_buffer();
return;
}
}
// 动态命令结束检测
if(cmd_index >= 5 && cmd_buffer[cmd_index-1] == 0x01){
if(memcmp(&cmd_buffer[cmd_index-5], "\xA6\xA6\xA6\xA6", 4) == 0){
printf("数据包计数: %d\n", packcount);
clear_cmd_buffer();
set_read_ble_finish(true);
return;
}
}
// 数据包处理
if(cmd_index >= 48){
packcount++;
// 添加数据处理逻辑
}
}
}
// 辅助函数
void clear_cmd_buffer()
{
cmd_index = 0;
memset(cmd_buffer, 0, sizeof(cmd_buffer));
}
更多推荐



所有评论(0)