玩轉單片機之智能車小露——通過UART為單片機增加TTY終端
單片機只能使用按鍵與程序進行交互嗎?有時候限于單片機有限的引腳,沒有多余的IO口設計按鍵以實現不同的功能,這時候怎么辦?
最簡單的是使用UART與PC進行通信,這樣PC上的鍵盤就可以變成控制單片機最靈活的工具。本文實現稍復雜但是炫酷的UART通信交互功能,類似于電腦Shell程序,通過字符串傳遞命令和參數,比如可以這樣(默認實現測試命令):
串口發送:echo hello,world!
串口接收:hello,world!
串口初始化及命令字符串接收
直接使用單片機ISP串口,波特率設置稍高一些避免通信時間過長。
SystickCallbackUART1函數負責檢測通信數據流是否結束,并打上結束標記。
void TTYInit(void){
GPIO_InitTypeDef gpio;
COMx_InitDefine com1;
gpio.Pin = GPIO_Pin_0|GPIO_Pin_1;
gpio.Mode = GPIO_PullUp;
GPIO_Inilize(GPIO_P3,&gpio);
com1.UART_Mode = UART_8bit_BRTx;
com1.UART_BRT_Use = BRT_Timer1;
com1.UART_BaudRate = 115200ul;
com1.UART_RxEnable = ENABLE;
com1.BaudRateDouble = DISABLE;
UART_Configuration(UART1,&com1);
NVIC_UART1_Init(ENABLE,Priority_1);
UART1_SW(UART1_SW_P30_P31);
}
//UART1 systick callback(10ms)
void SystickCallbackUART1(void){
if(--COM1.RX_TimeOut < 1){
RX1_Buffer[COM1.RX_Cnt] = '\0';
COM1.RX_Cnt = 0; //UART1 timeout reset RX_Cnt
TTYsig = TRUE;
}
}
串口命令行參數分割與解析
串口命令行默認格式為:cmd arg0 arg1 arg2 arg3 arg4各參數以空格區分,支持1個命令加最多5個參數,TTYArgPhase函數負責分割這些字符串命令和參數。
unsigned char *pTTYCmd;
unsigned char *pTTYArg[5];
//tty 命令行解析與參數分割
unsigned char TTYArgPhase(void){
unsigned char i = 0;
char *str = RX1_Buffer;
if(*str == ' ' || *str == '\0')
return FALSE;
pTTYCmd = str;
while(*str != '\0' || i > 4){
str++;
if(*str == ' '){
*str = '\0';
pTTYArg[i++] = ++str;
}
}
return TRUE;
}
命令解析并轉換為函數調用
在定時器(500ms)中判斷是否有新的命令,并解析命令轉調真正的功能函數,根據具體函數傳遞正確的參數類型。
unsigned char TTYsig,TTYInfork;
void TTYFork(void){
TTYsig = FALSE;
if(TTYArgPhase() == FALSE)
return;
if(strcmp(pTTYCmd,"echos") == 0 && pTTYArg[0] != NULL)
TTYEchoString(pTTYArg[0]);
if(strcmp(pTTYCmd,"echon") == 0 && pTTYArg[0] != NULL)
TTYEchoNumber(atoi(pTTYArg[0]));
if(strcmp(pTTYCmd,"echot") == 0)
TTYEchoTime();
// TODO: 在此處添加用戶代碼
if(strcmp(pTTYCmd,"exit") == 0){
TTYechot = FALSE;
}
*pTTYCmd = NULL; //目前由輸入者確保參數正確性
*pTTYArg[0] = NULL;
*pTTYArg[1] = NULL;
*pTTYArg[2] = NULL;
*pTTYArg[3] = NULL;
*pTTYArg[4] = NULL;
}
//Systick callback 500s
void SystickCallbackTTY(void){
if(TTYsig == TRUE)
TTYFork();
}
可命令行執行函數的設計
命令行可執行函數可以設計為兩類,一類是單次執行的,執行完成后即可退出,如echos和echon;
另一類需要持續運行,直到命令行收到退出命令exit后退出,如echot,真正的動作仍然需要在特定的定時函數里執行。
unsigned char TTYechot;
//tty 字符回顯函數
void TTYEchoString(char *str){
printf(str);
}
//tty 數字回顯函數
void TTYEchoNumber(int num){
printf("%hd",num);
}
//tty 循環顯示開機運行時間
void TTYEchoTime(void){
TTYechot = TRUE; //接收"exit"后復位
}
//Systick callback 1s
void SystickCallbackTTYEchot(void){
if(TTYechot == TRUE)
printf("Running time(s):%ld",systick);
}
實戰例程:七彩呼吸燈控制
以 玩轉單片機之智能車小露——七彩LED呼吸燈 為例,編寫命令行控制函數還不是手到擒來?
//顏色字符串轉換為整形
unsigned char ctoi(char *str){
if(strcmp(str,"red") == 0)
return BLED_COLOR_RED;
if(strcmp(str,"orange") == 0)
return BLED_COLOR_ORANGE;
if(strcmp(str,"yellow") == 0)
return BLED_COLOR_YELLOW;
if(strcmp(str,"green") == 0)
return BLED_COLOR_GREEN;
if(strcmp(str,"cyan") == 0)
return BLED_COLOR_CYAN;
if(strcmp(str,"blue") == 0)
return BLED_COLOR_BLUE;
if(strcmp(str,"purple") == 0)
return BLED_COLOR_PURPLE;
if(strcmp(str,"white") == 0)
return BLED_COLOR_WHITE;
return BLED_COLOR_OFF;
}
//模式字符串轉換為整形
unsigned char mtoi(char *str){
if(strcmp(str,"single") == 0)
return BLED_MODE_SINGLE;
if(strcmp(str,"color") == 0)
return BLED_MODE_COLOR;
return BLED_MODE_OFF;
}
void TTYFork(void){
。。。
if(strcmp(pTTYCmd,"bledon") == 0 && pTTYArg[0] != NULL)
BLEDTurnOn(ctoi(pTTYArg[0]));
if(strcmp(pTTYCmd,"bleddisplaycolor") == 0 && pTTYArg[0] != NULL && pTTYArg[1] != NULL && pTTYArg[2] != NULL)
BLEDDisplayColor((unsigned char)atoi(pTTYArg[0]),(unsigned char)atoi(pTTYArg[1]),(unsigned char)atoi(pTTYArg[2]));
if(strcmp(pTTYCmd,"bledbreath") == 0 && pTTYArg[0] != NULL && pTTYArg[1] != NULL)
BLEDBreath(mtoi(pTTYArg[0]),ctoi(pTTYArg[1]));
if(strcmp(pTTYCmd,"bledoff") == 0)
BLEDTurnOff();
。。。
}
- 本文采用的單片機為STC32G系列,感興趣的朋友可以參考測試,或去Gitee上下載例程。
- 下載地址:https://gitee.com/loganxiang/lgxsmartcar ,參考tty.h/tty.c。

浙公網安備 33010602011771號