STC - 库函数实验 - 用表驱动来实现串口应答
概述
准备用STC15库函数写个板子的测试程序. 今天将串口命令的收发的架子整完了, 有点收获.
实验环境
MDK5 for C51(keil C51)
知识点
-
基于表驱动的串口应答, 符合OCP(封闭开放原则). 当增加新的串口命令后, 流程不用改, 只需要在表中增加新的串口命令字符串和对应的实现函数名称. 以前还见过其他工程用一种处理接口注册的机制来实现流程处理的方法, 也很好维护. 不过, 这种实现是要占用内存的, 对于下位机来说, 能节省1byte的内存都是好的. 用表驱动的方法, 最大的好处是只占用代码空间, 不会占用内存空间. 对于大部分流程处理的操作, 在编译期都是可以确定的. 对于在编译期就能知道处理流程的操作, 用表驱动来处理是比较合理的. -
C51的函数指针写法和VC/GCC环境不太一样. 如果写错了, 也能编译过, 但是调用函数指针时会阻塞住(卡死, 不往下走) -
如果命令中出现中文字符, 有些中文字符不显示或显示乱码, 这时, 要在该中文字符后加上 “\xFD” -
为了不编译用不到的函数实现 在Options(魔术棒) => Device页 => 勾选 “Use Extended Linker(LX51) instead of B51” 在Options(魔术棒) => LX51 Misc页 => 在Misc controls 编辑框中填入 REMOVEUNUSED -
在代码区定义结构体或大数组, 需要使用code关键字进行修饰, 否则编译不过.
验证过的串口应答实现 - 基于表驱动
#include "stc/config.h"
#include "stc/usart.h"
#include "stc/delay.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#define LINE_60 "--------------------------------------------------------------------------------"
#define COM1_BAUDRATE_BPS 115200ul
#define COM2_BAUDRATE_BPS 115200ul
#define BOOL u8
#define UNUSED(x) (x != x)
typedef struct _tag_cmd_param {
int cmd_index;
const char* pc_cmd_name;
const char* pc_cmd_desc;
}TAG_CMD_PARAM;
typedef u8 (PFN_CMD_PROC)(TAG_CMD_PARAM* p_param);
u8 fn_proc_cmd_default(TAG_CMD_PARAM* p_param);
u8 fn_proc_cmd_help(TAG_CMD_PARAM* p_param);
typedef struct _tag_cmd_item {
int cmd_index;
const char* pc_cmd_name;
const char* pc_cmd_desc;
PFN_CMD_PROC* pfn_cmd_proc;
} TAG_CMD_ITEM;
code const TAG_CMD_ITEM g_cmd_array[] = {
{0, "help", "命令使用说明", fn_proc_cmd_help},
{1, "test_usb_micro_b", "测试左下角usb_micro-b接口", fn_proc_cmd_default},
{2, "test_usb_a", "测试左下角usb_A接口", fn_proc_cmd_default},
{3, "test_2uart_self_send_recv", "测试2个串口自收发", fn_proc_cmd_default},
{3, "test_ind_leds", "测试7个LED指示灯", fn_proc_cmd_default},
{4, "test_7seg", "测试8个7段数\xFD码管", fn_proc_cmd_default},
{5, "cmd_test_12864", "测试12864", fn_proc_cmd_default},
{6, "test_12864_backlight", "测试12864的背光", fn_proc_cmd_default},
{7, "test_1602", "测试1602", fn_proc_cmd_default},
{8, "test_exint_2key", "测试外中断的2个按键", fn_proc_cmd_default},
{9, "test_matrix_keys", "测试16个矩阵按键", fn_proc_cmd_default},
{10, "test_adc_keys", "测试16个ADC按键", fn_proc_cmd_default},
{11, "test_6pwm", "测试6个PWM", fn_proc_cmd_default},
{12, "test_e2prom", "测试e2prom的读写", fn_proc_cmd_default},
{13, "test_adc_ref_2d5v", "测试2.5V基准电压", fn_proc_cmd_default},
{14, "test_low_v", "测试低压检测", fn_proc_cmd_default},
{15, "test_xram", "测试外部32KB的XRAM", fn_proc_cmd_default},
{16, "test_rtc", "测试RTC时钟", fn_proc_cmd_default},
{17, "test_pca_pwm_as_adc", "用PWM波调频来测试ADC的值", fn_proc_cmd_default},
{18, "test_ntc", "测试ntc温度", fn_proc_cmd_default},
{19, "test_ir", "测试红外发送自接收", fn_proc_cmd_default},
{20, "test_pm25", "测试PM25存储", fn_proc_cmd_default},
{-1, NULL, NULL, NULL}
};
void Hardware_init(void);
void UART1_init(void);
void UART2_init(void);
void process_uart_cmd(void);
void my_assert(const char* pc_file_name, int iLine, BOOL bResult, const char* pDesc);
u8 wait_until_user_input_cmd_from_uart1(void);
int main(void)
{
Hardware_init();
PrintString1("me - STC15实验箱4 - 硬件出厂测试程序\r\n");
fn_proc_cmd_help(NULL);
do {
process_uart_cmd();
} while (1);
}
u8 fn_proc_cmd_help(TAG_CMD_PARAM* p_param)
{
int len = 0;
TAG_CMD_ITEM* pcmd_array = g_cmd_array;
UNUSED(p_param);
memset(&g_tmp_buf[0], 0, sizeof(g_tmp_buf));
sprintf(g_tmp_buf, "%s\r\n", LINE_60);
PrintString1(g_tmp_buf);
PrintString1("串口命令列表\r\n");
memset(g_tmp_buf, 0, sizeof(g_tmp_buf));
sprintf(g_tmp_buf, "%s\r\n", LINE_60);
PrintString1(g_tmp_buf);
do {
if ((NULL == pcmd_array)
|| (NULL == pcmd_array->pc_cmd_name)
|| (NULL == pcmd_array->pc_cmd_desc)
|| (NULL == pcmd_array->pfn_cmd_proc))
{
break;
}
memset(g_tmp_buf, 0, sizeof(g_tmp_buf));
my_assert(__FILE__, __LINE__, (strlen(pcmd_array->pc_cmd_name) < 26), pcmd_array->pc_cmd_name);
my_assert(__FILE__, __LINE__, (strlen(pcmd_array->pc_cmd_desc) < 30), pcmd_array->pc_cmd_desc);
len = sprintf(g_tmp_buf,
"cmd[%02d], name[%26s], desc[%30s]\r\n",
(int)pcmd_array->cmd_index,
pcmd_array->pc_cmd_name,
pcmd_array->pc_cmd_desc);
PrintString1(g_tmp_buf);
pcmd_array++;
} while(TRUE);
memset(g_tmp_buf, 0, sizeof(g_tmp_buf));
sprintf(g_tmp_buf, "%s\r\n", LINE_60);
PrintString1(g_tmp_buf);
PrintString1("请观察串口1和串口2输出, 如果能看到正\xFD常上报信息, 说明串口1, 串口2, USB通讯是好的\r\n");
PrintString1("请输入列出的测试命令, 进行后续测试\r\n");
return TRUE;
}
u8 wait_until_user_input_cmd_from_uart1(void)
{
u8 i = 0;
while (1)
{
delay_ms(1);
if(COM1.RX_TimeOut > 0)
{
if (0 == --COM1.RX_TimeOut)
{
if(COM1.RX_Cnt > 0)
{
if ((COM1.RX_Cnt >= 2) && ('\r' == RX1_Buffer[COM1.RX_Cnt - 2]) && ('\n' == RX1_Buffer[COM1.RX_Cnt - 1]))
{
break;
}
}
}
}
}
return COM1.RX_Cnt;
}
void process_uart_cmd(void)
{
int len = 0;
TAG_CMD_ITEM* pcmd_array = g_cmd_array;
TAG_CMD_PARAM param;
BOOL is_cmd_was_process = FALSE;
wait_until_user_input_cmd_from_uart1();
do {
if ((NULL == pcmd_array)
|| (NULL == pcmd_array->pc_cmd_name)
|| (NULL == pcmd_array->pc_cmd_desc)
|| (NULL == pcmd_array->pfn_cmd_proc)
|| (COM1.RX_Cnt < 3))
{
break;
}
RX1_Buffer[COM1.RX_Cnt - 2] = '\0';
len = strlen(RX1_Buffer);
if ((len <= 0) || (len >= (sizeof(g_tmp_buf) - 1)))
{
break;
}
memset(g_tmp_buf, 0, sizeof(g_tmp_buf));
strcpy(g_tmp_buf, RX1_Buffer);
if (
(0 == strcmp(g_tmp_buf, pcmd_array->pc_cmd_name))
|| (pcmd_array->cmd_index == atoi(g_tmp_buf))
)
{
param.cmd_index = pcmd_array->cmd_index;
param.pc_cmd_name = pcmd_array->pc_cmd_name;
param.pc_cmd_desc = pcmd_array->pc_cmd_desc;
(*pcmd_array->pfn_cmd_proc)(¶m);
is_cmd_was_process = TRUE;
break;
}
pcmd_array++;
} while(TRUE);
if (!is_cmd_was_process)
{
fn_proc_cmd_help(NULL);
}
COM1.RX_Cnt = 0;
}
void Hardware_init(void)
{
EA = 0;
UART1_init();
UART2_init();
EA = 1;
memset(g_tmp_buf, 0, sizeof(g_tmp_buf));
sprintf(g_tmp_buf, "COM1 - 初始化完成(%ld/N/8/1)\r\n", COM1_BAUDRATE_BPS);
PrintString1(g_tmp_buf);
memset(g_tmp_buf, 0, sizeof(g_tmp_buf));
sprintf(g_tmp_buf, "COM2 - 初始化完成(%ld/N/8/1)\r\n", COM2_BAUDRATE_BPS);
PrintString2(g_tmp_buf);
}
void UART1_init(void)
{
COMx_InitDefine COMx_InitStructure;
ES = 0;
COMx_InitStructure.UART_Mode = UART_8bit_BRTx;
COMx_InitStructure.UART_BRT_Use = BRT_Timer1;
COMx_InitStructure.UART_BaudRate = COM1_BAUDRATE_BPS;
COMx_InitStructure.Morecommunicate = DISABLE;
COMx_InitStructure.UART_RxEnable = ENABLE;
COMx_InitStructure.BaudRateDouble = DISABLE;
COMx_InitStructure.UART_Interrupt = ENABLE;
COMx_InitStructure.UART_Polity = PolityLow;
COMx_InitStructure.UART_P_SW = UART1_SW_P16_P17;
COMx_InitStructure.UART_RXD_TXD_Short = DISABLE;
USART_Configuration(USART1, &COMx_InitStructure);
ES = 1;
}
void UART2_init(void)
{
COMx_InitDefine COMx_InitStructure;
ES = 0;
COMx_InitStructure.UART_Mode = UART_8bit_BRTx;
COMx_InitStructure.UART_BRT_Use = BRT_Timer2;
COMx_InitStructure.UART_BaudRate = COM2_BAUDRATE_BPS;
COMx_InitStructure.Morecommunicate = DISABLE;
COMx_InitStructure.UART_RxEnable = ENABLE;
COMx_InitStructure.BaudRateDouble = DISABLE;
COMx_InitStructure.UART_Interrupt = ENABLE;
COMx_InitStructure.UART_Polity = PolityLow;
COMx_InitStructure.UART_P_SW = UART2_SW_P46_P47;
COMx_InitStructure.UART_RXD_TXD_Short = DISABLE;
USART_Configuration(USART2, &COMx_InitStructure);
ES = 1;
}
u8 fn_proc_cmd_default(TAG_CMD_PARAM* p_param)
{
int len = 0;
TAG_CMD_ITEM* pcmd_array = p_param;
if (NULL == p_param)
{
return FALSE;
}
memset(&g_tmp_buf[0], 0, sizeof(g_tmp_buf));
sprintf(g_tmp_buf, "您输入的命令是 : [%s]\r\n", (NULL != p_param->pc_cmd_name) ? p_param->pc_cmd_name : "NULL");
PrintString1(g_tmp_buf);
PrintString1("命令执行中, 请稍候...\r\n");
return TRUE;
}
void my_assert(const char* pc_file_name, int iLine, BOOL bResult, const char* pDesc)
{
int len = 0;
UNUSED(pc_file_name);
UNUSED(iLine);
UNUSED(pDesc);
if (!bResult)
{
do {
if (NULL != pDesc)
{
len = strlen(pDesc);
}
if (!bResult)
{
break;
}
} while (TRUE);
}
}
END
|