本帖最后由 oldbeginner 于 2014-6-20 15:24 编辑
*******************
串口 的暗号
*******************
在串口 和 上位机 的通讯中, 经常要用 到 “暗号”,这样上位机 和 单片机 才能互相 确认 对方。
这里主要理解 单片机 是如何 通过 接收到 的字符串 判断出 “自己人”。
主要内容参考
http://blog.csdn.net/gszhy/article/details/8594433
这篇文章的下半部分。
这就要求我们的单片机能够在连续接收到的串口数据序列中识别出符合自己板卡对应的通信协议,来进行控制操作,不符合则不进行任何操作。
简而言之就是,单片机要在一串数据中找到符合一定规律的几个字节的数据。
要实现上述 功能,
先 上一个 带 bug 的代码
然后串口中断部分
void ser()interrupt 4
{
static unsigned char count; //串口接收计数的变量
RI=0;//手动清某个寄存器,大家都懂的
receive[count]=SBUF;
if(count==0&&receive[count]==0xaa)//同时判断count跟收到的数据
{
count=1;
}
else if(count==1&&receive[count]==0x55)
{
count=2;
}
else if(count==2)
{
count++;
}
else if(count==3&&receive[count]== receive [2])//判断校验和,数据多的话是求//和,或者其他的校验方法,也可能是固定的帧尾
{
count=0;
uart_flag =1;//串口接收成功标志,为1时在主程序中回复,然后清零
ES=0; //关中断,回复完了再ES=1;
}
else
{
count=0;//判断不满足条件就将计数值清零
}
}
在 串口 中断 中,判断 接收 字符串 是否 有 “暗号”。
如果 确认 含有 “暗号”,则 讲 uart_flag 置 1,标示 收到信息。
上面的代码有 两个 bug:
1、如果数据帧发送一半,然后突然停止,再来重新发,就会丢失一帧的数据。比如先接受到aa 55,然后断了,再进来aa 55 01 01,就不受控制了。
2、如果在多设备通信中,属于其他设备的的帧数据最后一位是aa(或者最后两位为aa 55 ,或者最后3位为aa 55 板选),下一次通信的数据就接收不到了。
解决方案:
考虑到每次数据都是连续发送的(至少我们用labwindows做的上位机程序是这样的),成功接收到了一帧数据是要有一定时间回复的,也就是说如果接收到一半,但是很长时间没接收到数据,把计数值count清零就ok啦。
全局变量定义
unsigned char boardAddr;//板选地址,通过检测几个io引脚,具体怎么得到的就不写了,很简单的
unsigned char g_DatRev [10]={0};//接收缓存
bit retFlag=0;//为1代表串口接收到了一帧数据
串口初始化函数,晶振22.1184
void init_uart()
{
SCON = 0x50; //串口方式1允许接收
TMOD = 0x21; //定时器1,方式2,8位自动重载,同时配置定时器0,工作方式1
PCON = 0x80; // 波特率加倍
TH1 = 0xfa;
TL1 = 0xfa; //写入串口定时器初值
TH0=(65536-2000)/256; //写入定时器0初值,串口传输一个字节时间为(1/19200)*10,计算得0.52ms
TL0=(65536-2000)%256; //定时器0定时大约1ms多
EA=1;
ET0=1; //波特率:19200 22.1184M 初值:250(0xfa)
IE |= 0x90;
TR1 = 1;
}
串口中断函数
void UART_INT(void) interrupt 4
{
static unsigned char count;//串口接收计数的变量
RI = 0;
g_DatRev[count] = SBUF;
if(g_DatRev[count]==0xaa&&count==0) //帧头
{
count=1;
}
else if(count==1&&g_DatRev[count]==0x55)
{
count=2;
}
else if (count==2&&g_DatRev[2] == boardAddr)
{
CK = g_DatRev[count];
count=3;
}
else if(count>=3&&count<9)
{
CK += g_DatRev[count];
count ++;
}
else if(count == 9&&CK==g_DatRev[9])
{
ES = 0;
retFlag = 1;
count=0;
}
else
{
count=0;
}
resettimer();
}
//判断count不为0的话就启动定时器
void resettimer()
{
TR0=0;
TH0=(65536-2000)/256;
TL0=(65536-2000)%256;
if(count!=0)
{
TR0=1;
}
}
定时器中断函数
void T0_time()interrupt 1
{
TR0=0;
TH0=(65536-2000)/256;
TL0=(65536-2000)%256;
count=0;
}
感觉代码还是 有些问题的。
问题在于:只要一接收,count 不为0,一定会打开 定时器0,1ms 后,count 变为0,好像非常容易出错。
不过思路 非常值得借鉴,就是利用定时器,来判断 接收字节 之间 的时间 是否 过长,如果时间过长,表示传送结束。
本帖最后由 oldbeginner 于 2014-6-20 15:24 编辑
*******************
串口 的暗号
*******************
在串口 和 上位机 的通讯中, 经常要用 到 “暗号”,这样上位机 和 单片机 才能互相 确认 对方。
这里主要理解 单片机 是如何 通过 接收到 的字符串 判断出 “自己人”。
主要内容参考
http://blog.csdn.net/gszhy/article/details/8594433
这篇文章的下半部分。
这就要求我们的单片机能够在连续接收到的串口数据序列中识别出符合自己板卡对应的通信协议,来进行控制操作,不符合则不进行任何操作。
简而言之就是,单片机要在一串数据中找到符合一定规律的几个字节的数据。
要实现上述 功能,
先 上一个 带 bug 的代码
然后串口中断部分
void ser()interrupt 4
{
static unsigned char count; //串口接收计数的变量
RI=0;//手动清某个寄存器,大家都懂的
receive[count]=SBUF;
if(count==0&&receive[count]==0xaa)//同时判断count跟收到的数据
{
count=1;
}
else if(count==1&&receive[count]==0x55)
{
count=2;
}
else if(count==2)
{
count++;
}
else if(count==3&&receive[count]== receive [2])//判断校验和,数据多的话是求//和,或者其他的校验方法,也可能是固定的帧尾
{
count=0;
uart_flag =1;//串口接收成功标志,为1时在主程序中回复,然后清零
ES=0; //关中断,回复完了再ES=1;
}
else
{
count=0;//判断不满足条件就将计数值清零
}
}
在 串口 中断 中,判断 接收 字符串 是否 有 “暗号”。
如果 确认 含有 “暗号”,则 讲 uart_flag 置 1,标示 收到信息。
上面的代码有 两个 bug:
1、如果数据帧发送一半,然后突然停止,再来重新发,就会丢失一帧的数据。比如先接受到aa 55,然后断了,再进来aa 55 01 01,就不受控制了。
2、如果在多设备通信中,属于其他设备的的帧数据最后一位是aa(或者最后两位为aa 55 ,或者最后3位为aa 55 板选),下一次通信的数据就接收不到了。
解决方案:
考虑到每次数据都是连续发送的(至少我们用labwindows做的上位机程序是这样的),成功接收到了一帧数据是要有一定时间回复的,也就是说如果接收到一半,但是很长时间没接收到数据,把计数值count清零就ok啦。
全局变量定义
unsigned char boardAddr;//板选地址,通过检测几个io引脚,具体怎么得到的就不写了,很简单的
unsigned char g_DatRev [10]={0};//接收缓存
bit retFlag=0;//为1代表串口接收到了一帧数据
串口初始化函数,晶振22.1184
void init_uart()
{
SCON = 0x50; //串口方式1允许接收
TMOD = 0x21; //定时器1,方式2,8位自动重载,同时配置定时器0,工作方式1
PCON = 0x80; // 波特率加倍
TH1 = 0xfa;
TL1 = 0xfa; //写入串口定时器初值
TH0=(65536-2000)/256; //写入定时器0初值,串口传输一个字节时间为(1/19200)*10,计算得0.52ms
TL0=(65536-2000)%256; //定时器0定时大约1ms多
EA=1;
ET0=1; //波特率:19200 22.1184M 初值:250(0xfa)
IE |= 0x90;
TR1 = 1;
}
串口中断函数
void UART_INT(void) interrupt 4
{
static unsigned char count;//串口接收计数的变量
RI = 0;
g_DatRev[count] = SBUF;
if(g_DatRev[count]==0xaa&&count==0) //帧头
{
count=1;
}
else if(count==1&&g_DatRev[count]==0x55)
{
count=2;
}
else if (count==2&&g_DatRev[2] == boardAddr)
{
CK = g_DatRev[count];
count=3;
}
else if(count>=3&&count<9)
{
CK += g_DatRev[count];
count ++;
}
else if(count == 9&&CK==g_DatRev[9])
{
ES = 0;
retFlag = 1;
count=0;
}
else
{
count=0;
}
resettimer();
}
//判断count不为0的话就启动定时器
void resettimer()
{
TR0=0;
TH0=(65536-2000)/256;
TL0=(65536-2000)%256;
if(count!=0)
{
TR0=1;
}
}
定时器中断函数
void T0_time()interrupt 1
{
TR0=0;
TH0=(65536-2000)/256;
TL0=(65536-2000)%256;
count=0;
}
感觉代码还是 有些问题的。
问题在于:只要一接收,count 不为0,一定会打开 定时器0,1ms 后,count 变为0,好像非常容易出错。
不过思路 非常值得借鉴,就是利用定时器,来判断 接收字节 之间 的时间 是否 过长,如果时间过长,表示传送结束。
举报