串口通信和I2C

串口通信

通信的基本概念

  通信是一种以 数据通信 形式出现,在 计算机 与计算机之间或计算机与终端设备之间进行信息传递的方式。
  按照数据传送方式可分为串行通信和并行通信。按照通信的数据同步方式,可分为异同通信和同步通信。按照数据的传输方向又可分为单工、半双工和全双工通信。

串行通信与并行通信

串行通信

  串行通信是指使用一条数据线,将数据一位一位地依次传输,每一位数据占据一个固定的时间长度。其只需要少数几条线就可以在系统间交换信息,特别适用于计算机与计算机、计算机与外设之间的远距离通信。
在这里插入图片描述

  串行通信的特点:传输线少,长距离传送时成本低,且可以利用电话网等现成的设备,但数据的传送控制比并行通信复杂。

并行通信

  并行通信通常是将数据字节的各位用多条数据线同时进行传送,通常是 8位、16 位、32 位等数据一起传输。
在这里插入图片描述

  并行通信的特点:控制简单、传输速度快;由于传输线较多,长距离传送时成本高且接收方的各位同时接收存在困难,抗干扰能力差。

异步通信与同步通信

异步通信

  异步通信是指通信的发送与接收设备使用各自的时钟控制数据的发送和接收过程。为使双方的收发协调,要求发送和接收设备的时钟尽可能一致。
  异步通信是以字符(构成的帧)为单位进行传输,字符与字符之间的间隙(时间间隔)是任意的,但每个字符中的各位是以固定的时间传送的,即字符之间不一定有“位间隔”的整数倍的关系,但同一字符内的各位之间的距离均为"位间隔"的整数倍。
在这里插入图片描述
在这里插入图片描述

  异步通信的特点:不要求收发双方时钟的严格一致,实现容易,设备开销较小,但每个字符要附加 2~3 位用于起止位,各帧之间还有间隔,因此传输效率不高。

同步通信

  同步通信时要建立发送方时钟对接收方时钟的直接控制,使双方达到完全同步。此时,传输数据的位之间的距离均为“位间隔”的整数倍,同时传送的字符间不留间隙,即保持位同步关系,也保持字符同步关系。发送方对接收方的同步可以通过两种方法实现。如下图所示:
在这里插入图片描述

单工、半双工与全双工通信

单工

  单工是指数据传输仅能沿一个方向,不能实现反向传输。
在这里插入图片描述

半双工

  半双工是指数据传输可以沿两个方向,但需要分时进行。
在这里插入图片描述

全双工

  全双工是指数据可以同时进行双向传输。
在这里插入图片描述

通信速率

  通常以比特率(Bitrate)来表示。比特率是每秒钟传输二进制代码的位数,单位是:位/秒( bps)。如每秒钟传送 240 个字符,而每个字符格式包含 10 位(1 个起始位、1 个停止位、8 个数据位),这时的比特率为:10 位×240 个/秒 = 2400 bps
  波特率表示每秒钟传输了多少个码元。而码元是通信信号调制的概念,通信中常用时间间隔相同的符号来表示一个二进制数字,这样的信号称为码元。如常见的通信传输中,用 0V 表示数字 0,5V 表示数字 1,那么一个码元可以表示两种状态 0 和 1,所以一个码元等于一个二进制比特位,此时波特率的大小与比特率一致;如果在通信传输中,有 0V、 2V、4V 以及 6V 分别表示二进制数 00、 01、 10、 11,那么每个码元可以表示四种状态,即两个二进制比特位,所以码元数是二进制比特位数的一半,这个时候的波特率为比特率的一半。由于很多常见的通信中一个码元都是表示两种状态,所以我们常常直接以波特率来表示比特率。

串口通信简介

接口标准

  串口通信(Serial Communication),是指外设和计算机间通过数据信号线、地线等按位进行传输数据的一种通信方式,属于串行通信方式。串口是一种接口标准,它规定了接口的电气标准,没有规定接口插件电缆以及使用的协议。
  串口通信的接口标准有很多,有 RS-232C、 RS-232、 RS-422A、 RS-485 等。常用的是 RS-232 和 RS-485。RS-232 其实是 RS-232C 的改进,原理是一样的。这里我们就以 RS-232C 接口进行讲解。
  RS-232C 是 EIA(美国电子工业协会)1969 年修订 RS-232C 标准。RS-232C定义了数据终端设备(DTE)与数据通信设备(DCE)之间的物理接口标准。
  RS-232C 接口规定使用 25 针连接器,简称 DB25,连接器的尺寸及每个插针的排列位置都有明确的定义,如下图所示:
