目录
一、竞赛板串口通信相关资料解析
串口通信在蓝桥杯单片机竞赛中出现的次数不多,串口通信对竞赛学生来说也相对难一些,好在竞赛中考点不是很多,由于竞赛板硬件已经固定,只有串口1可用于考核,且串口1也作为程序下载的端口,在竞赛中也只能和上位机PC进行通信演示。
本例以第十届全国决赛中通信部分为例。
1、指令解析
查询数据指令:”ST\r\n”
查询参数指令: ”PARA\r\n”
通信中的指令格式是采用字符形式,在设置串口调试助手也必须采用字符形式发送和接收,其中的 “\r\n”是回车换行的意思,在窗口中并不显示,因此在输入发送指令时必须加回车,然后再按“发送数据”按钮,如下图中的指令就是查询数据指令(ST+回车)。
2、单片机串口接收数据解析
单片机收到的信息都是8位二进制信息,但通信过程要求以字符形式通信,即ASC-II码形式。ASC-II码也是8位二进制编码,在C语言编程中,给字符加单引号就是其ASC-II编码,如A:‘A’。
对0~9数字的ASC-II码是在0~9数值基础上加 30h(或0x30)。
“\r\n”对应的十六进制信息是0dh、0ah(0x0d、0x0a)。
3、返回指令格式
发送:”ST\r\n” 返回:$20,24.32\r\n
发送:”PARA\r\n” 返回:#35,30\r\n
发送:其它\r\n 返回:ERROR\r\n
返回信息包含数据和字符,数据有整数和浮点数,浮点数也定义成整数,在发送时人为添加小数点的ASC-II码。
二、程序设计
1、串口1初始化程序
用STC-ISP的“串口波特率计算器”功能产生初始化程序,注意系统频率要设置为11.0592MHz,用定时器T18位自动重装模式产生波特率,8位数据,波特率按赛题要求设置即可,本例设为9600。程序如下:
void UartInit(void) //9600bps@11.0592MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
AUXR &= 0xBF; //定时器时钟12T模式
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xFD; //设置定时初始值 9600
TH1 = 0xFD; //设置定时重载值 9600
ET1 = 0; //禁止定时器中断
TR1 = 1; //定时器1开始计时
}
在主程序开头调用该函数,并开通串口中断。
2、串口1中断服务函数设计
本例接收、发送数据都采用中断方式。
接收部分,定义接收数组存放信息,定义接收指针变量、数据长度等信息,根据信息结尾特征“0x0d 0x0a”信息判断指令是否结束,结束转存信息即长度供其它程序处理。
发送部分,定义发送数组存放信息,定义发送指针、数据长度等信息,由主程序或其它程序启动发送,在中断函数控制其余信息的发送。程序如下:
unsigned char Rx_data[10]; //接收数组
unsigned char Rx_buff[10]; //接收缓冲
unsigned char Rx_id=0; //接收存储指针
unsigned char Rx_Lenth; //接收数据长度
bit Analysis=0; //分析标志
unsigned char Tx_data[11]; //发送数组
unsigned char Tx_id=0; //发送指针
unsigned char Tx_Lenth; //发送长度
void inesp()interrupt 4 //串口1中断函数
{
unsigned char i;
if(RI) //接收中断
{
RI=0; //清中断标志
Rx_data[Rx_id]=SBUF; //保存信息
Rx_id++; //存储指针+1
if(Rx_id>1) //判读信息结尾
{
if((Rx_data[Rx_id-1]==0x0a)&&(Rx_data[Rx_id-2]==0x0d))//
{
for(i=0;i<Rx_id;i++)Rx_buff[i]=Rx_data[i]; //信息转存
Rx_Lenth=Rx_id; //保存信息长度
Rx_id=0; //存储指针清0
Analysis=1; //分析标志置1
}
}
}
if(TI) //发送中断
{
TI=0; //清中断标志
Tx_id++; //发送指针+1
if(Tx_id<Tx_Lenth)SBUF=Tx_data[Tx_id];//小于长度发下一个字节
}
}
3、接收信息分析处理函数
根据指令分析标志和接收数据的长度信息,分析指令信息,分别进行处理。
(1)分析指令函数结构
void Analys() //分析函数
{
Analysis=0; //清除分析标志
switch(Rx_Lenth)
{
case 4://判断查询数据指令
if(Rx_buff[0]=='S'&&Rx_buff[1]=='T')
{//查询数据指令
}
else {//错误指令
}
break;
case 6://判断查询参数指令
if(Rx_buff[0]=='P'&&Rx_buff[1]=='A'&&Rx_buff[2]=='R'&&Rx_buff[3]=='A')
{//查询参数指令
}
else {//错误指令
}
break;
default: //错误指令
break;
}
}
(2)查询数据指令程序
Tx_data[0]='$'; //数据信息开头
Tx_data[1]=Distance/10+0x30; //分拆距离数据
Tx_data[2]=Distance%10+0x30;
Tx_data[3]=','; //数据间分隔符
Tx_data[4]=Temp/1000+0x30; //分拆温度数据——整数
Tx_data[5]=Temp%1000/100+0x30;
Tx_data[6]='.'; //小数点
Tx_data[7]=Temp%100/10+0x30; //分拆温度数据——小数
Tx_data[8]=Temp%10+0x30;
Tx_data[9]=0x0d; //信息结尾
Tx_data[10]=0x0a; //回车换行
Tx_id=0; //发送指针
Tx_Lenth=11; //发送数据长度
SBUF=Tx_data[0]; //启动发送
(3)查询参数指令程序
Tx_data[0]='#'; //参数信息开头
Tx_data[1]=Dist_Para/10+0x30; //分拆距离参数
Tx_data[2]=Dist_Para%10+0x30;
Tx_data[3]=',';
Tx_data[4]=Temp_Para/10+0x30; //分拆温度参数
Tx_data[5]=Temp_Para%10+0x30;
Tx_data[6]=0x0d; //信息结尾
Tx_data[7]=0x0a; //回车换行
Tx_id=0; //发送指针
Tx_Lenth=8; //发送数据长度
SBUF=Tx_data[0]; //启动发送
(4)查询参数指令程序
Tx_data[0]='E'; //错误指令信息
Tx_data[1]='R';
Tx_data[2]='R';
Tx_data[3]='O';
Tx_data[4]='R';
Tx_data[5]=0x0d; //信息结尾
Tx_data[6]=0x0a; //回车换行
Tx_id=0; //发送指针
Tx_Lenth=7; //发送数据长度
SBUF=Tx_data[0]; //启动发送