标准框架:
这是一个上行AD和接收下行命令的标准框架,可以通过修改来适应于其他各种系统:
参数变量定义:
u16 sec=0; //定时计数
char buf[160]; //合成字符串缓存,用于一般的字符串处理
char recv[128];//用于串口的接收缓存
u8 rjs=0; //recv buf的计数指针,用于记录当前的接收数据存储位置
u8 iscmd; //==1 表示出于cmd记录中,状态 内部使用
u8 iscmdok; //==1 表示有命令处理,状态 消息循环中检测,当=1时,需处理cmd内部的命令
char cmd[128]; //需要处理的命令
u8 cjs; //cjs:cmd命令计数
char *cmds; //命令解释执行的指针
main函数
int main(void)
{
u16 a,b;
system_init(); //系统初始化
USART_ENABLE_CMD(); //打开串口命令处理
while(1) //主消息循环
{
//---处理上行(上传采集数据)
if (sec>1){ //定时器中断控制sec变量
CompADC(); //计算采集AD的平均值 [2]ADI [1]ADV [0]24V
sprintf(buf,"app.da(\"%d|%d|%d\");\r\n",After_filter[2],After_filter[1],After_filter[0]);
send(buf);
sec=0;
}
//--处理下行命令
if (iscmdok==1){ //串口接收中断控制iscmdok变量,当此变量=1的时候表示已经完整的传输过来一个cmd命令,该命令在cmd字符串中,参见串口中断程序
cmds=cmd; //执行cmd的开始
while(*cmds!=0){
//-----------------------------开始进入命令处理--------------------------------------
if ((*cmds=='D')&(*(cmds+1)=='A')&(*(cmds+2)=='V')){
...... //DAV命令的处理代码
}
//----------------
else if ((*cmds=='D')&(*(cmds+1)=='A')&(*(cmds+2)=='I')){
...... //DAI命令的处理代码
}
.....//其他的命令处理代码
//-----------------------------命令处理结束--------------------------------------
if (*cmds=='|'){ //有下一条命令需要继续解析
cmds++;
}
else{ //命令有错误或者解析完成,退出while循环
#ifdef DEBUG
if (*cmds!=0){
sprintf(buf,"err cmd:%s ",cmd);send(buf);
}
#endif
*cmds=0;
}
}
//----命令处理完成--------
iscmdok=0; //设置完成标志,以进入下一轮命令处理
}
}
}
这是一个主消息结构,可以看到,在一开始进入main函数后,系统执行了system_init(); 在该函数中,系统设置了GPIO、AD、DAC、串口、定时器等单片机的硬件环境,这个我们就详细讲解了,请参见代码
然后系统进入了while(1)组成的消息循环,消息循环分成两个部分,一个处理上行,一个处理下行
上行处理
void TIM14_IRQHandler(void) //界面刷新
{ //一秒1次
if(TIM_GetITStatus(TIM14 , TIM_IT_Update) == SET)
{ sec++;
TIM_ClearITPendingBit(TIM14, TIM_FLAG_Update); //清中断
}
}
首先,我们可以看到定时器中断,也就是sec变量会被定时器中断一秒一次的加一,当被加一后,消息中断中就立即执行串口发送命令完成上行处理
下行处理
void USART1_IRQHandler(void)
{ u8 v;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //是否接受有数据
{
v=USART_ReceiveData(USART1); //从PC接受
//在此书写接收中断处理代码
if (v=='[')
{ rjs=0;
iscmd=1;
}
else if(v==']') //命令接收完毕,存入cmd缓存,设置iscmdok标志,开始执行命令
{ recv[rjs++]=0;
iscmd=0;
for (v=0;v<rjs;v++) cmd[v]=recv[v];
iscmdok=1;
}
else if (iscmd==1)
{ recv[rjs]=v;
rjs++;
if (rjs==sizeof(recv))
{ iscmd=0;
rjs=0;
}
}
}
if(USART_GetITStatus(USART1, USART_IT_TC) != RESET) //是否有发送数据
{
USART_ClearITPendingBit(USART1, USART_IT_TC); //???
}
}
在串口中断程序中,如果串口收到屏幕发来的数据,就会运行该中断函数,并且获取值,通过各种全局变量的状态机机制,我们识别出中括号内还是外,如果在中括号内,则将数据累加到recv数组中,如果遇见了右中括号表示命令接收完毕,此时iscmd=1,并且接受的数据复制到cmd数组中;
在主消息循环中,一直在判断iscmd变量的值,一旦等于1表示有新的命令进来,于是开始执行命令,可以看到执行命令的是一个循环结构,用户可以在此框架中自行扩充或修改命令
一般来说,我们把命令分成两种,传递数值的和传递字符串的,我们写好了相应的处理函数
传递数值的命令
if ((*cmds=='D')&(*(cmds+1)=='A')&(*(cmds+2)=='V')){
//DAV:1234 命令处理,设置电压
cmds+=4; //+=4表示命令有3个字符,此时cmds指向冒号后的第一个字符
a=getnum();//获取:之后的数值到a
DAC_updataV(a); //使用a执行命令动作
#ifdef DEBUG //调试,输出a
sprintf(buf,"ok DAV:%d ",a);send(buf);
#endif
}
传递字符串的命令
if ((*cmds=='D')&(*(cmds+1)=='M')&(*(cmds+2)=='O')){
//DMO demo命令,本命令无用,纯粹演示一下如何获取字符串
cmds+=4;//+=4表示命令有3个字符,此时cmds指向冒号后的第一个字符
getstr();//获取字符串,获取后存在buf中
#ifdef DEBUG
send("ok DMO:");send(buf);
#endif
}