11-串口通信的基本原理与应用
串行通信概述
- 微控制器与外部设备的数据通信,根据连线结构和传送方式的不同,可以分为两种:并行通信和串行通信。
并行通信:指数据的各位同时发生或接收,每个数据位使用一条导线。
串行通信:指数据一位接一位地顺序发送或接收
-
串行通信有SPI、IIC、UART等多种,最常见最通用的就是指UART,大多数情况下,串口通信指的就是UART
-
串口通信的制式有:单工、半双工、全双工三种。
RS385总线式半双工的通信制式
串口通信的主要方式有两种:同步和异步。
同步串口通信:需要使用同一个时钟,以数据块为单元传送数据。
异步串口通信:每个设备都有自己的时钟信号,通信中双方的波特率要保持一致,以字符为单元进行数据帧传送,依次传送一个帧。
关于波特率计算
- 波特率:串口每秒钟传输的位数
- 在波特率的介绍之前需要先提到一个寄存器
SCON : 串行控制寄存器 (可位寻址)
SFR name | Address | bit | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
---|---|---|---|---|---|---|---|---|---|---|
SCON | 98H | name | SM0/FE | SM1 | SM2 | REN | TB8 | RB8 | TI | RI |
SM0/FE:当PCON寄存器中的SMOD0/PCON.6位为1时,该位用于帧错误检测。当检测到一个无效停止位时,通过UART接收器设置该位。它必须由软件清零.当PCON寄存器中的SMOD0/PCON.6位为0时,该位和SM1一起指定串行通信的工作
方式,如下表所示。
其中SM0、SM1按下列组合确定串行口1的工作方式:
SM0 | SM1 | 工作方式 | 功能说明 | 波特率 |
---|---|---|---|---|
0 | 0 | 方式0 | 同步移位串行方式:移位寄存器 | 当UART_M0x6 = 0时,波特率是SYSclk/12, 当UART_M0x6 = 1时,波特率是SYSclk / 2 |
0 | 1 | 方式1 | 8位UART,波特率可变 | 串行口1用定时器1作为其波特率发生器且定时器1工作于模式0(16位自动重装载模式)或串行口用定时器2作为其波特率发生器时, 波特率=(定时器T1的溢出率和定时器T2的溢出率 )/4 注意:此时波特率与SMOD无关。 当串行口1用定时器1作为其波特率发生器且定时器1工作于模式2(8位自动重装模式)时, 波特率=( 2SMOD/32 )×(定时器1的溢出率) |
1 | 0 | 方式2 | 9位UART | ( 2SMOD / 64) x SYSclk系统工作时钟频率 |
1 | 1 | 方式3 | 9位UART,波特率可变 | 当串行口1用定时器1作为其波特率发生器且定时器1工作于模式0(16位自动重装载模式)或串行口用定时器2作为其波特率发生器时, 波特率=(定时器1的溢出率或定时器2的溢出率)/4 注意:此时波特率与SMOD无关 当串行口1用定时器1作为其波特率发生器且定时器1工作于模式2(8位自动重装模式)时 波特率=( 2SMOD/32 )×(定时器1的溢出率) |
当定时器1工作于模式0(16位自动重装载模式)且AUXR.6/T1x12 = 0时,
定时器1的溢出率 = SYSclk/12/( 65536 - [RL_TH1,RL_TL1]) ;
当定时器1工作于模式0(16位自动重装载模式)且AUXR.6/T1x12 = 1时,
定时器1的溢出率 = SYSclk / (65536 - [RL_TH1,RL_TL1])
当定时器1工作于模式2(8位自动重装模式)且T1x12 = 0时,
定时器1的溢出率 = SYSclk/12/( 256 - TH1);
当定时器1工作于模式2(8位自动重装模式)且T1x12 = 1时,
定时器1的溢出率 = SYSclk / ( 256 - TH1)
当AUXR.2/T2x12 = 0时, 定时器T2的溢出率 = SYSclk / 12/ ( 65536 - [RL_TH2,RL_TL2] );
当AUXR.2/T2x12 = 1时, 定时器T2的溢出率 = SYSclk / ( 65536 - [RL_TH2,RL_TL2] );
SM2:允许方式2或方式3多机通信控制位。
在方式2或方式3时,如果SM2位为1且REN位为1,则接收机处于地址帧筛选状态。此时
可以利用接收到的第9位(即RB8)来筛选地址帧:若RB8=1,说明该帧是地址帧,地址信
息可以进入SBUF,并使RI为1,进而在中断服务程序中再进行地址号比较;若RB8=0,
说明该帧不是地址帧,应丢掉且保持RI=0。在方式2或方式3中,如果SM2位为0且REN位
为1,接收收机处于地址帧筛选被禁止状态。不论收到的RB8为0或1,均可使接收到的
信息进入SBUF,并使RI=1,此时RB8通常为校验位.
方式1和方式0是非多机通信方式,在这两种方式时,要设置SM2 应为0。
REN:允许/禁止串行接收控制位。由软件置位REN,即REN=1为允许串行接收状态,可启动
串行接收器RxD,开始接收信息。软件复位REN,即REN=0,则禁止接收。
TB8: 在方式2或方式3,它为要发送的第9位数据,按需要由软件置位或清0。例如,可用作数
据的校验位或多机通信中表示地址帧/数据帧的标志位。在方式0和方式1中,该位不用.
RB8: 在方式2或方式3,是接收到的第9位数据,作为奇偶校验位或地址帧/数据帧的标志位。
方式0中不用RB8(置SM2=0). 方式1中也不用RB8(置SM2=0, RB8是接收到的停止位)。
TI: 发送中断请求标志位。在方式0,当串行发送数据第8位结束时,由内部硬件自动置位,
即TI=1,向主机请求中断,响应中断后TI必须用软件清零,即TI=0。在其他方式中,
则在停止位开始发送时由内部硬件置位,即TI=1,响应中断后TI必须用软件清零。
RI: 接收中断请求标志位。在方式0,当串行接收到第8位结束时由内部硬件自动置位RI=1,
向主机请求中断,响应中断后RI必须用软件清零,即RI=0。在其他方式中,串行接收
到停止位的中间时刻由内部硬件置位,即RI=1,向CPU发中断申请,响应中断后RI必须
由软件清零。
但是我们通常使用定时器1的工作模式2 (8位自动重装)来产生波特率,TL1作为脉冲计数寄存器,TH1作为自动重装寄存器,当计数到最大值溢出时,TH1会自动重装到TL1中
UART口的数据发送与接收
2. 串行口数据缓冲寄存器SBUF
STC15系列单片机的串行口1缓冲寄存器(SBUF)的地址是99H,实际是2个缓冲器,写SBUF
的操作完成待发送数据的加载,读SBUF的操作可获得已接收到的数据。两个操作分别对应两个
不同的寄存器,1个是只写寄存器,1个是只读寄存器。
串行通道内设有数据寄存器。在所有的串行通信方式中,在写入SBUF信号(MOV SBUF,A)
的控制下,把数据装入相同的9位移位寄存器,前面8位为数据字节,其最低位为移位寄存器的
输出位。根据不同的工作方式会自动将“1”或TB8的值装入移位寄存器的第9位,并进行发送.
串行通道的接收寄存器是一个输入移位寄存器。在方式0时它的字长为8位,其他方式时为
9位。当一帧接收完毕,移位寄存器中的数据字节装入串行数据缓冲器SBUF中,其第9位则装入
SCON寄存器中的RB8位。
如果由于SM2使得已接收到的数据无效时,RB8和SBUF中内容不变.由于接收通道内设有输入移位寄存器和SBUF缓冲器,从而能使一帧接收完将数据由移位
寄存器装入SBUF后,可立即开始接收下一帧信息,主机应在该帧接收结束前从SBUF缓冲器中
将数据取走,否则前一帧数据将丢失。SBUF以并行方式送往内部数据总线
也就是说串行口有两个缓冲寄存器都叫SBUF,一个是发送寄存器,一个是接收寄存器,这两个寄存器在物理结构上是独立的,但是他们的地址都是相同的
当是9位UART的时候,前八位是数据字节,后一位是移位寄存器的输出位,
在方式2或方式3时,如果SM2位为1且REN位为1,则接收机处于地址帧筛选状态。此时可以利用接收到的第9位(即RB8)来筛选地址帧
- 这个重叠的地址靠读/写指令区分:
串行发送时,CPU向SBUF写入数据,此时99H表示发送缓存SBUF
串口接收时,CPU向SBUF读出数据,此时99H表示接收缓冲SBUF
- 数据发送,把数据丢进SBUF后,内核会自动将数据发送出去,内容发生完成后,会将TI标志位置1
发送数据程序:SBUF= 数据/变量 如:SBUF= 0X58;
- 数据接收:内核从串口接收到一个完整的数据后,会将RI标志位置1,用户用SBUF直接读取即可
接收数据程序:变量 = SBUF; 如:dat = SBUF
对于异步8位UART并且允许接收:SCON = 0X50;
对于IAP15F2K61S2单片机,你还要对辅助寄存器AUXR(0x8e) 进行设置
这边先了解下辅助寄存器AUXR:
3. 辅助寄存器AUXR
辅助寄存器AUXR的格式及各位含义如下:
AUXR : 辅助寄存器 (不可位寻址)
SFR name | Address | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
---|---|---|---|---|---|---|---|---|---|
AUXR | 8EH | T0x12 | T1x12 | UART_M0x6 | T2R | T2_C/\(\overline{T}\) | T2x12 | EXTRAM | S1ST2 |
T0x12: 定时器0速度控制位
0, 定时器0是传统8051速度,12分频;
1, 定时器0的速度是传统8051的12倍,不分频
T1x12: 定时器1速度控制位
0, 定时器1是传统8051速度,12分频;
1, 定时器1的速度是传统8051的12倍,不分频
如果UART1/串口1用T1作为波特率发生器,则由T1x12决定UART1/串口是12T还是1T
UART_M0x6: 串口模式0的通信速度设置位。
0, 串口1模式0的速度是传统8051单片机串口的速度,12分频;
1, 串口1模式0的速度是传统8051单片机串口速度的6倍,2分频
T2R: 定时器2允许控制位
0, 不允许定时器2运行;
1, 允许定时器2运行
T2_C/T: 控制定时器2用作定时器或计数器。
0, 用作定时器(对内部系统时钟进行计数);
1, 用作计数器(对引脚T2/P3.1的外部脉冲进行计数)
T2x12: 定时器2速度控制位
0, 定时器2是传统8051速度,12分频;
1, 定时器2的速度是传统8051的12倍,不分频
如果串口1或串口2用T2作为波特率发生器,则由T2x12决定串口1或串口2是12T还是1T.
EXTRAM: 内部/外部RAM存取控制位
0, 允许使用逻辑上在片外、物理上在片内的扩展RAM;
1, 禁止使用逻辑上在片外、物理上在片内的扩展RAM
S1ST2: 串口1(UART1)选择定时器2作波特率发生器的控制位
0, 选择定时器1作为串口1(UART1)的波特率发生器;
1, 选择定时器2作为串口1(UART1)的波特率发生器,此时定时器1得到释放,可以作为
独立定时器使用
串口1可以选择定时器1做波特率发生器,也可以选择定时器2作为波特率发生器。当设置AUXR寄存器中的S1ST2位(串行口波特率选择位)为1时,串行口1选择定时器2作为波特率发生器,此时定时器1可以释放出来作为定时器/计数器/时钟输出使用.对于STC15系列单片机,串口2只能使用定时器2作为波特率发生器,不能够选择其他定时器作为其波特率发生器;而串口1默认选择定时器2作为其波特率发生器,也可以选择定时器1作为其波特率发生器;串口3默认选择定时器2作为其波特率发生器,也可以选择定时器3作为其波特率发生器;串口4默认选择定时器2作为其波特率发生器,也可以选择定时器4作为其波特率发生器。
#include <REGX52.H>
sfr AUXR = 0x8E;
unsigned char urdat;
void _74HC138(unsigned char n) {
switch(n) {
case 4: P2=(P2&0x1f) | 0x80;
break;
case 5: P2=(P2&0x1f) | 0xa0;
break;
case 6: P2=(P2&0x1f) | 0xc0;
break;
case 7: P2=(P2&0x1f) | 0xe0;
break;
}
}
void SytemInit(void) {
_74HC138(5);
P0 = 0X00;
_74HC138(4);
P0 = 0xFF;
}
void UART_Init(void) {
// 设置定时器1
TMOD = 0x20;
AUXR = 0x00;
// 串口方式1,允许串行口接收控制位
SCON = 0x50;
// 9600
// 波特率=( 2^SMOD/32 )×(定时器1的溢出率)
// 由于此时产生的是方式1的波特率,所以溢出率为
// 溢出率: fosc/12 * (1/(2^8)-TH1);
TH1 = 0xf9;
TL1 = 0xf9;
// 打开定时器1
TR1 = 1;
// 开启中断
ES = 1;
EA = 1;
}
void SendByte(unsigned char dat) {
SBUF = dat; // 将数据放到自动重装寄存器中
while(TI == 0); //当TI 不等于1 的时候,就给TI清零
TI = 0;
}
void SendString(unsigned char *str) {
while(*str != '\0')
SendByte(*str++);
}
void main(void) {
SytemInit();
UART_Init();
while(1);
}
void UART_Rountine (void) interrupt 4 {
if(RI == 1) {
// 接收内容
urdat = SBUF;
RI = 0;
_74HC138(4);
P0 = urdat;
// 发送内容
SendByte(urdat+1);
}
}