首页 > 其他分享 >07:串口通信二

07:串口通信二

时间:2024-07-17 23:30:29浏览次数:11  
标签:定时器 07 void 寄存器 写入 通信 SBUF 串口 波特率

串口编程

1、与波特率之相关的寄存器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j8DCWyk5-1720973827296)(https://i-blog.csdnimg.cn/direct/e3d9031f80624989965e2c7032d80458.png)]

如图,与串口通信相关的寄存器主要是SCON和PCON寄存器。

2、PCON寄存器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K8GFUA4e-1720973827300)(https://i-blog.csdnimg.cn/direct/1fde62fb51c7497e970738a39950ff7f.png)]

SMOD:为1时,通信方式1,2,3波特率加倍,为0时不加倍。
SMOD0:帧错误检测位,为1时,SCON寄存器中的SM0用于帧错误检测。为0时,用于指定的串口工作方式

3、SCON寄存器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ROY56emb-1720973827301)(https://i-blog.csdnimg.cn/direct/ca0be444120045fa9fb3f54e7c9a1364.png)]

SM0:当PCON的SMOD0为1时,这个位用于帧错误检测。当SMOD0为0时,则用于通信方式的选择
SM0,SM1:
0     0           工作方式0 
0     1           工作方式1           8位异步位数据传输(波特率可配)
1     0           工作方式2           9位(波特率不可配)
1     1           工作方式3           9位(波特率可配)
SM2:允许方式2,3多机控制
REN:运行接收控制位,为1,允许接收;为0,禁止接收。
TB8/RB8先不管它
T1:发送中断请求
R1:接收中断请求
  • 工作方式0的波特率 = 系统晶振/12 = 11.0592MHz/12=11059200/12
  • 工作方式1的波特率 = (2^SMOD/32)*定时器1的溢出率
  • 工作方式2的波特率 = (2^SMOD/64)*11.0592MHz
  • 工作方式3的波特率 = (2^SMOD/32)*定时器1的溢出率

定时器1的溢出率:

  • 工作在12T时:溢出率 = 11.0592MHz / 12 / (256 - TH1)
  • 工作在6T时:溢出率 = 11.0592MHz / 6 / (256 - TH1)

4、配置的代码分析

void UartInit(void)		//[email protected]
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率
	AUXR &= 0xBF;		//定时器1时钟为Fosc/12,即12T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//清除定时器1模式位
	TMOD |= 0x20;		//设定定时器1为8位自动重装方式
	TL1 = 0xFD;		//设定定时初值
	TH1 = 0xFD;		//设定定时器重装值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
}
PCON &= 0X7F;代表PCON变为0xxx xxxx,则最高位变为0,其他位不变。因为PCON的初始值为00x1 0000,所以PCON = 00x1 0000,代表波特率不加倍
SCON = 0x50; 代表0101 0000。8位数据传输(波特率可变),可以读取数据
AUXR = 0X01; 代表降低时钟对外界的辐射
TMOD &= 0X0F;
TMOD |= 0X20; 代表TMOD = 0010 0000,选用定时器1,且为8位自动重装,低8位溢出时,自动将高8位的值给低8位
TL1 = 0XFD;
TH1 = 0XFD; 代表1111 1101,波特率 = (2^0/32)*(11059200/12/(256 - 253)) = 9600,则波特率为9600
TR1 = 1;打开定时器1。

5、向PC发送一段字符串

代码①:

#include <REGX52.H>
#include "intrins.h"

sfr AUXR = 0X8E;

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;
	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void UartInit(void)		//波特率9600
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x40;		//8位数据,可变波特率
	AUXR = 0x01;	
	TMOD &= 0x0F;		//清除定时器1模式位
	TMOD |= 0x20;		//设定定时器1为8位自动重装方式
	TL1 = 0xFD;		//设定定时初值
	TH1 = 0xFD;		//设定定时器重装值
	TR1 = 1;		//启动定时器1
}

void sendByte(char data_sj)
{
	SBUF = data_sj;/*单片机向SBUF里面开始写入数据,注意是开始,要经过一段时间才能写入完毕*/
}

void sendString(char *str)
{
	while(*str != '\0')
	{
		sendByte(*str);
		str++;
	}
}

