本文为博主 日月同辉,与我共生,csdn原创首发。希望看完后能对你有所帮助,不足之处请指正!一起交流学习,共同进步!
> 发布人:@日月同辉,与我共生_单片机-CSDN博客
> 欢迎你为独创博主日月同辉,与我共生点赞❤❤❤+关注👍+收藏🌹+评论☺。
系列专栏: CSDN-单片机串口通信学习系列🎁
> 我的格言是:"尽最大努力,做最好的自己!💪
要转载,请提前告知!!!
版权声明:本文为CSDN博主「日月同辉,与我共生」的原创文章,CSDN独一份。
目录
一、系统设计要求
最开始,单片机com1发送字符串Wait for Serial Communication Tset Start.和Please Send a string of data:给虚拟串口com3,接着虚拟串口发送多个数据(数据长度不定,但限制在20以下)给单片机com1,com1接收后重新将数据发送回com3。
二、系统设计原理
com3每发1个数据,单片机需要时间来接收,这个时间一般不会超过5ms,若超过5ms,则说明接收数据的工作已经完成,则将接收完成标志位recv_flag置1,最后在主程序中处理接收的数据(这里是重新发送给com3),因此可以利用c51单片机内部的定时器0定时1ms,定义计数变量recv_timer_cnt,该变量超过5,则说明接收完成,每接收一个数据,计数变量要清0。接收完成数据后,软件定时器变量清0(让定时器不再工作),同时重新发送数据给com3,并清除缓冲。
三、硬件设计
com1发送端TXD接com2发送端TXD,com1接收端RXD接com2接收端RXD。
虚拟终端RXD接TXD(因为单片机发送数据给com3,而虚拟终端可以理解为虚拟串口com3)。
四、软件设计
4.1串口初始化
串口工作方式为方式1(8位异步通信),定时器采用定时器T1的工作方式2(8位自动重载),波特率为9600bit/s,晶振频率为11.0592Mhz。接收一帧数据的初始化,采用中断法。
cpp
void UartInit(void) //9600bps@11.0592MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xFD; //设置定时初始值
TH1 = 0xFD; //设置定时重载值
ET1 = 0; //禁止定时器中断
ES=1; //串口中断打开
TR1 = 1; //定时器1开始计时
}
4.2接收中断
软件定时器标志位置1(定时器工作,开始定时)-->接收数据-->每接收一帧数据就计数清0
cpp
void ES_timers() interrupt 4 //接收中断
{
if(RI)
{
RI=0;
start_timer=1;//1.开定时器标志位置1
if(recv_cnt<MAX_REX_NUM) //在规定字符长度范围内接收数据
{
recv_buf[recv_cnt]=SBUF; //2.接收数据
recv_cnt++;
}
else
{
recv_cnt=MAX_REX_NUM;
}
recv_timer_cnt=0; //3.每接收一帧数据就计数清0
}
}
4.3定时器初始化
定时1ms:
cpp
void Timer0_Init(void) //1毫秒@11.0592MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x66; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
ET0=1;
TR0 = 1; //定时器0开始计时
}
4.4定时器中断
计数变量recv_timer_cnt超过5时,说明接收完成,计数变量recv_timer_cnt清0。
cpp
void T0_timer() interrupt 1
{
TR0=0;
if(start_timer == 1)
{
recv_timer_cnt++;
if(recv_timer_cnt>MAX_timer_cnt) //计数值超过规定范围说明接收完成
{
recv_timer_cnt=0;
recv_cnt=0;
recv_flag=1;//接收完成标志位置1
}
}
TL0 = 0x66; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TR0=1;
}
4.5主程序
软件定时器变量清0(定时器不再工作)-->接收完成标志位清0-->发送数据-->清除缓存
cpp
void main()
{
UartInit(); //调用串口初始化函数
Timer0_Init();
EA=1; //总中断允许
printf("Wait for Serial Communication Tset Start.\r\n");
printf("Please Send a string of data:\r\n");
while(1)
{
if(recv_flag)
{
start_timer=0;
recv_flag=0;//接收完成标志位清0
sendString(recv_buf);//发送数据
clr_recvbuffer(recv_buf);//清除缓冲函数
}
}
}
4.6发送数据
cpp
void sendByte(unsigned char dat) //发送一帧数据功能函数
{
SBUF=dat;
while(!TI);
TI=0;
}
void sendString(unsigned char *dat)//发送字符串函数
{
while(*dat != '\0')
{
sendByte(*dat++);
}
}
char putchar(char c)
{
sendByte(c);
return c;
}
4.7清除缓存
unsigned char *buf=recv_buf,则buf[i]=0是将第i+1个数据清0。
cpp
void clr_recvbuffer(unsigned char *buf)
{
unsigned char i;
for(i=0;i<MAX_REX_NUM;i++)
{
buf[i]=0;
}
}
4.8uart.h
cpp
#ifndef __UART_H__
#define __UART_H__
#include <reg51.h>
#include <stdio.h>
#define MAX_REX_NUM 20 //规定最大长度
#define MAX_timer_cnt 5 //定时计数规定值,超过该值,说明接收完成
extern unsigned char recv_buf[MAX_REX_NUM];//将数据存储到该数组中
extern unsigned char recv_cnt;
extern unsigned char start_timer;//软件定时器变量,=1说明定时器开始工作
extern unsigned char recv_timer_cnt;//软件定时器计数变量
extern unsigned char recv_flag;//接收完成标志位
void UartInit(void);
void sendByte(unsigned char dat);
void sendString(unsigned char *dat);
char putchar(char c);
void clr_recvbuffer(unsigned char *buf);
#endif
五、结果展示
最开始:显示正确
为了测试能否接收到不同长度的数据,做了2次实验。
第一次实验(长度为8):1 2 abc b cc 6 7 8
第二次实验(长度为4):1 2 abc 600
下一文将着重++判断数据帧头来接收一串数据++,亲爱的读者敬请期待,下一文更精彩!!!
一日不读书,胸臆无佳想。我叫不白吃,喜欢我的,可以支持我,博主名叫 @日月同辉,与我共生