STC51从入门到精通(汇编)~~~ 第八讲:串行通信技术

Posted Sumjess

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STC51从入门到精通(汇编)~~~ 第八讲:串行通信技术相关的知识,希望对你有一定的参考价值。


目录

​8.1 80C51单片机串行通信技术的特点​

​8.2 串行通信基本知识​

​8.2.1 数据通信​

​8.2.2 串行通信的传输方式​

​8.2.3 异步通信和同步通信​

​8.3 串行接口的组成和特性​

​8.3.1 串行口的结构​

​8.3.2 串行口控制器及控制寄存器​

​8.4  串行通信接口的工作方式​

​8.4.1 工作方式0​

​8.4.2 工作方式1​

​8.4.3 工作方式2和工作方式3​

​8.5  波特率设计​

​8.5.1 波特率的计算方法​

​8.5.2 波特率的产生  ​

​8.6 C语言程序示例​


8.1 80C51单片机串行通信技术的特点

  • 80C51单片机具有一个全双工串行通信接口,即能同时进行串行发送和接收。
  • 可以作UART(通用异步接收和发送器)
  • 可以作同步位移寄存器用。
  • 可以实现点对点的单机通信、多机通信和80C51与系统机的单机或多机通信。

8.2 串行通信基本知识

8.2.1 数据通信

通信方式有两种,即并行通信串行通信:

       并行通信是指数据的各位同时进行传送(发送或接收)的通信方式。其优点是传送速度快;缺点是数据有多少位,就需要多少根传送线。

       串行通信指数据是一位一位按顺序传送的通信方式。它的突出优点是只需一对传输线(利用电话线就可作为传送线),这样就大大降低了传送成本,特别适用于远距离通信;其缺点是传送速度较低。

8.2.2 串行通信的传输方式

  • 单工(或单向)配置,只允许数据向一个方向传送
  • 半双工(或半双向)配置,允许数据向两个方向中的任一方向传送,但每次只能有一个发送,一个接收;
  • 全双工(全双向)配置,允许同时双向传送数据,因此,全双工配置是一对单向配置,它要求两端的通信设备都具有完整和独立的发送和接收能力。

8.2.3 异步通信和同步通信

1、异步通信

STC51从入门到精通(汇编)~~~

  • 帧格式:一个字符由四部分组成:起始位、数据位、奇偶校验位和停止位。
  • 起始位(0):占用一位,用来通知接收设备一个待接收的字符开始到达。
  • 数据位:5~8位数据(规定低位在前,高位在后)
  • 奇偶校验位(可省略):也可用来确定一帧中的字符所代表信息的性质(地址/数据等)。
  • 停止位(1):停止位用来表征字符的结束。停止位可以是1位、1.5位或2位。接收端收到停止位后,知道上一字符已传送完毕

2、同步通信

STC51从入门到精通(汇编)~~~

3、波特率

1、波特率的定义每秒钟传送二进制数码的位数(亦称比特数),单位是b/s

2、假设数据传送速率是120字符/s,而每个字符格式包含10个代码(1个起始位、1个终止位、8个数据位)。这时,传送的波特率为

            (10b/字符)×120字符/s = 1200 b/s

8.3 串行接口的组成和特性

8.3.1 串行口的结构

STC51从入门到精通(汇编)~~~

  • 组成:两个物理上独立的串行数据缓冲寄存SBUF、发送控制器、接收控制器、输入移位寄存器和输出控制门。
  • 发送缓冲寄存器SBUF只能,不能读;
  • 接收缓冲寄存器SBUF只能,不能写。
  • 两个缓冲寄存器共用一个地址99H,可以用读/写指令区分。
  • 串行发送时,通过MOV SBUFA写指令,写入发送SBUF(99H),再由TxD一位一位地向外发送;
  • 串行接收时,RxD一位一位地接收数据,直到收到一个完整的字符数据后通知CPU,再通过MOV  ASBUF读指令,CPU从接收SBUF(99H)读出数据,送到累加器A中。

8.3.2 串行口控制器及控制寄存器

1、串行口控制寄存器SCON(98H)

STC51从入门到精通(汇编)~~~

SM0、SM1:串行口工作方式控制位,两位对应四种工作方式,如下表所示(fosc是晶振频率)。

STC51从入门到精通(汇编)~~~

8.4  串行通信接口的工作方式

8.4.1 工作方式0

      SM0 SM1=00时,串行接口选择工作方式0,为同步移位寄存器输入/输出方式,常用于扩展I/O口。串行数据通过RXD输入或输出,而TXD用于输出移位时钟,作为外接部件的同步信号。发送或接收的是8位数据(低位在前,高位在后)。

STC51从入门到精通(汇编)~~~

8.4.2 工作方式1

  1. 工作方式1SM0 SMl= 01,为可变波特率8位异步通信方式
  2. 发送数据由TXD端输出,接收数据由RXD端输入。
  3. 方式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

SMOD0时,波特率等于振荡器频率的1/64SMOD1时,波特率等于振荡器频率的1/32

3. 方式1和方式3的波特率

串行口方式1和方式3的波特率由定时器T1T2(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
【软件版本】V2.0
【最后更新】2019年06月10日
【相关信息参考下列地址】
【网 站】
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

 

以上是关于STC51从入门到精通(汇编)~~~ 第八讲:串行通信技术的主要内容,如果未能解决你的问题,请参考以下文章

16位汇编第八讲指令第四讲

逆向知识第八讲,if语句在汇编中表达的方式

I51开发板----STC15F2K60S2教程

SQL入门之第八讲——UPDATE更新语句

嵌入式Linux从入门到精通之第八节:GTK+详解

嵌入式Linux从入门到精通之第八节:GTK+详解