在这里插入图片描述

  RS-232C 还有一种 9 针的非标准连接器接口,简称 DB9。串口通信使用的大多都是 DB9 接口。DB25 和 DB9 接头有公头和母头之分,其中带针状的接头是公头,而带孔状的接头是母头。9 针串口线的外观图如下图所示:
在这里插入图片描述
在这里插入图片描述

  通常我们只使用 2、3、5 三个管脚,即 TXD、RXD、SGND
  RS-232C 对逻辑电平也做了规定,如下:
在 TXD 和 RXD 数据线上:

  1. 逻辑 1 为-3~-15V 的电压
  2. 逻辑 0 为 3~15V 的电压

在 RTS、CTS、DSR、DTR 和 DCD 等控制线上:

  1. 信号有效( ON 状态) 为 3~15V 的电压
  2. 信号无效( OFF 状态) 为-3~-15V 的电压

  由此可见,RS-232C 是用正负电压来表示逻辑状态,与晶体管-晶体管逻辑集成电路(TTL)以高低电平表示逻辑状态的规定正好相反。而我们 51 单片机使用的就是 TTL 电平,所以要实现 51 单片机与计算机的串口通信,需要进行 TTL与 RS-232C 电平转换,通常使用的电平转换芯片是MAX232。
  在串口通信中通常 PC 机的 DB9 为公头,单片机上使用的串口 DB9 为母头,通过一根直通串口线进行相连。在 9 针串口线实物图即为直通型串口线,串口线(COM)母头连接计算机 DB9 的公头,串口线公头连接单片机上使用的 DB9 母头,这样就是将 2、3、5 管脚直接相连。如果你要实现两台计算机串口通信,那么就需要一根交叉串口线,将 2 对 3、3 对 2、5 对 5 连接,交叉串口线一般两头都是母头。
  串口通信中还需要注意的是,串口数据收发线要交叉连接,计算机的 TXD要对应单片机的 RXD,计算机的 RXD 要对应单片机的 TXD,并且共 GND,如下图:
在这里插入图片描述

  前面我们说了单片机处理的是 TTL电平,需要使用 RS232 电平转换芯片,将 RS232 电平转换芯片串行数据输出管脚交叉连接在 DB9 母头上即可。

通信协议

  RS232 的通信协议比较简单,通常遵循 96-N-8-1 格式。
  “96”表示的是通信波特率为 9600。串口通信中通常使用的是异步串口通信,即没有时钟线,所以两个设备要通信,必须要保持一致的波特率,当然,波特率常用值还有 4800、 115200 等。
  “N”表示的是无校验位,由于串口通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、0 校验(space)、1 校验(mark)以及无校验(noparity)。
  “8”表示的是数据位数为 8 位,其数据格式在前面介绍异步通信中已讲过。当然数据位数还可以为 5、6、7 位长度。
  “1”表示的是 1 位停止位,串口通讯的一个数据包从起始信号开始,直到停止信号结束。数据包的起始信号由一个逻辑 0 的数据位表示,而数据包的停止信号可由 0.5、1、1.5 或 2 个逻辑 1 的数据位表示,只要双方约定一致即可。

串口内部结构

在这里插入图片描述

  上图中右边的 TXD 和 RXD 为单片机 IO 口,TXD 对应的是 P3.1 管脚,RXD 对应的是 P3.0 管脚。其内部工作方式在后面小节会介绍。

串口相关寄存器

串口控制寄存器 SCON

在这里插入图片描述

  SM0 和 SM1 为工作方式选择位:
在这里插入图片描述

  SM2:多机通信控制位,主要用于方式 2 和方式 3。当 SM2=1 时可以利用收到的 RB8 来控制是否激活 RI(RB8=0 时不激活 RI,收到的信息丢弃;RB8=1 时收到的数据进入 SBUF,并激活 RI,进而在中断服务中将数据从 SBUF 读走)。当SM2=0 时,不论收到的 RB8 为 0 和 1,均可以使收到的数据进入 SBUF,并激活 RI(即此时 RB8 不具有控制 RI 激活的功能)。通过控制 SM2,可以实现多机通信。
  REN:允许串行接收位。由软件置 REN=1,则启动串行口接收数据;若软件置
