单片机串口调试系统实现
1.1前言
在调试单片机程序时,一般我们通过仿真器进行调试,让程序一步一步的执行,或者通过打印的方式看关键的位置的参数对不对。这样调试对于不是很复杂的系统确实可以,但是当系统比较复杂时,不可能一步一步的看,效率太低了,需要不断修改程序,烧写,调试。
我们可以针对我们比较关心的地方,设置一些调试指令以及对应的函数,我们可以根据我们的需要通过指令去执行我们想要执行的功能模块,来在运行期间发现可能出现的问题。
1.2 串口调试框架
串口调试系统框架图如上图所示,一般在单片机开发中,我们会为我们用到的单片机资源编写对应的业务功能函数,在应用逻辑上调用这些功能函数完成我们需要实现的应用功能。这样系统是正常运行的,但是当系统出现异常时,我们不能快速判断出问题出在什么地方,因为可能是多个模块在一起时导致了异常,我们无法判断出是哪个模块出现了问题,这时候我们通过仿真调试一步步找到出问题的模块,或者通过日志的方式。这两种方式都需要反复烧写程序运行调试,浪费时间,而且当在现场时,也不方便调试程序。
这时候我们需要加入串口调试,或者网络调试等,我们可以为我们的实际业务逻辑创建一个镜像,模拟不同场景,和实际场景作对比,我们可以快速找到问题在哪。
1.3 实现
遵循高内聚低耦合的设计思想,我们将串口调试系统分为三个部分。
我们可以将硬件设备如串口,网络等抽象出来,调试管理者向硬件设备注册,功能模块向串口调试管理者注册。这样设计的好处就是当硬件设备从串口变成了网络,我们只需要向新设备注册对应的接口就可以了,不需要做太多修改,功能模块和调试管理者之间也是这种关系。这样我们可以高度模块化,提高开发效率。降低了耦合性。
1.3.1 硬件设备抽象
以STM32F407ZGT6串口作为调试接口为例,使用HAl库。
uart.h
#ifndef __UART_H__
#define __UART_H__
#ifdef __cplusplus
extern "C"{
#endif
typedef void (*UARTRxCpltHandler)(void *);//接收完成回调指针
typedef void (*UARTTxCpltHandler)(void *);//发送完成回调指针
typedef struct{
UART_HandleTypeDef *huart;
void *handle;
UARTRxCpltHandler handler;
} UARTRxCpltList; //注册接收设备管理数组
typedef struct{
UART_HandleTypeDef *huart;
void *handle;
UARTTxCpltHandler handler;
} UARTTxCpltList;//注册发送设备管理数组
//注册接收完成回调
int UartRegisterRxCpltHandler(UART_HandleTypeDef *huart, UARTRxCpltHandler handler, void * handle);
//注销接收完成回调
int UartUnRegisterRxCpltHandler(UART_HandleTypeDef *huart);
//注册发送完成回调
int UartRegisterTxCpltHandler(UART_HandleTypeDef *huart, UARTTxCpltHandler handler, void * handle);
//注销发送完成回调
int UartUnRegisterTxCpltHandler(UART_HandleTypeDef *huart);
#ifdef __cplusplus
}
#endif
#endif
uart.c
#include "uart.h"
#define UART_MAX_DEVICE_NUMBER 5 //串口设备数
UARTTxCpltList g_UartTxCpltList[UART_MAX_DEVICE_NUMBER+1] = {0};
UARTRxCpltList g_UartRxCpltList[UART_MAX_DEVICE_NUMBER+1] = {0};
int UartRegisterRxCpltHandler(UART_HandleTypeDef *huart, UARTRxCpltHandler handler, void * handle)
{
int i;
for (i = 0; i < UART_MAX_DEVICE_NUMBER; i++)
{
if (g_UartRxCpltList[i].huart == huart
|| NULL == g_UartRxCpltList[i].huart)
{
break;
}
}
if (i >= UART_MAX_DEVICE_NUMBER)
{
return -1;
}
if (NULL == g_UartRxCpltList[i].huart)
{
g_UartRxCpltList[i].huart = huart;
}
g_UartRxCpltList[i].handler = handler;
g_UartRxCpltList[i].handle = handle;
return 0;
}
int UartUnRegisterRxCpltHandler(UART_HandleTypeDef *huart)
{
int i;
for (i = 0; i < UART_MAX_DEVICE_NUMBER; i++)
{
if (g_UartRxCpltList[i].huart == huart)
{
g_UartRxCpltList[i].huart = NULL;
g_UartRxCpltList[i].handler = NULL;
g_UartRxCpltList[i].handle = NULL;
return 0;
}
}
return -1;
}
int UartRegisterTxCpltHandler(UART_HandleTypeDef *huart, UARTTxCpltHandler handler, void *handle)
{
int i;
for (i = 0; i < UART_MAX_DEVICE_NUMBER; i++)
{
if (g_UartTxCpltList[i].huart == huart
|| NULL == g_UartTxCpltList[i].huart)
{
break;
}
}
if (i >= UART_MAX_DEVICE_NUMBER)
{
return -1;
}
if (NULL == g_UartTxCpltList[i].huart)
{
g_UartTxCpltList[i].huart = huart;
}
g_UartTxCpltList[i].handler = handler;
g_UartTxCpltList[i].handle = handle;
return 0;
}
int UartUnRegisterTxCpltHandler(UART_HandleTypeDef *huart)
{
int i;
for (i = 0; i < UART_MAX_DEVICE_NUMBER; i++)
{
if (g_UartTxCpltList[i].huart == huart)
{
g_UartTxCpltList[i].huart = NULL;
g_UartTxCpltList[i].handler = NULL;
g_UartTxCpltList[i].handle = NULL;
return 0;
}
}
return -1;
}
//HAL库回调
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
INT16 i;
for (i = 0; i < UART_MAX_DEVICE_NUMBER; i++)
{
if (huart == g_UartTxCpltList[i].huart)
{
if (g_UartTxCpltList[i].handler != NULL)
{
(g_UartTxCpltList[i].handler)(g_UartTxCpltList[i].handle);
}
return;
}
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
INT16 i;
for (i = 0; i < UART_MAX_DEVICE_NUMBER; i++)
{
if (huart == g_UartRxCpltList[i].huart)
{
if (g_UartRxCpltList[i].handler != NULL)
{
(g_UartRxCpltList[i].handler)(g_UartRxCpltList[i].handle);
}
return;
}
}
}
1.3.2 调试管理模块
cmd_ment.h
#ifndef __CMD_H__
#define __CMD_H__
#ifdef __cplusplus
extern "C"{
#endif
typedef int (*CommandHandler)(char *InBuf, int len);
typedef int (*CmdParamHandler)(char *pParam, int len);
typedef struct{
const char cmdName[16]; //名称
const char cmdDesc[64]; //描述
CommandHandler pfCommandHandler;
} CmdModuleInfo_S;
typedef struct tag_CmdModuleList {
struct tag_CmdModuleList* pNext;
const CmdModuleInfo_S *pInfo;
} CmdModuleList_S;
typedef struct tag_CmdParamInfo {
const char szParam[16];
const char szParamDesc[48];
CmdParamHandler pHandler;
} CmdParamInfo_S;
void CmdPrintf(const char* fmt, ...);
void CmdGeneralParamHelpHandler(const CmdParamInfo_S *pInfo, INT16 count);
void registerCmdModule(const CmdModuleInfo_S *pInfo);
void CmdInit(void);
#ifdef __cplusplus
}
#endif
#endif
1.3.3 功能模块
这里为了方便没有将led驱动和cmd分开,按照高内聚低耦合的思想是要分开的,这里是标准库的,和HAL库差别不大,换成HAL函数就行。
ledcmd.h
#ifndef __LED_H
#define __LED_H
void LED_Init(void);//初始化
uint8_t LED_ReadState(uint8_t lednum);
void LED_On(uint8_t lednum);
void LED_Off(uint8_t lednum);
void LED_Toggle_Red(uint16_t ms);
void LED_Toggle_Gree(uint16_t ms);
void registerCMD_LED(void);
#endif
ledcmd.c
#include "led.h"
#include "delay.h"
#include "usart.h"
int32_t CmdLedHandler(char *InBuf, uint32_t len);
const CmdModuleInfo_S g_stCmdInfoLed = {
"Led",
"led on/off/toggle commands",
CmdLedHandler,
};
int32_t CmdLedParamHelpHandler(char *pParam, uint32_t len);
int32_t CmdLedParamListHandler(char *pParam, uint32_t len);
int32_t CmdLedParamOnHandler(char *pParam, uint32_t len);
int32_t CmdLedParamOffHandler(char *pParam, uint32_t len);
int32_t CmdLedParamtoggleHandler(char *pParam, uint32_t len);
const CmdParamInfo_S g_szCmdLedParams[] = {
{"help", "show this help", CmdLedParamHelpHandler},
{"list", "list current led state", CmdLedParamListHandler},
{"on", "on led modules, eg on 0>>led0 on,on 1>>led1 on", CmdLedParamOnHandler},
{"off", "off led modules,eg off 0>>led0 off,off 1>>led1 off", CmdLedParamOffHandler},
{"toggle", "toggle led modules,eg toggle 0>>led0 toggle,toggle 1>>led1 toggle", CmdLedParamtoggleHandler},
};
int32_t CmdLedHandler(char *InBuf, uint32_t len)
{
char *pContent = InBuf;
char *pBlank;
char *pParam;
char i;
printf("\r\n");
pParam = strchr(pContent, ' ');
while (*pParam == ' ') {
pParam++;
}
pBlank = strchr(pParam, ' ');
if (pBlank != NULL)
{
pContent = pBlank + 1;
while (*pContent == ' ' && pContent < (InBuf + len))
{
++pContent;
}
}
for (i = 0; i < (sizeof(g_szCmdLedParams) / sizeof(CmdParamInfo_S)); i++)
{
if (0 == strncmp(g_szCmdLedParams[i].szParam, pParam, strlen(g_szCmdLedParams[i].szParam)))
{
if (NULL != g_szCmdLedParams[i].pHandler)
{
return (g_szCmdLedParams[i].pHandler)(pContent, (pParam + len - pContent));
}
}
}
return 0;
}
int32_t CmdLedParamListHandler(char *pParam, uint32_t len)
{
printf("\r\nLed0 State is %s\r\n",(LED_ReadState(0)? "off":"on"));
printf("Led1 State is %s\r\n",(LED_ReadState(0)? "off":"on"));
return 0;
}
int32_t CmdLedParamHelpHandler(char *pParam, uint32_t len)
{
CmdGeneralParamHelpHandler(g_szCmdLedParams, (sizeof(g_szCmdLedParams) / sizeof(CmdParamInfo_S)));
return 0;
}
int32_t CmdLedParamtoggleHandler(char *pParam, uint32_t len)
{
int enable;
uint8_t filled = 0;
filled = sscanf(pParam,"%d",&enable);
if(filled == 1)
{
if(enable == 0)
{
LED_Toggle_Red(2);
printf("set led0 toggle success!\r\n");
}
else
{
LED_Toggle_Gree(2);
printf("set led1 toggle success!\r\n");
}
}
return 0;
}
int32_t CmdLedParamOnHandler(char *pParam, uint32_t len)
{
int enable;
uint8_t filled = 0;
filled = sscanf(pParam,"%d",&enable);
if(filled == 1)
{
if(enable == 0)
{
LED_On(0);
printf("set led0 on success!\r\n");
}
else
{
LED_On(1);
printf("set led1 on success!\r\n");
}
}
return 0;
}
int32_t CmdLedParamOffHandler(char *pParam, uint32_t len)
{
int enable;
uint8_t filled = 0;
filled = sscanf(pParam,"%d",&enable);
if(filled == 1)
{
if(enable == 0)
{
LED_Off(0);
printf("set led0 off success!\r\n");
}
else
{
LED_Off(1);
printf("set led1 off success!\r\n");
}
}
return 0;
}
void registerCMD_LED(void)
{
registerCmdModule(&g_stCmdInfoLed);
}
//初始化PF9和PF10为输出口.并使能这两个口的时钟
//LED IO初始化
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//使能GPIOF时钟
//GPIOF9,F10初始化设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化
//GPIO_SetBits(GPIOF,GPIO_Pin_9 | GPIO_Pin_10);//GPIOF9,F10设置高,灯灭
}
void LED_Toggle_Red(uint16_t ms)
{
//delay_ms(ms);
GPIO_ToggleBits(GPIOF,GPIO_Pin_9);
}
void LED_Toggle_Gree(uint16_t ms)
{
//delay_ms(ms);
GPIO_ToggleBits(GPIOF,GPIO_Pin_10);
}
uint8_t LED_ReadState(uint8_t lednum)
{
if(lednum == 0)
{
return GPIO_ReadOutputDataBit(GPIOF, GPIO_Pin_9);
}
else
{
return GPIO_ReadOutputDataBit(GPIOF, GPIO_Pin_10);
}
}
void LED_On(uint8_t lednum)
{
if(lednum == 0)
{
GPIO_ResetBits(GPIOF, GPIO_Pin_9);
}
else
{
GPIO_ResetBits(GPIOF, GPIO_Pin_10);
}
}
void LED_Off(uint8_t lednum)
{
if(lednum == 0)
{
GPIO_SetBits(GPIOF, GPIO_Pin_9);
}
else
{
GPIO_SetBits(GPIOF, GPIO_Pin_10);
}
}