在进行调试和维护时,常常需要与单片机进行交互,获取、设置某些参数或执行某些操作,nr_micro_shell正是为满足这一需求,针对资源较少的MCU编写的基本命令行工具。虽然RT_Thread组件中已经提供了强大的finsh命令行交互工具,但对于ROM、RAM资源较少的单片机,finsh还是略显的庞大,在这些平台上,若仍想保留基本的命令行交互功能,nr_micro_shell是一个不错的选择。
nr_micro_shell具有以下优点
1.占用资源少,使用简单,灵活方便。使用过程只涉及两个shell_init()和shell()两个函数,无论是使用RTOS还是裸机都可以方便的应用该工具,不需要额外的编码工作。
2.交互体验好。完全类似于linux shell命令行,当串口终端支持ANSI(如Hypertrm终端)时,其不仅支持基本的命令行交互,还提供Tab键命令补全,查询历史命令,方向键移动光标修改功能。
3.扩展性好。nr_micro_shell为用户提供自定义命令的标准函数原型,只需要按照命令编写命令函数,并注册命令函数,即可使用命令。
nr_micro_shell和相同配置下的finsh (finsh不使用msh)占用资源对比
原始工程 | 添加nr_micro_shell增加量 | 添加finsh增加量 | |
ROM | 63660 | +3832 | +26908 |
RAM | 4696 | +1104 | +1304 |
两者配置都为
· 最多3条历史命令。
· 支持Tab补全 。
· 命令行最大长度为100。
· 最多10个命令参数。
· 命令行线程堆栈为512字节。
1、下载源码:
https://gitee.com/nrush/nr_micro_shell.git
2、添加到工程,在前面移植基础工程的基础之上添加移植代码。
然后添加进编译,将目录添加进CmakeLists。
3、编写用户代码:
Shell_uart.c/h
在Shell_uart.c中首先启动shell_init(); //NR_MICRO_SHELL
然后编写stm32 UART的接收、错误的三个回调函数:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART1) //shell { if(((g_shell_uart.rx.write_i+1)&0x1ff) != g_shell_uart.rx.read_i) { g_shell_uart.rx.buff[g_shell_uart.rx.write_i++] = uart_recv_buff[0] & 0xff; g_shell_uart.rx.write_i &= 0x1ff;//256Byte } HAL_UART_Receive_IT(huart,uart_recv_buff,1);// } } // void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART1) //shell { HAL_UART_Receive_IT(huart,uart_recv_buff,1);// } }
在接收函数中,我们将接收的字符缓存到缓冲区。
在loop函数中,我们判断如果有数据,就通过shell(g_shell_uart.rx.buff[g_shell_uart.rx.read_i++]);将接收到的字符回传给串口。
void shell_usart_loop(void) { if(g_shell_uart.rx.read_i != g_shell_uart.rx.write_i) { shell(g_shell_uart.rx.buff[g_shell_uart.rx.read_i++]); g_shell_uart.rx.read_i &= 0x1ff; //256Byte } }
4、增加shell 命令:
#include "string.h" #include "ctype.h" static void list_cmd(void) { unsigned int i = 0; for (i = 0; nr_shell.static_cmd[i].fp != NULL; i++) { shell_printf("%s\t\t", nr_shell.static_cmd[i].cmd); if (nr_shell.static_cmd[i].description != NULL) shell_printf("\"%s\"\t\t", nr_shell.static_cmd[i].description); shell_printf("\r\n"); } } /** * @brief ls command */ void shell_ls_cmd(char argc, char *argv) { if (argc > 1) { if (!strcmp("cmd", &argv[argv[1]])) { list_cmd(); } else if (!strcmp("-v", &argv[argv[1]])) { shell_printf("ls version 1.0.\r\n"); } else // if (!strcmp("-h", &argv[argv[1]])) { goto exit_lable; } return; } shell_printf("ls need more arguments!\r\n\r\n"); exit_lable: shell_printf("useage: ls [options]\r\n"); shell_printf("options: \r\n"); shell_printf("\t -h \t: show help\r\n"); shell_printf("\t -v \t: show version\r\n"); shell_printf("\t cmd \t: show all commands\r\n"); } void shell_help_cmd(char argc, char *argv) { list_cmd(); } /** * @brief test command */ void shell_test_cmd(char argc, char *argv) { unsigned int i; shell_printf("test command:\r\n"); for (i = 0; i < argc; i++) { shell_printf("paras %d: %s\r\n", i, &(argv[argv[i]])); } } #ifdef NR_SHELL_USING_EXPORT_CMD NR_SHELL_CMD_EXPORT(help, shell_help_cmd, "help"); NR_SHELL_CMD_EXPORT(ls, shell_ls_cmd, "list cmd"); NR_SHELL_CMD_EXPORT(test, shell_test_cmd, "test cmd"); #else const static_cmd_st static_cmd[] = { {"help", shell_help_cmd, "list cmd"}, {"ls", shell_ls_cmd, "list cmd"}, {"test", shell_test_cmd, "test cmd"}, {"\0", NULL}}; #endif
运行效果:
通过shell的移植,就可以很好的跟F769进行交互了。
使用命令控制板载LED的开关
添加命令:
void shell_led_cmd(char argc, char *argv) { if(argc == 2) { if(!strcmp("LED", &argv[argv[0]]) ) { if(!strcmp("on", &argv[argv[1]])) { HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_SET); shell_printf("LED on\r\n"); } else if(!strcmp("off", &argv[argv[1]])) { HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_RESET); shell_printf("LED off\r\n"); } else { shell_printf("ERRO CMD:led %s\r\n", argv[1]); } } else { shell_printf("ERRO CMD:led %s\r\n", argv[0]); } } }
再把命令添加进cmd组:
const static_cmd_st static_cmd[] = { {"help", shell_help_cmd, "list cmd"}, {"ls", shell_ls_cmd, "list cmd"}, {"test", shell_test_cmd, "test cmd"}, {"LED", shell_led_cmd, "LED on/off"}, {"\0", NULL} };
在终端中就可以实时控制LED的关与灭了:
| \ | | _ \ | \/ (_) ___ _ __ ___ / ___|| |__ ___| | | | \| | |_) | | |\/| | |/ __| '__/ _ \ \___ \| '_ \ / _ \ | | | |\ | _ < | | | | | (__| | | (_) | ___) | | | | __/ | | |_| \_|_| \_\ |_| |_|_|\___|_| \___/ |____/|_| |_|\___|_|_| nr@root:ls cmd help "list cmd" ls "list cmd" test "test cmd" LED "LED on/off" nr@root:LED on LED on nr@root:LED off LED off nr@root: