蓝桥杯的串口收发功能都离不开SBUF,SBUF是单片机内部的硬件寄存器,这里分为读SBUF(从接收缓冲区取走一个字节)和写SBUF(向发送缓冲区里写一个字节)。
然后就是putchar函数了,重写putchar函数就可以实现使用C语言中很实用的printf函数进行发送数据了。
extern char putchar(char ch)
{
SBUF = ch;
while(TI==0);
TI = 0;
return ch;
}
TI和RI分别是发送和接收标志位,当发出或接收到一个字节后 硬件自动将该标志位置1,要实现多字节的收发 需要手动把标志位清零。
个人觉得串口难点在于串口的接收解析,终端设备通过串口助手向单片机发出数据之后,单片机要想正确解析信息并做出相应执行功能,就需要解析这个数据。因此就用到了读SBUF寄存器。
首先先了解发送的协议规则,以下是第十七届蓝桥杯省赛真题。

通过分析题目可知 要接收的命令格式是#设备地址? 因此这里帧头就是# 帧尾是? 中间的三位数字就是数据帧。以下是解析代码。
void Uart1_Isr(void) interrupt 4
{
if (RI) //检测串口1接收中断
{
RI = 0; //清除串口1接收中断请求位
//Receive_Buf[Receive_index] = SBUF;
if(SBUF == '#')//识别到帧头
{
Receive_index = 0;
}
else if(SBUF == '?')//识别据帧尾
{
Receive_Buf[Receive_index] = '\0';
Receive_flag = 1;
}
else{//帧头帧尾之间的数据帧
Receive_Buf[Receive_index++] = SBUF;
}
}
}
首先通过 读SBUF识别到命令的帧头’#’,识别到之后,将接收数组的下标设为0,之后下标自增1,并判断读SBUF是否是帧尾 ‘?’ ,如果是帧尾的话,就设置此下标的数组数据为’\0’,代表字符串的结束,并设置接收标志位Receive_flag =1,代表此次解析完成。如果既不是帧头或帧尾的话那么就是数据帧。流程其实就是先识别到帧头,然后依次存入数据帧,直到识别到数据帧尾。
解析完成之后我们就要判断接收数组中的数据是否是跟题目要求的一样。
void Uart_Proc()
{
unsigned char recv_addr = 0;
if(Receive_flag == 0)return;
Receive_flag = 0;
recv_addr = (Receive_Buf[0] - '0')*100 + (Receive_Buf[1] - '0')*10 + (Receive_Buf[2] - '0');
if(recv_addr == device_addr)
{
printf("%.1fkPa@%02d:%02d",(float)(pressure/10.0),(int)RTC_buf[0],(int)RTC_buf[1]);
}
}
这里判断串口中断函数中是否完成接收,也就是判断Receive_flag 标志位是否为1,为1代表接收到了符合题目要求的数据,之后就要进行数据检验。串口里的数字不能直接进行判断,因为他是字符串,因此就要想到ASCII 码,假如我想正确把字符’5’转换成数字5 需要减去’0’,对应ASCII码就是 ‘5’ – ‘0’ = 53 – 48 = 5。
然后就开始拼数字,题目里是三位数,因此把解析到的(字符百位数字-‘0’) * 100 + (字符十位数字-‘0’) *10 + 字符个位数字 – ‘0’。将相加的值存到变量中判断是否和设置的设备地址相同,如果相同就按照题目要求输出 “压力值kPa@时间”。