STM32 CubeMX软件I2C实验与EEPROM使用理论和实验详解

第五章 stm32 cubemx 软件I2C实验以及EEPROM的使用理论及实验过程

目录

  • 第五章 stm32 cubemx 软件I2C实验以及EEPROM的使用理论及实验过程
  • 前言
  • IIC概述
  • IIC物理层
  • IIC协议层
  • IIC读写概述
  • 起始、停止信号及代码
  • 数据有效性及代码
  • 响应ACK及代码
  • 地址及数据方向
  • 前言

    本章将讲解stm32通讯协议中的IIC协议,利用cubeMX完成软件和硬件IIC的实现,并结合实验数据,给人更为深刻的体验。
    我们结合IIC的具体协议和逻辑分析仪得到的具体实验数据理解IIC协议。

    IIC概述

    I2C通讯协议是由Phiilps公司开发的,由于它引脚少,硬件实现简单,可扩展性强,不需要USART、CAN等通讯协议的外部收发设备,现在被广泛地使用在系统内多个集成电路(IC)间的通讯。

    llC: Inter Integrated Circuit,集成电路总线,是一种同步串行半双工通信总线。其中同步说明这种通信方式需要时钟线;串行说明数据一位一位(一个字节8位即0000 0000)在一个数据线上朝一个方向发送;半双工说明一个时间只能进行接收或者发送;总线就是传输数据的通道,如果有多个设备想使用总线进行传输数据多个都需要挂载在总线上,注意在总线上可以有多个主机,多个从机;协议则是传输数据的规则,首先我们讲解该协议。

    IIC物理层

    IIC物理层

    如图所示,即位IIC的物理层,由图可明显看到所有的设备挂载在,两条l2C总线下,一条双向串行数据线(SDA)用来传递数据,一条串行时钟线(SCL)用于数据收发同步。总线通过上拉电阻接到电源。当I2C设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。
    要点

  • IIC总线协议是一个支持多设备的总线。在一个l2C通讯总线中,如图,可连接多个I2C通讯设备,支持多个通讯主机及多个通讯从机。
  • 多个设备并不是指无限多个,连接到相同总线的IC数量要受到总线的最大电容400pF限制。
  • 每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的通信。
  • 多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。
  • 具有三种传输模式:标准模式传输速率为100kbit/s ,快速模式为400kbit/s,高速模式3.4Mbit/s,但目前大多/2C设备尚不支持高速模式。
  • IIC协议层

    I2C协议定义了通讯的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环节。接下来我们将逐个进行实验。

    IIC读写概述

    主机写入到从机的基本过程,如图所示。由主机发出起始信号表示开始通信,然后发送从机地址及数据传输方向,然后释放总线(总线上有上拉电阻,总线拉高即为释放总线)交给从机,得到从机应答ACK或非应答NACK,紧接着进行数据的接收或者数据传输的终止。
    主机写入到从机

    实验结果
    结果如图所示。
    接下来进行具体讲解,各个信号如何产生、代码实现、实验反馈。

    起始、停止信号及代码

    理论说明
    如图所示
    总线电平

  • 起始:当SCL线是高电平时,SDA线从高电平向低电平切换。

  • 停止:当SCL是高电平时,SDA线由低电平向高电平切换。

  • 代码实现
    代码如下(示例):

    void I2C_SCL_1()//SCL电平拉高
    {
        HAL_GPIO_WritePin(GPIO_PORT_I2C, I2C_SCL_PIN, GPIO_PIN_SET);
    }
    void I2C_SCL_0()
    {
        HAL_GPIO_WritePin(GPIO_PORT_I2C, I2C_SCL_PIN, GPIO_PIN_RESET);
    }
    void I2C_SDA_1()
    {
        HAL_GPIO_WritePin(GPIO_PORT_I2C, I2C_SDA_PIN, GPIO_PIN_SET);
    }
    void I2C_SDA_0()
    {
        HAL_GPIO_WritePin(GPIO_PORT_I2C, I2C_SDA_PIN, GPIO_PIN_RESET);
    }
    static void i2c_Delay(void)
    {
    	uint8_t i;
    	for (i = 0; i < 10; i++);
    }
    void i2c_Start(void)
    {
    	/* 当SCL线是高电平时,SDA线从高电平向低电平切换。*/
    	I2C_SDA_1();
    	I2C_SCL_1();
    	i2c_Delay();
        
    	I2C_SDA_0();
    	i2c_Delay();
        
    	I2C_SCL_0();
    	i2c_Delay();
    }
    void i2c_Stop(void)
    {
    	/* 当SCL是高电平时,SDA线由低电平向高电平切换 */
    	I2C_SDA_0();
    	I2C_SCL_1();
    	i2c_Delay();
    	I2C_SDA_1();
    }
    

    实验验证

    数据有效性及代码

    理论说明
    如图所示
    数据有效段

    I2C使用SDA信号线来传输数据,使用SCL信号线进行数据同步。SDA数据线在SCL的每个时钟周期传输一位数据。

    SCL为高电平的时候SDA表示的数据有效,即此时的SDA为高电平时表示数据“1”,为低电平时表示数据“0”。
    当SCL为低电平时,SDA的数据无效,一般在这个时候SDA进行电平切换,为下一次表示数据做好准备。
    代码实现
    这个代码函数功能是读取一个字节的数据,利用for循环依次读取8位数据。

    #define I2C_SDA_READ   HAL_GPIO_ReadPin(GPIO_PORT_I2C, I2C_SDA_PIN)
    
    uint8_t i2c_ReadByte(void)
    {
    	uint8_t i;
    	uint8_t value;
    
    	value = 0;
    	for (i = 0; i < 8; i++)
    	{
    		value <<= 1;
    		I2C_SCL_1();
    		i2c_Delay();
    		if (I2C_SDA_READ)
    		{
    			value++;
    		}
    		I2C_SCL_0();
    		i2c_Delay();
    	}
    	return value;
    }
    

    这个代码函数功能是发送一个字节的数据,利用for循环依次发送8位数据。

    void i2c_SendByte(uint8_t oneByte)
    {
    	uint8_t i;
    
    	/* 数据由高位到低位依次发送 */
    	for (i = 0; i < 8; i++)
    	{		
    		if (oneByte& 0x80)
    		{
    			I2C_SDA_1();//判断为1发送1
    		}
    		else
    		{
    			I2C_SDA_0();
    		}
    		i2c_Delay();
    		I2C_SCL_1();
    		i2c_Delay();	
    		I2C_SCL_0();
    		if (i == 7)
    		{
    			 I2C_SDA_1(); //发送完成后释放总线等待应答
    		}
    		oneByte<<= 1;	/* 左移做下一次判断*/
    		i2c_Delay();
    	}
    }
    

    实验验证

    响应ACK及代码

    理论说明
    I2C的数据和地址传输都带响应。响应包括“应答(ACK)”和“非应答(NACK)”两种信号。每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据。
    应答信号:主机SCL拉高,读取从机SDA的电平,为低电平表示产生应答。应答信号为低电平时,规定为有效应答(ACK),表示已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),表示接收该字节失败。

    传输时主机产生时钟,在第9个时钟时,数据发送端会释放SDA的控制权,由数据接收端控制SDA,若SDA为高电平,表示非应答信号(NACK),低电平表示应答信号(ACK)。
    产生应答信号

    代码实现
    该代码实现包括三个函数,第一个函数为产生应答信号,第二函数为产生非应答信号,第三个函数为判断应答。第一、二个函数如上述所示,第三个函数需要注意在读取ACK/NACK信号时先进行释放总线,即将SDA总线拉高交给其他需要响应的设备控制。

    void i2c_Ack(void)
    {
    	I2C_SDA_0();
    	i2c_Delay();
    	I2C_SCL_1();
    	i2c_Delay();
    	I2C_SCL_0();
    	i2c_Delay();//应答信号为低电平时,规定为有效应答(ACK)
    	I2C_SDA_1();
    }
    void i2c_NAck(void)
    {
    	I2C_SDA_1();
    	i2c_Delay();
    	I2C_SCL_1();
    	i2c_Delay();
    	I2C_SCL_0();
    	i2c_Delay();	
    }
    uint8_t i2c_WaitAck(uint16_t timeout)
    {
    	uint8_t re,ucErrTime=0;
    
    	I2C_SDA_1();//释放SDA总线
    	i2c_Delay();
    	I2C_SCL_1();
    	i2c_Delay();
        while(I2C_SDA_READ)//等待ACK//NACK
        {
            re = 0;
            ucErrTime++;
            if(ucErrTime>timeout)
            {
                return re;
            }
            else re = 1;
        }
    	I2C_SCL_0();
    	i2c_Delay();
    	return re;
    }
    
    

    实验验证

    地址及数据方向

    I2C总线上的每个设备都有自己的独立地址,主机发起通讯时,通过SDA信号线发送设备地址(SLAVE_ADDRESS)来查找从机。设备地址可以是7位或10位。
    紧跟设备地址的一个数据位R/W用来表示数据传输方向,数据方向位为“1”时表示主机由从机读数据,该位为“0”时表示主机向从机写数据。
    以EEPROM 24C01为例,其地址如图所示。

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32 CubeMX软件I2C实验与EEPROM使用理论和实验详解

    发表回复