今日继续学习提升蓝桥杯国赛能力水平。
有道是:卜心事、灯花无语,百感孤单,鸳被羞展......
梦方圆,又丛钟、声声惊断。
诗人杨玉衔孤单影只,偏偏又多遭磨难,一路坎坷......
正如我近日来学习提升串口通信技能一样,遇到诸多设计上的险阻。
本篇主要解决以下串口通信方面的问题:
1.上位主机发送命令字符串,单片机接收校对后执行指令
2.单片机某个变量在改变,要求与字符串拼接后发送给主机
注意:本文不是零基础开始的,需要对串口有基础认识,会用串口收发单八位字节
目录
如零基础学习串口,请传送到这篇文章:
本文提供问题解决的工程文件:
关于单片机接收字符串指令问题的解决:
关于拼接变量与字符串发送的问题:
如零基础学习串口,请传送到这篇文章:
蓝桥杯单片机串口通信学习提升笔记_NULL指向我的博客-CSDN博客
本文提供问题解决的工程文件:
问题一过程文件:
https://download.csdn.net/download/qq_64257614/87808393?spm=1001.2014.3001.5503
问题二过程文件:
https://download.csdn.net/download/qq_64257614/87809191?spm=1001.2014.3001.5503
关于单片机接收字符串指令问题的解决:
你是否也疑惑于某些省赛国赛题目中,类似于
“单片机接收到上位机指令“START\r\n”,上报XXX数据”
“如设备接收到错误指令,返回“ERROR\r\n” ”
的要求,其实他们本意就是考察我们对串口收发的熟悉程度。
我们可以从以下实验来学习强化这方面的知识:
/*
本实验练习串口通信:主要练习以下内容:
数组接收判断上位机的命令
收到 START\r\n 就 打印 OVER\r\n
其余都打印 ERROR\r\n
*/
我们首先在变量定义来讲解:
bit URX_Over = 0;
unsigned char idata URX[10] = 0;
unsigned char idata URX_Num = 0;
unsigned char idata URX_tt = 0;
1.URX_Over是标志位,当其值为1时,会进入函数处理比较字符串,PS:它将在定时器中出现,
2.URX[10] 是字符串数组,他用于接受上位机发来的字符串命令
3.URX_Num 用来辅助字符串数组URX[10] 接收SBUF寄存器的内容
4.URX_tt 用来标记接收是否完成,它同时在定时器中会进行自加,
每次RI不为0,接收数据时,它都会被清零, 直到接收完毕,
接收完毕后它就不会再被清零了
此时的它在定时器中不断自加,到一定值后 就会 刷新标志位URX_Over,
从而推动 字符串比较进程的开展。
涉及以上过程的代码如下贴出:
此段代码对应串口中断的过程:
bit URX_Over = 0;
unsigned char idata URX[10] = 0;
unsigned char idata URX_Num = 0;
unsigned char idata URX_tt = 0;
//串口1中断服务函数
void Uart_1_serv() interrupt 4
{
if(RI)
{
RI=0; URX_tt = 0;
if(URX_Num < 10) { URX[URX_Num++] = SBUF; }
}
}
此段代码是定时器中的过程:
void Timer0Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0x01; //设置定时器模式
TL0 = 0x20; //设置定时初始值
TH0 = 0xD1; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=1;
ET0=1;
}
void Timer0(void) interrupt 1
{
TL0 = 0x20; //设置定时初始值
TH0 = 0xD1; //设置定时初始值
if(URX_Num > 0){if(++URX_tt == 30) { URX_Over = 1;} }
}
最后是主程序While()循环中,对字符串命令的判断:
#include "stdio.h"
#include "string.h"
u8 str1[ ]="START\r\n";
if(URX_Over == 1)
{
URX_Over =0;
if(strncmp(URX,str1,7)==0) Uart_Sendstring("OVER\r\n");
else Uart_Sendstring("ERROR\r\n");
URX_Num = 0;
}
此处需要注意:URX_Num = 0; 这句
表示处理完了字符串命令,就清零,以便URX[10] 接收下个命令字符串
下载后进行调试,效果如下:
证明我们的串口字符串命令收发非常顺利!!!
关于拼接变量与字符串发送的问题:
我们都知道printf 函数的一般调用格式为:printf("<格式化字符串>", <参量表>)
以下为在chitgpt搜索到的关于%bu格式转换字符的原理与应用:
在Keil编程中,
使用printf函数的%bu格式转换字符是用于
将一个unsigned char类型的整数以十进制的形式输出。
%bu是printf函数的格式控制字符串中的占位符,
用于指示需要输出一个unsigned char类型的整数。
在基础知识方面,
unsigned char类型是一种无符号字符类型,它可以存储0到255之间的整数。
它通常用于表示二进制数据的字节和字符。
在C语言中,
可以使用%u格式控制字符串输出unsigned char类型的整数,
但是由于printf函数默认将char类型看作有符号类型,
因此使用%u格式控制字符串输出unsigned char类型的整数时可能会出现问题。
因此,为了避免这种问题,可以使用%bu格式控制字符串来输出unsigned char类型的整数。
下面是一个使用%bu格式控制字符串输出unsigned char类型的整数的例子:
unsigned char value = 255;
printf("The value is %bu\n", value);
输出结果为:
The value is 255
于是,我们便知道了该如何拼接变量与字符了
以下为实践内容要求:
定义test1与 test2,每300ms自加,每次自加后发送:
the new test1 is (test1的值)\r\n the new test2 is (test2的值)\r\n
我们只需对照着要求,在定时器中使他们自加,然后附上printf函数格式化输出即可:
定时器中并没有直接放printf函数,因为主函数调用过了,防止报错重入警告:
void Timer0(void) interrupt 1
{
u16 i;
TL0 = 0x20; //设置定时初始值
TH0 = 0xD1; //设置定时初始值
i++;
if(URX_Num > 0){if(++URX_tt == 30) { URX_Over = 1;} }
if(i==300)
{
i=0;
test1++;test2++;
if(test1==10) test1=0;
if(test2==10) test2=0;
test_flag=1;
}
}
以下为主函数:
void main()
{
u8 test=2;
cls_buzz_led(); //关闭外设
UartInit(); //初始化串口
Timer0Init();
//以下三句是开机串口功能初始化测试用:
printf("Welcome to stc15f2k60s2\n");
printf("%c",test+'0');
SendData(test+'0');
while(1)
{
if(URX_Over == 1)
{
URX_Over =0;
if(strncmp(URX,str1,7)==0) Uart_Sendstring("OVER\r\n");
else Uart_Sendstring("ERROR\r\n");
URX_Num = 0;
}
if(test_flag==1)
{
test_flag=0;
printf("the new test1 is %02bu\r\n the new test2 is %02bu\r\n ",(unsigned char)test1,(unsigned char)test2);
}
}
}
其中最重要的拼接部分就是:
printf("the new test1 is %02bu\r\n the new test2 is %02bu\r\n ",(unsigned char)test1,(unsigned char)test2);
下载后进行串口调试:效果如下:
在此,我们的所有问题就这么解决了,希望各位看官多多三连支持!!