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