这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » 通讯状态机

共1条 1/1 1 跳转至

通讯状态机

助工
2008-07-15 09:29:37     打赏

在最近做的一个LED显示的项目中,所有的控制,数据和测试命令全部是由上位机用通讯方式下发的.由于之前对通讯问题没有很好重视,所以在这个项目中,认真的解决了这个问题.通讯报文的处理方式很多.状态机的方式有他的优点.一个是很迅速,一个是占用的内存很少,效率很高.在这里给出个例子.希望对大家有一点参考价值.

首先,设置通讯中断

void Timer2() interrupt 5 using 2        
{ TF2=0;        // 清定时器2溢出标志
   
 LedScan();   //LED扫描中断服务程序
    if (RI)       // 判有无通信
   ReadSbuf(); //接收处理
      
}

/*通讯初始化*/

void serial_init (void);//用户自编

/*以报文格式如下为例*/

#define  RECID1   0   // 包头状态1
#define  RECID2   1   // 包头状态2
#define  RECADDR  2   // 地址
#define  RECCMD  3   // 命令
#define  RECBH  4   // 编号
#define  RECLEN   5   // 长度
#define  RECBUF   6   //  数据
#define  RECEND   7   //  结束符
#define  RECSUM   8   //  校验

/******************************************
 ReadSbuf()  分析一帧条通信数据
******************************************/

void ReadSbuf(void)

com_rt=0;                                     //485通讯方式,控制硬件处于接收状态
 RI = 0;   
 switch(rState)
 {  case RECID1: if(SBUF==2)    // 启始字符1,一字节      
       rState = RECID2;      
     break;
    case RECID2: if(SBUF==2)    // 启始字符2,一字节      
       rState="RECADDR";
     else
       rState="RECID1";      
     break;
    case RECADDR:rState = RECCMD;  // 地址,一字节(暂没用)       
     len=SBUF;      
     break;
    case RECCMD: if (SBUF==0x35) 
     { APLD="0xeb";break; } // 给出再线编程标志 
     else
       rState = RECBH;  // 命令,一字节(暂没用)      
     dsp[rn].cn= 0;            
     break;
    case RECBH: dsp[rn].kn=SBUF-0x30; // 编号,一字节            
     rState = RECLEN;
     rk=0;len=0;
     break;
    case RECLEN: len <<=4;    // 长度,四字节      
     len+=SBUF-0x30;      
     if(++rk>=4)
     { rk="0";len -= 7;
       rState = RECBUF;
     } break;
    case RECBUF: dsp[rn].p[rk]=SBUF;  // 接收字符 len-7个       
     if(++rk>=len)
       rState = RECEND;                  
     break;
    case RECEND: if(SBUF==3)    // 结束符
     { rState="RECSUM";
       dsp[rn].p[rk]=0;rk=0; 
       sm |=com_tab[rn];  // 置对应显示位
       if(++rn>7) rn="0";  
     }
     else
        rState="RECID1";
     break;
    case RECSUM: len=SBUF;    // 读掉2字节校验和
     if(++rk>=2)             
       rState="RECID1";
     break;
    default:  len=SBUF;
     rState=RECID1;       
 }   
/*从上面的例子可以看出,每个中断接收一个字节后,都要判断该字节是否正确,如果正确,通过给rState赋值,使状态机向后跳转.也就是每次进入CASE语句时,只执行一种情况.如果报文中途出错,则回到原始状态*/




关键词: 通讯     状态机     rState     break    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]