本帖最后由 jf_1137202360 于 2023-4-15 17:33 编辑
转自公众号,欢迎关注
工程源码
前言
为了方便后面开发测试,我们需要一定的和开发板交互的手段,所以我们先来基于串口实现一个简单的命令行工具。
过程实现串口FIFO首先实现基于环形缓冲区的串口接收驱动。 添加uart fifo实现代码
Drivers\\\\\\\\SYSTEM\\\\\\\\usart\\\\\\\\usart.c中
- #include \\\\\\\"./SYSTEM/usart/usart_fifo.h\\\\\\\"
复制代码
HAL_UART_RxCpltCallback修改为
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
- {
- if (huart->Instance == USART_UX) /* 如果是串口1 */
- {
- #if 0
- if ((g_usart_rx_sta & 0x8000) == 0) /* 接收未完成 */
- {
- if (g_usart_rx_sta & 0x4000) /* 接收到了0x0d(即回车键) */
- {
- if (g_rx_buffer[0] != 0x0a) /* 接收到的不是0x0a(即不是换行键) */
- {
- g_usart_rx_sta = 0; /* 接收错误,重新开始 */
- }
- else /* 接收到的是0x0a(即换行键) */
- {
- g_usart_rx_sta |= 0x8000; /* 接收完成了 */
- }
- }
- else /* 还没收到0X0d(即回车键) */
- {
- if (g_rx_buffer[0] == 0x0d)
- g_usart_rx_sta |= 0x4000;
- else
- {
- g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = g_rx_buffer[0];
- g_usart_rx_sta++;
- if (g_usart_rx_sta > (USART_REC_LEN - 1))
- {
- g_usart_rx_sta = 0; /* 接收数据错误,重新开始接收 */
- }
- }
- }
- }
- #endif
- uart_rx_handler(&g_rx_buffer[0], 1);
- }
- }
复制代码
即收到数据调用uart_rx_handler进行入缓冲区操作。
添加发送接口
- void usart_send(uint8_t value)
- {
- while ((USART_UX->SR & 0X40) == 0); /* 等待上一个字符发送完成 */
- USART_UX->DR = value; /* 将要发送的字符 ch 写入到DR寄存器 */
- }
复制代码
对应.h中添加申明void usart_send(uint8_t value);
usart_fifo.c
- #include
- #include
- #include <ARM_compat.h>
- #include \\\"SYSTEM/usart/usart.h\\\"
- uint8_t uart_ring_buffer[128];
- typedef struct
- {
- uint32_t datalen_u32;
- uint32_t maxlen_u32;
- uint32_t in_u32;
- uint32_t out_u32;
- uint8_t* buffer_pu8;
- }ring_buffer_t;
- ring_buffer_t s_ring_buffer_t=
- {
- .datalen_u32 = 0,
- .maxlen_u32 = sizeof(uart_ring_buffer),
- .in_u32 = 0,
- .out_u32 = 0,
- .buffer_pu8 = uart_ring_buffer,
- };
- void uart_rx_handler(const uint8_t *buffer, uint32_t length)
- {
- for(uint32_t i=0;i
- {
- if(s_ring_buffer_t.datalen_u32 < s_ring_buffer_t.maxlen_u32)
- {
- s_ring_buffer_t.buffer_pu8[s_ring_buffer_t.in_u32] = buffer[i];
- s_ring_buffer_t.datalen_u32++;
- s_ring_buffer_t.in_u32++;
- s_ring_buffer_t.in_u32 %= s_ring_buffer_t.maxlen_u32;
- }
- else
- {
- /* full */
- break;
- }
- }
- }
- int uart_read(uint8_t *buff, uint32_t len)
- {
- uint32_t readlen = 0;
- uint32_t mask;
- if(s_ring_buffer_t.datalen_u32 == 0)
- {
- return 0;
- }
- __disable_irq();
- for(uint32_t i=0;i
- {
- if(s_ring_buffer_t.datalen_u32 > 0)
- {
- buff[i] = s_ring_buffer_t.buffer_pu8[s_ring_buffer_t.out_u32];
- s_ring_buffer_t.datalen_u32--;
- s_ring_buffer_t.out_u32++;
- s_ring_buffer_t.out_u32 %= s_ring_buffer_t.maxlen_u32;
- readlen++;
- }
- else
- {
- break;
- }
- }
- __enable_irq();
- return readlen;
- }
- int uart_write(uint8_t *buff, uint32_t len)
- {
- for(uint32_t i=0; i
- {
- usart_send(buff[i]);
- }
- return 0;
- }
- void uart_init(void)
- {
- }
复制代码
usart_fifo.h
准备shell代码添加代码
添加头文件包含路径
shell依赖
需要实现shell.c中的shell_getchar和putchar。
- static int shell_getchar(unsigned char *data)
- {
- int erro=0;
- //driver_uart_recv(getstdiouart(), data, 1,10,&erro);
- if(0 == uart_read(data, 1))
- {
- erro = 1;
- }
- if(erro!=0)
- {
- return -1;
- }
- return 0;
- }
复制代码
putchar因为重定向了标准输入输出已经有了。
测试main.c中
- #include \\\\\\\"shell.h\\\\\\\"
-
- while (1)
- { shell_exec_shellcmd();
- delay_ms(1);
- }
复制代码
接上串口,回车打印sh> 输入help打印如下
这样可以自由的添加交互命令了。
总结 以上通过实现串口接收环形FIFO的驱动,方便应用层进行调用。并给予此实现了简洁的SHELL交互命令,非阻塞,可以方便的添加命令。
附录源码 shell.c
- /**
- *****************************************************************************
- * \\\\\\\\brief 平台相关(PLATFORM)SHELL模块(SHELL)相关接口实现.
- * \\\\\\\\details
- * All rights reserved.
- * \\\\\\\\file shell.c
- * \\\\\\\\author
- * \\\\\\\\version 1.0
- * \\\\\\\\date
- * \\\\\\\\note 使用前请参考注释.\\\\\\\\n
- * \\\\\\\\since 新建
- * \\\\\\\\par 修订记录
- * - 初始版本
- * \\\\\\\\par 资源说明
- * - RAM:
- * - ROM:
- *****************************************************************************
- */
- #include
- #include
- #include \\\\\\\"shell.h\\\\\\\"
- #include \\\\\\\"SYSTEM/usart/usart_fifo.h\\\\\\\"
- /*****************************************************************************
- *
- * 内部数据
- *
- ****************************************************************************/
- #define SHELL_CMD_LEN 64 /**< shell命令缓冲区长度 */
- extern const shell_cmd_cfg shell_cmd_list[ ]; /**< shell_fun中定义 */
- extern const shell_cmd_cfg shell_cmd_list_app[ ]; /**< app_shellfun中定义 */
- static int shellpassed = 1; /**< shell密码是否校验 0已经校验 1未校验 */
- static unsigned char cmd_buf[SHELL_CMD_LEN]=\\\\\\\"\\\\\\\\r\\\\\\\";
- static int cmd_buf_index=0; /**< 当前接收到的命令字符数 */
- /*****************************************************************************
- *
- * 内部接口函数实现
- *
- ****************************************************************************/
- /**
- *****************************************************************************
- * \\\\\\\\fn static int shell_getchar(unsigned char *data)
- * \\\\\\\\brief 读取一个字符.
- * \\\\\\\\note .
- * \\\\\\\\param[out] data 存储读到的数据.
- * retval 0 成功.
- * retval -1 失败.
- *****************************************************************************
- */
- static int shell_getchar(unsigned char *data)
- {
- int erro=0;
- //driver_uart_recv(getstdiouart(), data, 1,10,&erro);
- if(0 == uart_read(data, 1))
- {
- erro = 1;
- }
- if(erro!=0)
- {
- return -1;
- }
- return 0;
- }
- /**
- *****************************************************************************
- * \\\\\\\\fn static unsigned int shell_cmd_len(char const *cmd)
- * \\\\\\\\brief 获取命令字符长度.
- * \\\\\\\\note 空格或者\\\\\\\\0结束.
- * \\\\\\\\param[in] cmd 字符串
- * return unsigned int 命令字符的长度
- *****************************************************************************
- */
- static unsigned int shell_cmd_len(unsigned char const *cmd)
- {
- unsigned char const *p = cmd;
- unsigned int len = 0;
- while((*p != \\\\\\\' \\\\\\\') && (*p != 0))
- {
- p++;
- len++;
- }
- return len;
- }
- /**
- *****************************************************************************
- * \\\\\\\\fn static void shell_check_passwd(void)
- * \\\\\\\\brief shell密码确认.
- * \\\\\\\\note 空格或者\\\\\\\\0结束.
- *****************************************************************************
- */
- static void shell_check_passwd(void)
- {
- unsigned int i;
- unsigned char ch[6] = {0};
- unsigned char pw[7] = SHELL_PASSWORD_STR;
- while(1)
- {
- printf(\\\\\\\"\\\\\\\\r\\\\\\\\nPassword:\\\\\\\");
- memset(ch, 0, sizeof(ch));
- for (i = 0; i < sizeof(ch); i++)
- {
- ch[i] = getchar();
- putchar(\\\\\\\'\\\\\\\\b\\\\\\\');
- putchar(\\\\\\\'*\\\\\\\');
- }
- if (memcmp(pw, ch, sizeof(ch)) == 0)
- {
- printf(\\\\\\\"\\\\\\\\r\\\\\\\\n\\\\\\\");
- break;
- }
- printf(\\\\\\\"\\\\\\\\r\\\\\\\\nAccess denied\\\\\\\\r\\\\\\\\n\\\\\\\");
- }
- }
- /**
- *****************************************************************************
- * \\\\\\\\fn static int shell_cmd_check(unsigned char *cmd, char const *str)
- * \\\\\\\\brief 匹配命令字符.
- * \\\\\\\\note .
- * \\\\\\\\param[in] cmd 字符串
- * \\\\\\\\param[in] str 匹配字符
- * retval 0 匹配成功
- * retval 1 匹配失败
- *****************************************************************************
- */
- static int shell_cmd_check(unsigned char *cmd, unsigned char const *str)
- {
- unsigned int len1 = shell_cmd_len((unsigned char const *)cmd);
- unsigned int len2 = shell_cmd_len(str);
- if(len1 != len2)
- {
- return 1;
- }
- return memcmp(cmd, str, len1);
- }
- /**
- *****************************************************************************
- * \\\\\\\\fn static unsigned int shell_read_line(int get(void), unsigned int len)
- * \\\\\\\\brief shell读命令行.
- * \\\\\\\\note 回车结束,可以使用Backspace键清除输入.
- * \\\\\\\\param[in] get 输入接口函数
- * \\\\\\\\param[in] p 接收缓冲区
- * \\\\\\\\param[in] len 需要接收的长度
- * return unsigned int 实际接收的长度
- *****************************************************************************
- */
- static unsigned int shell_read_line(int get(unsigned char* tmp))
- {
- unsigned char ch = \\\\\\\'\\\\\\\\r\\\\\\\';
- unsigned int count;
- unsigned char tmp;
- /*开始打印一次\\\\\\\"sh>\\\\\\\"*/
- if(cmd_buf[0]==\\\\\\\'\\\\\\\\r\\\\\\\')
- {
- printf(\\\\\\\"sh>\\\\\\\\r\\\\\\\\n\\\\\\\");
- memset(cmd_buf,0x00,sizeof(cmd_buf));
- }
- /*如果接收到字符往下走,否则返回*/
- if(get(&tmp)==0)
- {
- ch = tmp;
- }
- else
- {
- return 0;
- }
- /*如果接收到非打印字符且当前接收缓冲区不为0则认为接收到一帧否则打印\\\\\\\"SH>\\\\\\\"*/
- if((ch == \\\\\\\'\\\\\\\\r\\\\\\\' || ch == \\\\\\\'\\\\\\\\n\\\\\\\' || ch < \\\\\\\' \\\\\\\' || ch > \\\\\\\'~\\\\\\\') && (ch != \\\\\\\'\\\\\\\\b\\\\\\\'))
- {
- if(cmd_buf_index==0)
- {
- printf(\\\\\\\"sh>\\\\\\\\r\\\\\\\\n\\\\\\\");
- }
- else
- {
- count = cmd_buf_index;
- cmd_buf[cmd_buf_index]=0;
- cmd_buf_index =0;
- printf(\\\\\\\"\\\\\\\\r\\\\\\\\n\\\\\\\");
- return count;
- }
- }
- else
- {
- if(ch == \\\\\\\'\\\\\\\\b\\\\\\\')
- {
- if(cmd_buf_index != 0)
- {
- cmd_buf_index--;
- putchar(\\\\\\\'\\\\\\\\b\\\\\\\');
- putchar(\\\\\\\' \\\\\\\');
- putchar(\\\\\\\'\\\\\\\\b\\\\\\\');
- cmd_buf[cmd_buf_index]= \\\\\\\'\\\\\\\\0\\\\\\\';
- }
- }
- else
- {
- /*如果接收到打印字符且当前接收缓冲区满则认为接收完一帧\\\\\\\"*/
- putchar(ch);
- cmd_buf[cmd_buf_index++] = ch;
- if(cmd_buf_index>=(sizeof(cmd_buf)-1))
- {
- count = cmd_buf_index;
- cmd_buf[cmd_buf_index]=0;
- cmd_buf_index =0;
- printf(\\\\\\\"\\\\\\\\r\\\\\\\\n\\\\\\\");
- return count;
- }
- }
- }
- return 0;
- }
- /**
- *****************************************************************************
- * \\\\\\\\fn int shell_exec_cmdlist(unsigned char* cmd)
- * \\\\\\\\brief 搜索命令列表并执行.
- * retval 0 成功
- * retval -1 失败
- * \\\\\\\\note .
- *****************************************************************************
- */
- int shell_exec_cmdlist(unsigned char* cmd)
- {
- int i;
- /*平台相关命令*/
- for (i=0; shell_cmd_list[i].name != 0; i++)
- {
- if (shell_cmd_check(cmd, shell_cmd_list[i].name) == 0)
- {
- shell_cmd_list[i].func(cmd);
- return 0;
- }
- }
- // /*应用相关命令*/
- // for (i=0; shell_cmd_list_app[i].name != 0; i++)
- // {
- // if (shell_cmd_check(cmd, shell_cmd_list_app[i].name) == 0)
- // {
- // shell_cmd_list_app[i].func(cmd);
- // return 0;
- // }
- // }
- if(shell_cmd_list[i].name == NULL)
- {
- printf(\\\\\\\"unkown command\\\\\\\\r\\\\\\\\n\\\\\\\");
- return -1;
- }
- return 0;
- }
- /*****************************************************************************
- *
- * 对外接口函数实现
- *
- ****************************************************************************/
- /**
- *****************************************************************************
- * \\\\\\\\fn void shell_exec_shellcmd(void)
- * \\\\\\\\brief 执行shell命令.
- * \\\\\\\\note 任务周期调用该函数.
- *****************************************************************************
- */
- void shell_exec_shellcmd(void)
- {
- if (!shellpassed)
- {
- shell_check_passwd();
- shellpassed = 1;
- }
- if(shell_read_line(shell_getchar))
- {
- shell_exec_cmdlist(cmd_buf);
- }
- }
复制代码
shell.h
shell_fun.c
- /**
- *****************************************************************************
- * \\\\\\\\brief 平台层(PLATFORM)SHELL命令模块(SHELL_FUN)相关接口实现.
- * \\\\\\\\details
- * All rights reserved.
- * \\\\\\\\file shell_fun.c
- * \\\\\\\\author
- * \\\\\\\\version 1.0
- * \\\\\\\\date
- * \\\\\\\\note 平台相关命令.\\\\\\\\n
- * \\\\\\\\since 新建
- * \\\\\\\\par 修订记录
- * - 初始版本
- * \\\\\\\\par 资源说明
- * - RAM:
- * - ROM:
- *****************************************************************************
- */
- #include
- #include
- #include
- #include
- #include \\\\\\\"shell_fun.h\\\\\\\"
- #include \\\\\\\"shell.h\\\\\\\"
- /*****************************************************************************
- *
- * 内部数据
- *
- ****************************************************************************/
- const shell_cmd_cfg shell_cmd_list[ ] =
- {
- /*1.帮助相关*/
- { \\\\\\\"help\\\\\\\", HelpFun, \\\\\\\"help\\\\\\\"}, /*打印帮助信息*/
- { 0, 0 },
- };
- /*****************************************************************************
- *
- * 内部接口函数实现
- *
- ****************************************************************************/
- /*****************************************************************************
- *
- * 对外接口函数实现
- *
- ****************************************************************************/
- /*****************************************************************************
- *
- * 帮助相关
- *
- ****************************************************************************/
- void HelpFun(void* param)
- {
- unsigned int i;
- printf(\\\\\\\"\\\\\\\\r\\\\\\\\n\\\\\\\");
- printf(\\\\\\\"**************\\\\\\\\r\\\\\\\\n\\\\\\\");
- printf(\\\\\\\"* SHELL *\\\\\\\\r\\\\\\\\n\\\\\\\");
- printf(\\\\\\\"* V1.0 *\\\\\\\\r\\\\\\\\n\\\\\\\");
- printf(\\\\\\\"**************\\\\\\\\r\\\\\\\\n\\\\\\\");
- printf(\\\\\\\"\\\\\\\\r\\\\\\\\n\\\\\\\");
- for (i=0; shell_cmd_list[i].name != 0; i++)
- {
- printf(\\\\\\\"%02d.\\\\\\\",i);
- printf(\\\\\\\"%-16s\\\\\\\",shell_cmd_list[i].name);
- printf(\\\\\\\"%s\\\\\\\\r\\\\\\\\n\\\\\\\",shell_cmd_list[i].helpstr);
- }
- }
- #if 0
- void SetTimeFun(void * cmdbuf)
- {
- unsigned int year, month, day, week, hour, minute, second;
- unsigned int len = sscanf((char const *)cmdbuf, \\\\\\\"%*s %d %d %d %d %d %d %d\\\\\\\", &year, &month, &day, &week, &hour, &minute, &second);
- if (len == 7)
- {
- struct tm tm_time;
- tm_time.tm_year = year -1900;
- tm_time.tm_mon = month - 1;
- tm_time.tm_mday = day;
- tm_time.tm_wday = week;
- tm_time.tm_hour = hour;
- tm_time.tm_min = minute;
- tm_time.tm_sec = second;
- tm_time.tm_isdst = -1;
- driver_time_settm(&tm_time);
- }
- else
- {
- printf(\\\\\\\"usage: \\\\\\\\r\\\\\\\\n\\\\\\\\tsettime \\\\\\\\r\\\\\\\\n\\\\\\\");
- }
- }
- #endif
复制代码
shell_fun.h
- /**
- *****************************************************************************
- * \\\\\\\\brief 平台层(PLATFORM)SHELL命令模块(SHELL_FUN)相关数据结构和接口描述.
- * \\\\\\\\details
- * All rights reserved.
- * \\\\\\\\file shell_fun.h
- * \\\\\\\\author
- * \\\\\\\\version 1.0
- * \\\\\\\\date
- * \\\\\\\\note 平台相关命令.\\\\\\\\n
- * \\\\\\\\since 新建
- * \\\\\\\\par 修订记录
- * -
- * \\\\\\\\par 资源说明
- * - RAM:
- * - ROM:
- *****************************************************************************
- */
- #ifndef __SHELL_FUN_H
- #define __SHELL_FUN_H
- #ifdef __cplusplus
- extern \\\\\\\"C\\\\\\\" {
- #endif
- /*****************************************************************************
- *
- * 帮助相关
- *
- ****************************************************************************/
- void HelpFun(void* param);
- /*****************************************************************************
- *
- *
- *
- ****************************************************************************/
- #ifdef __cplusplus
- }
- #endif
- #endif
复制代码
|