REN=0,则禁止接收。
  TB8:在方式 2 或方式 3 中,是发送数据的第 9 位,可以用软件规定其作用。可以用作数据的奇偶校验位,或在多机通信中,作为地址帧/数据帧的标志位。在方式 0 和方式 1 中,该位未用到。
  RB8:在方式 2 或方式 3 中,是接收到数据的第 9 位,作为奇偶校验位或地址帧/数据帧的标志位。在方式 1 时,若 SM2=0,则 RB8 是接收到的停止位。
  TI:发送中断标志位。在方式 0 时,当串行发送第 8 位数据结束时,或在其它方式,串行发送停止位的开始时,由内部硬件使 TI 置 1,向 CPU 发中断申请。在中断服务程序中,必须用软件将其清 0,取消此中断申请。
  RI:接收中断标志位。在方式 0 时,当串行接收第 8 位数据结束时,或在其它方式,串行接收停止位的中间时,由内部硬件使 RI 置 1,向 CPU 发中断申请。也必须在中断服务程序中,用软件将其清 0,取消此中断申请。

电源控制寄存器 PCON

  SMOD:波特率倍增位。在串口方式 1、方式 2、方式 3 时,波特率与 SMOD 有关,当 SMOD=1 时,波特率提高一倍。复位时,SMOD=0。

串口工作方式

方式 0

  方式 0 时,串行口为同步移位寄存器的输入输出方式。主要用于扩展并行输入或输出口。数据由 RXD(P3.0)引脚输入或输出,同步移位脉冲由 TXD(P3.1)引脚输出。发送和接收均为 8 位数据,低位在先,高位在后。波特率固定为fosc/12。对应的输入输出时序图如下所示:

①方式 0 输出
在这里插入图片描述

②方式 0 输入
在这里插入图片描述

方式 1

  方式 1 是 10 位数据的异步通信口。TXD 为数据发送引脚,RXD 为数据接收引脚,传送一帧数据的格式如下所示。其中 1 位起始位,8 位数据位,1 位停止位。
在这里插入图片描述

对应的输入输出时序图如下所示:
①方式 1 输出
在这里插入图片描述

②方式 1 输入
在这里插入图片描述

  用软件置 REN 为 1 时,接收器以所选择波特率的 16 倍速率采样 RXD 引脚电平,检测到 RXD 引脚输入电平发生负跳变时,则说明起始位有效,将其移入输入移位寄存器,并开始接收这一帧信息的其余位。接收过程中,数据从输入移位寄存器右边移入,起始位移至输入移位寄存器最左边时,控制电路进行最后一次移位。当 RI=0,且 SM2=0(或接收到的停止位为 1)时,将接收到的 9 位数据的前8 位数据装入接收 SBUF,第 9 位(停止位)进入 RB8,并置 RI=1,向 CPU 请求中断。

方式 2 和方式 3

  方式 2 或方式 3 时为 11 位数据的异步通信口。TXD 为数据发送引脚,RXD 为数据接收引脚。其数据格式如下所示:
对应的输入输出时序图如下所示:
在这里插入图片描述

①方式 2、方式 3 输出
在这里插入图片描述

  发送开始时,先把起始位 0 输出到 TXD 引脚,然后发送移位寄存器的输出位(D0)到 TXD 引脚。每一个移位脉冲都使输出移位寄存器的各位右移一位,并由TXD 引脚输出。第一次移位时,停止位“1”移入输出移位寄存器的第 9 位上,以后每次移位,左边都移入 0。当停止位移至输出位时,左边其余位全为 0,检测电路检测到这一条件时,使控制电路进行最后一次移位,并置 TI=1,向 CPU请求中断。
②方式 2、方式 3 输入
在这里插入图片描述

  接收时,数据从右边移入输入移位寄存器,在起始位 0 移到最左边时,控制电路进行最后一次移位。当 RI=0,且 SM2=0(或接收到的第 9 位数据为 1)时,接收到的数据装入接收缓冲器 SBUF 和 RB8(接收数据的第 9 位),置 RI=1,向CPU 请求中断。如果条件不满足,则数据丢失,且不置位 RI,继续搜索 RXD 引脚的负跳变。

串口的使用方法

(1)如何计算波特率
  以下列出了几种方式下波特率的计算公式:
方式 0 的波特率 = fosc/12
方式 2 的波特率 =(2SMOD/64)· fosc
方式 1 的波特率 =(2SMOD/32)·(T1 溢出率)
方式 3 的波特率 =(2SMOD/32)·(T1 溢出率)
其中 T1 溢出率 = fosc /{12×[256 -(TH1)]}
在使用串口通信时,定时器 1 工作方式为 2,
串口工作方式为 1,以开发板晶振是 11.0592Mh 为例,假如晶振频率是 12M。

串口初始化步骤

  如何使用串口,大家可以按照以下几个步骤配置。
