/**********************************************************************************
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;
}
}
}
|
|