当前位置: 首页 > news >正文

串口通信(6)应用定时器中断+串口中断实现接收一串数据

 本文为博主 日月同辉,与我共生,csdn原创首发。希望看完后能对你有所帮助,不足之处请指正!一起交流学习,共同进步!

> 发布人:@日月同辉,与我共生_单片机-CSDN博客

> 欢迎你为独创博主日月同辉,与我共生点赞❤❤❤+关注👍+收藏🌹+评论☺。

系列专栏: CSDN-单片机串口通信学习系列🎁

> 我的格言是:“尽最大努力,做最好的自己!💪

要转载,请提前告知!!!

版权声明:本文为CSDN博主「日月同辉,与我共生」的原创文章,CSDN独一份。

10bc64f8fd3241a0948c08e1dcf000ca.png

目录

一、系统设计要求

二、系统设计原理

三、硬件设计

四、软件设计

4.1串口初始化

4.2接收中断

4.3定时器初始化

4.4定时器中断

4.5主程序

4.6发送数据

4.7清除缓存

4.8uart.h

五、结果展示

一、系统设计要求

最开始,单片机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)。

2b076428a73546d18466361547f84710.png

四、软件设计

4.1串口初始化

串口工作方式为方式1(8位异步通信),定时器采用定时器T1的工作方式2(8位自动重载),波特率为9600bit/s,晶振频率为11.0592Mhz。接收一帧数据的初始化,采用中断法。

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

void ES_timers() interrupt 4 //接收中断
{if(RI){ RI=0; start_timer=1;//1.开定时器标志位置1if(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:

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。

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-->发送数据-->清除缓存

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;//接收完成标志位清0sendString(recv_buf);//发送数据clr_recvbuffer(recv_buf);//清除缓冲函数}}
}

4.6发送数据

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。

void clr_recvbuffer(unsigned char *buf)
{unsigned char i;for(i=0;i<MAX_REX_NUM;i++){buf[i]=0;}
}

4.8uart.h

#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

五、结果展示

最开始:显示正确

00bc45c236624e9fbe82e7296bce4cbe.png

为了测试能否接收到不同长度的数据,做了2次实验。

第一次实验(长度为8):1 2 abc b cc 6 7 8

9d935dea82ca44e0ae1824c196a407c1.png

92931fa34c744d6cadc5aedb9f4e319f.png

第二次实验(长度为4):1 2 abc 600

b9127ccfa2a3403197efe8ede5e766af.png

053a34320e5b413f80349cab904c4e89.png

下一文将着重判断数据帧头来接收一串数据,亲爱的读者敬请期待,下一文更精彩!!!

一日不读书,胸臆无佳想。我叫不白吃,喜欢我的,可以支持我,博主名叫@日月同辉,与我共生

@日月同辉,与我共生_单片机基础,单片机串口通信-CSDN博客@日月同辉,与我共生擅长单片机基础,单片机串口通信,等方面的知识,@日月同辉,与我共生关注stm32,c语言,51单片机,proteus,单片机领域.https://blog.csdn.net/LIN___IT?spm=1000.2115.3001.5343

 

 

http://www.lryc.cn/news/216257.html

相关文章:

  • 【WinForm详细教程六】WinForm中的GroupBox和Panel 、TabControl 、SplitContainer控件
  • gradle与maven
  • 2.Docker基本架构简介与安装实战
  • 拓世法宝 | 数字经济崛起,美业如何抓住流量风口?
  • Scala 泛型编程
  • 索引失效的场景有哪些?
  • Java进阶04 final关键字、abstract抽象、interface接口、JDK8与JDK9中接口的区别、内部类和匿名类
  • Python的web自动化学习(五)Selenium的隐式等待(元素定位)
  • 20231102从头开始配置cv180zb的编译环境(欢迎入坑,肯定还有很多问题等着你)
  • CentOS 安装HTTP代理服务器 Squid
  • ubuntu下开发提效的小tips
  • Java反射详解:入门+使用+原理+应用场景
  • PostgreSQL 工具的相关介绍
  • 结合组件库实现table组件树状数据的增删改
  • Microsoft 365 管理自动化
  • unraid 安装并设置 zerotier 内网穿透安装 unraid 局域网内其他设备
  • 如何调试 Dubbo 协议调用过程
  • C++初阶 类和对象(上)
  • SoftwareTest4 - 咋设计一个好的测试用例
  • 自定义 Spring Boot Starter 组件
  • 功率放大器的种类和作用是什么
  • 分析外贸SEO推广流程?网站谷歌SEO优化方法?
  • 前端工程化需要知道的一些知识
  • 默认路由配置
  • Annotorious入门教程:图片注释工具
  • 一台服务器是否能够安装多个SSL证书?
  • 如何使用UDP打洞进行内网穿透
  • 如何滴水不漏的学完C语言?
  • 数据库深入浅出,数据库介绍,SQL介绍,DDL、DML、DQL、TCL介绍
  • 拓世大模型 | 立足行业所需,发力终端,缔造智能无限可能