目录
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语言程序示例
通信方式有两种,即并行通信和串行通信:
并行通信是指数据的各位同时进行传送(发送或接收)的通信方式。其优点是传送速度快;缺点是数据有多少位,就需要多少根传送线。
串行通信指数据是一位一位按顺序传送的通信方式。它的突出优点是只需一对传输线(利用电话线就可作为传送线),这样就大大降低了传送成本,特别适用于远距离通信;其缺点是传送速度较低。
1、异步通信
2、同步通信
3、波特率
1、波特率的定义是每秒钟传送二进制数码的位数(亦称比特数),单位是b/s。
2、假设数据传送速率是120字符/s,而每个字符格式包含10个代码(1个起始位、1个终止位、8个数据位)。这时,传送的波特率为
(10b/字符)×120字符/s = 1200 b/s
1、串行口控制寄存器SCON(98H)
SM0、SM1:串行口工作方式控制位,两位对应四种工作方式,如下表所示(fosc是晶振频率)。
当SM0 SM1=00时,串行接口选择工作方式0,为同步移位寄存器输入/输出方式,常用于扩展I/O口。串行数据通过RXD输入或输出,而TXD用于输出移位时钟,作为外接部件的同步信号。发送或接收的是8位数据(低位在前,高位在后)。
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)。
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所确定。
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×波特率)
/*******************************************************************************
================================================================================
【平 台】STC89C51_sumjess平台
【编 写】sumjess
【E-mail 】[email protected]
【软件版本】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 //编译器自带的库用 < > 编译器包含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