资讯详情

STM32硬件I2C与软件模拟I2C超详解

目录

  • 一.I2C协议简介
  • 二.I2C物理层
  • 三.I2C协议层
    • I2C 基本读写过程
    • 1.空闲状态
    • 2.起始信号和停止信号
    • 3.数据有效性
    • 4.地址和数据方向
    • 5.应答和非应答信号
  • 四.硬件I2C
    • I2C外设功能框图(重点)
    • 1.通信引脚
    • 2.时钟控制逻辑
    • 3.数据控制逻辑
    • 4.整体控制逻辑
    • 5.STM32的I2C外设通信过程(超级重要)
      • 主发送器
      • 主接收器
    • 6.I2C结构体的初始化
  • 五.EEPROM简介
    • 1.STM32向从机EEPROM写字节
    • 2.STM32向从机EEPROM多字节(页写入)
    • 3.STM32随机读取EEPROM内部任何地址的数据
    • 4.STM32随机顺序读取EEPROM内部任何地址的数据
  • 六.硬件I2C读写EEPROM实验
    • 实验目的
    • 实验原理
    • 源码
    • 实验效果
  • 七.软件模式I2C协议
    • 实验目的
    • 实验原理
    • 源码
  • 八.总结

一.I2C协议简介

芯片)等通信协议,目前广泛应用于系统中的多个集成电路(IC)间的通讯。

二.I2C物理层

在这里插入图片描述

三.I2C协议层

I2C规定通信时钟、起始信号和停止信号只能由主机产生

I2C 基本读写过程

1.空闲状态

2.起始信号与停止信号

起始信号和停止信号是在SCL 是高电平期间,SDA线电平切换的过程,而不是单纯的高低电平。

3.数据有效性

4.地址及数据方向

5.应答与非应答信号

四.硬件I2C

I2C外设功能框图(重点)

1.通信引脚

2.时钟控制逻辑

3.数据控制逻辑

  • 移位寄存器以“数据寄存器”为数据源,把数据一位一位地通过SDA信号线发送出去;

4.整体控制逻辑

主机模式与从机模式

5.STM32的I2C外设通信过程(超级重要)

I2C主模式:

主发送器

主设备等待读SR1寄存器,紧跟着将从地址写入DR寄存器

主接收器

接收数据之前,判断数据寄存器是否有数据,也就数据寄存器非空(RNXE),CPU就可以读取数据寄存器中的数据啦。

  • 主设备在从设备接收到最后一个字节后发送一个NACK。接收到NACK后,从设备释放对SCL和SDA线的控制;主设备就可以发送一个停止/重起始条件。

硬件I2C写代码必须熟练掌握和理解主发送器和主接收器的过程,只要你理解了写代码还不是信手拈来,简简单单,然后写代码你会发送就是上面的过程一模一样

6.I2C初始化结构体

五.EEPROM简介

1.STM32向从机EEPROM写入一个字节

2.STM32向从机EEPROM写入多个字节(页写入)

总结:

3.STM32随机读取EEPROM内部任何地址的数据

4.STM32随机顺序读取EEPROM内部任何地址的数据

六.硬件I2C读写EEPROM实验

实验目的

实验原理

详情请看——>GPIO端口的八种工作模式

源码

i2c_ee.h

#ifndef __IIC_EE_H
#define __IIC_EE_H

#include "stm32f10x.h"
#include <stdio.h>
//IIC1
#define EEPROM_I2C I2C1
#define EEPROM_I2C_CLK RCC_APB1Periph_I2C1
#define EEPROM_I2C_APBxClkCmd RCC_APB1PeriphClockCmd
#define EEPROM_I2C_BAUDRATE 400000

// IIC1 GPIO 引脚宏定义
#define EEPROM_I2C_SCL_GPIO_CLK (RCC_APB2Periph_GPIOB)
#define EEPROM_I2C_SDA_GPIO_CLK (RCC_APB2Periph_GPIOB)
#define EEPROM_I2C_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
     
#define EEPROM_I2C_SCL_GPIO_PORT GPIOB 
#define EEPROM_I2C_SCL_GPIO_PIN GPIO_Pin_6
#define EEPROM_I2C_SDA_GPIO_PORT GPIOB
#define EEPROM_I2C_SDA_GPIO_PIN GPIO_Pin_7

//STM32自身地址1 与从机设备地址不相同即可(7位地址)
#define STM32_I2C_OWN_ADDR 0x6f
//EEPROM设备地址
#define EEPROM_I2C_Address 0XA0
#define I2C_PageSize 8


//等待次数
#define I2CT_FLAG_TIMEOUT ((uint32_t)0x1000)
#define I2CT_LONG_TIMEOUT ((uint32_t)(10 * I2CT_FLAG_TIMEOUT))



