STM32H743xx串口1中断接收不定长数据并根据自定义ASCII协议处理,实现多参数的协议解析以及读写操作

编译器平台及例程说明

编译器平台说明


1. Toolchain : MDK-ARM Community  Version: 5.30.0.0(Kile V5)
2. Encoding  : Encode in UTF-8 without signature
3. Device Specific Packs : Keil.STM32H7xx_DFP.2.7.0.pack
4. Preprocessor Symbols Define : USE_HAL_DRIVER, STM32H743xx
    USE_HAL_DRIVER : 允许使用HAL库驱动
    STM32H743xx    : STM32H743xx芯片
5. Chip Type : STM32H743VIT6, Flash:2MByte, ROM:1MByte
6. 在stm32h7xx_hal_conf.h文件中HSE_VALUE为外部高速振荡器,默认25MHZ。此值必须与硬件保持一致。

例程说明

本例程是在 STM32H743xx串口1中断接收不定长数据并转发用HAL实现 基础上实现的,这部分有疑问的请自行查看


1. STM32H743xx串口1中断接收不定长数据并根据自定义ASCII协议处理,实现多参数的协议解析以及读写操作

一、宏定义说明


/* 指令表大小 */
#define UART_CMD_TAB_SIZE                                                               (sizeof(UART_CMD_TAB) / sizeof(UART_CMD_TAB[0]))

/* 协议头 */
#define UART_ASCII_PROTOCOL_HEADER                                                      "xSuper:"

/* 协议头长度 不计算'\0' */
#define UART_ASCII_HEADER_SIZE                                                          (sizeof(UART_ASCII_PROTOCOL_HEADER) - 1)

/* 参数表大小 */
#define UART_ASCII_ARG_TAB_SIZE                                                         (20)   

/* 参数个数可变 */
#define UART_ASCII_ARG_NUM_VARIABLE                                                    (0xFF)   

/* 指令索引无效 */
#define UART_ASCII_CMD_INDEX_INVALID                                                   (0xFE)   

/* 指令最小长度 */
#define UART_ASCII_CMD_MIN_LEN                                                         (5)  




/* 串口1接收缓存大小 */
#define UART1_RXD_BUF_SIZE                                                                          480

/* 串口1接收缓存大小 */
#define UART1_TXD_BUF_SIZE                                                                          480

二、变量的定义


UART_HandleTypeDef USART1_HandlerType = {0};

//RxState[0..13] : 接收到的数据长度
//RxState[14]    : (1)已接收到0x0D  (0)未接收到0x0D
//RxState[15]    : (1)已接收完成    (0)接收未完成
u16 RxState = 0; //串口1接收状态
static u8 RxBufIRQ[1] = {0}; //串口1中断接收缓存
u8 __attribute__ ((aligned(4))) UART1_RXD_BUF[UART1_RXD_BUF_SIZE] = {0}; //串口1接收缓存

u8 __attribute__ ((aligned(4))) UART1_TXD_BUF[UART1_TXD_BUF_SIZE] = {0}; //串口1发送缓存



/* 指向串口接收数据缓存 */
static char * pRxDat = NULL;

/* 指向串口发送数据缓存 */
static char * pTxDat = NULL;

/* 从串口中解析的参数 */
static s32 ArgTab[UART_ASCII_ARG_TAB_SIZE] = {0};

/* 指令表 */
const ProtocolHandler_TypeDef UART_CMD_TAB[] = 
{
    { "SysReset",    usproHandler_SystemReset, 0    },     /* 系统复位 */
    { "SetBaudRate", usproHandler_SetBaudRate, 1    },     /* 设置波特率 */
    { "TestDemo",    usproHandler_TestDemo,    0xFF },     /* 测试例程 */
};

三、结构体说明


/* 处理回调类型 */
typedef u16 (* ProtocolHandler)(char * pOutDat, s32 * pArg, u16 len);

/* 字节对齐 */
#pragma pack()
typedef struct
{
    const char *    strName;    /* 指令名称 */
    ProtocolHandler proHandler; /* 回调函数 */
    u8              ubArgNum;   /* 参数个数 */
}ProtocolHandler_TypeDef;
#pragma pack()

四、自定义ASCII协议初始化