void main()
{
	UartInit();
	while(1)
	{
		sendString("wohaoshuai");
		Delay1000ms();
	}
}

出现的现象:

wwwoohhwwo

  • 为什么是乱的喃?

因为啊,单片机向SBUF写入数据需要移位寄存器进行操作,而移位寄存器操作也是需要时间的,假设需要10us。当第一个数据写入并发送出去后,要等一段时间第二个数据才能写入成功,而这段时间SBUF里面只有一个w,而发送数据不需要时间,所以他会不断的把SBUF里面的w进行向外发送。
在这里插入图片描述

其实可以这样理解,如上图:SBUF = data_sj;开始向SBUF里面写入数据,而在这段代码后面,有一行代码代表着将SBUF里面的数据输出给上位机
										  只是系统将这行代码隐藏起来了。不然程序员自己编写
   类似:SBUF = data-sj;开始向SBUF里面写入数据
        internal = SBUF 将SBUF里面的数据输出给上位机 (被隐藏)
  • 解决方法1:
    只需要在写入SBUF后面添加一个延迟函数,等待向SBUF成功写入数据后,然后才执行数据输出的代码

代码①:

void sendByte(char data_sj)
{
	SBUF = data_sj;//开始向SBUF里面写入数据
	Delay10ms();//等待10ms,让数据成功写入SBUF里面
	internal = SBUF;//这行代码被隐藏了,不可编辑的
}
  • 解决方法2:
    通过中断请求标志位
    在这里插入图片描述

如图,当使用工作方式1(8位数据传输),当8位数据通过移位寄存器成功写入结束时,TI变为1。例如第二个o用8位二进制数据表示,当第8位通过移位寄存器成功写入时,也代表着字符o成功的被写入SBUF里面,此时TI自动变为1,但是变为1后需要手动置0 ,以便下次数据的写入成功标志
代码②:

void sendByte(char data_sj)
{
	SBUF = data_sj;
	while(!TI);/*还没有写入完毕时,TI=0,则一直困在这个循环里面,当写入完毕时,TI=1,退出循环,进入下一行程序*/
	TI = 0;
}

还没有写入完毕时,TI=0,则一直困在这个循环里面,当写入完毕时,TI=1,退出循环,进入下一行程序

6、PC机向单片机发送字符控制LED1灯的亮灭

#include <REGX52.H>
#include "intrins.h"

sfr AUXR = 0X8E;
sbit LED1 = P3^7;

void Delay300ms()		//@11.0592MHz
{
	unsigned char i, j, k;
	_nop_();
	i = 3;
	j = 26;
	k = 223;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void UartInit(void)		//波特率9600
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x40;		//8位数据,可变波特率
	REN = 1;				//运行单片机读取数据
	AUXR = 0x01;	
	TMOD &= 0x0F;		//清除定时器1模式位
	TMOD |= 0x20;		//设定定时器1为8位自动重装方式
	TL1 = 0xFD;		//设定定时初值
	TH1 = 0xFD;		//设定定时器重装值
	TR1 = 1;		//启动定时器1
}

void main()
{
	char mark;//第一一个mark存储字符
	LED1 = 1;
	UartInit();
	while(1)
	{
		Delay300ms();
		if(RI == 1)  //表示上位机给单片机的SBUF已经写入数据完成了,RI会自动变为1,而需要手动置0,以便下次写入完成进行标志。
		{
			RI = 0;//手动置0
			mark = SBUF;  //将SBUF里面的数存放在变量mark中
			if(mark == 'o')//如果读取的字符是O
			{
					LED1 = 0; //开灯
			}
			if(mark == 'c')
			{
					LED1 = 1;
			}
		}
	}
}

其实可以这样理解:

mark = SBUF;代表着将SBUF里面的数据交给mark这个变量。而在行代码之前,同样有一行代码代表着上位机将数据写入SBUF。
			只是这行代码被隐藏,不可编辑
	类似:SBUF = internal; 上位机将数据写入SBUF(被隐藏)
          mark = SBUF; SBUF将数据存在变量mark中

在这里插入图片描述

