C語言三劍客--一個簡單的命令直譯器
阿新 • • 發佈:2018-12-20
這是C語言三劍客書(三本書,不記得是哪一個了)的一個簡單的C語言實現的的命令直譯器,加在微控制器軟體工程裡,用來除錯,還是比較靈活方便的。
自制命令如下
1. 返回晶片 的ID值
&GetID
12345
2. 設定比例調節器的值為 12
& 12 SetP
......
實現如下:
1. 建立棧,數值棧 和 字元棧
static int stack[STKSIZE]; static char cstack[CSTKSIZE]; static int sp; static int csp; /* name: push description:將資料num壓棧 author: Terry time: 2012/4/29 */ void push(int num) { if(sp == STKSIZE) { Debug("Stack Full!\n"); sp = 0; return; } stack[sp++] = num; } /* name: pop description:資料彈出,由函式返回值返回 author: Terry time: 2012/4/29 */ int pop(void) { if(sp == 0) { Debug("Stack empty!!!\n"); return 0; } return (stack[--sp]); } /* name: pushc description:字元c壓棧 author: Terry time: 2012/4/29 */ void pushc(char c) { if(csp == CSTKSIZE) { Debug("CStack Full!\n"); csp = 0; return; } cstack[csp++] = c; } /* name: popc description:字元彈出,由返回值返回 author: Terry time: 2012/4/29 */ char popc() { if(csp == 0) { Debug("CStack empty!!!\r\n"); return 0; } return (cstack[--csp]); } /*返回數值棧指標*/ int getsp() { return sp; } /*返回字元棧指標*/ int getcsp() { return csp; } /* name: popcstr description:彈出一個字串 x:字串長度, *p接受字串的地址 author: Terry time: 2012/4/29 */ int popcstr(int x , char *p) { int i; for(i = 0;i < x; i++) { p[i] = popc(); if(p[i] == 0 ) break; } p[i] = 0; return i; }
2. 命令直譯器
巧妙構建結構體,命令列表
typedef struct dtable { union { struct { unsigned char len; char words[7]; }bytes; char bits[8]; }id; void (*fun)(); }table; const table dictionary[] = { {5,'G','e','t','I','D',0,0,getid}, {5,'S','e','t','P',0,0,0,setup}, {7,'g','e','t','i','n','f','o',getinfo}, {6,'T','e','s','t','s','h',0,Testsh}, };
命令呼叫函式
void GetID(void)
{
uint32_t cpuid[3];
cpuid[0] = *(uint32_t *)(0x1ffff7e8); //STM32 全球統一的ID號
cpuid[1] = *(uint32_t *)(0x1ffff7ec);
cpuid[2] = *(uint32_t *)(0x1ffff7f0);
printf("%x %x %x \r\n",cpuid[0],cpuid[1],cpuid[2]);
}
/*其它三個函式略*/
命令直譯器主程式
/*初始化*/ void CLI_Init() { sp = 0; csp = 0; numdic = (int)(sizeof(dictionary)/sizeof(dictionary[0])); //計算命令個數 } /* name: trypush description:將非命令輸入嘗試壓棧,轉為資料或者字串 author: Terry time: 2012/4/29 */ int trypush(char *str) { int i; int val = 0; if(isalpha(str[0])) //如果首字元是字元 { for(i = strlen(str) -1; i >= 0; i--) pushc(str[i]); push((int)(strlen(str))); } else { for(i = 0; i< (int)strlen(str); i++) { if(isdigit(str[i])) //如果是數字 val = val * 10 +str[i] - '0'; else { printf("!!%s error???",str); return 1; } } push(val); } return 0; } /* name: decipher description:命令直譯器 author: Terry time: 2012/4/29 */ void decipher(void const * argument) { char *tok; int8_t err; struct dtable cmds; unsigned char match; unsigned char i; printf("welcome use the CLI\r\n"); printf("version 1.0\r\n"); CLI_Init(); while(1) { HAL_UART_Receive_DMA(&huart1,rx_buffer,STRLENTH); //DMA的方式接收資料,一旦有空閒中斷髮生,則結束資料接收 if(Rec_flg.recv_end_flag ==1) //recv_end_flag 串列埠資料成功接收 { memcpy(str,rx_buffer,Rec_flg.rx_len); Rec_flg.recv_end_flag = 0; Rec_flg.rx_len=0; printf("\r\n$"); tok = strtok((char *)str," "); if(tok) { do { cmds.id.bytes.len = (unsigned char)strlen(tok); for(i = 0; i < 7; i++) if(i < cmds.id.bytes.len) cmds.id.bytes.words[i] = (tok[i]); else cmds.id.bytes.words[i] = 0; match = 0; for(i = 0; i < numdic && !match; i++) { if(memcmp(dictionary[i].id.bits ,cmds.id.bits ,8) == 0) { match = 1; (*dictionary[i].fun)(); } } err = 0; if(!match) { if(trypush(tok)) err = 1; } tok = strtok(NULL," "); }while(tok && !err); //strtok 只能在一個任務中使用,涉及到全域性變數 } } osDelay(100); } } /*需要標頭檔案 #include "string.h" #include "stdio.h" #include "ctype.h" */
這個方法本人數次嘗試,功能非常簡單,比較實用,適合給系統留個小後門,方便現場修改和優化系統引數。當然還有其它方式,比如ModBus RTU等,這裡分享一下,不喜勿噴。