【STM32】入门(七):I2C硬件控制方式

这篇具有很好参考价值的文章主要介绍了【STM32】入门(七):I2C硬件控制方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、简介

之所以叫“I2C硬件控制方式”是与“软件控制方式”相对。I2C软件控制,就是写程序直接操作两个GPIO引脚,分别作为时钟线SCL和数据线SDA,按照I2C协议的时序要求,操作GPIO输入、输出、高电平、低电平。
听着就很复杂,好在STM32中有I2C的硬件实现,即通过简单的操作寄存器即可实现收发数据。

2、手册

2.1 寄存器功能框图

【STM32】入门(七):I2C硬件控制方式

2.2 I2C引脚

STM32F407ZGT6中有3个I2C总线,对应的引脚如下图所示。
其中I2C1默认引脚是PB6、PB7,可以重映射到PB8、PB9上。
【STM32】入门(七):I2C硬件控制方式

2.3 寄存器

寄存器地址:
【STM32】入门(七):I2C硬件控制方式
【STM32】入门(七):I2C硬件控制方式

3、代码详解

I2C基本编程步骤:初始化时钟、配置引脚、起始信号、读、写、终止信号

3.1 I2C初始化

3.1.1 初始化时钟

I2C在APB1总线上,并且I2C1的引脚位PB6、PB7,因此使能使能GPIOB时钟,以及I2C的时钟

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); 
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); 

【STM32】入门(七):I2C硬件控制方式

3.1.2 配置引脚位开漏输出

static void I2C_GPIO_Config(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure; 

  #a)使能与 I2C 有关的时钟
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); 
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    
  #b)配置SCL和SDA引脚位开漏输出GPIO_Mode_AF_OD
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
  GPIO_Init(GPIOB, &GPIO_InitStructure);	
}

3.1.3 设置I2C工作模式

设置工作模式、占空比、地址7位或10位、通信速率等

工作模式有三种:I2C、SMBusDevice、SMBusHost。

SMBus (System Management Bus,系统管理总线)和I2C类似,但是在时序特性上有一些差异:

首先,SMBus需要一定数据保持时间,而 I2C总线则是从内部延长数据保持时间。
SMBus具有超时功能,因此当SCL太低而超过35 ms时,从器件将复位正在进行的通信。相反,I2C采用硬件复位。
SMBus具有一种警报响应地址(ARA),因此当从器件产生一个中断时,
	它不会马上清除中断,而是一直保持到其收到一个由主器件发送的含有其地址的ARA为止。
SMBus只工作在从10kHz到最高100kHz。最低工作频率10kHz是由SMBus超时功能决定的。
static void I2C_Mode_Configu(void)
{
  I2C_InitTypeDef  I2C_InitStructure; 

  #a)设置位I2C模式
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	
  #b)设置高低电平占空比,这个不用纠结,可以随意设置,一般设备兼容性都没问题
  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;

  #c)设置自己的地址为7
  I2C_InitStructure.I2C_OwnAddress1 =I2Cx_OWN_ADDRESS7; 
  
  #d)默认使能ACK,当需要发送NACK时,再重新设置
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;
	 
  #e)设置I2C的寻址地址为7
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	
  #f)设置时钟为:400000
  I2C_InitStructure.I2C_ClockSpeed = 400000;
  
  #g)初始化I2C1:(APB1PERIPH_BASE + 0x5400)
  I2C_Init(I2C1, &I2C_InitStructure);
  
  #h)使能 I2C1
  I2C_Cmd(I2C1, ENABLE);   
}

3.2 写操作

【STM32】入门(七):I2C硬件控制方式

uint32_t I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr) 
{
  #a)发送起始信号“S”
  I2C_GenerateSTART(I2C1, ENABLE);

  I2CTimeout = I2CT_FLAG_TIMEOUT;  
  #b)等待起始信号发送成功:测试 EV5 即可
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))  
  {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(0);
  } 
  
  I2CTimeout = I2CT_FLAG_TIMEOUT;
  #c)发送从地址
  I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);
  
  #d)等待从地址发送成功:测试 EV6 即可
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
  {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);
  }  
  #e)发送需要写入EEPROM的地址(本质也是数据)
  I2C_SendData(I2C1, WriteAddr);
  
  I2CTimeout = I2CT_FLAG_TIMEOUT;
  #f)等待数据发送成功:测试 EV8 即可
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(2);
  } 
  
  #g)发送需要写入的数据
  I2C_SendData(I2C1, *pBuffer); 
  
  I2CTimeout = I2CT_FLAG_TIMEOUT;  
  #h)等待数据发送成功:测试 EV8 即可
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);
  } 
  
  #i)发送停止信号“P”
  I2C_GenerateSTOP(I2C1, ENABLE);
  
  return 1;
}