①确定 T1 的工作方式(TMOD 寄存器);
②确定串口工作方式(SCON 寄存器);
③计算 T1 的初值(设定波特率),装载 TH1、TL1;
④启动 T1(TCON 中的 TR1 位);
⑤如果使用中断,需开启串口中断控制位(IE 寄存器)。
  设置串口为工作方式 1、波特率为 9600、波特率加倍、使用中断。其配置程序如下:

#include <REGX52.H>
#include "delay.h"

void uart_init()
{
    TMOD|=0x20;//设置计数器工作方式为2 8位重载定时器
    SCON=0x50;//设置串口的工作方式为1
    PCON=0x80;         //设置波特率加倍
    TH1=0xFA;//计算器重载值
    TL1=0xFA; //计数器初值
    ES=1;//打开串口中断
    EA=1;//打开总中断
    TR1=1; //打开计数器
}

void main()
{
	uart_init();
    while(1);
}
void uart_isr() interrupt 4
{
    unsigned char rec_data;
    RI=0;//清除接收中断,继续接收数据
    rec_data=SBUF;//接收数据RX引脚
    SBUF=rec_data; //发送数据TX引脚
    while(!TI){};//当TI=1时数据发送完成
    TI=0;
}
查看程序的运行需要串口调试助手

程序运行结果如下:
在这里插入图片描述

硬件设计

开发板上板载一个 USB 转串口模块。其硬件电路如下所示:
在这里插入图片描述

  从上图中可以看出,通过 CH340 芯片把 51 单片机的串口与 PC 机的 USB 口进行连接,不仅可以实现程序的烧入,还可实现串口通信功能。根据前面介绍,串口通信需将数据收发管脚交叉连接,所以可以看到在 CH340 芯片的 2 和 3 脚已做处理。电路中其他部分是自动下载电路部分,目的是控制单片机的电源,无需冷启动。使用 USB 转串口芯片,免去了一根串口线,使用普通 USB 数据线(支持安卓手机数据线)就可以进行串口通信。
  从上图中可以看到 CH340 的 2、3 脚串口并非直接连接到单片机串口,而是连接在 P5 端子上,这样就把 CH340 的串口与单片机串口独立出来,为什么不直接连接而要使用这个 P5 端子呢?这是方便用户可以使用开发板上的 USB 转 TTL模块(也就是 CH340 转串口模块)做一些串口类模块的调试,比如:WIFI、蓝牙、GPS、GPRS 等,直接利用 PC 上位机来调试模块。同时也方便用户使用板载 USB转 TTL 模块给其它类型单片机下载程序。如果使用黄色跳线帽将 P5 端子的 1、2 短接,3、4 短接,那么 CH340 串口与单片机串口是连接一起的,此时即可实现程序的下载或串口通信。

I2C

I2C介绍

  I2C(Inter-Integrated Circuit)总线是由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。是微电子通信控制领域广泛采用的一种总线标准。它是同步通信的一种特殊形式,具有接口线少,控制方式简单,器件封装形式小,通信速率较高等优点。I2C 总线只有两根双向信号线。一根是数据线 SDA,另一根是时钟线 SCL。由于其管脚少,硬件实现简单,可扩展性强等特点,因此被广泛的使用在各大集成芯片内。

I2C 物理层

I2C 通信设备常用的连接方式如下图所示:
在这里插入图片描述

它的物理层有如下特点:
(1)它是一个支持多设备的总线。“总线”指多个设备共用的信号线。在
一个 I2C 通讯总线中,可连接多个 I2C 通讯设备,支持多个通讯主机及多个通
讯从机。
(2)一个 I2C 总线只使用两条总线线路,一条双向串行数据线(SDA),一
条串行时钟线(SCL)。数据线即用来表示数据,时钟线用于数据收发同步。
(3)每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址
进行不同设备之间的访问。
(4)总线通过上拉电阻接到电源。当 I2C 设备空闲时,会输出高阻态,而
当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。
(5)多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定
由哪个设备占用总线。
(6)具有三种传输模式:标准模式传输速率为 100kbit/s,快速模式为
400kbit/s,高速模式下可达 3.4Mbit/s,但目前大多 I2C 设备尚不支持高速模
式。
(7)连接到相同总线的 IC 数量受到总线的最大电容 400pF 限制。
下面我们来了解下 I2C 总线常用的一些术语:
  主机:启动数据传送并产生时钟信号的设备;
  从机:被主机寻址的器件;
  多主机:同时有多于一个主机尝试控制总线但不破坏传输;
  主模式:用 I2CNDAT 支持自动字节计数的模式; 位 I2CRM,I2CSTT,I2CSTP控制数据的接收和发送;
  从模式:发送和接收操作都是由 I2C 模块自动控制的;
  仲裁:是一个在有多个主机同时尝试控制总线但只允许其中一个控制总线并使传输不被破坏的过程;
  同步:两个或多个器件同步时钟信号的过程;
  发送器:发送数据到总线的器件;
  接收器:从总线接收数据的器件。

