完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
2个回答
|
|
shell 层与硬件无关,有无操作系统都可以使用,适用于stm32等32位小端的单片机,支持历史纪录功能,tab 键补全命令,提供命令行参数解释函数,可以响应tab、backspace、上下左右编辑等功能,并提供一个简易版的vi 文本编辑功能。支持多交互接口,各个接口间数据流互不影响。
其中此文件夹中的文件都与硬件平台无关,但可能与编译平台有关。此库编译版本要在C99以上,或用GCC编译。根据不同的硬件平台分别写了不同的控制台demo, F1 文件夹的是STM32F1 相关的控制台, F4 则是 F4xx 系列的控制台,但是L1平台的我并没有调通,手上也没有这个板子,所以先放着。 文件说明: avltree.c :平衡二叉树相关实现代码,在注册命令较多的时候可以启用平衡二叉树进行索引匹配。 getopt.c :有些编译环境,如 KEIL5 中,没有函数getopt() ,这是其源码,是我在网上找的。要是用 gcc 相关的编译平台可以 #include heaplib.c : 内存管理,其实这个是我原封不动从freertos 的 heap_4.c 拷过来的,在heaplib.h 提供了部分宏支持,可以脱离操作系统使用。 shell.c:命令行相关,支持 table 键补全,支持上下左右箭头响应,提供参数解析,历史纪录。支持多个交互,如串口,telnet,或者u***,可各自建立交互。 tasklib.c:协程控制器。有需要的话使用协程可以简化代码的编写。我把它模拟成一个操作系统。 ustdio.c:提供 printk 函数,重定义 printf 函数 vim.c:这是我仿照 linux 的 vi 写的一个建议的文本编辑器,依赖 shell ,可以实现简易的文本编辑。 F1/F4/L1:不同硬件平台的相关串口控制台实现,提供串口在线升级功能。 LittleFS: LittleFS 是一个用于 spi flash 的文件系统,先放这。 基本使用 使用这个库的基本功能只需要把 shell.c 、shell.h 、ustdio.c 、ustdio.h 和 kernel.h 这几个文件包含进文件工程里面即可。系统的使用可以大致分为以下几个步骤: 0.初始化硬件部分。 1.编写硬件对应的void puts(char * buf , uint16_t len) 发送函数。 2.shell_init(sign,puts)初始化输入标志和默认输出。 3.新建一个交互shellx 并初始化shell_input_init(&shellx,puts); 4.接收到一包数据后,调用shell_input(&shellx,buf,len) 以下用stm32cubemx新建串口工程实际说明。Mcu选择为STM32F103VET6; 配置 SYS -> DEBUG 为 Serial Wire : 配置 RCC -> HSE 为 Crystal , 配置 USART1 -> Mode 为 asynchronization ,并打开USART1 的中断: 调整时钟为外部晶振,其余配置保留原始值即可: 最后生成MDK-KEIL5 工程。把 shell.c 、ustdio.c 复制到工程文件夹 src 中,并加入文件, containerof.h、shell.h、ustdio.h复制到 inc 文件夹中。 接下来需要编写串口的发送函数,类型如下: void puts(char *data,uint16_t len) , 为了方便此处在main.c下编写,内容如下: 编写串口对应的接收回调函数,如下: 在 main.c 中include “shell.h”,新建一个交互usart1_shell;如下: 在 main() 中添加如下代码,初始化整个系统,其中,shell_init()初始化默认的输入标志和printf/printk的默认输出,默认输出可以在线重定义流向,shell_input_init()初始化交互。 编译并下载代码。然后用 SecureCRT 或者 putty 连接串口,连续敲回车出现输入标志,则说明系统正常运行: 调用 shell_init() 后,系统默认内置三条命令,输入命令“cmd-list”回车,获取所有命令列表: 至此shell 系统已经基本成功跑起,可以尝试 tab 键命令补全,但上下箭头回溯历史,左右箭头编辑命令行等功能还不能用,因为箭头按键是3个字节数据,目前是接收一个字节就输入shell_input()一次,数据包被分割输入,所以需要使用这部分功能,需要接收完整一包数据后才调用shell_input()输入,比如利用空闲中断,此处修改接收回调 开启空闲中断: 修改usart1的中断函数,添加空闲中断处理代码: 修改main()函数while(1)处理 至此,shell系统基本可以完整跑起来了,已可以使用上下左右箭头按键的功能。代码链接: https://pan.baidu.com/s/1ij9EXbxYwMCqrZkuDcLvOw 下面介绍 shell用户命令的注册和使用。 用户命令的注册和使用 目前这个库提供了两个宏定义来实现用户命令的注册,分别是 shell_register_command(name,func); shell_register_confirm(name,func,info); 1 2 shell_register_command用于一般的命令注册,name为命令字符,如“reboot”,需要注意的是,同一串字符串不能注册多次,即不能注册同一条命令多次,以先到先得的原则会只注册第一条。func为命令对应的执行代码,类型为 void cmd_fn(void * arg); 1 其中输入形参void * arg 为命令行的输入内存指针。以hello-world命令为例,编写对应的执行代码: void helloworld(void * arg) { printk("this is hello world commandrn");//或者printf } 便可以在cmd-list里面找到对应的命令,在终端输入hello-world,会反馈打印内容。此外还有另外一种带确认信息的注册方式: shell_register_confirm (“hello-world2”,helloworld,“sure to test this command?”); 这种方式在输入命令以后需要输入[y/Y/n/N]确认命令执行。如下 命令行的参数解析 上文提到,命令对应的执行函数类型为 void cmd_fn(void * arg); 其中的void * arg是把命令行内存首地址传入,如在终端输入"hello-world 1234" 回车,shell会先匹配到 helloworld 对应的执行代码,并把整串输入字符串的首地址作为arg输入给函数,用户可对此进行参数解析。当前库提供两个函数用于解析命令行参数 int cmdline_param (char * str,int * argv,uint32_t maxread); int cmdline_strtok(char * str ,char ** argv,uint32_t maxread); cmdline_param()可以把命令行后面所跟参数转为整形数据,不过仅支持整形的转换,包括正负数和十六进制,转换结果存储于 argv 内,字符串转换正常返回参数个数,有非数字字符会返回<0。大致如下: void demo_cmd(void * arg) { int argv[4]; int argc = cmdline_param((char*)arg,argv,4); printk("get %d parametersrn",argc); for(int i = 0 ; i < argc ; ++i) printk("argv[%d]:%drn",i,argv); } cmdline_strtok()是对命令行的输入字符串进行分割,把输入分割为一串指针数组输出到argv[]中。需要注意的是这个函数会改变命令行的输入内存内容(把空格替换了字符串结束符)。如下 void demo2_cmd(void * arg) { char * argv[4]; int argc =cmdline_strtok((char*)arg,argv,4); printk("get %d parametersrn",argc); for(int i = 0 ; i < argc ; ++i) printk("argv[%d]:"%s"rn",i,argv); } 然后注册命令测试 shell_register_command(“param2int”,demo_cmd); shell_register_command(“param-get”,demo2_cmd); 运行结果如下: 利用 cmdline_strtok() ,可以实现linux 的 getopt() 选项输入支持。由于getopt() 是gnuc的库,所以上述库还收录了 getopt() 的源码,有需要的可以把getopt.c和getopt.h加入工程便可使用getopt()函数进行输入选项分类,代码如下: void demo3_cmd(void * arg) { int opt; int argc; char* argv[8]; argc = cmdline_strtok((char*)arg,argv,8); optind = 1;//getopt()之前,这个值要为 1 while ((opt = getopt(argc, argv, "ab:c:de::")) != -1) { printk("optind: %drn", optind); switch (opt) { case 'a': printk("HAVE option: -arn"); break; case 'b': printk("HAVE option: -brn"); printk("The argument of -b is %srn", optarg); break; case 'c': printk("HAVE option: -crn"); printk("The argument of -c is %srn", optarg); break; case 'd': printk("HAVE option: -drn"); break; case 'e': printk("HAVE option: -ern"); printk("The argument of -e is %srn", optarg); break; case '?': printk("Unknown option: %crn",(char)optopt); break; } } } 结果如下: 另外,getopt.c不是作者所写,编译可能会有些许警告,而且其源码编译下来也不小,还是按需使用吧。 源码链接:https://gitee.com/somebug/atomlib/blob/master/appdemo/f103-shell-demo-2.0.zip |
|
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1777 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1621 浏览 1 评论
1080 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
728 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1678 浏览 2 评论
1938浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
731浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
570浏览 3评论
595浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
554浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 09:57 , Processed in 1.048649 second(s), Total 76, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号