单片机串口通信包含波特率计算(12M/11.0592M)与SMOD加倍

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

很多同学在学习单片机过程中遇到了很多的问题,比如串口,串口是单片机的一块重要知识,学不好学不会都将对单片机而言是一种缺憾,最近我遇到了问题,怎样设置波特率,SMOD是波特率加倍的一个困惑之地,见后续


正文内容

一、了解什么是波特率,干什么用?

官方:

指的是信号被调制以后在单位时间内的变化,即单位时间内载波参数变化的次数,如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为240Bd,比特率为10位*240个/秒=2400bps……。

我的理解:

波特率就是单片机发送和接收数据时双方的一种约定,是用高低电平代表数字0-1传送数据比特(bit)的一种方式,比如我们采用9600波特率发送数据,意思是一秒可以传送9600个bit,8个bit为一个字节(byte),可以换算,比如我们发送1个字节的数据0X0A(展开:00001010,十进制也就是10),这个波特率让串口端口引脚高低电平变换00001010高低电平切换,每1/9600秒发送一个0-1电平。

**

关于为什么加这种约定:

**就是为了避免通信双方约定波特率不同,导致误码,A以1/9600的速率发送了 01 B接受时用1/4800速率接受,这样只能接受到电平1,因此B获得到的电平是1,漏掉了0,这就是波特率不同导致的问题。

二、计算波特率与串口通信

1.公式

请添加图片描述在这里插入图片描述
上面就是计算波特率的通用公式,任何请况下都能使用,可以理解一下。

2.12M和11.05926M晶振区别

我们用上面的11.05926M时,计算9600波特率时,得到的TH1极其接近250,但是当我们用12M晶振时,计算9600波特率便会发现,TH1=249.5多点,而转换为16进制,没法带小数部分,因此就要进行四舍五入,将TH1近似为250或者249,此处我近似为249,作为初始装载值,但是由于一点一点误差的积累,便带来了某个数据的错误,因此就出现了个别数据的误码。

要避免上述误码,可以换一种波特率,比如4800,自己可以尝试计算一下TH1就行,看看多大的误差。肯定越小越好!
在这里插入图片描述
偶尔误码情况!

3.串口通信收发代码

直接运行即可,加了一个串口中断,发送数据时可引发中断,上传数据包中的数据!我这是12M****晶振下的串口收发!读者注意!!!
如果是11.0592M晶振请用上面公式计算TH1=TL1的初始值

