51单片机系列--串口通讯
串行通信和并行通信
串行通信和并行通信都是一种通信传输方式,都适用于计算机与计算机、计算机与单片机之间的数据通信,在传输中存在相互转换的关系。但是两者在使用上还是有着不同的:
- 一次传输的传输量不同
并行通信传送八路信号,一次并行传送传送完整的一个字节信息。串行通信在一个方向上只能传送一路信号,一次只能传送一个二进制位,传送一个字节信息时,只能一位一位地依次传送。 - 传输速度不同
串行的传输速度慢,但是对线路的要求低一些。 并行的对线路的要求高,但是速度快。 - 传输距离不同
串行线路仅使用一对信号线,线路成本低并且抗干扰能力强,因此可以用在长距离通讯上;而并行线路使用多对信号线(还不包括额外的控制线路),线路成本高并且抗干扰能力差,因此对通讯距离有非常严格的限制。
并行通信图
串行通信图
同步通信与异步通信
串行通信分为同步通信与异步通信,区别:
- 同步通信要求接收端时钟频率和发送端时钟频率一致,发送端发送连续的比特流;异步通信时不要求接收端时钟和发送端时钟同步,发送端发送完一个字节后,可经过任意长的时间间隔再发送下一个字节。
- 同步通信效率高,异步通信效率较低。
- 同步通信较复杂,双方时钟的允许误差较小;异步通信简单,双方时钟可允许一定误差。
- 同步通信可用于点对多点,异步通信只适用于点对点。
通俗点说,就是同步是终端A告诉终端B后,等到终端B跑过来后两个终端小伙伴一起搞事情;异步是终端A告诉终端B后,终端A就直接跑去干活了。
电平标准
TTL电平:+5V表示1,0V表示0
RS232电平:-3~-15V表示1,+3~+15V表示0
RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号)
常用通信接口
传输方向
1. 全双工:通信双方可以在同一时刻互相传输数据
2. 半双工:通信双方可以互相传输数据,但必须分时复用一根数据线
3. 单工:通信只能有一方发送到另一方,不能反向传输
4. 异步:通信双方各自约定通信速率
5. 同步:通信双方靠一根时钟线来约定通信速率
6. 总线:连接各个设备的数据传输线路(类似于一条马路,把路边各住户连接起来,使住户可以相互交流)
知识点细分
**波特率:**单片机或计算机在串口通信时的速率。其大小为每秒传输二进制数的位数,单位为:bps。比如:每秒传输255帧数据,一帧数据是十个二进制数,则传输速率就是255x10=2550(bps)。两个终端之间进行串口通信,波特率要一致才能进行。
比特率是每秒钟传输二进制代码的位数,单位是:位/秒(bps)。如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位、1个停止位、8个数据位),这时的比特率为:10位×240个/秒 = 2400 bps
**检验位:**用于数据验证
**停止位:**用于数据帧间隔
**波特率设置:**波特率是基于定时器T1工作方式2进行的,没了解过定时器的小伙伴可以看一下我写过的51单片机系列–定时器中断。
网上给出的波特率的计算方式为:
其中
1.SMOD
属于PCON寄存器,不可位寻址,置0的时候不加倍,置1的时候波特率加倍。
2. fosc
fosc就是51的晶振频率,我使用的52单片机的是11.0529MHz
3.(256-T初)
T1的工作方式2是八位数据自动装填(八位二进制数的范围是0~255,共256个数),初始值在开始时装入TH1和TL1,工作时只有TH1计数,当TH1溢出时把TL1中的初始值重新赋值给TH1,这样就实现了自动装填。
(256-T初)代表着每次定时器计数的次数。
设置方法
首先-设置定时器T1:工作模式寄存器TMOD设为0X20(工作方式2);
然后-计算T1的初始值并装载TH1和TL1,波特率为9600bps时TH1=0XFD、TL1=0XFD;
最后-启动T1:编辑TCON寄存器中的TR1,使TR1=1(打开T1定时器)。通过设置PCON寄存器PCON=0X00设置SMOD=0(不加倍)。
如何确定串行口控制
SM0=0、SM1=1,和打开串行口的允许接收位:REN=1
打开中断
打开总中断和串口通信中断:EA=1、ES=1。
SBUF寄存器
单片机的内部硬件自带发送和接收数据的功能,它是通过SBUF寄存器实现的。SBUF寄存器有两个,一个是SBUF发送寄存器,另一个是SBUF接收寄存器,但两者的地址都为99H。所以在逻辑上只有一个SBUF,而在物理结构上,这又是两个完全独立的寄存器。如果CPU写SBUF,数据就会被送入发送寄存器准备发送;如果CPU读SBUF,则读入的数据一定来自接收寄存器。
TI与RI
TI和RI都在SCON寄存器中。
TI是发送中断标志位,当数据发送完成后,TI由硬件置1,TI置1后向CPU提出中断申请,进入中断函数后需要软件置0(TI=0);
RI是接收中断标志位,当数据接收完成后,RI由硬件置1,RI置1后向CPU提出中断申请,进入中断函数后需要软件置0(RI=0);
示例代码(串口通信闪烁灯)
main.c
#include <REGX52.H>
#include "Delay.h"
#include "UART.h"
sbit led=P2^2;
void main()
{
UART_Init(); //串口初始化
while(1)
{
}
}
void UART_Routine() interrupt 4
{
if(RI==1) //如果接收标志位为1,接收到了数据
{
led=~led; //读取数据,取反后输出到LED
Delay(1000);
UART_SendByte(SBUF); //将受到的数据发回串口
RI=0; //接收标志位清0
}
}
UART.c
#include <REGX52.H>
/** * @brief 串口初始化,4800bps@12.000MHz * @param 无 * @retval 无 */
void UART_Init()
{
SCON=0x50;
PCON |= 0x80;
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xF3; //设定定时初值
TH1 = 0xF3; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
EA=1;
ES=1;
}
/** * @brief 串口发送一个字节数据 * @param Byte 要发送的一个字节数据 * @retval 无 */
void UART_SendByte(unsigned char Byte)
{
SBUF=Byte;
while(TI==0);
TI=0;
}
/*串口中断函数模板 void UART_Routine() interrupt 4 { if(RI==1) { RI=0; } } */
UART.h
#ifndef __UART_H__
#define __UART_H__
void UART_Init();
void UART_SendByte(unsigned char Byte);
#endif
串口通信助手界面
还没有评论,来说两句吧...