单片机只能使用按键与程序进行交互吗?有时候限于单片机有限的引脚,没有多余的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_CntTTYsig = 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。
