1.13.1.通信有关的常见概念
1.13.2.什么是串行通信
1.13.3.51单片机的串行通信
1.13.4.STC51的串行通信相关寄存器1
1.13.5.STC51的串行通信相关寄存器2
1.13.6.STC51的串行通信实战1
1.13.7.STC51的串行通信实战2
1.13.8.STC51的串行通信实战3
1.13.9.STC51的串行通信实战4
1.13.10.STC51的串行通信实战5
1.13.11.RS485介绍
本节课较为完整的给大家讲一下串口通信,本节课的学习会带领大家打开了通信的大门,对今后其他的有线/无线通信的学习会有帮助!
单片机学习三大重点:中断、定时器/计数器、串口通信
1.13.1.通信有关的常见概念
本节讲述了通信有关的基本概念,如通信的约定、编码传输、同步异步、电平信号差分信号等,这些基本概念对理解通信有很重要意义。
1.13.2.什么是串行通信
本节介绍串行通信的相关概念,如波特率、数据位、停止位、校验位等,这些概念是串行通信实验中必须掌握的。
1.13.3.51单片机的串行通信
本节讲述51单片机中的串行通信,重点是对STC51单片机中串行通信相关的数据手册部分的带读和讲解。
1.13.4.STC51的串行通信相关寄存器1
本节讲述STC51单片机中串口通信相关的寄存器
1.13.5.STC51的串行通信相关寄存器2
本节讲述STC51单片机中串口通信相关的寄存器
1.13.6.STC51的串行通信实战1
本节开始实战,首先是接线方式的分析和三种可行的接线方式的讲述。
1.13.7.STC51的串行通信实战2
本节接上节进行接线实战,使用官方测试代码对三种接线方法进行检测,先将整个环节打通以便后续实验时排除操作问题。
1.13.8.STC51的串行通信实战3
本节讲述串口的初始化,主要是各种寄存器位的设置。
1.13.9.STC51的串行通信实战4
本节继续串口的初始化,主要是波特率的计算方式、及相关寄存器的设置。
1.13.10.STC51的串行通信实战5
本节编写串口发送字符串函数,及使用中断方式进行串口的接收的编写。(串口中断)
1.13.11.RS485介绍
本节讲述RS485的诞生背景及其与UART的区别和联系,RS485的特点等,目的是让大家对远距离的差分串行通信有所了解,为将来项目中应用MODBUS等协议打下基础。
Linux串口编程
1.13.1.1、什么是通信
(1)人和人之间的通信:交谈、写信(滞后)、烽火、手势等 (发收双方+媒介)
(2)人和计算机之间的通信:按键、鼠标、触摸屏、显示器等 (以后会不会用脑电波来和计算机通信?)
(3)计算机和计算机之间的通信?有线、无线
咱们学习的所有的通信,都是计算机和计算机之间的通信:WiFi、Zigbee、SPI、I2C、GSM/GPRS.....,后面讲的通信都是指计算机和计算机的通信!
1.13.1.2、通信的关键
(1)事先约定(通信格式、速率、时间(同步)、编解码方式)
(2)基本信息单元(bit位/字节/数据包...):信息是基本信息单元的整数倍
(3)有效信息的编码、传输和解码(信息都是要编解码的,编码的原因是和传输信道有关的)
比如:你想发送“吃饭”,先编码成二进制,再成电平信号,解码是和编码对应的。
1.13.1.3、通信的专业性概念 参考串口通讯详解
1.串行和并行通信
(1)串行通信
一根数据线、一位一位地依次传输,每一位占用一个固定的时间长度!
优点:占用引脚资源少;
缺点:速度相对较慢。
(2)并行通信
多条数据线、多位同一时间、共同传输,多位一般是指:8/16/32位
优点:速度快;
缺点:占用引脚资源多。
2.异步和同步通信
(1)异步通信
优点:容易实现、不需要额外的数据开销、不容易出现数据错乱;
缺点:每个字符都要加起止位,传输效率低。
(2)同步通信
收发设备上方会使用一根信号线传输信号,在时钟信号驱动下双方进行协调,同步数据。例如,通讯中通常双方会统一规定在时钟信号的上升沿或者下降沿对数据线进行采样。
优点:通信效率高;
缺点:时钟允许误差小,稍稍时钟出错就可能导致数据错乱;
3.单工、半双工、全双工
4.电平信号和差分信号
电平信号和差分信号是用来描述通信线路传输方式的。也就是说如何在通信线路上表达 1 和 0.
1.13.1 中咱们讲了异步/同步通信、串行/并行通信、单工/双工/全双工通信,这三种通信组合起来就是多种通信方式,例如:UART(通用异步收发器):全双工异步串行通信
1.13.2.1、串口通信基础
串口通信分为很多种,像串行通信、RS-232、RS-422和RS-485、USB.....
(1)串行通信:一种特定的通信协议,早期发明的时候没有起名字,所以这种通信协议就叫做串行通信!USB这种按理说也属于串行通信,只不过现在单独拿出来讲了!
(2)以后看见这几个词:串行通信、串口通信、UART、USART,说的都是串行通信
台式机现在还在保留的DB9串行接口!
(3)常见的串行通信接口
这节课说的串口通信就是异步、串行、全双工,也就是UART这种串行通信
1.13.2.2、串行通信的主要用途
(1)早期:计算机之间短距离通信(15米内),不能做长距离的通信。属于完备通信机制(会考虑到很多的因素,有一个完备的协议规定)
优点:数据不易出错
缺点:传输太慢,考虑的太多!所以现在通信都是用USB 3.0和网络!
(2)现在:CPU之间近距离通信、调试信息输入输出,非完备通信(现在因为不用来做重要通信,所以像速率协商、校验都去掉了)
1.13.2.3、串行通信的工作方式
(1)3根线(GND、RxD、TxD)和9根线(DB9)
R(receive),T(transmit),GND是用来提供参考电平的。没有了校验、调制...功能
用RS232的原因:
单片机芯片串口和 PC机rs232 的电平标准是不一样的:
现在9线基本上被淘汰了,就算你看到有9线的,也可能只用了其中的3根线,像下面这种。所以现在基本上都是3线的了!
(2)数据的发送和接收
(3)数据处理
数据在发送方和接收方的CPU中都以字节为单位整字节处理
举例:传输大写字母A
1.13.2.4、串行通信的主要概念
下面这些都是串口的初始化设置,通信之前双方都约定好!
帧:
- 比特率:每秒钟传输二进制代码的位数,单位是:位/秒( bps)
-例如:每秒钟传送 240 个字符,而每个字符格式包含 10 位(1 个起始位、1 个停止位、8 个数据位),这时的比特率为:10 位×240 个/秒 = 2400 bps
波特率:每秒钟传输多少码元,比特率=波特率*log2(码元状态)
-例如:如果在通信传输中,有 0V、 2V、4V 以及 6V 分别表示二进制数 00、 01、 10、 11,那么每个码元可以表示四种状态,即两个二进制比特位,此时波特率是比特率的一半。
常见的通信码元都是两种状态,所以波特率就等于比特率,常见的有常用的波特率有 4800bps、9600bps、115200bps等。
RS232一般遵循“ 96-N-8-1”原则:9600波特率、N无校验位、8位数据位、1位停止位
1.13.3.1、先搞清楚以下问题
(1)串行通信功能是SoC的一个内部外设提供的,与CPU本身无关,CPU只是处理通信的数据运算+控制!
串口通信靠的是串行模块!
(2)各种不同SoC的串行通信大同小异
不要想着同时学会各种单片机的串行通信,先学会STC51的
(3)串行通信经常作为主控SoC与其他外部芯片之间的通信接口
这个好理解吧,上面芯片和芯片可以通信,芯片和PC可以通信。
1.13.3.2、STC51单片机的串行通信简介
数据手册
1.13.4.1、总体浏览
1.13.4.2、SCON 串行控制寄存器
SM0/FE:当SMOD0/PCON.6 = 1时,用作FE:帧错误检测;(硬件自动控制)
当SMOD0/PCON.6 = 0时,用作SM0,和SM1共同指定串行通信工作方式:
1.13.4.3、串口发送时的软硬件协作方式
(1)查询方式(polling)
硬件在发送完一帧数据后会将一个标志位置位(标志位本来是0)。软件需要不断读取这个标志位的值来判断硬件是否完成了发送(如果读出来是0就表示硬件还在发还没完还在忙,软件就等待;如果读出来的是1则说明硬件已经发完了上一帧数据,这时候软件就给硬件发送一帧数据)。
因为串口发送完这个事件对CPU来说是个异步事件,所以这里查询方式来处理和之前讲过的查询方式处理按键是非常类似的。
(2)中断方式。(interrupt)
查询方式处理的劣势是CPU必须一直守着串口发送,在串口发送完所有字节之前CPU不能离开去做别的事情,这对CPU来说是极大的浪费(因此CPU的速度比串口发送的速度快多了)。因此用中断方式来处理串口发送是非常合适的,可以提升CPU使用率。
(3)常见情况下:串口发送会使用查询方式,而串口接收只能使用中断方式。
1.13.4.4、PCON 电源控制寄存器
(1)SMOD:波特率倍增位。
(2)所谓波特率加倍,就是正常计算出的波特率假设是2400,那么SMOD=1时则实际的波特率就是4800;当SMOD=0时不加倍,也就是2400还是2400.
则我们最后初始化以下SCON和PCON
REN:= 1,允许串口接收数据;= 0,禁止串口接收数据;
SMO:= 1,方式1、2、3波特率加倍;= 0,方式1、2、3波特率不加倍!
SCON:
0x40:不接收数据
0x50:接收数据
PCON:
0x00:波特率不加倍
0x80:波特率加倍
1.13.5.1、SBUF
是2个缓冲器,写SBUF的操作完成待发送数据的加载,读SBUF的操作可获得已接收到的数据。两个操作分别对应两个不同的寄存器,1个是只写寄存器,1个是只读寄存器。
1.13.5.2、IE
ES、EA是串口中断的使能寄存器。
ET1可用于后面的定时器/计数器,涉及到波特率的计算。
波特率怎么算呢??上面串口的工作模式那里提到过!代公式就行呗!
方式 1 的波特率 =(2^SMOD/32)*(T1 溢出率)
T1溢出率 = fosc /{12×[256 -TH1]}
fosc为外部晶振的频率可以用51 波特率初值设定.exe 小工具来算!
1.13.5.3、IPH&IP
目标:将PC机与51单片机通过串口连接起来,目的是51单片机和PC机的串口工具收发数据!
1.13.6.1、硬件接线分析
(1)PC机的串口情况:台式机串口(DB9/USB转串口)、笔记本USB转串口(笔记本里面有个芯片
(2)开发板原理图分析
1.13.6.2、接线方案
(1)使用板载CH340G,也就是直接用单片机的USB(最推荐),单片机默认跳线帽
(2)使用DB9接口USB转串口线:用DB9接口的USB转串口线、注意跳线帽接到DB9一侧
(3)使用TTL接口USB转串口线:只接三根线:TxD、RxD、GND
可以直接拿我们的电脑和P3.0、TxD、GND接起来通信,但是电脑这边不太好弄,还需要买一个USB转TTL的线!
1.13.7.1、使用板载CH340进行串口实践
(1)接线+下载程序
检查下跳线帽。接线就是电源线呗,插在USB上。
(2)查设备管理器确定COM号
hex文件路径:\8.serial\发送数据\程序\pro.hex
程序功能:单片机通过串口给PC机的串口助手发送“普中科技有限公司”
波特率设置为4800、N-8-1
(3)使用普中下载软件自带的串口助手监视
(4)使用第三方串口助手软件监视
1.13.7.2、使用DB9接口USB转串口线
(1)接线+跳线帽调整
现在USB就不能下载了!
(2)注意对下载程序的影响
不管跳线帽如何,串口助手都会有数据显示!
(3)使用各种方式进行监视
- 串口初始化
T1工作模式
串口工作模式
波特率计算- 串口发送函数
- 串口接收函数
1.13.8.1、串口初始化函数
预设条件:48-N-8-1 :4800波特率、N无校验位、8位数据位、1位停止位
初始化的主要工作:就是去设置相关的寄存器
①确定串口工作方式(SCON 寄存器);
②确定 T1 的工作方式(TMOD 寄存器):T1的工作方式的选择去看手册:8.3 P195
选择自动重载模式 why?
TL1 的溢出不仅置位 TF1 ,而且将 TH1 内容重新装入 TL1 , TH1 内容由软件预置,重装时 TH1 内容不变。
TMOD = 0x20;//工作方式2
③计算 T1 的初值(设定波特率),装载 TH1、TL1;
④启动 T1(TCON 中的 TR1 位);
⑤如果使用中断,需开启串口中断控制位(IE 寄存器)。
void uart_init(void)
{
//波特率加倍
SCON = 0x50; //串口工作方式1
PCON = 0x80; //加倍之后,波特率计算用2400就可以
//波特率计算
TMOD = 0x20; //T1设置为工作方式2
TH1 = 0xF3; //波特率为2400
TL1 = 0xF3;
ET1 = 1; //T1使能
ES = 1; //串口使能
EA = 1; //中断总开关
TR1 = 1; //开始计数
}
1.13.9.1、波特率计算
方式 1 的波特率 =(2^SMOD/32)*(T1 溢出率)
T1溢出率 = fosc /{12×[256 -TH1]}
fosc为外部晶振的频率可以用51 波特率初值设定.exe 小工具来算!
1.13.10.1、串口发送字符
1.13.10.2、串口发送字符串
#include
void uart_init(void);
void uart_send_byte(unsigned char c);
void uart_send_str(unsigned char *str);
void delay();
void main()
{
uart_init();
while(1)
{
uart_send_byte('A');
uart_send_str("对不起,大家久等了");
delay();
}
}
//4800,N,8,1
void uart_init(void)
{
//波特率加倍
SCON = 0x50; //选择串口工作方式1,并且允许接受数据
PCON = 0x80; //要加倍,后面波特率设置成2400就行
TMOD = 0x20; //定时器方式2
TH1 = 0xF3;
TL1 = 0xF3; //4800/2
EA = 1;
TR1 = 1;
}
void uart_send_byte(unsigned char c)
{
SBUF = c;
while(!TI);
TI = 0;
}
void uart_send_str(unsigned char *str)
{
while(*str != '\0'){
uart_send_byte(*str);
str++;
}
}
void delay()
{
unsigned char i=100,j=100;
while(i--)
while(j--);
}
1.13.10.2、串口接收函数编写,需要用中断
ET1 = 1;
中断处理函数,见手册:
void uart_isr(void) interrupt 4 using 1
{
unsigned char tmp;
if (RI)
{
tmp = SBUF; // 读取SBUF,其实就是读出了串口接收到的1字节
RI = 0;
}
// 至此已经读到了PC发给单片机的1个字节,但是单片机没有显示器没法显示
// 给人看。
// 我们这里用一个最简单的方法来测试,就是直接回发
uart_send_byte(tmp);
}
完整代码:
#include
void uart_init(void);
void uart_send_byte(unsigned char c);
void uart_send_str(unsigned char *str);
void delay();
void main()
{
uart_init();
while(1);
// while(1)
// {
// uart_send_byte('A');
// uart_send_str("对不起,大家久等了");
// delay();
// }
}
//4800,N,8,1
void uart_init(void)
{
//波特率加倍
SCON = 0x50; //选择串口工作方式1,并且允许接受数据
PCON = 0x80; //要加倍,后面波特率设置成2400就行
TMOD = 0x20; //定时器方式2
TH1 = 0xF3;
TL1 = 0xF3; //4800/2
ES = 1;
EA = 1;
TR1 = 1;
}
void uart_send_byte(unsigned char c)
{
SBUF = c;
while(!TI);
TI = 0;
}
void uart_send_str(unsigned char *str)
{
while(*str != '\0'){
uart_send_byte(*str);
str++;
}
}
void delay()
{
unsigned char i=100,j=100;
while(i--)
while(j--);
}
//串口中断服务程序
void uart_isr(void) interrupt 4 using 1
{
unsigned char tmp;
unsigned char k ;
if(RI)
{
tmp = SBUF;
RI = 0;
}
}
1.13.11.1、UART的缺点:传输距离受限
(1)理论上RS232不超过15米
(2)理论上TTL电平通信距离更短
(3)实际上几百米也有人宣称做到了,但是稳定性不能保证
(4)波特率越高通信距离越近:最常用:9600/115200
1.13.11.2、远距离传输怎么办?
(1)提高电压标准
(2)提高通信线抗干扰能力、降低阻抗(加绝缘层/加网丝/采用平衡驱动器)
(3)使用差分信号
1.13.11.3、RS485(RS422)
RS232 是全双工点对点的通信
而 RS485 是半双工通信(2 线制),可以一对多点进行组网
特点:
(1)接口电平低,不易损坏芯片:
(2)传输速率高。
(3)抗干扰能力强
(4)传输距离远,支持节点多
(5)差分信号负逻辑、半双工、只提供物理层通信能力,不提供数据链路层协议,需要用户自定义,或者使用标准协议如MODBUS协议。
485连线图
1.13.11.4、MAX485介绍
接线分析:
P1.0接RE,当P1.0为0时,为接收模式;当P1.0为1时为发送模式!
P3.0(TXD)接RXD2,P3.1(RXD)接TXD2;
和之前程序相比,只需要增加一位RS485_RE来控制接收还是输出就可以了,代码如下!
#include "reg52.h"
typedef unsigned int u16;
typedef unsigned char u8;
sbit RS485DIR=P1^0; //RS485DIR=0为接收状态 RS485DIR=1为发送状态
void delay(u16 i)
{
while(i--);
}
void UsartInit()
{
SCON=0X50; //设置为工作方式 1
TMOD=0X20; //设置计数器工作方式 2
PCON=0X80; //波特率加倍
TH1=0XF3; //计数器初始值设置,注意波特率是 4800 的
TL1=0XF3;
ES=1; //打开接收中断
EA=1; //打开总中断
TR1=1; //打开计数器
RS485DIR=0;
}
void main()
{
UsartInit(); // 串口初始化
while(1);
}
void Usart() interrupt 4
{
u8 receiveData;
if(RI)
{
receiveData=SBUF;//出去接收到的数据
RI = 0;//清除接收中断标志位
delay(100);
}
RS485DIR=1;
SBUF=receiveData;//将接收到的数据放入到发送寄存器
while(!TI); //等待发送数据完成
TI=0; //清除发送完成标志位
RS485DIR=0;
}
本节课程序下载链接:串口通信
本节课结束!