前言
提示:
1.上一章测试一种方法:简单协议下利用串口中断实时接收数据并校验后进行解析。
2.实际项目开发时,主机下发命令后,从机首先进行握手确认,数据错误情况下要进行相应回应(如错误指令)。
3.本章继续丰富开发,增加主从应答机制
提示:以下是本篇文章正文内容,下面案例可供参考
一、场景
示例:
主机下发命令,从机中断解析并应答,主函数处理事件
二、编程实现
1.自定义协议
如:
##主机类型定义命令类型(查询,设置,器件控制等等)
以控制数码管显示0x01为例
##从机握手应答:
a.数据正确回复:BB66BB8000[SUM_CHECK][XOR_CHECK]
b.和校验错误回复:BB66BB8100[SUM_CHECK][XOR_CHECK]
c.异或校验错误回复:BB66BB8200[SUM_CHECK][XOR_CHECK]
数据区数值显示在数码管上,仅作最大2组显示为例
2.代码设计
第一步:基于已调试过的工程,确认一串数据正确被接收并返回
第二步:配置UART中断服务函数:
1.判断帧头2.数据长度确认3.数据缓存4.校验判断5.应答:正确或错误提示
void uart_ISR() interrupt 4
{
UC i;
if(RI)
{
RI = 0;
//超时接收处理方案
// timer_start = 1;
// recv_buf[recv_Cnt] = SBUF;
// recv_Cnt++;
// ctimer_Cnt = 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:
sum_check = recv_data;
xor_check = recv_data;
recv_buf[recv_Cnt] = recv_data; //3.数据类型,存第一个数
machine_step = 4;
break;
case 4:
data_length = recv_data; // 数据长度
sum_check += recv_data;
xor_check ^= recv_data;
recv_Cnt++;
recv_buf[recv_Cnt] = recv_data;
machine_step = 5;
break;
case 5:
sum_check += recv_data;
xor_check ^= recv_data;
recv_Cnt++;
recv_buf[recv_Cnt] = recv_data;
if(data_length < recv_Cnt) //不满足时,依旧是状态5
{
machine_step = 6;
}
break;
case 6:
if(sum_check == recv_data) //5.校验判断 //recv_data已经是新的一个字节,
{
machine_step = 7;
}
else
{
machine_step = 0; //累加和错误,下次重新开始判断
sum_check = 0; //校验清0,否则下一串数据在状态3时出错
xor_check = 0;
//7.接收应答:和校验错误提示
for(i = 0; i<7; i++)
{
sendByte(sum_check_error[i]);
}
}
break;
case 7:
if(xor_check == recv_data)
{
recv_flag = 1; //6.数据正确,标志置1
cRealLen = recv_Cnt + 1; //缓冲区长度(数据类型+数据长度+数据区)
//7.接收应答:接收正确
for(i = 0; i<7; i++)
{
sendByte(recv_correct[i]);
}
}
else
{
machine_step = 0; //异或校验错误,下次重新开始判断
//8.接收应答:异或校验错误提示
for(i = 0; i<7; i++)
{
sendByte(xor_check_error[i]);
}
}
sum_check = 0; //校验清0,否则下一串数据在状态3时出错
xor_check = 0;
machine_step = 0; //++的数都要记得在某个地方清0
recv_Cnt = 0; //不清也ok,养成习惯清除
break;
default:break;
}
}
}
其中,便于演示,应答提示提前分配ROM常量:
unsigned char code recv_correct[] = {0xBB,0x66,0xBB,0x80,0x00,0x80,0x80};
unsigned char code sum_check_error[] = {0xBB,0x66,0xBB,0x81,0x00,0x81,0x81};
unsigned char code xor_check_error[] = {0xBB,0x66,0xBB,0x82,0x00,0x82,0x82};
第3步:主函数处理:
缓冲区数据:数据类型+数据长度+数据区
功能:数据区数值显示在数码管上,16进制
if(recv_flag)
{
recv_flag = 0;
// timer_start = 0; //关掉定时器,防止T0一直在执行
for (i = 0; i < cRealLen; i++)
{
uart_Recv[i] = vbuf[i];
}
// sendString(vbuf); //test
sendString(uart_Recv);
Exchange_Func();
clr_recvbuffer(vbuf);
}
void Exchange_Func(void)
{
if(0x01 == uart_Recv[0]) //仅作演示,数据类型01控制数码管显示
{
switch(uart_Recv[1]) //数据长度代表显示的位数
{
case 1:
SEG_DisBuf[0] = 23;
SEG_DisBuf[1] = 23;
SEG_DisBuf[2] = uart_Recv[2] >> 4;
SEG_DisBuf[3] = uart_Recv[2] & 0x0F;
break;
case 2:
SEG_DisBuf[0] = uart_Recv[2] >> 4;
SEG_DisBuf[1] = uart_Recv[2] & 0x0F;
SEG_DisBuf[2] = uart_Recv[3] >> 4;
SEG_DisBuf[3] = uart_Recv[3] & 0x0F;
break;
case 3:
break;
default:break;
}
}
3.测试验证
实测ok
总结
1.限制于无仿真器,故在UART中断服务函数中调试时,插入几处sendByte(),方便观察进行到哪一步。发现数据紊乱,原因在于一帧数据溢出进入服务函数时,调用的sendByte()又进入一次函数,数据被覆盖。
2.样例为方便演示。实际情况下,接收应答的处理可以设置标志位,在主函数中处理,中断服务函数中工作尽量少。
3.样例较上一章优点在于:不局限数据长度、接收应答机制
上一篇:#C51串口通讯5-#一串数据#中断定时+超时接收+接收应答+CRC校验
下一篇:#C51串口通讯3-#一串数据#中断即时解析用户自定义协议
推荐阅读最新更新时间:2024-11-03 12:35
设计资源 培训 开发板 精华推荐
- 【涂鸦智能】智能的温湿度计
- 使用 Microchip Technology 的 TCL1117-5.00 的参考设计
- DCP3001
- LT6656BIDC-4.096、4.096V 扩展电源范围电压基准的典型应用
- ATEtheRNET1-XPRO、Ethernet1 Xplained Pro 是 Atmel Xplained Pro 评估平台的扩展板
- LT1071 多输出反激式转换器设计说明
- 超低噪声正弦波驱动转换器(5V 至 15V)
- AM2DM-1215DH60-NZ ±15 Vout、2W 双路输出 DC-DC 转换器的典型应用
- LT1952EGN-1、LTC3900CS8、LT4430ES6 演示板,Vin=18V-36V,Vout=5V @ 20A
- 紧凑、多功能、准确、三态可编程电源监控器