打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

LiSun

打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

根据串行通信原理设计搭建了三方之间交互通信环境,通过协议相互收发数据,模块实现情况。该设计实现三方交互通信方式,数据传输灵活、方便、可靠,具有较高的实用性。

仅供参考

/********************************************************************************
* @file    uart_ble_module.c (从机端)
* @author  jianqiang.xue
* @version V1.0.0
* @date    2022-04-02
* @brief   [协议]
串口格式: 0x55 0x56 CMD(1byte) LEN(1byte) DATA(*) SUM(1byte)
NUS格式:  CMD(1byte) LEN(1byte) DATA(*) SUM(1byte)

CMD: 高7bit决定数据通道方向。 0--串口 1--NUS
LEN:  DATA长度
SUM: 将CMD+LEN+DATA进行累计,然后取低8位。
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <string.h>
#include <stdbool.h>

#include "bsp_gpio.h"
#include "bsp_uart.h"
#include "log.h"
/* Private Includes ----------------------------------------------------------*/
#include "business_gpio.h"
#include "business_function.h"
#include "app_main.h"
#include "uart_ble_module.h"
#if BS_POWER_SWITCH
#include "biz_power.h"
#endif
#if BS_NRF_BLE_SUPPORT
#include "biz_ble.h"
#endif
/* Private Define ------------------------------------------------------------*/

#define PROT_CMD_HEAD_PACK(BUFF, CMD, LEN)     \
do                                             \
{                                              \
    BUFF[0] = 0x55;                            \
    BUFF[1] = 0x56;                            \
    BUFF[2] = CMD;                             \
    BUFF[3] = LEN;                             \
}while(0);                                     \

/* External Variables --------------------------------------------------------*/
/* Private Macro -------------------------------------------------------------*/
/* Private Variables ---------------------------------------------------------*/
uint8_t data_temp[32]               = {0};

/* Private Function Prototypes -----------------------------------------------*/
static uint8_t get_checksum(uint8_t *data, uint8_t len)
{
    uint16_t sum = 0;
    for (uint8_t i = 0; i < len; i++)
    {
        sum += data[i];
    }
    return sum & 0x00FF;
}

/**
 * @brief  发送数据给ble串口通道(消息入队,非实时发送)
 * @param  *data: 欲发送内容
 * @param  len: 内容长度(字节大小)
 */
static void send_data(uint8_t *data, uint16_t len)
{
    if ((data[2] & 0x80) == 0x80)
    {
        biz_ble_data_send(data + 2, len - 2);
    }
    else
    {
        bsp_uart_send_nbyte(BOARD_UART_COMM, data, len);
    }
}

/**
 * @brief  [MCU->BLE] 获取设备信息 -- 响应指令
 */
static void response_get_device_info(bool dir)
{
    uint8_t temp_len = 0;
    PROT_CMD_HEAD_PACK(data_temp, (dir << 8) | PROT_CMD_GET_DEVICE_INFO_RES, BLE_MAC_MAX_VAL + strlen(FIRMWARE_DATE));
    temp_len = 4;
    // mac
    memcpy(&data_temp[4], get_ble_mac_addr(), BLE_MAC_MAX_VAL);
    temp_len += BLE_MAC_MAX_VAL;
    // version
    memcpy(&data_temp[temp_len], FIRMWARE_DATE, strlen(FIRMWARE_DATE));
    temp_len += 6;
    // CHECKSUM
    data_temp[temp_len] = get_checksum(data_temp + 2, temp_len - 2);
    send_data(data_temp, temp_len + 1);
}

/**
 * @brief  [MCU->BLE] 获取设备名称 -- 响应指令
 */
static void response_get_device_name(bool dir)
{
    uint8_t temp_len = 0;
    PROT_CMD_HEAD_PACK(data_temp, (dir << 8) | PROT_CMD_GET_DEVICE_NAME_RES, strlen(PRODUCT_NAME));
    temp_len = 4;
    // 设备名称
    memcpy(data_temp + temp_len, PRODUCT_NAME, strlen(PRODUCT_NAME));
    temp_len += strlen(PRODUCT_NAME);

    // CHECKSUM
    *(data_temp + temp_len) = get_checksum(data_temp + 2, temp_len - 2);
    send_data(data_temp, temp_len + 1);
}