同理,RI代表着数据是否被成功写入SBUF里面,上位机成功将数据写入SBUF里面。则RI会自动变为1,同样的需要手动置0,以便下次数据的写入标志

标签:定时器,07,void,寄存器,写入,通信,SBUF,串口,波特率
From: https://blog.csdn.net/qq_51284092/article/details/140413454

相关文章

  • ORA-00756 ORA-10567故障处理---惜分飞
    联系:手机/微信(+8617813235971)QQ(107644445)标题:ORA-00756ORA-10567故障处理作者:惜分飞©版权所有[未经本人同意,不得以任何形式转载,否则有进一步追究法律责任的权利.]数据库异常断电之后,recover报ORA-00756ORA-10567等错SQL>recoverdatabase;ORA-00756:恢......
  • stm32F407SPI-RC522-NFC卡-移植
    目录stm32F407SPI-RC522-NFC卡-移植-简易版nfc卡的原理RC522读卡器的原理应用场景移植步骤好用的代码完整代码stm32F407SPI-RC522-NFC卡-移植-简易版学习spi,移植nfc卡的原理卡内有芯片,0区存卡的id原来要两重密码才能修改卡中数据RC522读卡器的原理应用场景移植步骤问淘......
  • SPI通信协议
    目录串行外设接口概述基本概念引脚定义工作模式数据格式串行外设接口概述基本概念串行外设接口(SerialPeripheralInterface)的简称也叫做SPI,是一种高速的、全双工同步通信的一种接口,串行外设接口一般是需要4根线来进行通信(NSS、MISO、MOSI、SCK),但是如果打算实现单向通信(最少3根......
  • I2C通信协议
    目录内部集成电路概述基本概念引脚说明通信速率通信过程空闲状态开始信号数据传输应答信号停止信号器件地址内部集成电路概述基本概念内部集成电路(InterIntegratedCircuit)的简称叫做IIC或者I2C,是一种简单的、半双工同步通信的串行通信接口,IIC总线是上世纪80年代(1982年)由飞利......
  • ROS服务通信机制实操Python
    ROS服务通信机制实操Python步骤流程vscode配置服务端客户端编辑配置文件编译并执行优化实现参数的动态提交优化先启动客户端后启动服务端ROS服务通信的理论查阅:ROS服务通信流程理论ROS服务通信的自定义srv数据的准备可以查阅:ROS服务通信自定义srv在模型实现中,ROSm......
  • Python实现基于http通信的protobuf数据传输的案例,包括请求者和接收者
    个人名片......
  • 2024-07-17 如何在vscode部署你的代码块,从而在新建页面时能快速搭建模板(windows环境)
    步骤一:打开vscode,按住ctrl+shif+p唤出命令窗口 步骤二:在窗口中输入命令,并回车Preferences:OpenUserSnippets 对,就是这个代码片段,接着输入你想添加代码的某某语言or脚本,比如我要添加vue的代码片段输入vue,回车,会显示vue.json文件出来给你更改,我的是这样 注意:如果你......
  • 2024-07-17 搭建一个node+express服务器,并把静态资源部署到该服务器(本地开发)
    前言:请确保你已安装了node,没有你得先装这个。步骤一://创建文件夹mkdirexpress-node//创建完了进入该文件夹cdexpress-node//初始化npminit-y//安装expressnpmiexpress前提工作都准备好后,在express-node文件夹里新建文件server.js,作为启动服务器的入口文件......
  • 1078 破密
    这个问题可以通过逐个解密字符的方式来解决。我们可以根据给定的加密规则,反向计算出原文的每个字符。以下是解题步骤:1.初始化变量:首先,我们需要初始化一个变量prev,用于存储上一个字符的密文的ASCII码。2.解密字符:然后,我们可以逐个解密字符。对于第一个字符,由于其密文与原......
  • 云计算实训07——搭建ssh服务、创建用户并授权、在RealServer创建code账号、SSH认证原
    一、搭建ssh服务1.安装ssh服务yum-yinstallopensshyum-yinstallssh-serveryum-yinstallssh-client2.关闭防火墙和selinux#关闭防⽕墙(临时)systemctlstopfirewalld#关闭开机⾃启动systemctldisablefirewalld#关闭selinux(临时)sete......