本帖最后由 黑皮男 于 2016-11-28 13:18 编辑
对于开发者来说,串口是一个很好的调试接口,串口可以输出开发者希望得到的数据,同时也可以发送相应的控制指令。最近看到micropython这种脚本语言在 STM32上的应用,简化了程序的开发,这个确实很有吸引力。命令行交互对于程序开发者来说提供了很大便利。这里来实现自己的命令行,并与 单片机进行交互。这是一个很有乐趣的事。这里使用的串口助手是Tera Term,先来张效果图,help命令可以查看当前支持命令,以及可以列出单个命令的提示信息。图中led_ctl LED3 1命令可以打开LED3.此外还实现了存储2条历史输入命令的功能,以及退格控制。当然有个很明显的缺点,就是命令名中不能有空格,单条参数内也不能有空格。F412的内存和ROM空间都足够大,有足够的发挥空间,这里做的比较简陋 ,有很多地方需要改进,可移植性比较差,仅能适用串口命令行,所以这里仅仅是抛砖引玉,大家共同讨论共同进步。
实现命令控制的原理就是通过串口不断读入数据,当遇到命令结束符时,把当前接收到的命令数据发送给命令解析任务进行命令解析并处理。关键就再命令解析这一部分 。命令个的格式是【命令+空格+参数1+空格+参数2+...】,命令以及参数之间是以空格为分节符的。这样做的一个缺点是命令名中不能存在空格,如果存在空格就会解析错误。
调试组件的组织方式是shell.c实现了命令的接收和解析,而shell_app.c是实现具体的用户命令。struct _shell_func定义了命令控制块包括命令名,命令的解析执行函数,命令参数个数,以及命令描述。func_map定义了支持的命令列表。通过查表来匹配输入的命令。
- struct _shell_func{
- char *name;
- void *fn;
- UINT8_T argc;
- UINT8_T * brief;
- };
复制代码
首先是初始化函数,初始化了shell_q命令队列,以及输出相应的信息,这里调用了上一篇内容中实现的串口发送函数。
- void shell_init(void){
- #if ENABLE_DMEM==1
- q_init(&shell_q, (Q_Node *)func_q, FUNC_QUEUE_SIZE);
- #endif
- com_writeex(COM2, "rn==========================================rnrn", 0);
- com_writeex(COM2," Version: ", 0);
- com_writeex(COM2,VERSION_STR, 0);
- com_writeex(COM2," Author: Arnornrn", 0);
- com_writeex(COM2,"==========================================rnrn", 0);
- com_writeex(COM2,"arno>", 0);
-
- }
复制代码
接下来是shell_readline函数,在中断中调用,主要是字符接收,字符控制,以及判断是否接受完一条命令,如果接收完成,则把此条命令加入到队列中。
- void shell_readline(char data){
- struct _shell_func * func;
- UINT8_T * pfunc;
- INT16_T temp;
- UINT8_T * pbuf;
- #if ENABLE_DMEM==0
- if(shell_flag==CMD_RXNE){
- return;
- }
- #endif
- if((shell_readpos==0)&&(('n'==data)||('r'==data))){
- com_write(COM2,"rnarno>", 0);
- com_flush(COM2);
- shell_readpos=0;
- }
- else if(('n'==data)||('r'==data)){
- shell_flag = CMD_RXNE;
- shell_buffer[shell_cursor][shell_readpos]='\0';
- #if ENABLE_DMEM==1
- pfunc = dmem_malloc(shell_readpos+1);
- if(pfunc!=NULL){
- memcpy(pfunc, shell_buffer[shell_cursor], shell_readpos+1);
- if(ERROR_OK!=q_add(&shell_q, (Q_Node)pfunc)){
- dmem_free(pfunc);
- }
- shell_cursor++;
- if(++cmd_num>SHELL_BUFFER_NUMS-1){
- cmd_num--;
- }
- tcmd_num = cmd_num;
- }
- shell_readpos= 0;
-
- if(shell_cursor>=SHELL_BUFFER_NUMS){
- shell_cursor=0;
- }
- #endif
-
- }
- else if('b'==data){
- if(shell_readpos!=0){
- shell_readpos--;
- com_write(COM2, "b b", 3); //清楚光标后的字符
- com_flush(COM2);
-
- }
- }
- else{
- shell_buffer[shell_cursor][shell_readpos++]=data;
- com_write(COM2,(UINT8_T const *)&data, 1);
- com_flush(COM2);
- #if ENABLE_DMEM==1
- //只有使能了动态内存的时候才使能历史恢复功能
- if((shell_readpos>=3)&&(0x42==data)&&(0x1B==shell_buffer[shell_cursor][shell_readpos-3])&&(0x5B==shell_buffer[shell_cursor][shell_readpos-2])){
- //下翻历史纪录
- //com_write(COM2, "x1Bx5Bx41", 0);//此时光标已向下移动移位,所以光标需往上移动移位
- //com_flush(COM2);
- if(shell_readpos>=3){
- shell_readpos-=3;
- }
- shell_buffer[shell_cursor][shell_readpos]='\0';
- if(cmd_num>=(tcmd_num-1)){
- return;
- }
- temp = 3*shell_readpos;
- if(temp!=0){
- pbuf = dmem_malloc(temp+1);
- if(pbuf!=NULL){
- temp = 0;
- while(shell_readpos!=0){
- memcpy(pbuf+temp, "b b", 3);
- temp+=3;
- shell_readpos--;
- }
- *(pbuf+temp)='\0';
- com_write(COM2, pbuf, 0);
- com_flush(COM2);
- }
- }else{
- shell_buffer[shell_cursor][0]='\0';
- }
- shell_cursor++;
- cmd_num++;
- if(shell_cursor>=SHELL_BUFFER_NUMS){
- shell_cursor = 0;
- }
- shell_readpos = strlen((char const *)shell_buffer[shell_cursor]);
- com_write(COM2, (UINT8_T *)shell_buffer[shell_cursor], 0);
- com_flush(COM2);
- }
- else if((shell_readpos>=3)&&(0x41==data)&&(0x1B==shell_buffer[shell_cursor][shell_readpos-3])&&(0x5B==shell_buffer[shell_cursor][shell_readpos-2])){
- //上翻历史纪录
- com_write(COM2, "x1Bx5Bx42", 0);//此时光标已向上移动移位,所以光标需往下移动移位
- com_flush(COM2);
- if(shell_readpos>=3){
- shell_readpos-=3;
- }
- shell_buffer[shell_cursor][shell_readpos]='\0';
- if(cmd_num==0){
- return;
- }
- temp = 3*shell_readpos;
- if(temp!=0){
- pbuf = dmem_malloc(temp+1);
- if(pbuf!=NULL){
- temp = 0;
- while(shell_readpos!=0){
- memcpy(pbuf+temp, "b b", 3);
- temp+=3;
- shell_readpos--;
- }
- *(pbuf+temp)='\0';
- com_write(COM2, pbuf, 0);
- com_flush(COM2);
- }
- }else{
- shell_buffer[shell_cursor][0]='\0';
- }
- if(shell_cursor==0){
- shell_cursor = SHELL_BUFFER_NUMS-1;
- }else{
- shell_cursor--;
- }
- shell_readpos = strlen((char *)shell_buffer[shell_cursor]);
- com_write(COM2, (UINT8_T *)shell_buffer[shell_cursor], 0);
- com_flush(COM2);
- cmd_num--;
- }
- #endif
- }
- }
复制代码
接下来是重点解析命令的函数,此函数解析一条命令,把命令字符串与命令列表中的命令进行对比,如果匹配成功,则返回该命令控制块。
- struct _shell_func *shell_getfunc(char * str){
- UINT8_T i;
- for(i=0;i
- if(0==memcmp(func_map[i].name, str, strlen(func_map[i].name))){
- if((func_map[i].argc!=0)&&(func_map[i].argc!=MAX_FUNC_PARAMS)){
- if(*(str+strlen(func_map[i].name))==' '){
- return (struct _shell_func *)&func_map[i];
- }else if(*(str+strlen(func_map[i].name))=='\0'){
- return (struct _shell_func *)&func_map[i];
- }
- }else{
- return (struct _shell_func *)&func_map[i];
- }
- }
- }
- return NULL;
- }
复制代码
shell任务解析完命令后会调用shell_execufunc函数执行本条命令。
- void shell_execfunc(struct _shell_func *func, char *params){
- char *pstr = NULL;
- UINT8_T i=0;
- char *buf[10];
- pstr = strstr(params, " ");
- while(pstr!=NULL){
-
- pstr[0]='\0';
- buf[i]=params;
- params = pstr+1;
- i++;
- pstr = strstr(params, " ");
- }
- buf[i]=params;
- if((func->argc!=MAX_FUNC_PARAMS)&&(i==func->argc)){
- if(func->argc!=0){
- ((ShellFunc)(func->fn))(i, (char **)buf);
- }else{
- ((void (*)(void))func->fn)();
- }
-
- }else{
- ((ShellFunc)(func->fn))(i, (char **)buf);
- }
-
- }
复制代码
最后是shell任务,任务负责解析并执行命令命令。
- void shell_task(void){
- struct _shell_func *func;
- #if ENABLE_DMEM==1
- UINT8_T * pfunc;
- if(ERROR_OK==q_get(&shell_q, (Q_Node *)&pfunc)){
- func = shell_getfunc((char *)pfunc);
- if(func!=NULL){
- shell_execfunc(func, (char *)pfunc);
-
- }
- com_writeex(COM2,"rnarno>", 0);
- dmem_free(pfunc);
- }
- #else
- if(shell_flag ==CMD_RX){
- return;
- }
- func = shell_getfunc((char *)shell_buffer[shell_cursor]);
- if(func!=NULL){
- shell_execfunc(func, (char *)shell_buffer[shell_cursor]);
- }
- com_writeex(COM2,"rnarno>", 0);
- shell_readpos= 0;
- shell_flag= CMD_RX;
- #endif
-
- }
复制代码
0
|
|
|
|