/**
 * @brief  [BLE->MCU] 获取电量状态 -- 响应指令
 * @note   协议包(括号里面是字节位):HEADER(0,1) CMD(2) LENGTH(3) BAT_SOC(4) CHANRG(5) CHECKSUM(6)
 *         BAT_LEVEL: 0~100(success)||0xff(0xff)
 */
static void response_bat_state(bool dir)
{
#if BS_POWER_SWITCH
    uint8_t temp_len = 0;
    PROT_CMD_HEAD_PACK(data_temp, (dir << 8) | PROT_CMD_GET_BAT_SOC_RES, 2);
    temp_len = 4;
    // bat_soc
    data_temp[4] = get_bat_soc_val();
    data_temp[5] = get_usb_state();
    temp_len += 2;
    // CHECKSUM
    *(data_temp + temp_len) = get_checksum(data_temp + 2, temp_len - 2);
    send_data(data_temp, temp_len + 1);
#endif
}

/**
 * @brief  [BLE->MCU] 获取蓝牙地址 -- 响应指令
 * @note   协议包(括号里面是字节位):HEADER(0,1) CMD(2) LENGTH(3) MAC(4,5,6,7,8,9) CHECKSUM(10)
 */
static void response_ble_addr(bool dir)
{
    uint8_t temp_len = 0;
    PROT_CMD_HEAD_PACK(data_temp, (dir << 7) | PROT_CMD_GET_BLE_ADDR_RES, BLE_MAC_MAX_VAL);
    temp_len = 4;
    // mac
    memcpy(&data_temp[4], get_ble_mac_addr(), BLE_MAC_MAX_VAL);
    temp_len += BLE_MAC_MAX_VAL;
    // CHECKSUM
    data_temp[temp_len] = get_checksum(data_temp + 2 , temp_len - 2);
    send_data(data_temp, temp_len + 1);
}

/**
 * @brief  [BLE->MCU] 蓝牙进入配对模式(直连广播) -- 响应指令
 * @note   协议包(括号里面是字节位):HEADER(0,1) CMD(2) LENGTH(3) RESULT(4) CHECKSUM(5)
 *         RESULT 0--success 1--failed
 */
static void response_ble_enter_pair_mode(bool dir)
{
    uint8_t temp_len = 0;
    PROT_CMD_HEAD_PACK(data_temp, (dir << 7) | PROT_CMD_BLE_IN_PAIRING_RES, 1);
    temp_len = 4;
    // 处理蓝牙进入直连广播(暂时未写) biz_ble_services.c
    // 先判断当前是否广播,如果有,则先暂停广播,修改广播信息,再起开启广播。填写返回状态
    data_temp[4] = 0;
    temp_len += 1;
    // CHECKSUM
    *(data_temp + temp_len) = get_checksum(data_temp + 2, temp_len - 2);
    send_data(data_temp, temp_len + 1);
    LOG_I("<INFO> [ble_enter_pair]: %02x\r\n", data_temp[4]);
}

/**
 * @brief  [BLE->MCU] 蓝牙进入白名单配对模式(白名单广播) -- 响应指令
 * @note   协议包(括号里面是字节位):HEADER(0,1) CMD(2) LENGTH(3) RESULT(4) CHECKSUM(5)
 *         RESULT 0--success 1--failed
 */
static void response_ble_enter_whitelist_pair_mode(bool dir)
{
    uint8_t temp_len = 0;
    PROT_CMD_HEAD_PACK(data_temp, (dir << 7) | PROT_CMD_BLE_WHITELIST_PAIRING_REQ, 1);
    temp_len = 4;
    // 处理蓝牙进入直连广播(暂时未写) biz_ble_services.c
    // 先判断当前是否广播,如果有,则先暂停广播,修改广播信息,再起开启广播。填写返回状态
    data_temp[4] = 0;
    temp_len += 1;
    // CHECKSUM
    *(data_temp + temp_len) = get_checksum(data_temp + 2, temp_len - 2);
    send_data(data_temp, temp_len + 1);
    LOG_I("<INFO> [ble_enter_pair]: %02x\r\n", data_temp[4]);
}

