常用通信时序(UART、IIC、SPI,RS232、RS485)及协议(Modbus)
通讯时序
1. UART
通讯时序图:
类 型:串行异步通信
总线定义:
TXD:发送数据线
RXD:接收数据线
数据传输:
①接收方RX初始电平为1
②带起始位0和停止位1
③先发送低位再高位
④传输数据位以字节为单位,一次只能传输一字节
⑤以波特率为时基约定通信双方接收和发送时间点
注意事项:
在进行UART通信时,双方的波特率必须一致
模拟UART通信伪算法
作用:将从串口接收到的数据+1再发送出去
读取方法:采取中断模拟波特率的方式,在每个数据位的中间处读取数据,因此我们可以看出,读取起始位的时候是一半的波特率,后面都是完整的波特率,这样就能保证每次都是在数据位的中间去读取数据。
实现流程:
①while(RxdPin)
②StartRxd();
③while(RxdEnd)
④StartTxd(RxdBuff+1);
⑤while(RxdEnd);
程序解析:
① 等待RXD引脚出现低电平,即起始信号
② 启动接收,实质就是开启中断,在中断里接收,中断的间隔就是设置的特率,即每达到一个波特率中断就会执行一次,接收起始信号时波特率为一半。
③ 经过了②开启了中断之后,到达了设定的波特率就会进入中断处理数据,当中断处理完起始信号、8位数据位、停止信号之后就会置位接收结束标志位告诉程序接收完毕。
④ 将保存在接收缓冲区的数据+1再发送出去,和接收的方法大同小异。
⑤ 等待中断发送完毕,置位发送标志位
2. IIC
通讯时序图:
类 型:串行同步通信
总线定义:
SCL : 时钟线
SDA: 数据线
数据传输:
① 默认两总线因为上拉电阻的缘故保持高电平
② 带起始信号和停止位信号
③ 先发送高位再低位
④ 传输数据位以字节为单位,只要不发送停止信号可以无限传输数据
⑤ 以当前时钟线和数据线的高低电平状态来决定当前是何种信号
注意事项:
① IIC总线必须外接上拉电阻。
② 规定当SCL处于低电平时,SDA是可以变化的,当SCL为高电平是读取SDA的时间,因此这段时间SDA必须是一个稳定的电平状态,不允许发生改变。
③ IIC通信是没有命令和数据概念的,比如OLED的IIC通信模式,会涉及到IIC发送的是地址还是命令,这是由OLED的驱动决定的,IIC只能读写数据而已(读1/写0),比如OLED就规定了,如果你在当前传输协议中写入了一个0x00,那么后面传输的所有数据都为命令,如果写入的是0x40,那么后面的就全是数据了。
IIC通信流程(写入数据):
① I2cStart();
② I2cWriteByte(I2cAddress);
③ I2cWaitAck();
④ I2cWriteByte(RegisterAddress);
⑤ I2cWaitAck();
⑥ I2cWriteByte(Data);
⑦ I2cWaitAck();
⑧ I2cStop();
程序解释
①:此为I2c的起始信号,根据时序图我们可以看出,初始状态SDA和SCL都为高电平,当开始进行IIC通信时,SDA先拉低,继而SCL拉低,这就完成了IIC的起始信号。
②:此为I2c写数据的函数,具体实现过程根据时序图可知有以下步骤:
- 拉低SCL
- 改SDA的引脚模式为输出
- 循环8次
- 写入需要写入的SDA的数据(延迟一下)(从高到低以字节为单位发送)
- 拉高SCL通知从机读取数据写入(延迟一下)
- 拉低SCL
- 循环8次
- 拉低SCL以便接收Ack
- 拉高SDA,也叫释放总线,用于后面接收Ack(接收到则SDA被从机拉低)
③:等待Ack,拉高SCL读取,再拉低SCL释放
④:停止信号,首先都输出低电平,SCL拉高(延迟一下)SDA拉高(延迟一下)
上面只是演示了IIC写操作的流程,其实读操作也是一样的,唯一不同的两个地方,一是在发送第二个寄存器地址的时候,最后一位应改为写模式,第二个就是读写操作函数上的区别,唯一的区别就是写入的时候,是输出SDA的电平,而读取的时候是检测SDA的电平,其他地方是一样的
3. SPI
类 型:高速全双工同步通信总线
总线定义:
SCS/NSS、CS: 片选使能(可以自定义引脚而不用硬件规定引脚)
SCL : 时钟线
MOSI: 主发从收
MISO: 主收从发
模 式:
CPOL:0—SCL空闲为低电平 1—SCL空闲为高电平
CPHA:0—SCL基数边沿采样 1—SCL偶数边沿采样
主要是用来适配和各种不同种类的SPI协议器件通信
通讯时序图:
数据传输:
① 拉低SCS为起始信号,拉低SCS之前的SCL电平由CPOL决定
② 在边沿触发和采样,具体哪个边沿采样哪个边沿触发是根据CPHA来决定的
③ 不规定一次时序传输的字节数,但是要和从机能一次接收的字节数保
持一致
④ 可设置数据传输字节是先高后低还是先低后高
⑤ 根据时序图可知数据接收和发送是同时进行的,也就是全双工通信
4. RS323
5. RS485
通信协议
1. Modbus
简介:modbus是一种串行半双工的通信协议,主要有以下几个种类:
Modbus-RTU+Modbus-ASCII
Modbus-TCP
Modbus-Plus
一般的话,一个设备只会有以上的一种协议
一般来说,Modbus-RTU+Modbus-ASCII主要应用在RS-232,RS485,RS-422上,在工业上应用较多。Modbus-RTU是一种紧凑的,采用2进制的数据表示方式,不方便人们阅读,而Modbus-ASCII方便阅读,但是比较麻烦。目前来说,主要还是用Modbus-RTU类型,下面主要介绍Modbus——RTU格式的使用方法。
1.1. 帧组成结构
一帧的结构主要由:设备地址+功能码+数据+RTC校验组成
地址:占1字节,范围0-255,有效范围为1-257,其他的都是特殊用途的,比如255就是广播地址,即所有的从设备都响应。一般正常通信的话是根据主机发送的从机地址来辨别主机是和哪个从机进行通信的。
功能码:功能码顾名思义就是表示你这条数据帧是准备干嘛的,是读还是写这些。
数据:功能码的不同数据也会有所不同,这个等到下面的实战讲解再提
RTC校验:实际上就是通过一种公式将所有数据帧计算成一个值,然后接收和发送的对比这个值,如果是一模一样的说明发送正确,只要有一个位的数据出错RTC校验出来的值就会不同。
1.2. 实战案例讲解
先介绍一下我们主要使用的3个功能码0x03:读n个寄存器的数据
0x06:写一个寄存器的数据
0x10:写多个寄存器的数据
假设我主机向从机发送帧数据为:01 03 0101 0001 840A
从机回复数据为 :01 03 02 1234 B533
实际的数据帧是用字节表示的,为了方便阅读我把相同功能的字节整合在一起成为2个字节,根据上面所讲的数据帧的结构和功能码的作用我们大致可读出这两句指令所代表的的含义。
主机的数据帧解析
01为设备地址
03为功能码
0101这两个字节因为都是代表读取的寄存器的地址,寄存器地址是要16位表示的,因此我给他们整合在一起
0001是指我只读1个寄存器的数据
840A是RTC计算出来的16位的校验位,这个是软件计算出来的,我们真正通过协议发送的时候是不需要加这两个字节的。
从机回复数据解析
前面两个字节是一样的,我们不去理会,从02开始,意思是读取数据的字节数是2个,为什么是2个?因为寄存器地址是16位的,就是2字节,所以我们一般收到的从机回复的读取数据的字节数都是2的倍数,紧跟着1234是数据内容,这里是我瞎写的,真正实际读取的话,读取到的就是你这个寄存器内部的实际值是多少这里就会显示多少。后面就不用说了,也是校验位,也是通过返回的数据帧软件自动计算出来的
再用两个例子来说明一下
主发:01 06 0000 0001 480A
从回:01 06 0000 0001 480A
解释:在设备1中修改其寄存器0000的值为0001发送的释义相同。
主发:02 10 0000 0001 02 1122 2A19
从回:02 10 0000 0001 01C9
解释:在设备2中的0000为起始地址连续修改0001(即修改1个寄存器的值)个寄存器的值,一共2个字节的内容为为1122,从设备回复你修改的寄存器起始地址及修改的个数即可,内容不必回复,因为有校验位核对。
主发:03 10 0000 0002 04 1122 3344 425A
从回:03 10 0000 0002 41C8
解释:在从设备3中的0000为起始地址连续修改0002个寄存器的值,一共4个字节的内容为1122和3344,校验位为425A,从机回复内容同上。