串口调试系统

单片机串口调试系统实现

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);
		}	
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值