I2C 协议层

  I2C 的协议定义了通信的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环节。

数据有效性规定

  I2C 总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
在这里插入图片描述

  每次数据传输都以字节为单位,每次传输的字节数不受限制。

起始和停止信号

  SCL 线为高电平期间,SDA 线由高电平向低电平的变化表示起始信号;SCL线为高电平期间,SDA 线由低电平向高电平的变化表示终止信号。
在这里插入图片描述

  起始和终止信号都是由主机发出的,在起始信号产生后,总线就处于被占用的状态;在终止信号产生后,总线就处于空闲状态。
起始信号代码实现

void iic_start()
{
    IIC_SDA =1;
    delay_10us(1);
    IIC_SCL =1;
    delay_10us(1);
    IIC_SDA=0;
    delay_10us(1);
    IIC_SCL =0;
    delay_10us(1);
}

终止信号代码实现

void iic_stop()
{
    IIC_SDA=0;
    delay_10us(1);
    IIC_SCL=1;
    delay_10us(1);
    IIC_SDA=1;
    delay_10us(1);
}

应答响应

  每当发送器件传输完一个字节的数据后,后面必须紧跟一个校验位,这个校验位是接收端通过控制 SDA(数据线)来实现的,以提醒发送端数据我这边已经接收完成,数据传送可以继续进行。这个校验位其实就是数据或地址传输过程中的响应。响应包括“应答(ACK)”和“非应答(NACK)”两种信号。作为数据接收端时,当设备(无论主从机)接收到 I2C 传输的一个字节数据或地址后,若希望对方继续发送数据,则需要向对方发送“应答(ACK)”信号即特定的低电平脉冲,发送方会继续发送下一个数据;若接收端希望结束数据传输,则向对方发送“非应答(NACK)”信号即特定的高电平脉冲,发送方接收到该信号后会产生一个停止信号,结束信号传输。
在这里插入图片描述

  每一个字节必须保证是 8 位长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有 9 位)。
  由于某种原因从机不对主机寻址信号应答时(如从机正在进行实时性的处理工作而无法接收总线上的数据),它必须将数据线置于高电平,而由主机产生一个终止信号以结束总线的数据传送。
  如果从机对主机进行了应答,但在数据传送一段时间后无法继续接收更多的数据时,从机可以通过对无法接收的第一个数据字节的“非应答”通知主机,主机则应发出终止信号以结束数据的继续传送。
  当主机接收数据时,它收到最后一个数据字节后,必须向从机发出一个结束传送的信号。这个信号是由对从机的“非应答”来实现的。然后,从机释放 SDA线,以允许主机产生终止信号。这些信号中,起始信号是必需的,结束信号和应答信号都可以不要。
代码实现

应答信号
void iic_ack()
{
    IIC_SCL=0;
    IIC_SDA=0;
    delay_10us(1);
    IIC_SCL=1;
    delay_10us(1);      // 读数据
    IIC_SCL=0;
}

非应答信号
void iic_nack()
{
    IIC_SCL=0;
    IIC_SDA=1;
    delay_10us(1);
    IIC_SCL=1;
    delay_10us(1);      // 读数据
    IIC_SCL=0;
}

等待答应

void iic_wait_ack()
{
    unsigned char time = 0;
    IIC_SCL=1;
    delay_10us(1);
    while(IIC_SDA)      // 如果是低电平,等待
    {
        time++;
        if(time>1000)
        {
            iic_stop();
            return 1;
        }
    }
    IIC_SCL=0;
    return 0;
}

写一个字节

void iic_write_byte(unsigned char dat)
{
    unsigned char i;
    IIC_SCL =0;
    for(i=0; i<8; i++){
        if((dat & 0x80)>0){
            IIC_SDA = 1;
        }else {
            IIC_SDA = 0;
        }
        dat <<=1 ; 
        delay_10us(1);
        IIC_SCL=1;
        delay_10us(1);      // 钳住数据
        IIC_SCL=0;
        delay_10us(1);
    }
}

读取数据

unsigned char iic_read_data(unsigned char ack)
{
    unsigned char i, dat=0;
    for(i=0; i<8; i++){
        IIC_SCL=0;
        delay_10us(1);
        IIC_SCL=1;
        dat <<=1;
        if(IIC_SDA){
            dat++;
        }
        delay_10us(1);
    }
    if(!ack){
        iic_nack();
    }else{
        iic_ack();
    }
    return dat;
}
  • 20
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值