系列文章目录-串口通讯
/C51串口通讯调试目录:/
第5章:#C51串口通讯5-#一串数据#中断定时+超时接收+接收应答+CRC校验
第4章:#C51串口通讯4-#一串数据#中断即时解析用户自定义协议(握手接收应答)
第3章:#C51串口通讯3-#一串数据#中断即时解析用户自定义协议
第2章:#C51串口通讯2-#一串数据#定时中断实现超时接收(推荐)
第1章:#C51串口通讯1-#一串数据#接收与发送(基础概念)
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
一.场景
测试一帧数据(字符串、字符)、固定长度收/发(不建议),基础概念篇
1.方案设计
-
方案1:检测固定字节的数据,下位机接收并加1返回至上位机
-
方案2:检测回车符结束/固定帧尾的数据,下位机接收并加1返回至上位机
2.代码设计
2.1方案1:
2.1.1 中断服务函数传输一帧数据(1Byte),寄存器SBUF
2.1.2 建立缓冲区数组recv_buf[MAX_LENGTH]。其中,MAX_LENGTH***数组长度大小要大于实际接收的数据长度***。因为字符串结尾是’\0’,否则会出错
unsigned char recv_buf[MAX_LENGTH];
#define MAX_NUM 3 //一串数组数据最大的索引号
#define MAX_LENGTH 4 //一个字符串数据实际长度 '\0'
2.1.3接收到固定数据长度的字节数时,置标志recv_flag = 1
void uart_ISR() interrupt 4
{
static unsigned int recv_Cnt = 0;
if(RI)
{
RI = 0;
recv_buf[recv_Cnt] = SBUF;
recv_Cnt++;
if(recv_Cnt == MAX_NUM)
{
recv_flag = 1;
set_buzz(BUZZ_TYPE2);
recv_Cnt = 0;
}
}
}
2.1.4 主函数循环检测,并即时处理
方法1:
while(1)
{
if(recv_flag)
{
for(i = 0; i < MAX_NUM; i++)
{
P1 = 0xFF;
recv_buf[i] += 1;
sendByte(recv_buf[i]);
cLedDis = _crol_(0xFE,i);
P1 &= cLedDis;
Delay_xms(1000);
}
recv_flag = 0;
}
}
方法2:
利用字符串结尾’\0’检测一串数据发送完成
sendString(recv_buf);
void sendString(unsigned char *dat)
{
while(*dat != '\0')
{
sendByte(*dat ++);
}
}
2.1.5缺点
- 长度固定,一旦错误接收或发送紊乱
- 数据存在0时容易中断
- pass
2.2方案2:
2.2.1 中断服务函数建立临时缓冲数组temp,建立保护:大于开辟数据区的数据去除,同时蜂鸣提示
void uart_ISR() interrupt 4
{
static unsigned int recv_Cnt = 0;
unsigned char temp;
if(RI)
{
RI = 0;
temp = SBUF;
if(temp != 0x0D) //0x0D为一个字符串的回车符 '\n',或者帧尾检测
{
recv_buf[recv_Cnt] = temp;
recv_Cnt++;
if(recv_Cnt > MAX_LENGTH) //数据大于开辟的缓存区,则放弃剩余数据,同时报错
{
recv_Cnt = MAX_LENGTH;
set_buzz(BUZZ_TYPE2);
}
}
else
{
cRealLen = recv_Cnt;
recv_flag = 1;
recv_Cnt = 0;
}
}
}
2.2.2 返回实际长度的数据
if(recv_flag)
{
for(i = 0; i < cRealLen; i++)
{
P1 = 0xFF;
recv_buf[i] += 1;
sendByte(recv_buf[i]);
cLedDis = _crol_(0xFE,i);
P1 &= cLedDis;
Delay_xms(1000);
}
recv_flag = 0;
// sendString(recv_buf); //全部返回
}
总结
缺点
- 中间不能出现特定的“结束符”,否则会出错
下一章:#C51串口通讯2-#一串数据#定时中断实现超时接收(推荐)