/**
 * @brief  [BLE->MCU] 蓝牙连接状态获取 -- 响应指令
 * @note   协议包(括号里面是字节位):HEADER(0,1) CMD(2) LENGTH(3) RESULT(4) CHECKSUM(5)
 *         RESULT 0--未连接 1--已连接
 */
static void response_ble_connect_state(bool dir)
{
    uint8_t temp_len = 0;
    PROT_CMD_HEAD_PACK(data_temp, (dir << 7) | PROT_CMD_BLE_CONN_STATE_RES, 1);
    temp_len = 4;
    data_temp[4] = get_ble_conn_state();
    temp_len += 1;
    // CHECKSUM
    *(data_temp + temp_len) = get_checksum(data_temp, temp_len);
    send_data(data_temp, temp_len + 1);
    LOG_I("<INFO> [ble_conn_ste]: %02x\r\n", data_temp[4]);
}

/**
 * @brief  [MCU->MP] 命令透传指令 -- MCU -> MP(手机)
 * @note   协议包(括号里面是字节位):HEADER(0,1) CMD(2) LENGTH(3) 协议包(n字节) CHECKSUM(n+1)
 */
static void response_mcu_to_mp(uint8_t *data, uint16_t len)
{
#if BLE_NUS_ENABLED && BS_NRF_BLE_SUPPORT
    biz_ble_data_send(data, len);
#endif
}

/**
 * @brief  [MCU->MP] 命令透传指令 -- MP(手机) -> MCU
 * @note   协议包(括号里面是字节位):HEADER(0,1) CMD(2) LENGTH(3) 协议包(n字节) CHECKSUM(n+1)
 */
static void response_mp_to_mcu(uint8_t *data, uint16_t len)
{
    bsp_uart_send_nbyte(BOARD_UART_COMM, data, len);
}

/**
 * @brief  [协议第一层] 对CMD进行分别处理
 * @param  *data: 数据指针
 * @param  len: 数据长度
*/
static void prot_dispose_data(uint8_t *data, uint16_t len)
{
    // 将首字节的方向去除
    LOG_D("<DEBUG> [nrf_ble]: %x  %x\r\n", ((uint8_t)(data[0] << 1) >> 1), data[0]);
    switch(((uint8_t)(data[0] << 1 )>> 1))
    {
        case PROT_CMD_GET_DEVICE_INFO_REQ:
            response_get_device_info((data[0] & 0x80));
            LOG_D("<DEBUG> [nrf_ble]: PROT_CMD_GET_DEVICE_INFO_REQ\r\n");
            break;
        case PROT_CMD_GET_DEVICE_NAME_REQ:
            response_get_device_name((data[0] & 0x80));
            LOG_D("<DEBUG> [nrf_ble]: PROT_CMD_GET_DEVICE_NAME_REQ\r\n");
            break;
        case PROT_CMD_GET_BAT_SOC_REQ:
//           LOG_D("<DEBUG> [nrf_ble]: PROT_CMD_GET_BAT_SOC_RES %02x %02x %02x %02x\r\n", data[3], data[4], data[5], data[6]);
            response_bat_state((data[0] & 0x80));
            break;
        case PROT_CMD_GET_BLE_ADDR_REQ:
            response_ble_addr((data[0] & 0x80));
            LOG_D("<DEBUG> [nrf_ble]: PROT_CMD_GET_BLE_ADDR_REQ\r\n");
            break;
        case PROT_CMD_BLE_IN_PAIRING_RES:
            response_ble_enter_pair_mode((data[0] & 0x80));
            LOG_D("<DEBUG> [nrf_ble]: PROT_CMD_BLE_IN_PAIRING_REQ %d\r\n", data[4]);
            break;
        case PROT_CMD_BLE_WHITELIST_PAIRING_REQ:
            response_ble_enter_whitelist_pair_mode((data[0] & 0x80));
            LOG_D("<DEBUG> [nrf_ble]: PROT_CMD_BLE_WHITELIST_PAIRING_REQ %d\r\n", data[4]);
            break;
        case PROT_CMD_BLE_CONN_STATE_REQ:
            response_ble_connect_state((data[0] & 0x80));
            LOG_D("<DEBUG> [nrf_ble]: PROT_CMD_BLE_CONN_STATE_REQ %d\r\n", data[4]);
            break;
        case PROT_CMD_MCU_TO_MP:
            response_mcu_to_mp(data, len);
            LOG_D("<DEBUG> PROT_CMD_MCU_TO_MP \r\n");
            break;
        case PROT_CMD_MP_TO_MCU:
            response_mp_to_mcu(data, len);
            LOG_D("<DEBUG> PROT_CMD_MP_TO_MCU \r\n");
            break;
        default:
            break;
    }
    if ((data[0] & 0x80) != 0x80)
    {
        bsp_uart_reset_rxbuff(BOARD_UART_COMM);
    }
}

