提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、了解什么是波特率,干什么用?
- 官方:
- 我的理解:
- 关于为什么加这种约定:
- 二、计算波特率与串口通信
- 1.公式
- 2.12M和11.05926M晶振区别
- 3.串口通信收发代码
- 三、总结
前言
很多同学在学习单片机过程中遇到了很多的问题,比如串口,串口是单片机的一块重要知识,学不好学不会都将对单片机而言是一种缺憾,最近我遇到了问题,怎样设置波特率,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/