系列文章目录-串口通讯
/C51串口通讯调试目录:/
第5章:#C51串口通讯5-#一串数据#中断定时+超时接收+接收应答+CRC校验
第4章:#C51串口通讯4-#一串数据#中断即时解析用户自定义协议(握手接收应答)
第3章:#C51串口通讯3-#一串数据#中断即时解析用户自定义协议
第2章:#C51串口通讯2-#一串数据#定时中断实现超时接收(推荐)
第1章:#C51串口通讯1-#一串数据#接收与发送(基础概念)
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
1.上一章(中断定时+超时接收)的逻辑,适用于协议较为复杂的情况,即中断判断接收结束,数据放置缓冲区,主函数中解析数据。
2.实际开发中,用户自定义协议的帧头是可预见的,包括数据长度等。
3.本章测试使用中断即时解析自定义协议
提示:以下是本篇文章正文内容,下面案例可供参考
一、场景
示例一串数据:固定帧头区(AA 66 AA )+数据类型(01/02)+数据区+和校验+异或校验
其中,01LED,02蜂鸣器 ,数据区为工作时间,低位在前高位在后
二、编程实现
1.知识点
a.“状态机”的算法思想
状态机是有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型。
包括:State(状态)、Event(事件)、Action(动作)、Transition(转换)
链接:什么是状态机
b.用户自定义协议一般格式:
帧头 | 地址 | 数据类型 | 数据长度 | 数据区 | 校验 | 帧尾 |
---|---|---|---|---|---|---|
大多数无 |
eg:
数据类型包括外部负载,如led、继电器、蜂鸣器
2.代码设计
1.串口中断服务函数中判断数据有效性,仅保存数据区到缓冲区recv_buf[]
2.校验ok后清相关变量,置数据有效接收标志1
void uart_ISR() interrupt 4
{
if(RI)
{
RI = 0;
recv_data = SBUF;
switch(machine_step)
{
case 0:
if(0xAA == recv_data) //1.帧头符合,状态+1,下一次中断进入后继续检测,否则丢弃
{
machine_step = 1;
}
else
{
machine_step = 0;
}
break;
case 1:
if(0x66 == recv_data)
{
machine_step = 2;
}
else
{
machine_step = 0;
}
break;
case 2:
if(0xAA == recv_data)
{
machine_step = 3;
recv_Cnt = 0; //2.即将进入数据区,计数启动
}
else
{
machine_step = 0;
}
break;
case 3: //3.校验计算
sum_check += recv_data;
xor_check ^= recv_data;
recv_buf[recv_Cnt] = recv_data; //4.数据区存储到缓冲区
recv_Cnt++;
if(recv_Cnt >2)
{
machine_step = 4;
}
break;
case 4:
if(sum_check == recv_data) //5.校验判断 //recv_data已经是新的一个字节,
{
machine_step = 5;
}
else
{
machine_step = 0; //累加和错误,下次重新开始判断
sum_check = 0; //校验清0,否则下一串数据在状态3时出错
xor_check = 0;
}
break;
case 5:
if(xor_check == recv_data)
{
recv_flag = 1; //6.数据正确,标志置1
}
else
{
machine_step = 0; //异或校验错误,下次重新开始判断
}
sum_check = 0; //校验清0,否则下一串数据在状态3时出错
xor_check = 0;
machine_step = 0; //++的数都要记得在某个地方清0
recv_Cnt = 0; //不清也ok,养成习惯清除
break;
default:break;
}
}
}
3.主函数中执行数据解析:
数据类型01时LED工作,02时蜂鸣器工作,recv_buf[1]时间低位,recv_buf[2]数据高位,整合成unsigned int
void Convert(unsigned char *vbuf)
{
UC i;
if(recv_flag)
{
recv_flag = 0;
// timer_start = 0; //关掉定时器,防止T0一直在执行
for (i = 0; i < cRealLen; i++)
{
uart_Recv[i] = vbuf[i];
}
sendString(vbuf); //test
Exchange_Func();
clr_recvbuffer(vbuf);
}
}
void Exchange_Func(void)
{
// UC cSchIndex; //帧头不是指定特征帧头时,移位查找
// UC cErr_Info[] = {'e','r','r','o','r','\n'};
// UC fvalid; //有效数据标志
switch(recv_buf[0])
{
case 1:
recv_Led_time = recv_buf[2];
recv_Led_time <<= 8;
recv_Led_time += recv_buf[1];
break;
case 2:
recv_Beep_time = recv_buf[2];
recv_Beep_time <<= 8;
recv_Beep_time += recv_buf[1];
break;
default:break;
}
4.T0定时器中断服务函数中将计数–处理,计时
void Timer0_ISR() interrupt 1
{
TR0 = 0; //进T0中断首先关闭定时器
if(recv_Led_time)
{
recv_Led_time--;
fLedShine = 1;
}
else
{
fLedShine = 0;
}
if(recv_Beep_time)
{
recv_Beep_time--;
set_buzz(BUZZ_TYPE1);
}
else
{
BUZZER = 1;
}
主函数数据解析开放性实现功能
总结
1.本章仅简单测试设计框架:“中断即时解析用户自定义数据”,较上一章而言,优点在于简易的协议情况下,处理速度更快。
2.引用“状态机”的编程思想
3.根据实际情况选择合适的代码方案。
上一章:#C51串口通讯2-#一串数据#定时中断实现超时接收(推荐)
下一章:#C51串口通讯4-#一串数据#中断即时解析用户自定义协议(握手接收应答,非固定长度)