3.3 读操作

【STM32】入门(七):I2C硬件控制方式

uint32_t I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)
{  
  I2CTimeout = I2CT_LONG_TIMEOUT;
  
  #a)等待是否可以读
  //*((u8 *)0x4001080c) |=0x80; 
  while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))
  {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(9);
  }
  
  #b)发送起始信号“S”
  I2C_GenerateSTART(I2C1, ENABLE);
  //*((u8 *)0x4001080c) &=~0x80;
  
  I2CTimeout = I2CT_FLAG_TIMEOUT;
  #c)等待起始信号发送成功:测试 EV5 即可
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
  {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(10);
  }

  #d)发送从地址
  I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);

  I2CTimeout = I2CT_FLAG_TIMEOUT;
  #e)等待从地址发送成功:测试 EV6 即可
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
  {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(11);
  }
    
  #f)EV6后执行EV6_1:清除EV6 (再次设置PE位)
  I2C_Cmd(I2C1, ENABLE);

  #g)发送需要读取的地址
  I2C_SendData(I2C1, ReadAddr);  

   
  I2CTimeout = I2CT_FLAG_TIMEOUT;
  #h)等待数据发送成功:测试 EV8 即可
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(12);
  }
    
  #i)复合命令:再次发送起始信号“S”
  I2C_GenerateSTART(I2C1, ENABLE);
  
  I2CTimeout = I2CT_FLAG_TIMEOUT;
  #j)等待起始信号发送成功:测试 EV5 即可
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
  {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(13);
  }
    
  #k)发送从地址
  I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Receiver);
  
  I2CTimeout = I2CT_FLAG_TIMEOUT;
  #l)等待从地址发送成功:测试 EV6 即可
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
  {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(14);
  }
  
  #m)循环读
  while(NumByteToRead)  
  {
    if(NumByteToRead == 1)
    {
      
      #n)读取完毕,发送NACK
      I2C_AcknowledgeConfig(I2C1, DISABLE);
      
      #o)发送停止信号“P”
      I2C_GenerateSTOP(I2C1, ENABLE);
    }

    #p)每次读取一个字节前,先测试 EV7    
    I2CTimeout = I2CT_LONG_TIMEOUT;
    while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)==0)  
	{
		if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);
	} 
    {      
      #q)读取一字节
      *pBuffer = I2C_ReceiveData(I2C1);
      pBuffer++; 
      NumByteToRead--;        
    }   
  }

  #r)为下一次读取做准备,即将ACK设置为1
  I2C_AcknowledgeConfig(I2C1, ENABLE);
  
  return 1;
}

3.4 待机状态

向EEPROM写入数据后,调用这个函数等待EEPROM 内部擦写完毕。

这个函数主要实现是向EEPROM 发送它设备地址,检测EEPROM 的响应,若EEPROM 接收到地址后返回应答信号,则表示EEPROM 已经准备好,可以开始下一次通讯。函数中检测响应是通过读取STM32 的SR1 寄存器的ADDR 位及AF 位来实现的,当I2C 设备响应了地址的时候,ADDR 会置1,若应答失败,AF 位会置1。文章来源地址https://www.toymoban.com/news/detail-400824.html

void I2C_EE_WaitEepromStandbyState(void)      
{
  vu16 SR1_Tmp = 0;

  do
  {
    #a)发送起始信号“S”
    I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);
    #b)读取I2C1 SR1 寄存器
    SR1_Tmp = I2C_ReadRegister(EEPROM_I2Cx, I2C_Register_SR1);
    #c)发送从地址
    I2C_Send7bitAddress(EEPROM_I2Cx, EEPROM_ADDRESS, I2C_Direction_Transmitter);
  }while(!(I2C_ReadRegister(EEPROM_I2Cx, I2C_Register_SR1) & 0x0002));
  
  #d)清除AF信号
  I2C_ClearFlag(EEPROM_I2Cx, I2C_FLAG_AF);
  #e)发送停止信号“P”    
  I2C_GenerateSTOP(EEPROM_I2Cx, ENABLE); 
}