/* Public Function Prototypes ------------------------------------------------*/

/**
 * @brief  [协议] 对串口数据进行协议检查 格式:头(2字节 0x55 0x56) 命令(1字节) 长度(n字节) 检验和(1字节)
 * @note   为biz_uart.c文件提供  [给串口中断回调]
 * @param  *data: 串口数据
 * @param  len: 数据长度
 */
void uart_ble_module_prot_dispose_data(uint8_t *data, uint16_t len)
{
    if (data[0] != 0x55)
    {
        bsp_uart_reset_rxbuff(BOARD_UART_COMM);
        return;
    }
    if (len == 2 && data[1] != 0x56)
    {
        bsp_uart_reset_rxbuff(BOARD_UART_COMM);
        return;
    }

    if (len < data[3] + 5)
    {
        return;
    }
    uint8_t checksum = 0;
    checksum = get_checksum(data + 2, len - 3);
    if (checksum != data[len - 1])
    {
        LOG_E("<ERR> [prot_uart]: check fail %02x|%02x\r\n", checksum, data[len - 1]);
        bsp_uart_reset_rxbuff(BOARD_UART_COMM);
        return;
    }
//     LOG_D("<DEBUG> [nrf_ble]: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x||len:%d\r\n",
//             data[0], data[1], data[2], data[3], data[4],
//             data[5], data[6], data[7], data[8], data[9], len);
    prot_dispose_data(data + 2, len - 3);
}

/**
 * @brief  [协议] 对NUS数据进行协议检查 格式:命令(1字节) 长度(n字节) 检验和(1字节)
 * @note   为biz_uart.c文件提供 [给nus接收中断回调]
 * @param  *data: NUS数据
 * @param  len: 数据长度
 */
void nus_ble_module_prot_dispose_data(uint8_t *data, uint16_t len)
{
    if (len < data[1] + 3)
    {
        return;
    }
    uint8_t checksum = 0;
    checksum = get_checksum(data, len - 1);
    if (checksum != data[len - 1])
    {
        LOG_E("<ERR> [prot_nus]: check fail %02x|%02x\r\n", checksum, data[len - 1]);
        bsp_uart_reset_rxbuff(BOARD_UART_COMM);
        return;
    }
//     LOG_D("<DEBUG> [nus_ble]: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x||len:%d\r\n",
//             data[0], data[1], data[2], data[3], data[4],
//             data[5], data[6], data[7], data[8], data[9], len);
    prot_dispose_data(data, len - 1);
}

头文件:

/********************************************************************************
* @file    uart_ble_module.h (从机端)
* @author  jianqiang.xue
* @version V1.0.0
* @date    2022-04-02
* @brief   [协议]
串口格式: 0x55 0x56 CMD(1byte) LEN(1byte) DATA(*) SUM(1byte)
NUS格式:  CMD(1byte) LEN(1byte) DATA(*) SUM(1byte)

CMD: 高7bit决定数据通道方向。 0--串口 1--NUS
LEN:  DATA长度
SUM: 将CMD+LEN+DATA进行累计,然后取低8位。
********************************************************************************/

#ifndef __PROTOCOL_UART_BLE_MODULE_H
#define __PROTOCOL_UART_BLE_MODULE_H

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include "business_function.h"

/* Struct --------------------------------------------------------------------*/

/* Define --------------------------------------------------------------------*/
// [协议]xx.pdf
#define PROT_CMD_GET_DEVICE_INFO_REQ        0X01    // 获取设备信息 -- 请求命令
#define PROT_CMD_GET_DEVICE_INFO_RES        0x02    // 获取设备信息 -- 响应指令