/**********************************************************************************************************************************************
 * 函数名 : vInit_UART_ASCII_Protocol
 * 描  述 : ASCII协议初始化
 **********************************************************************************************************************************************/
void vInit_UART_ASCII_Protocol(void)
{
    pRxDat = (char *)UART1_RXD_BUF;//串口1接收缓存
    pTxDat = (char *)UART1_TXD_BUF;//串口1发送缓存
}

五、获取指令索引


/**********************************************************************************************************************************************
 * 函数名 : ubString_Compare
 * 描  述 : 字符串比较
 * 输  入 : srcStr : 源字符串
 *          dstStr : 目的字符串
 * 输  出 : (0)字符串不同 (1)字符串相同
 **********************************************************************************************************************************************/
u8 ubString_Compare(char * srcStr, char * dstStr)
{
    while((*srcStr != '\0') && (*dstStr != '\0'))
    {
        if((*srcStr++) != (*dstStr++))
        {
            return 0;
        }
    }

    return 1;
}


/**********************************************************************************************************************************************
 * 函数名 : GetCmd_Index
 * 描  述 : 在指令表中匹配指令索引
 * 输  入 : pInDat : 源数据
 * 输  出 : 指令索引 (0xFE)匹配无效
 **********************************************************************************************************************************************/
static u8 GetCmd_Index(char * pInDat)
{
    u8 i = 0;

    for (i = 0; i < UART_CMD_TAB_SIZE; ++i)
    {
        if(ubString_Compare(pInDat, (char *)UART_CMD_TAB[i].strName))
        {
            return i;
        }
    }

    return UART_ASCII_CMD_INDEX_INVALID;
}

六、获取参数表


/**********************************************************************************************************************************************
 * 函数名 : usGet_Cmd_Arg
 * 描  述 : 从源数据获取参数
 * 输  入 : pInDat : 源数据
 *          pArg   : 参数存储
 *          lenArg : 参数存储最大长度
 * 输  出 : 参数个数
 **********************************************************************************************************************************************/
static u16 usGet_Cmd_Arg(char * pInDat, s32 * pArg, u16 lenArg)
{
    u8  nFlg = 0; /* 负数标志 */
    u16 len  = 0; /* 参数个数 */
    s32 num  = 0; /* 参数  */

    while(1)
    {
        nFlg = 0;
        num = 0;

        /* 非数字 */
        while((*pInDat < '0') || (*pInDat > '9'))
        {
            /* 结束 */
            if((*pInDat == '\r') || (*pInDat == '\0'))
            {
                return len;
            }

            /* 负数 */
            if(*pInDat == '-')
            {
                pInDat++;
                nFlg = 1;
                break;
            }

            pInDat++;
        }

        /* 数字 参数 */
        while((*pInDat >= '0') && (*pInDat <= '9'))
        {
             num *= 10;
             num += (*pInDat - '0');
             pInDat++;
        }

        /* 保持参数 */
        pArg[len++] = nFlg ? -num : num;   

        /* 参数过多 */  
        if(len > lenArg)
        {
            return len;
        }
    }
}

七、自定义ASCII协议解析


/**********************************************************************************************************************************************
 * 函数名 : usASCII_Protocol_Analytic
 * 描  述 : ASCII协议解析
 * 输  入 : pOutDat : 输出数据
 *          pInDat : 源数据
 *          len    : 源数据长度
 * 输  出 : 输出数据长度
 **********************************************************************************************************************************************/
u16 usASCII_Protocol_Analytic(char * pOutDat, char * pInDat, u16 len)
{
    u8 res   = 0;
    u8 id    = 0;
    u16 lenArg = 0;
    ProtocolHandler Handler = NULL;
    
    /* 添加结束符 */
    pInDat[len] = '\0';

    while (*pInDat != '\0')
    {
        /* 头部判断 */
        res = ubString_Compare(pInDat, (char *)UART_ASCII_PROTOCOL_HEADER);

        /* 头部正确 */
        if(res)
        {
            /* 获取指令索引  */
            id = GetCmd_Index(&pInDat[UART_ASCII_HEADER_SIZE]);

            /* 指令索引有效 */
            if(UART_ASCII_CMD_INDEX_INVALID != id)
            {
                /* 获取参数 */
                lenArg = usGet_Cmd_Arg(&pInDat[UART_ASCII_HEADER_SIZE + UART_ASCII_CMD_MIN_LEN], ArgTab, UART_ASCII_ARG_TAB_SIZE);

                /* 参数个数有效 */
                if((UART_ASCII_ARG_NUM_VARIABLE == UART_CMD_TAB[id].ubArgNum) || (UART_CMD_TAB[id].ubArgNum == lenArg))
                {
                    /* 执行回调 */
                    Handler = UART_CMD_TAB[id].proHandler;
                    if(Handler != NULL)
                    {
                        return Handler(pOutDat, ArgTab, lenArg);
                    }
                }
            }
            else
            {
                /* 无效命令 */
                return sprintf(pOutDat, "xSuper:err-1\r\n");
            }
        }
        else
        {
            pInDat++;
        }
    }

    return 0;
}

