shuichan_old/V1.5/STM32F103_App1/HardWare/USER_CMD/ble_at.c

195 lines
6.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ble_at.c - HLK-B40 蓝牙透传模块 AT 配置
*
* 接线:模块 PC5(功能按键输入) 接单片机 PB0。
* 进 AT 模式PB0 拉低 1s 后释放(手册要求 0.5~3s
* 回透传模式AT 模式下发送 AT+TS=1。
* 上电默认透传模式。
*/
#include "ble_at.h"
#include "uart.h"
#include "log.h"
#include "main.h"
#include "system.h"
#include "24c02.h"
#include "stdio.h"
#include "string.h"
#define BLE_PC5_PORT GPIOB
#define BLE_PC5_PIN GPIO_PIN_0
#define BLE_PC5_LOW() HAL_GPIO_WritePin(BLE_PC5_PORT, BLE_PC5_PIN, GPIO_PIN_RESET)
#define BLE_PC5_HIGH() HAL_GPIO_WritePin(BLE_PC5_PORT, BLE_PC5_PIN, GPIO_PIN_SET)
/* EEPROM 缓存区已配置好的蓝牙名132~15726B避开其它占用 */
#define BLE_CACHE_ADDR 132
#define BLE_POWER_ADDR 158 /* EEPROM已配置的发射功率132~157 名称缓存, 160 日志等级) */
#define BLE_CACHE_LEN 26
/* PB0 开漏输出:释放时由模块 PC5 内部上拉保持高电平 */
void ble_at_init(void)
{
GPIO_InitTypeDef g = {0};
__HAL_RCC_GPIOB_CLK_ENABLE();
BLE_PC5_HIGH();
g.Pin = BLE_PC5_PIN;
g.Mode = GPIO_MODE_OUTPUT_OD;
g.Pull = GPIO_NOPULL;
g.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(BLE_PC5_PORT, &g);
BLE_PC5_HIGH();
}
static void ble_delay(uint32_t ms)
{
while (ms >= 100) {
HAL_Delay(100);
IWDG_Feed();
ms -= 100;
}
if (ms) HAL_Delay(ms);
}
/* 清空 USART1 待处理行 */
static void ble_flush_rx(void)
{
while (USART1_GetCommand() != NULL) { }
}
/* 发送 AT 命令并等待期望应答按行匹配子串0=成功 */
static int ble_at_cmd(const char *cmd, const char *expect, int timeout_ms)
{
char line[64];
int n = snprintf(line, sizeof(line), "%s\r\n", cmd);
ble_flush_rx();
HAL_UART_Transmit(&huart1, (uint8_t *)line, n, 500);
int t = timeout_ms / 50;
while (t-- > 0) {
ble_delay(50);
const char *resp = USART1_GetCommand();
if (resp) {
if (strstr(resp, expect)) {
log_info("> BLE AT: %s", resp);
return 0;
}
if (strstr(resp, "ERROR")) {
log_warn("> BLE AT 应答错误: %s", resp);
return -1;
}
}
}
log_warn("> BLE AT 超时: %s", cmd);
return -1;
}
/* 上电执行一次:进 AT 模式 → 蓝牙名称查询/设置为 BLE_NAME → 需要时重启模块生效。
* 先查询后设置:名字已正确则整个流程跳过(不留 AT 窗口,避免 APP 数据撞进 AT 命令) */
void ble_setup_name(void)
{
char cmd[48];
/* EEPROM 缓存命中(名称+功率都对)则跳过整个 AT 流程(零窗口,蓝牙 APP 不断联) */
char cache[BLE_CACHE_LEN] = {0};
eepromReadData(BLE_CACHE_ADDR, cache, BLE_CACHE_LEN);
cache[BLE_CACHE_LEN - 1] = 0;
uint8_t pwr_cache = 0xFF;
eepromReadData(BLE_POWER_ADDR, &pwr_cache, 1);
if (strcmp(cache, BLE_NAME) == 0 && pwr_cache == BLE_TX_POWER) {
log_info("> BLE: 配置已缓存(%s/功率%d),跳过设置", BLE_NAME, BLE_TX_POWER);
return;
}
/* AT 窗口内静音日志UART1 与模块共用,日志字节会污染模块的 AT 命令解析 */
log_mute(1);
/* 进 AT 模式并查询当前名称:无应答则重新拉 PC5 再试,最多 3 轮 */
const char *cur = NULL;
for (int round = 0; round < 3 && !cur; round++) {
BLE_PC5_LOW();
ble_delay(1100); /* 拉低 1s 进 AT 模式 */
BLE_PC5_HIGH();
ble_delay(600); /* 等模块切换到 AT 模式 */
ble_flush_rx();
HAL_UART_Transmit(&huart1, (uint8_t *)"AT+NAME=?\r\n", 12, 500);
int t = 30;
while (t-- > 0 && !cur) {
ble_delay(50);
cur = USART1_GetCommand();
}
}
if (!cur) {
log_mute(0);
log_warn("> BLE: 3 轮 AT 均无应答(模块未接/被手机占用/PC5 未拉低)");
return;
}
if (strstr(cur, BLE_NAME) && pwr_cache == BLE_TX_POWER) {
/* 名称与功率都正确:直接回透传,不动任何设置 */
ble_at_cmd("AT+TS=1", "OK", 1500);
log_mute(0);
log_info("> BLE: 名称已是 %s无需设置", BLE_NAME);
return;
}
if (strstr(cur, BLE_NAME)) {
/* 名称对但功率变了:只重设发射功率 */
snprintf(cmd, sizeof(cmd), "AT+RFPOWER=%d", BLE_TX_POWER);
ble_at_cmd(cmd, "OK", 1500);
ble_at_cmd("AT+REBOOT=1", "OK", 1500);
uint8_t p = BLE_TX_POWER;
eepromWriteData(BLE_POWER_ADDR, &p, 1);
log_mute(0);
log_info("> BLE: 发射功率已设置为 %d", BLE_TX_POWER);
return;
}
/* 需要设置:发 AT+NAME最多重试 3 次)。
* 注意:本模块设置类参数重启后才生效,当场回查查到的仍是旧名,
* 不能用作校验——改完直接重启,下次开机的查询才是真正的校验 */
int ok = -1;
for (int i = 0; i < 3 && ok != 0; i++) {
snprintf(cmd, sizeof(cmd), "AT+NAME=%s", BLE_NAME);
ok = ble_at_cmd(cmd, "OK", 1500);
}
if (ok == 0) {
#if BLE_UUID_CUSTOM
/* 顺带设置透传 GATT UUIDFFE0/FFE1通用 BLE 串口 APP 可连 */
snprintf(cmd, sizeof(cmd), "AT+UUIDS=%s", BLE_UUID_SERVICE);
ble_at_cmd(cmd, "OK", 1500);
snprintf(cmd, sizeof(cmd), "AT+UUIDR=%s", BLE_UUID_TX);
ble_at_cmd(cmd, "OK", 1500);
snprintf(cmd, sizeof(cmd), "AT+UUIDW=%s", BLE_UUID_RX);
ble_at_cmd(cmd, "OK", 1500);
#endif
/* 顺带设置发射功率 */
snprintf(cmd, sizeof(cmd), "AT+RFPOWER=%d", BLE_TX_POWER);
ble_at_cmd(cmd, "OK", 1500);
/* 手册说明:设置类参数重启后才生效,重启模块使新名称生效;
* 模块重启后默认就是透传模式,无需再发 AT+TS=1 */
for (int i = 0; i < 2; i++) {
if (ble_at_cmd("AT+REBOOT=1", "OK", 1500) == 0) break;
}
eepromWriteData(BLE_CACHE_ADDR, (void *)BLE_NAME, strlen(BLE_NAME) + 1);
{
uint8_t p = BLE_TX_POWER;
eepromWriteData(BLE_POWER_ADDR, &p, 1);
}
log_mute(0);
log_info("> BLE: 名称/UUID/功率已设置完成");
} else {
ble_at_cmd("AT+TS=1", "OK", 1500); /* 确保回到透传 */
log_mute(0);
log_warn("> BLE: 设置名称失败(模块未接或应答异常)");
}
}
/* 强制重新执行蓝牙设置(蓝牙 BLESET 命令触发):清缓存后重跑 */
void ble_force_setup(void)
{
eepromWriteData(BLE_CACHE_ADDR, "", 1);
ble_setup_name();
}