#define PROT_CMD_GET_DEVICE_NAME_REQ        0x03    // 获取设备名称 -- 请求命令
#define PROT_CMD_GET_DEVICE_NAME_RES        0x04    // 获取设备名称 -- 响应指令

#define PROT_CMD_GET_BLE_VER_REQ            0x07    // 获取蓝牙固件版本 -- 请求命令
#define PROT_CMD_GET_BLE_VER_RES            0x08    // 获取蓝牙固件版本 -- 响应指令

#define PROT_CMD_GET_BAT_SOC_REQ            0x09    // 获取电池电量 -- 请求命令
#define PROT_CMD_GET_BAT_SOC_RES            0x0A    // 获取电池电量 -- 响应指令

#define PROT_CMD_GET_CHARG_REQ              0X0B    // 获取充电状态 -- 请求命令
#define PROT_CMD_GET_CHARG_RES              0X0C    // 获取充电状态 -- 响应指令

#define PROT_CMD_GET_BLE_ADDR_REQ           0X0D    // 获取蓝牙地址 -- 请求命令
#define PROT_CMD_GET_BLE_ADDR_RES           0X0E    // 获取蓝牙地址 -- 响应指令

#define PROT_CMD_BLE_IN_PAIRING_REQ         0X0F    // 蓝牙进入配对模式 -- 请求命令
#define PROT_CMD_BLE_IN_PAIRING_RES         0X10    // 蓝牙进入配对模式 -- 响应指令

#define PROT_CMD_BLE_WHITELIST_PAIRING_REQ  0X11    // 蓝牙进入白名单配对模式 -- 请求命令
#define PROT_CMD_BLE_WHITELIST_PAIRING_RES  0X12    // 蓝牙进入白名单配对模式 -- 响应指令

#define PROT_CMD_BLE_CONN_STATE_REQ         0X13    // 蓝牙连接状态获取 -- 请求命令
#define PROT_CMD_BLE_CONN_STATE_RES         0X14    // 蓝牙连接状态获取 -- 响应指令

#define PROT_CMD_BLE_SLEEP_REQ              0X15    // 蓝牙进入睡眠 -- 请求命令

#define PROT_CMD_CLEAR_BLE_PAIR_REQ         0X16    // 删除所有配对信息 -- 请求命令

#define PROT_CMD_BLE_IN_DTM_MODE_REQ        0X17    // 进入 DTM 测试模式 -- 请求命令

#define PROT_CMD_BLE_IN_FIXED_FREQUENCY_REQ 0X18    // 进入定频测试 -- 请求命令

#define PROT_CMD_SET_LED_STATE_REQ          0X19    // LED 设置 -- 请求命令
#define PROT_CMD_SET_LED_STATE_RES          0X1A    // LED 设置 -- 响应指令

#define PROT_CMD_GET_LED_STATE_REQ          0X1B    // 蓝牙LED状态获取 -- 请求命令
#define PROT_CMD_GET_LED_STATE_RES          0X1C    // 蓝牙LED状态获取 -- 响应指令

#define PROT_CMD_SET_BAT_INFO_REQ           0X1D    // 设置电池信息(SOC_CHRG) -- 请求命令
#define PROT_CMD_SET_BAT_INFO_RES           0X1F    // 设置电池信息(SOC_CHRG) -- 响应指令

#define PROT_CMD_MCU_TO_MP                  0X70    // 命令透传指令 -- MCU  --> 手机
#define PROT_CMD_MP_TO_MCU                  0x71    // 命令透传指令 -- 手机  --> MCU

#define PROT_CMD_BLE_HID_DATA_REQ           0x74    // BLE_HID数据上报 -- 请求命令

/* External Variables --------------------------------------------------------*/

/* Public Function Prototypes ------------------------------------------------*/

void uart_ble_module_prot_dispose_data(uint8_t *data, uint16_t len);
void nus_ble_module_prot_dispose_data(uint8_t *data, uint16_t len);
#endif

posted on 2022-08-13 11:00  xuejianqiang  阅读(47)  评论(0编辑  收藏  举报
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033