一、通信分为串行通信和并行通信
1.1、并行通信
并行通信通常是将数据字节的各位用多条数据线同时进行传送,每一位数据都需要一传输线
并行通信优点:
控制简单、相对传输速度快
并行通信优点:
传输线较多,长距离传送时成本高且收发方的各位同时接收存在困难。
1.2、串行通信
串行通信是将数据字节分成一位一位的形式在一条传输线上逐个地传送,此时只需要条数据线,外加一条公共信号地线和若干控制信号线。因为一次只能传送一位,所以对于个字节的数据,至少要分8位才能传送完毕
1.2.1、串行通信的必要过程
发送是将串行数据变成并行数据,接收时要把串行数据变成并行数据。
串行通信优点:
串行通信传输线少,长距离传送成本低,当然也可利用现成电话网等,
串行通信缺点:
数据的传送控制比并行通信复杂。
1.2.2、串行通信的两种方式
异步串行通信和同步串行通信
异步串行通信
异步串行通信指收发双方使用各自的时钟控制数据的接收和发送数据。收发双方的时钟尽可能一致,这样才能保证双方收发数据协调一致。
异步串行通信以字符为单位进行传输,字符之间的时间间隔是任意的,字符中的各位是以固定的时间传送,字符中存在位间隔的概念,既即发送下个位数据到上一个发送的位数据之间的时间间隔是发送一个位数据时间的n倍
异步通信字符信息包括: 起始位+数据位+奇偶校验位+停止位
同步串行通信
同步通信时发送方时钟要控制接收方的时钟,以达到完全同步。位之间存在位间隔,传输的字符间没有时间空隙。
1.2.3、串行通信的模式
- 单工:指数据传输仅能沿一个方向,不能实现反向传输
- 半双工:指数据传输可以沿两个方向,但需要分时进行
- 全双工: 指数据可以同时进行双向传输
1.2.4、串行通信的校验
- 奇偶校验:紧跟数据位的一位是校验位,如果是奇校验,数据位1的个数和校验位1的个数之后是奇数,同理偶校验和是偶数
- 代码和校验:发送方将数据各位的异或值放到校验位,接收方按照同样方式求异或和,并和校验位进行比较
- 循环冗余校验:通过数学运算进行循环校验
1.3、51单片机串口
波特率:单片机或计算机在串口通信时的速率,定义每秒传输二进制代码的位数,1波特= 1bps。
51单片机有一个全双工串行通信口,有两个相互独立的收发缓存器,都是SBUF,地址相同(99H),单片机的波特率由定时器/计数器产生,可以通过查询或中断的方式对收发数据进行处理。
51单片机有四种工作模式,由SCON和PCON两个寄存器进行控制
SCON:串行控制寄存器,可位寻址
PCON:电源控制寄存器,不可位寻址
当PCON中的SMOD0 = 0时,SCON中的SM0和SM1一起组成串行的四种工作模式。
SMOD控制波特率是否加倍
- SMOD=0:串口方式1,2,3 时,波特率正常
- SMOD=1:串口方式1,2,3 时,波特率加倍
1.3.1 波特率与定时器初值的计算
T1的溢出率就是定时器T1溢出的频率,计数满了自然会溢出,然后从头开始定时计数。
上图的中SYSclk 为系统晶振频率,通常为12MHZ或11.0592,当然还有6MHZ,频率越大,功耗越大,对于串品来说,用11.0592可以产生准备的值。用12MHZ会有一定的误差,累积到一定程度就会出问题。
定时器也有四种工作方式,由TMOD中的M1和M0进行控制
TMOD timer mode 不可位寻址
定时器1中M1和M0组合如下:
M1 | M0 | |
0 | 0 | 13位定时器/计数器,兼容8048定时模式,TL1只用低5位参与分频,TH1整个8位全用 |
0 | 1 | 16位定时器/计数器,TL1、TH1全用 |
1 | 0 | 8位自动重装载定时器,当溢出时将TH1存放的值自动重装入TL1 |
1 | 1 | 定时器/计数器1此时无效(停止计数) |
51单片机通常使用的波特率为9600bps,定时器1通常使用方式2,因为方式2是自动重装,如果使用其它方式可能会产生误差。在这种情况下,如何计算预装初值?
单片机时钟周期为1/11059200 s
单片机是12T模式,即一个机器周期=12时钟周期 = 12 / 11059200 s
定时器1在预装初值x的情况下,定时时间为(256 - x) * 12 / 11059200
定时器1工作方式2的溢出率为:1/ ((256 - x) * 12 / 11059200 )
由上图`串口工作模式`,工作方式1,可得9600 = (1/32)*11059200 /(256 - x) * 12
计算得x = 253, 也即TH1 = 253 ,TL1 = 253;
1.4、测试源码
#include "reg52.h"
#include <intrins.h>
sfr AUXR = 0x8E;
sbit led = P3^7;
void uart_init() {
AUXR = 0x01;
TMOD &= 0X0F;
TMOD |= 0X20;
SCON = 0X50;
TH1 = 0XFD;
TL1 = 0XFD;
TR1 = 1;
EA = 1;
ES = 1;
}
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void sendByte(char a) {
SBUF = a;
while(!TI);
TI = 0;
}
void sendString(char *a) {
char *p = a;
while(*p != '\0') {
sendByte(*p);
p ++;
}
}
void main() {
uart_init();
while(1) {
Delay1000ms();
sendString("hello, world\r\n");
}
}
void UART_Handle() interrupt 4 {
if(RI) {
RI = 0;
if(SBUF == 1) {
led = 0;
}
if(SBUF == 0) {
led = 1;
}
}
}
注意事项
- 1、在实际操作的过程中,串口向上位发送数据的时候,要配置sfr AUXR = 0x8E;否则会出现乱码。
- 2、如果未用中断函数,不要开始开启中断,否则会一直反复重启。