到了这里,关于【STM32】入门(七):I2C硬件控制方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32F407系列硬件I2C笔记

    STM32F407系列有3个硬件I2C: I2C1:该接口位于GPIOB引脚上,包括PB6(I2C1_SCL)和PB7(I2C1_SDA)。 I2C2:该接口位于GPIOB引脚上,包括PB10(I2C2_SCL)和PB11(I2C2_SDA)。 I2C3:该接口位于GPIOA和GPIOC引脚上,包括PA8(I2C3_SCL)和PC9(I2C3_SDA)。   硬件I2C的速度比软件I2C更快,硬件I2C通常可以

    2024年02月04日
    浏览(17)
  • STM32 SHT40驱动源码(使用硬件I2C)

    目录 简介: SHT40.c: SHT40.h 测试结果:         SHT40是瑞士Sensirion公司推出的第四代温湿度传感器,内部集成加热器用于去除表面微小液滴。集成I2C接口,典型的相对湿度精度1.8%RH,典型温度精度0.2℃,运行在0-100%RH和-40-125℃的环境中。 主控:STM32H7B0VBT6 平台:STM32CubeIDE SHT4

    2024年03月19日
    浏览(35)
  • 【STM32】STM32学习笔记-硬件I2C读写MPU6050(35)

    I2C(Inter-Integrated Circuit)总线是一种由NXP(原PHILIPS)公司开发的两线式串行总线,用于连接微控制器及其外围设备。多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机等特性。 串行的 8 位双向数据传输位速率在标准模式下可

    2024年01月25日
    浏览(22)
  • STM32F030硬件I2C代码及解析

    刚接触STM32的时候,第一个学习的就是I2C,当时去网上学习别人写得I2C代码,虽然能用,但是当时并不理解为什么要这么配置,特别希望有人把代码掰碎了讲讲看,今天突然想起来,就把以前写的I2C代码拿出来掰碎了捋捋,希望对新手有些帮助。 先说说STM32的I2C: ST的M3系列还

    2024年02月08日
    浏览(16)
  • 【STM32学习】——STM32-I2C外设&硬件读写MPU6050&软硬件读写波形对比

    目录 前言 一、I2C外设 二、硬件I2C操作流程 1.主机发送时序 3.其他时序

    2024年02月10日
    浏览(13)
  • 【STM32】软件I2C控制频率

    在上一篇文章中,我们已经介绍了整个软件I2C的实现原理,但是也遗留了一个问题,那就是I2C速率的控制,其实就是控制SCL信号的频率。 微秒级延时 在上篇文章中,我们使用了SysTick进行延时,具体如下: 关于SysTick延时的原理,可以参考这篇文章 HAL库下的systick 底层配置

    2024年02月11日
    浏览(20)
  • STM32配合cubeMX硬件I2C驱动0.96寸OLED

    目录 一、简单介绍 1.1   OLED 1.2   I2C协议 二、实战 2.1 工程配置 2.2 测试工程 2.3 波形分析 三、驱动OLED 3.1 初始化代码 3.2 清屏函数 3.3 设置坐标函数 3.4 显示字符函数 3.5 显示字符串函数 3.6 显示图片函数 附录 驱动代码文件 oled.c oled.h f6x8.h 有机发光二极管 (英语:Organic

    2024年02月08日
    浏览(18)
  • 01_STM32软件+硬件I2C读取MPU6050(HAL库)

    目录 1、I2C简介 2、I2C时序单元 2.1 起始条件 2.2 终止条件 2.3 发送一个字节 2.4 接收一个字节 2.5 发送应答 2.6 接收应答 3、I2C完整时序 3.1 指定地址写一个字节 3.2 当前地址读一个字节 3.2 指定地址读一个字节 4、简单软件I2C代码(HAL) 4.1 软件I2C 4.2 软件I2C读MPU6050寄存器 5、ST

    2024年04月17日
    浏览(17)
  • RT-Thread在STM32硬件I2C的踩坑记录

    参考文章: 1.将硬件I2C巧妙地将“嫁接”到RTT原生的模拟I2C驱动框架 2.基于STM32F4平台的硬件I2C驱动实现笔记 3.《rt-thread驱动框架分析》- i2c驱动   最近打算用RT-Thread做一个小demo玩玩,其中需要用I2C通信驱动一个oled屏幕,但是找了一圈也没找到RTT中对硬件I2C的支持方式以及

    2024年02月11日
    浏览(22)
  • STM32F407硬件I2C实现MPU6050通讯(CUBEIDE)

    工程代码 https://download.csdn.net/download/weixin_52849254/87886714 I2C1通道可选择三种不同的通讯协议:I2C、SMBus-Alert-mode、SMBus-two-wire-Interface。 SMBus (System Management Bus,系统管理总线), 为系统和电源管理这样的任务提供了一条控制总线,SMBus与I2C总线之间在时序特性上存在一些差别 修改

    2024年02月09日
    浏览(20)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包