打印
[DemoCode下载]

单片机通用串口发送接收程序

[复制链接]
33|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
loutin|  楼主 | 2025-1-12 04:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
/**********************************************************************************
                  MS51单片机通用串口发送接收程序

数据包的帧格式为:第一字节为同步信号(SYNC)。
                  第二字节为地址(ADDRESS)。
      第三字节为命令(COMMAND)。
      第四字节为数据块的长度(DATA SIZE),值为后面要传输的数据的字节数(0~255),
                    如果该帧没有额外的数据,则应为0。
      第五字节到第DATA SIZE + 4 字节为传输的数据(DATA)。
      最后一字节为校验和(CHECKSUM),累加校验,值为前面所以数据的累加。
************************************************************************************/
#include <reg51.h>
#include <intrins.h>



//定义FSA状态常量
#define FSA_INIT      0     //初始状态
#define FSA_ADDRESS   1     //接收地址状态
#define FSA_COMMAND   2     //接收命令状态
#define FSA_DATASIZE  3     //接收数据的字节数状态
#define FSA_DATA      4     //接收数据状态
#define FSA_CHECKSUM  5     //接收校验状态



//定义信号分析常量
#define  SYNC      0x33     //同步信号的定义,可以根据自己的需求改成其它值
#define  YOUR_ADDR 0x43     //定义自己系统的地址,可以根据自己的需求改成其它值



//定义输入命令
  //根据自己的需求定义相关的命令
  //For example:
  #define CMD_RESET      0x01
  #define CMD_START     0x02
  #define CMD_DISPLAY   0x03
  #define CMD_CLEAR     0x04
  #define CMD_ACK       0xFF



#define  RECV_TIMEOUT  10 //定义超时时间



unsigned char
recv_state = FSA_INIT,   //当前状态
recv_timer = 0,          //时间计数
recv_chksum,             //保存当前输入的校验值
recv_ctr,                //接收数据缓冲区的索引
recv_buf[35];            //保存接收数据



unsigned char
trans_buf[7],           //输出数据缓冲区
trans_ctr,              //输出数据指针
trans_size,             //输出数据字节数
trans_chksum;           //输出数据的校验字节



//定义命令是否合法的查询表
unsigned char code valid_cmd[256] = { //如果输入命令有效则为1
    0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //00 - 0F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10 - 1F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20 - 2F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //30 - 3F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40 - 4F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //50 - 5F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //60 - 6F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //70 - 7F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //80 - 8F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //90 - 9F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //A0 - AF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //B0 - BF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //C0 - CF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //D0 - DF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //E0 - EF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //F0 - FF
};



/*****************************************************************************************
功能:serial_int
描述:运行串口 FSA。
参数:无
返回:无
*****************************************************************************************/
void serial_int(void) interrupt 4
{
    unsigned char data c;
if(_testbit_(TI) )   //输出中断
{
     trans_ctr++;     //输出缓冲区指针加1
  if(trans_ctr < trans_size) //数据是否输出完毕
  {
      if(trans_ctr == (trans_size - 1) ) //输出校验字节
   {
       SBUF = trans_chksum;
   }
   else
   {
       SBUF = trans_buf[trans_ctr];  //输出当前字节
    trans_chksum += trans_buf[trans_ctr];  //更新校验字节
   }
  }
}



if(_testbit_(RI) )   //接收中断
{
     c = SBUF;
  switch(recv_state)
  {
   case FSA_INIT:
       if(c == SYNC)  //同步字节
    {
        recv_state = FSA_ADDRESS; //下一个状态
     recv_timer = RECV_TIMEOUT;
     recv_chksum = SYNC;
    }
    break;

   case FSA_ADDRESS:
       if(c == YOUR_ADDR)  //本系统的地址
    {
        recv_state = FSA_COMMAND;
     recv_timer = RECV_TIMEOUT;
     recv_chksum += c;
    }
    else     //不是本系统的地址
    {
        recv_state = FSA_INIT; //返回系统初始状态
     recv_timer = 0;
    }
    break;


   case FSA_COMMAND:
       if(!valid_cmd[c])  //命令无效
    {
        recv_state = FSA_INIT;  //返回系统初始状态
     recv_timer = 0;
    }
    else
    {
        recv_state = FSA_DATASIZE;
     recv_chksum += c;
     recv_buf[0] = c; //保存命令
     recv_timer = RECV_TIMEOUT;
    }
    break;

   case FSA_DATASIZE:   //字节个数
       recv_chksum += c;
    recv_buf[1] = c;
    if(c)   //是否有数据
    {
        recv_ctr = 2;
     recv_state = FSA_DATA;
    }
    else
    {
        recv_state = FSA_CHECKSUM;
    }
    recv_timer = RECV_TIMEOUT;
    break;

   case FSA_DATA:   //读取数据
       recv_chksum += c;
    recv_buf[recv_ctr] = c; //保存数据
    recv_ctr++;
    if ((recv_ctr - 2) == recv_buf[1] )  //数据接收完毕
    {
        recv_state = FSA_CHECKSUM;
    }
    recv_timer = RECV_TIMEOUT;
    break;

   case FSA_CHECKSUM:
       if (recv_chksum == c)   //校验字节核对正确
    {
        c = 1;              //用c表面是否要建立应答信号
       //根据需要加入自己的命令处理程序
             //命令处理程序也可以在其它的函数实现,节省中断时间,具体做法是在此处置为一标志位
    //在其它程序判断标志位是否执行命令处理程序
    //For example:
    //cmd_valid = 1;
        switch (recv_buf[0])
     {                  
      case CMD_RESET:
                 break;
      case CMD_START:
           break;
      case CMD_DISPLAY:
           break;
      case CMD_CLEAR:
            break;
      case CMD_ACK:
           break;
      default:
           break;
     }
    if (c)      //建立应答,可以根据自己的需要更改应答程序
    {
        trans_buf[0] = SYNC;   //信息头
        trans_buf[1] = YOUR_ADDR;
     trans_buf[2] = CMD_ACK;
     trans_buf[3] = 1;
     trans_buf[4] = recv_buf[1]; //被回应的命令
     trans_ctr = 0;              //设置缓冲区指针到第一个字节
     trans_size = 6;             //总共发送6个字节
     SBUF = SYNC;                //发送起始字节
     trans_chksum = SYNC;        //初始化校验值
    }
    }
   default:      //复位FSA
       recv_timer = 0;
    recv_state = FSA_INIT;
    break;
  }
}
}


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

61

主题

1381

帖子

0

粉丝