目录
8.1 80C51单片机串行通信技术的特点
- 80C51单片机具有一个全双工串行通信接口,即能同时进行串行发送和接收。
- 可以作UART(通用异步接收和发送器)用
- 可以作同步位移寄存器用。
- 可以实现点对点的单机通信、多机通信和80C51与系统机的单机或多机通信。
8.2 串行通信基本知识
8.2.1 数据通信
通信方式有两种,即并行通信和串行通信:
并行通信是指数据的各位同时进行传送(发送或接收)的通信方式。其优点是传送速度快;缺点是数据有多少位,就需要多少根传送线。
串行通信指数据是一位一位按顺序传送的通信方式。它的突出优点是只需一对传输线(利用电话线就可作为传送线),这样就大大降低了传送成本,特别适用于远距离通信;其缺点是传送速度较低。
8.2.2 串行通信的传输方式
- 单工(或单向)配置,只允许数据向一个方向传送;
- 半双工(或半双向)配置,允许数据向两个方向中的任一方向传送,但每次只能有一个发送,一个接收;
- 全双工(全双向)配置,允许同时双向传送数据,因此,全双工配置是一对单向配置,它要求两端的通信设备都具有完整和独立的发送和接收能力。
8.2.3 异步通信和同步通信
1、异步通信
- 帧格式:一个字符由四部分组成:起始位、数据位、奇偶校验位和停止位。
- 起始位(0):占用一位,用来通知接收设备一个待接收的字符开始到达。
- 数据位:5~8位数据(规定低位在前,高位在后)
- 奇偶校验位(可省略):也可用来确定一帧中的字符所代表信息的性质(地址/数据等)。
- 停止位(1):停止位用来表征字符的结束。停止位可以是1位、1.5位或2位。接收端收到停止位后,知道上一字符已传送完毕
2、同步通信
3、波特率
1、波特率的定义是每秒钟传送二进制数码的位数(亦称比特数),单位是b/s。
2、假设数据传送速率是120字符/s,而每个字符格式包含10个代码(1个起始位、1个终止位、8个数据位)。这时,传送的波特率为
(10b/字符)×120字符/s = 1200 b/s
8.3 串行接口的组成和特性
8.3.1 串行口的结构
- 组成:两个物理上独立的串行数据缓冲寄存SBUF、发送控制器、接收控制器、输入移位寄存器和输出控制门。
- 发送缓冲寄存器SBUF只能写,不能读;
- 接收缓冲寄存器SBUF只能读,不能写。
- 两个缓冲寄存器共用一个地址99H,可以用读/写指令区分。
- 串行发送时,通过“MOV SBUF,A”写指令,写入发送SBUF(99H),再由TxD一位一位地向外发送;
- 串行接收时,RxD一位一位地接收数据,直到收到一个完整的字符数据后通知CPU,再通过“MOV A,SBUF”读指令,CPU从接收SBUF(99H)读出数据,送到累加器A中。
8.3.2 串行口控制器及控制寄存器
1、串行口控制寄存器SCON(98H)
SM0、SM1:串行口工作方式控制位,两位对应四种工作方式,如下表所示(fosc是晶振频率)。
8.4 串行通信接口的工作方式
8.4.1 工作方式0
当SM0 SM1=00时,串行接口选择工作方式0,为同步移位寄存器输入/输出方式,常用于扩展I/O口。串行数据通过RXD输入或输出,而TXD用于输出移位时钟,作为外接部件的同步信号。发送或接收的是8位数据(低位在前,高位在后)。
8.4.2 工作方式1
- 工作方式1,SM0 SMl= 01,为可变波特率的8位异步通信方式。
- 发送数据由TXD端输出,接收数据由RXD端输入。
- 方式1以10位为一帧传输,设有1个起始位(0),8个数据位和1个停止位(1)。其帧格式起始位(0),8个数据位和1个停止位(1)。
8.4.3 工作方式2和工作方式3
SM1 SM0= 10,串行接口选择工作方式2,
SM1 SM0= 11,串行接口选择工作方式3。
方式2或方式3是一个9位的异步串行通信接口,TXD为数据发送端,RXD为数据接收端。
方式2的波特率固定为fosc/64或fosc/32,
方式3的波特率由定时器T1或T2 (80C52)的溢出率所确定。
方式2和方式3以11位为1帧传输,设有1个起始位(0),8个数据位,1个附加第9位和1个停止位(1)。
8.5 波特率设计
8.5.1 波特率的计算方法
1. 方式0波特率
方式0波特率 = fosc /12
若振荡器频率fosc = 12MHz,则波=fosc/12=12MHz/12=1MHz/s,即1μs移位一次。
2. 方式2波特率
方式2波特率 = (2^SMOD/64) × fosc
SMOD为0时,波特率等于振荡器频率的1/64;SMOD为1时,波特率等于振荡器频率的1/32。
3. 方式1和方式3的波特率
串行口方式1和方式3的波特率由定时器T1或T2(89C52等单片机)的溢出率和SMOD所确定。
8.5.2 波特率的产生
1. 用定时器T1产生波特率
方式1和方式3波特率 =(2^SMOD/32) ×(T1溢出率)
溢出周期 =12/振荡器频率×(256-X)
溢出率为溢出周期的倒数,所以有
波特率 = 2^SMOD ×振荡器频率/[32×12×(256-X)]
定时器T1在工作方式2时的初值为
X = 256 - fosc×(SMOD+1)/(384×波特率)
8.6 C语言程序示例
/*******************************************************************************
================================================================================
【平 台】STC89C51_sumjess平台
【编 写】sumjess
【E-mail 】1371129880@qq.com
【软件版本】V2.0
【最后更新】2019年06月10日
【相关信息参考下列地址】
【网 站】
https://blog.csdn.net/qq_38351824
http://www.51hei.com/bbs/mcu-2-1.html
---------------------------------------------------------------------------------
【dev.env.】MDK4.02及以上版本
【Target 】STC89C51
第一次修订:2019/05/09
第二次修订:2019/05/21
第三次修订:2019/06/10
【problem 】
(1)库内补充的不全面;
(2)库内解释部分不全面;
(3)库内还存在一定的bug;
【direction】
下一步的目标就是把库继续集成!
【explain 】
为了方便使用,我也自己写了很多的库,和优化了算法和表示方式!
【warning】
目前程序中暂无错误 !
---------------------------------------------------------------------------------
没有完美的代码,只有不断的奉献,大家一起努力;
赠人玫瑰手留余香,欢迎大家反馈bug!
================================================================================
********************************************************************************/
#include <reg52.h> //编译器自带的库用 < > 编译器包含C52的定义
#include "UART_Sum.h"
//////////////////////////////////////////////////
//STC51只有一个串口 RXD---P3.0 TXD---P3.1
//////////////////////////////////////////////////
/*以下为四种波特率的计算公式:
//
//方式0的波特率 = f(osc)/12
//方式1的波特率 = 2^(SMOD)/32 x (T1溢出率)
//方式2的波特率 = 2^(SMOD)/64 x f(osc)
//方式3的波特率 = 2^(SMOD)/32 x (T1溢出率)
//
//式中f(osc)为系统晶振频率,通常为12MHz或11.0592MHz;SMOD是PCON寄存器的最高位- SMOD=0;串口方式1,2,3时,波特率正常。SMOD=1;串口方式1,2,3时,波特率加倍。
// T1溢出率即定时器T1溢出的频率-只要算出T1定时器
//每溢出一次所需的时间T,那么T的倒数1/T就是他的溢出率。
//只有定时器2可以减少由于时间上带来的误差,因为方式二可以自动装载 */
// 在在具体操作串行口之前,需要对单片机的一些与串口有关的特殊寄存器做初始化设置,主要是设置产生波特率的定时器1、串行口控制和中断控制,具体步骤如下:
// 一、确定T1的工作方式(编程TMOD寄存器);
// 二、计算T1的初值,装载TH1,TL1;
// 三、启动T1(编程TCON中的TR1位);
// 四、确定串行口工作方式(编程SCON寄存器);
// 五、串行口工作在中断方式时,要进行中断设置(编程IE,IP寄存器)。
// 常用波特率初值表
//
//波特率 晶振 初值 误差(%) 晶振 初值 误差(12MHz晶振)(%)
//(bps) (MHz) (SMOD=0) (SMOD=1) (MHz)(SMOD=0) (SMOD=1) (SMOD=0) (SMOD=1)
//300 11.0592 0xA0 0X40 0 12 0X98 0X30 0.16 0.16
//600 11.0592 0XD0 0XA0 0 12 0XCC 0X98 0.16 0.16
//1200 11.0592 0XE8 0XD0 0 12 0XE6 0XCC 0.16 0.16
//1800 11.0592 0XF0 0XE0 0 12 0XEF 0XDD 2.12 -0.79
//2400 11.0592 0XF4 0XE8 0 12 0XF3 0XE6 0.16 0.16
//3600 11.0592 0XF8 0XF0 0 12 0XF7 0XEF -3.55 2.12
//4800 11.0592 0XFA 0XF4 0 12 0XF9 0XF3 -6.99 0.16
//7200 11.0592 0XFC 0XF8 0 12 0XFC 0XF7 8.51 -3.55
//9600 11.0592 0XFD 0XFA 0 12 0XFD 0XF9 8.51 -6.99
//14400 11.0592 0XFE 0XFC 0 12 0XFE 0XFC 8.51 8.51
//19200 11.0592 —— 0XFD 0 12 —— 0XFD —— 8.51
//28800 11.0592 0XFF 0XFE 0 12 0XFF 0XFE 8.51 8.51
/*
方式0时,串行口为同步移位寄存器的输入/输出方式,主要用于扩展并行输入或输出口。
!!!注意!!!串行口工作模式0并不是一个同步串口通信方式,他主要用途是与外面的同步移位寄存器相连。 具体见本篇程序下文件夹的word
数据由RXD(P3.0)引脚输入或输出,同步移位脉冲由TXD(P3.1)引脚输出。发送和接收均为8位数据,低位在先,高位在后。
方式0的波特率 = f(osc)/12
*/
void Init_UART_0(void) //使用方式1 --- 1次中断为5ms,200次为1s
{
SCON=0; //设置T1定时器工作方式2
EA=1; //开总中断
ES=1; //开串口中断
TI=0;
}
#if 0
/////////////////配合主函数定时使用示例////////////////
////////////////////////输出波形///////////////////////
void main()
{
Init_UART_0();
while(1)
{
SBUF=0xaa; //发送接收到的数据
delay(1);
}
}
void serial() interrupt 4
{
TI=0;
}
#endif
/*
方式1的波特率 = 2^(SMOD)/32 x (T1溢出率)
方式1是10位数据的异步通信口,其中1位起始位,8位数据位,1位停止位。
TXD(P3.1)为数据发送引脚,RXD(P3.0)为数据接收引脚。
其传输波特率是可变的,对于51单片机,波特率由定时器1的溢出率决定。
通常我们在做单片机与单片机串口通信、单片机与计算机串口通信、计算机与计算机串口通信时,基本都选择方式1,因此这种方式大家务必要完全掌握。
*/
void Init_UART_1(void) //使用方式1 --- 1次中断为5ms,200次为1s
{
TMOD=0x20; //设置T1定时器工作方式2
TH1=0xfd; //T1定时器装初值
TL1=0xfd; //T1定时器装初值
TR1=1; //启动T1定时器
REN=1; //允许串口接收
SM0=0; //设定串口工作方式1
SM1=1; //设定串口工作方式1
EA=1; //开总中断
ES=1; //开串口中断
}
#if 0
//////////////如果不使用可不写中断服务函数/////////////
/////////////////配合主函数定时使用示例////////////////
//////////////////收到什么发什么///////////////////////
uchar b=0,flag=0;
void main()
{
Init_UART_1();
while(1)
{
if(flag==1)
{
ES=0; //发送数据时,关串口中断
flag=0; //清除标志位
SBUF=b; //发送接收到的数据
while(!TI);//直到发送完毕,发送结束TI为1
TI=0; //置0,准备下一次发送
ES=1; //开启串口中断
}
}
}
void serial() interrupt 4
{
b=SBUF; //赋值,读取接收到的数据
flag=1; //写入标志位
RI=0; //置0等待下次中断
}
#endif
/*
方式2,3都为11位数据的异步通信口。
TXD(P3.1)为数据发送引脚,RXD(P3.0)为数据接收引脚。
这两种方式下,起始位1位,数据9位(含1位附加的第9位,发送时为SCON中的TBS,接收时为RBS),停止位1位,一帧数据为11位。
方式2的波特率固定为晶振频率的1/64或1/32,方式3的波特率由定时器Tl的溢出率决定。
方式2和方式3的差别仅在于波特率的选取方式不同,在两种方式下,接收到的停止位与SBUF,RBS及RI都无关。
方式2的波特率 = 2^(SMOD)/64 x f(osc)
*/
void Init_UART_2(void) //使用方式2 --- 具体情况时,需修改
{
SCON = 0x50; //REN=1允许串行接受状态,串口工作模式2 (1010 0000) SM0 SM1 SM2 REN
TMOD|= 0x20; //定时器工作方式2
PCON|= 0x80; //波特率提高一倍
TH1 = 0xF4; //波特率2400、数据位8、停止位1。效验位无 (12M)
TL1 = 0xF4; //因为 PCON|= 0x80; 波特率提高一倍为4800
TR1 = 1; //开启定时器1
ES = 0; //开串口中断
EA = 0; // 开总中断
}
#if 0
void main()
{
Init_UART_2();
while(1)
{
SBUF=0x01; //发送接收到的数据
delay(1);
}
}
void serial() interrupt 4
{
TI=0;
}
#endif
/*
方式2,3都为11位数据的异步通信口。
TXD(P3.1)为数据发送引脚,RXD(P3.0)为数据接收引脚。
这两种方式下,起始位1位,数据9位(含1位附加的第9位,发送时为SCON中的TBS,接收时为RBS),停止位1位,一帧数据为11位。
方式2的波特率固定为晶振频率的1/64或1/32,方式3的波特率由定时器Tl的溢出率决定。
方式2和方式3的差别仅在于波特率的选取方式不同,在两种方式下,接收到的停止位与SBUF,RBS及RI都无关。
方式2的波特率 = 2^(SMOD)/64 x f(osc)
*/
void Init_UART_3(void) //使用方式3 --- 具体情况时,需修改
{
TMOD = 0x20; // 定时器1 方式 2
SM0=1; // 设定串口工作方式3
SM1=1; // 设定串口工作方式3
TH1 = 0XFD; // 定时器1初值
TL1 = 0XFD; // 定时器1初值
EA=1; // 开总中断
ES = 1; // 串口中断
TR1 = 1; // 开启定时器1
TI=0; //置0,准备下一次发送
}
#if 0
void main()
{
Init_UART_3();
while(1)
{
SBUF=0xaa; //发送接收到的数据
delay(1);
}
}
void serial() interrupt 4
{
TI=0;
}
#endif
来源:CSDN
作者:Sumjess
链接:https://blog.csdn.net/qq_38351824/article/details/104685741