#include "reg51.h"			 //
#include <intrins.h>
typedef unsigned int u16;	 
typedef unsigned char u8;
unsigned int array[]={0XAA, 0X01 ,0X1A, 0X05,0X01, 0X00, 0X00, 0X11, 0X01, 0X01,0X02 ,0X00 ,0X00 ,0X11 ,0X01 ,0X01,0X03 ,0X00 ,0X00 ,0X11 ,0X01 ,0X01,0X04, 0X00,0X00 ,0X11 ,0X01 ,0X01 ,0X05 ,0X00, 0X00 ,0X11, 0X01, 0X01 ,0XFF,0X11,0X01,0X20};//根据实际数据情况,我这是随便写的!嘿嘿
unsigned int array1[2];
sbit led = P2^1;
sbit led1 = P2^0;
void Delay5ms()		//@12.000MHz
{
	unsigned char i, j;
	i = 59;
	j = 90;
	do
	{
		while (--j);
	} while (--i);
}
void Delay1000ms()		//@12.000MHz
{
	unsigned char i, j, k;
	_nop_();
	_nop_();
	i = 46;
	j = 153;
	k = 245;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
void usartinit()
{
	SCON=0X50;//ÔÊÐí´®ÐнÓÊÜ£¬Ñ¡Ôñ·½Ê½¶þ½øÐÐ8λ×Ô¶¯ÖØ×°ÔØ
	TMOD=0X20;//Æô¶¯¶¨Ê±Æ÷1 ¹¤×÷ģʽ2 8λ×Ô¶¯ÖØ×°ÔÔ
	PCON=0X80;//²¨ÌØÂʱ¶Æµ
	//4800 4800波特率情况下无误码率
	//TH1=0XF3;
	//TL1=0XF3;
	//9600 装载值,存在个别数据误码 
	TH1=0XF9;
	TL1=0XF9;
	
	TR1=1;
	ES=1;//´ò¿ª´®¿ÚÖжÏ
	EA=1;//´ò¿ª×ÜÖжÏ
}	

void usart() interrupt 4  //²»ÒªÂ©µôÀ¨ºÅ ´®¿ÚÖжÏ4
{
	u8 reivedata;
	u8 num;
	if(RI)//接收数据,RI变成1
	{
		reivedata=SBUF;接受的东西存放到reivedata中,这里没使用
		RI=0;//接受中断清空
		for(num=0;num<38;num++)
		{
			SBUF = array[num];//中断控制循环发送数据包
			Delay5ms();//必须加一定延时,否则发送不完也会导致误码情况的发生!
		}
		led=~led;//灯反转 检测是否进入串口中断!
	}
	if(TI)
	{
		TI=0;//清空发送中断标志位
	}
}
void main()
{	
	u8 i;
	usartinit();//初始化
	while(1)
	{
		Delay1000ms();//时间偏长了
		for(i=0;i<38;i++)
		{
			SBUF = array[i];//循环发送数据包
			Delay5ms();
		}
		led1=~led1;//检测while()循环是否正常,防止程序卡死到其他位置
	}
}

三、总结

欢迎大家学习交流!不足之处恳请批评指正,一起交流,一起进步! 人生没有终点,即使在苦难中痛不欲生!

清华yuan镜像:pip install 包名 -i https://pypi.tuna.tsinghua.edu.cn/simple/

### 51单片机12MHz11.0592MHz晶振频率的区别 在设计基于51系列单片机的系统时,通常会选择11.0592MHz作为晶振频率而非12MHz。这种选择主要源于串口通信中的波特率设置需求以及其精度要求。 #### 波特率计算原理 51单片机的串口波特率可以通过定时器T1来设定。对于方式1和方式3而言,波特率计算公式如下: \[ \text{波特率} = \frac{\text{fosc}}{12 \times (2^{SMOD}) \times (\text{T1溢出周期})} \] 其中: - \( f_{\text{osc}} \) 是系统的时钟频率; - SMOD波特率加倍位(当SMOD=1时,波特率翻倍); - T1溢出周期取决于TH1寄存器的初值。 为了实现常见的标准波特率(如9600bps),\( f_{\text{osc}} \) 需要满足特定条件以使上述公式的分母能够整除分子[^2]。 #### 使用11.0592MHz的优点 11.0592MHz的设计使得通过简单的二进制分割可以获得精确的标准波特率。具体来说,该频率可以被分解为多个因子,从而更容易匹配常用的波特率数值。例如,当采用11.0592MHz晶振并配置合适的定时器初值时,可以在不引入显著误差的情况下支持高达57600bps的波特率[^3]。 #### 使用12MHz的局限性 尽管12MHz提供了更高的基础运行速度,但它并不适合用于需要精准波特率的应用场景。原因在于无法利用简单的方法调整到完全符合工业标准的数据传输速率。即使经过复杂的补偿措施后仍然可能存在一定程度上的偏差,这可能导致高速通讯过程中出现误码现象[^1]。 因此,在实际应用当中如果涉及到较为严格的同步或者异步串行接口操作,则更倾向于选取那些便于生成无失真信号波形的晶体震荡源——即像11.0592 MHz这样的特殊定制型产品而不是通用规格下的纯数字整数单位Hz级选项比如12 MHz版本。 ```c // 示例代码展示如何初始化串口以获得指定波特率 void initUART(unsigned int baudRate){ unsigned int timerValue; // 计算TH1初始值以便得到期望的波特率 timerValue = (unsigned int)(256 - ((float)fosc / (baudRate * 12))); TMOD |= 0x20; // 设置模式2自动重载 TH1 = timerValue; // 加载计数器初值至TH1 TL1 = TH1; // 初始化TL1等于TH1 SCON = 0x50; // 8-bit UART, REN enabled TR1 = 1; // 启动定时/计数器1 } ``` 以上函数展示了如何根据给定的波特率参数去初始化UART模块,并假设`fosc`变量存储当前使用的CPU主频(这里应替换为你所选的具体值如11059200或12e6).
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值