☰
嵌入式常用总线协议记录(I2C,SPI, Modbus 485, CAN...)
2026/9/30 1:40:25 网站建设 项目流程
常用的总线协议,I2C,SPI,CAN,MODBUS RTU485,随笔记录,除了CAN总线,其他都用过无数次了,有时间再补一补把,太基础了

目录

  • 一、I2C
    • I2C速度
    • I2C软件实现
  • 二、SPI
    • SPI 基本介绍
    • SPI 的通讯模式
    • SPI速度
  • 三、MODBUS RTU 485
    • 3.1 RS485
    • 3.2 Modbus 协议
    • 3.3 Modbus 和 RS485 关系和区别
    • 3.4 Modbus-RTU 协议格式说明
      • 3.4.1 地址码
      • 3.4.2 功能码
      • 3.4.3 数据区
      • 3.4.4 CRC校验
      • 3.4.5 寄存器地址与PLC组态地址
  • 四、CAN

一、I2C

I2C速度

I2C 通讯的速度,有100K , 400K, 3.4M(一般来说比较少) 三种(bps)。

I2C软件实现

起始信号:时钟线高电平的时候,数据线由高变低

voidi2c_start(void){sda_high;delay_us(5);scl_high;delay_us(10);sda_low;delay_us(10);scl_low;//使SCL置低,准备发送或者接受数据delay_us(10);}

结束信号:时钟线高电平的时候,数据线由低变高

voidi2c_stop(void){sda_low;delay_us(5);scl_low;delay_us(10);scl_high;delay_us(5);sda_high;delay_us(10);}

ACK:正常的时钟周期,保持低电平,主机和从机都需要响应ACK

voidIIC_Ack(void){scl_low;//SCL为低,SDA为低,SCL为高,SDA为低,应答低电平有效,SCL为低,产生应答信号// MYSDA_OUT;sda_low;delay_us(10);scl_high;delay_us(10);scl_low;delay_us(10);sda_high;}

NACK:正常的之中周期,保持高电平,一般在接收数据的最后一个字节,发送NACK,表示接收完成

voidIIC_NAck(void){scl_low;//SCL为低,SDA为高,SCL为高,SCL为低// MYSDA_OUT;sda_high;delay_us(10);scl_high;delay_us(10);scl_low;}

I2C 发送数据:

voidIIC_Send_Byte(u8 txd){u8 t;// MYSDA_OUT;MYIIC_CLK_LOW;//拉低时钟开始数据传输 ,SCL为低,SDA变高或者变低(数据位),SCL变高,SCL变低,期间SDA为1既1,为0既0for(t=0;t<8;t++)//一个字节8位,一位一位发送{MYIIC_CLK_LOW;if((txd&0x80)>>7)//从最高位开始发送,如果是1,发送高电平MYIIC_DATA_HIGH;elseMYIIC_DATA_LOW;txd<<=1;//SDA处理完毕,此时可以将SCL拉高接受数据,拉高以后延时拉低delay_us(10);//MYIIC_CLK_HIGH;delay_us(10);MYIIC_CLK_LOW;delay_us(5);}}

I2C数据读取 :

//读1个字节,ack=1时,发送ACK,ack=0,发送nACKu8IIC_Read_Byte(unsignedcharack){unsignedchari,receive=0;// MYSDA_IN;//SDA设置为输入for(i=0;i<8;i++){MYIIC_CLK_LOW;//SCL为由低变高,在SCL高的时候去读 SDA的数据delay_us(10);MYIIC_CLK_HIGH;receive<<=1;//第一次这里还是0,第二次开始每次接收的数据做移动一位,从高位开始接收if(MYIIC_DATA_STATE)receive++;//如果数据为1,++以后就是1,数据为0,不执行就是0;delay_us(10);}if(!ack)IIC_NAck();//发送nACKelseIIC_Ack();//发送ACKreturnreceive;}

I2C等待 ACK:

u8MYIIC_Wait_Ack(void){u8 ucErrTime=0;delay_us(5);MYIIC_DATA_HIGH;delay_us(5);//MCU DATA 置高,外面高就是高,外面低就是低MYIIC_CLK_HIGH;delay_us(5);//CLK 高电平期间数据有效while(MYIIC_DATA_STATE)//低电平为有应答,高电平无应答{ucErrTime++;if(ucErrTime>250){MYIIC_Stop();return1;}}delay_us(10);MYIIC_CLK_LOW;return0;}

半双工!!!

二、SPI

SPI 基本介绍

SPI(Serial Peripheral Interface,串行外设接口)是一种高速、全双工、同步通信总线,常用于短距离通讯,主要应用于 EEPROM、FLASH、实时时钟、AD 转换器、还有数字信号处理器和数字信号解码器之间。

SPI的4根线:

  • SDO/MOSI – 主设备数据输出,从设备数据输入;
  • SDI/MISO – 主设备数据输入,从设备数据输出;
  • SCLK – 时钟信号,由主设备产生;
  • CS/SS – 从设备使能信号,由主设备控制。当有多个从设备的时候,因为每个从设备上都有一个片选引脚接入到主设备机中,当我们的主设备和某个从设备通信时将需要将从设备对应的片选引脚电平拉低或者是拉高(一般来说是低电平选中)。

SPI 以主从方式工作,通常有一个主设备和一个或多个从设备。通信由主设备发起,主设备通过 CS 选择要通信的从设备,然后通过 SCLK 给从设备提供时钟信号,数据通过 MOSI 输出给从设备,同时通过 MISO 接收从设备发送的数据。

主设备能够控制时钟,因为SPI通信并不像UART或者IIC通信那样有专门的通信周期,起始信号,结束信号;所以SPI协议能够通过控制时钟信号线,当没有数据交流的时候我们的时钟线要么是保持高电平要么是保持低电平。

SPI 的通讯模式

SPI 的 有四种模式:

CPOL=0,表示当SCLK=0时处于空闲态,空闲低电平,所以有效状态就是SCLK处于高电平时
CPOL=1,表示当SCLK=1时处于空闲态,空闲高电平,所以有效状态就是SCLK处于低电平时
CPHA=0,表示数据采样是在第1个边沿
CPHA=1,表示数据采样是在第2个边沿

所以最终有 4 种配置可选 :

模式CPHACPHA说明
000空闲时SCLK为低电平,数据在第一个边沿(即上升沿)采样
101空闲时SCLK为低电平,数据在第二个边沿(即下降沿)采样
210空闲时SCLK为高电平,数据在第一个边沿(即下降沿)采样
311空闲时SCLK为高电平,数据在第二个边沿(即上升沿)采样

模式0:CPOL=0, CPHA=0 -> 空闲时SCLK为低电平,数据在第一个边沿(即上升沿)采样。
模式1:CPOL=0, CPHA=1 -> 空闲时SCLK为低电平,数据在第二个边沿(即下降沿)采样。
模式2:CPOL=1, CPHA=0 -> 空闲时SCLK为高电平,数据在第一个边沿(即下降沿)采样。
模式3:CPOL=1, CPHA=1 -> 空闲时SCLK为高电平,数据在第二个边沿(即上升沿)采样。

当 CPHA= 1 的时候:

当 CPHA= 0 的时候:

不同的从设备可能在出厂时由工厂配置为某种通信模式,无法改变,所以我们得根据从设备的通讯模式来设置主设备的模式。

比如我们常用的 SPI Flash W25QXX 系列,可以在文档资料中看到其支持的工作模式:

SPI速度

已经有器件可达 50Mbps,一般情况下,SPI模块的最大时钟频率为系统时钟频率的1/2。

全双工!!!

三、MODBUS RTU 485

3.1 RS485

RS-485则是通信线路,只是一种硬件接口。

基本概念:

RS485百度百科

RS485具有A、B两根线,并且通过A、B两根线之间的压差来定义1和0。A和B的压差在+(2-6)V内为高电平,A和B的压差在-(2-6)V内为低电平。由此就定义了RS485的电气接口和电平。

虽然RS485通讯链 用一对双绞线将 各个接口的 “A”“ B” 端连接起来,就可以进行通信了,但是为了保证整个系统的稳定性,还是建议将各个设备共 负极(地),来确保网络的稳定性。

半双工!!!

3.2 Modbus 协议

基本概念:

Modbus通讯协议百度百科

在进行多机通信的时候,Modbus协议规定每个控制器必须要知道它们的设备地址,识别按照地址发送过来的数据,决定是否要产生动作,产生何种动作,如果要回应,控制器将生成的反馈信息用Modbus协议发出。

Modbus有两种通信传输方式,一种是ASCII模式,一种是RTU模式。

  • RTU方式:也叫十六进制 例如:发送0x03:0000 0011
  • ASC方式:0x03 (发送0 :0x30:0011 0000 )( 发送3:0x33:0011 0011)

ASCII 的通信效率低,方便调试,实际应用比较少;工业上都采用RTU方式,效率高。

工业应用上一般 Modbus 485 波特率为9600 或者 4800,因为速度越快传输距离越短,速度太慢也影响效率

3.3 Modbus 和 RS485 关系和区别

RS485只是一种硬件接口,他只是把来自单片机UART的信号,翻转电平进行传输,并驱动线缆。
所以RS485其实只是一种硬件接口驱动芯片。
Modbus是一种软件协议,规定了一种语言。
Modbus可以跑在RS485上,也能跑在RS232上,也能跑在POWERBUS。
Modbus可以支持多种电气接口,如RS-232、RS-485等,还可以在各种介质上传送,如双绞线、光纤、无线等。

同理。
RS485上可以用Modbus,也能用其他自拟协议。协议只是软件。

Modbus只是通信协议的一种,就像汉语和英语一样,就是一种交流的语言,一种机器之间交流的语言。那么在交流之前肯定要有沟通的桥梁吧,那就是传输媒介485或232或其他电气规则,同一种协议可以用不同的传输媒介方式如485或232但是同一传输线路上不能同时存在两种协议.

3.4 Modbus-RTU 协议格式说明

3.4.1 地址码

通讯地址: 0~247

对于一主多从的通讯架构中,主机为0。从设备地址为 1~247。

主机发送地址码 0 ,一般称为广播数据,从机无需响应。

3.4.2 功能码

ModBus通讯规约可定义的功能码为1到127。

比如: 03H 为 读寄存器功能码; 16H 为 写寄存器功能码。


从设备的回应数据包格式:

  • 回应数据包和主机查询的数据包格式包是一致的
  • 正常回应时,功能码与主机发的功能码一致(1~127)
  • 异常的回应,功能码要在收到的功能码基础上加上128 例如:发 0x03 收:0x03 +128

3.4.3 数据区

常见的功能码的数据吗格式一般在Modbus通用协议中已经做了规范。

比如: 对于03功能码,后面跟的数据包括 2个字节表示寄存器地址,2个字节表示想要读取的寄存器个数

返回的3功能码,后接1个字节的返回字节个数(该个数应为上述读取寄存器个数的两倍,因为一个寄存器对应两个字节,比如上图中返回的数据应该是 01 03 20 xxxxxxx)

再看个例子:

3.4.4 CRC校验

CRC 校验:CRC - 16 ,低位在前,高位在后。这个CRC校验代码网上也很多,下面是我自己上传的一个资源:

CRC校验代码

3.4.5 寄存器地址与PLC组态地址

如图所示,对于从机而言,有寄存器地址 和 PLC组态地址的分别:

  • 寄存器PLC地址指存放于控制器中的地址,这些控制器可以是PLC,也可以使触摸屏,或是文本显示器。PLC地址一般采用10进制描述,共有5位,其中第一位代码寄存器类型。

  • 寄存器modbus协议地址指通信时使用的寄存器地址,在实际编程中,由于寄存器PLC地址前缀的区分作用,所以只需说明后4位数,而且需转换为4位十六进制地址。
    例如PLC地址40001对应寻址地址0x0000,40002对应寻址地址0x0001,寄存器寻址地址一般使用16进制描述。再如,PLC寄存器地址40003对应协议地址0002,PLC寄存器地址30003对应协议地址0002。在实际编程中,由于前缀的区分作用,所以只需说明后4位数,而且需转换为4位十六进制地址。

  • 支持 Modbus 协议的设备或软件,使用时用户直接设置或看到的应当是 Modbus 数据地址。Modbus 地址所访问的数据,是通过各种 “功能”读写而来。 功能码是 Modbus 地址的底层。 如果 Modbus 通 信的一方提供的所谓 Modbus 协议只有功能码,则需要注意了解此 功能号与 Modbus 地址间的对应关系。

四、CAN

通常四线线路实现全双工数据传输,二线线路实现单工或半双工数据传输。在采用频分法、时间压缩法、回波抵消技术时,二线线路也可实现全双工数据传输。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询