八、自定义ASCII协议处理


/**********************************************************************************************************************************************
 * 函数名 : vUART_ASCII_Protocol_Handler
 * 描  述 : ASCII协议处理
 * 说  明 : 1. 此函数需放在主函数中运行或定时处理
 **********************************************************************************************************************************************/
void vUART_ASCII_Protocol_Handler(void)
{
    u16 len = 0;

    /* 串口接收数据完成 */
    if(RxState & 0x8000)
    {
        /* 添加结束符 */
        pRxDat[RxState & 0x3FFF] = 0;

        
        /* 接收内容解析 */
        len = usASCII_Protocol_Analytic(pTxDat, pRxDat, (RxState & 0x3FFF));
        if(len > 0)
        {
            /* 发送数据到上位机 */
            HAL_UART_Transmit(&USART1_HandlerType, (u8 *)pTxDat, len, 200);

            /* 等待发送完成 */
            while(__HAL_UART_GET_FLAG(&USART1_HandlerType, UART_FLAG_TC) != SET);
        }

        /* 清空接收状态 */
        RxState = 0;
    }
}

九、回调函数处理


/**********************************************************************************************************************************************
 * 函数名 : usproHandler_SystemReset
 * 描  述 :  系统复位
 * 输  入 : pOutDat : 输出数据
 *          pArg    : 参数表
 *          len     : 有效参数长度
 * 输  出 : 输出数据长度
 **********************************************************************************************************************************************/
static u16 usproHandler_SystemReset(char * pOutDat, s32 * pArg, u16 len)
{
    dprintf("System Reset...\r\n");
    return sprintf(pOutDat, "xSuper:ok\r\n");
}


static u16 usproHandler_SetBaudRate(char * pOutDat, s32 * pArg, u16 len)
{
    dprintf("Set Baud Rate...%d\r\n", *pArg);
    return sprintf(pOutDat, "xSuper:ok BaudRate:%d\r\n", *pArg);
}


static u16 usproHandler_TestDemo(char * pOutDat, s32 * pArg, u16 len)
{
    dprintf("Test Demo...");
    for(u16 i = 0; i < len; ++i)
    {
        dprintf("%d  ", *pArg++);
    }
    dprintf("\r\n");

    return sprintf(pOutDat, "xSuper:ok\r\n");
}

十、测试例程


int main(void)
{
    static u8 i = 0;

    vStartUp_System();
    vInit_System_BSP();
    vInit_USART1(115200);
    vInit_UART_ASCII_Protocol();
    vShow_PlatformDevice_Info();
    
    while (1)
    {
        /* 定时处理协议数据解析 */
        vUART_ASCII_Protocol_Handler();

        HAL_Delay(10);
        if((++i) > 50)
        {
            i = 0;
            USER_LED_CPL();
        }
    }
}

十一、测试效果


00> Segger Rtt Init Ok...
00> STM32H743VIT6 Start Running...
00> 8-STM32H743xx_CubeMx_USART_UserProtocol......
00> Debug Versions......
00> Compile Date : Apr  9 2022 21:51:42
00> 
00> System Reset...
00> Set Baud Rate...9600
00> Test Demo...85  -600  857  -200  8886  

发送的指令 xSuper:SysReset

在这里插入图片描述

发送的指令 xSuper:SetBaudRate,9600

在这里插入图片描述

发送的指令 xSuper:TestDemo,85,-600,857,-200,8886

在这里插入图片描述

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值