/*信息输出*/
#define EEPROM_DEBUG_ON 0
#define EEPROM_INFO(fmt,arg...) printf("<<-EEPROM-INFO->> "fmt"\n",##arg)
#define EEPROM_ERROR(fmt,arg...) printf("<<-EEPROM-ERROR->> "fmt"\n",##arg)
#define EEPROM_DEBUG(fmt,arg...) do{ 
          \ if(EEPROM_DEBUG_ON)\ printf("<<-EEPROM-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\ }while(0)

void I2C_EE_Config(void);
void EEPROM_Byte_Write(uint8_t addr,uint8_t data);	
uint32_t  EEPROM_WaitForWriteEnd(void);	
uint32_t  EEPROM_Page_Write(uint8_t addr,uint8_t *data,uint16_t Num_ByteToWrite);																					
uint32_t  EEPROM_Read(uint8_t *data,uint8_t addr,uint16_t Num_ByteToRead);
void I2C_EE_BufferWrite(uint8_t* pBuffer,uint8_t WriteAddr, uint16_t NumByteToWrite);
#endif /* __IIC_EE_H */

i2c_ee.c

#include "i2c_ee.h"


//设置等待时间
static __IO uint32_t  I2CTimeout = I2CT_LONG_TIMEOUT;   

//等待超时,打印错误信息
static uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode);


void I2C_EE_Config(void)
{ 
        
	GPIO_InitTypeDef    GPIO_InitStuctrue;
	I2C_InitTypeDef     I2C_InitStuctrue;
	//开启GPIO外设时钟
	EEPROM_I2C_GPIO_APBxClkCmd(EEPROM_I2C_SCL_GPIO_CLK|EEPROM_I2C_SDA_GPIO_CLK,ENABLE);
	//开启IIC外设时钟
	EEPROM_I2C_APBxClkCmd(EEPROM_I2C_CLK,ENABLE);
	
	//SCL引脚-复用开漏输出
  GPIO_InitStuctrue.GPIO_Mode=GPIO_Mode_AF_OD;
  GPIO_InitStuctrue.GPIO_Pin=EEPROM_I2C_SCL_GPIO_PIN;
	GPIO_InitStuctrue.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(EEPROM_I2C_SCL_GPIO_PORT,&GPIO_InitStuctrue);
	//SDA引脚-复用开漏输出
	GPIO_InitStuctrue.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_InitStuctrue.GPIO_Pin = EEPROM_I2C_SDA_GPIO_PIN;
	GPIO_InitStuctrue.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(EEPROM_I2C_SDA_GPIO_PORT,&GPIO_InitStuctrue);
	
	//IIC结构体成员配置
   I2C_InitStuctrue.I2C_Ack=I2C_Ack_Enable;
	I2C_InitStuctrue.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;
	I2C_InitStuctrue.I2C_ClockSpeed=EEPROM_I2C_BAUDRATE;
	I2C_InitStuctrue.I2C_DutyCycle=I2C_DutyCycle_2;
	I2C_InitStuctrue.I2C_Mode=I2C_Mode_I2C;
	I2C_InitStuctrue.I2C_OwnAddress1=STM32_I2C_OWN_ADDR;
	I2C_Init(EEPROM_I2C,&I2C_InitStuctrue);
	I2C_Cmd(EEPROM_I2C,ENABLE);

}

//向EEPROM写入一个字节
void  EEPROM_Byte_Write(uint8_t addr,uint8_t data)
{ 
        
	//发送起始信号
	I2C_GenerateSTART(EEPROM_I2C,ENABLE);
	//检测EV5事件
	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT)==ERROR);
	//发送设备写地址
	I2C_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Transmitter);
	//检测EV6事件
	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);
	//发送要操作设备内部的地址
	I2C_SendData(EEPROM_I2C,addr);
	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR);
  I2C_SendData(EEPROM_I2C,data);
	//检测EV8_2事件
	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED )==ERROR);
	//发送停止信号
	I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
	
}

//向EEPROM写入多个字节
uint32_t  EEPROM_Page_Write(uint8_t addr,uint8_t *data,uint16_t Num_ByteToWrite)
{ 
        
	
	 I2CTimeout = I2CT_LONG_TIMEOUT;
	//判断IIC总线是否忙碌
	while(I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY))   
	{ 
        
		if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);
	} 
	//重新赋值
	I2CTimeout = I2CT_FLAG_TIMEOUT;
	//发送起始信号
	I2C_GenerateSTART(EEPROM_I2C,ENABLE);
	//检测EV5事件
	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT)==ERROR)
	{ 
        
		 if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(2);
	} 
	I2CTimeout = I2CT_FLAG_TIMEOUT;
	//发送设备写地址
	I2C_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Transmitter);
	//检测EV6事件
	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR)
	{ 
        
		 if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);
	} 

	I2CTimeout = I2CT_FLAG_TIMEOUT;
	//发送要操作设备内部的地址
	I2C_SendData(EEPROM_I2C,addr);
	//检测EV8事件
	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR)
	{ 
        
		 if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(4);
	} 

	while(Num_ByteToWrite)
	{ 
        
		I2C_SendData(EEPROM_I2C,*data);
		I2CTimeout = I2CT_FLAG_TIMEOUT;
		while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR)
		{ 
        
				if((I2CTimeout--) == 0) return   I2C_TIMEOUT_UserCallback(5);
		} 
		 Num_ByteToWrite--;
		 data++;
	}

	I2CTimeout = I2CT_FLAG_TIMEOUT;
	//检测EV8_2事件
	while( I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED )==ERROR)
	{ 
        
				if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(6);
	 } 
	//发送停止信号
	I2C_GenerateSTOP(EEPROM_I2C,ENABLE);
	 return 1;
}

//向EEPROM读取多个字节
uint32_t EEPROM_Read(uint8_t *data,uint8_t addr,ui

标签: x9315wp集成电路

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台