IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32 IIC(I2C)总线协议 -> 正文阅读

[嵌入式]STM32 IIC(I2C)总线协议

概览

在这里插入图片描述
在这里插入图片描述

IIC总线,有两条线构成 。利用开漏结构构成的总线,低 开漏,高 上拉。
SDA数据线,用于在总线上传输数据,时钟高数据有效。数据线上拉电阻拉高,IC通信口默认高阻态。
SCL时钟线,时钟信号。驱动移位寄存器,提供数据传输的节拍。时钟默认上拉电阻拉高。IC口默认高阻态。
通信速率与要求
在这里插入图片描述
通信过程

在这里插入图片描述
在这里插入图片描述

START:数据线默认高电平,在SCL为高的状态下拉低数据线打破默认状态。表示有数据即将发送,总线各设备做好准备。处于休眠中的设备会在这个时刻唤醒。
P-STOP:在SCL为高的状态下数据线恢复静默高电平。表示本次通信结束。总线数据线恢复到静默状态。
在这里插入图片描述
数据传输最先传输最高有效位
SLAVE ADDRESS:从机地址,表示接下来的数据归属,总线上N个设备,该数据发送给谁。这个设备被动接收数据。
R/W:信号是读还是写
A:回复确认信号有效为 低 (非静默状态)
过程:有设备需要使用总线发送数据。
1.设备输出SCL,SCL总线开始。
2.设备发送START bit,此时CLK保持高有效
3.CLK 拉低 开始第一个时钟
4.在时钟节拍下,SDA数据按照MSB 依次发送。
5.发送器每发送一个字节后,在第9个时钟脉冲期间释放数据线。发送完成后,主机等待从机ACK–A。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
几种模式下的参数要求
在这里插入图片描述
在这里插入图片描述

术语

在这里插入图片描述

总线仲裁。

多个主机发起通信需求 ,最先出现1的设备被淘汰,因为静默电平位1

在这里插入图片描述
可以理解为SCL被拉低时,相当于SCL接地,那么其他设备无法把SCL拉高。
在这里插入图片描述
同理数据,SDA一旦被拉低,发出的高信号无法传达至总线,所以信息传递失败,故仲裁出局。

在这里插入图片描述

主设备发送数据 0 时,直接拉低SDA数据线通过上图的方式。所以这个时候其他设备发出高,SDA数据线上的电平任然是0.

读写时序

主机发起通信,写数据
在这里插入图片描述
1.起始 ,SDA和SCL都为高的状态下。SDA由高变低打破静默状态
这是传输数据的一个开始
2.主机需要把传输的数据(地址信息),放到数据寄存器中。然后在硬件的主导下按照SCL的节拍依次把移位寄存器的内容发送到SDA总线上。从机需要在SCL高电平期间读取SDA信号。在 硬件的主导下按照SCL的节拍依次读取电平装入移位寄存器。
主机需要给 数据寄存器装填数据。硬件检查数据装填完成后,开始发送数据。
3.从机在硬件主导下开始计数,在第八个时钟下降沿处,准备做应答ACK。主机这个时候需要读取ACK消息,所以此时主机要释放SDA线(浮空),这时从机的 ACK (低)输出到SDA上,主机在SCL高电平上读取ACK
这个过程不需要CPU的 参与所以,硬件完全主导。
4.下个时刻主机开始传输第二字节的数据,那么需要 CPU或者DMA的参与把 数据装入数据寄存器中。装载完成后开始数据 传输。
读时序
在这里插入图片描述
同理
深刻的理解通信时序后,对 硬件主导的I2C机制理解会轻松许多 。

STM32的I2C

STM32 I2C结构

在这里插入图片描述
I2C核心为数据移位寄存器,按照SCLK移入或者发出数据。用于数据缓存的数据寄存器。
默认工作在从机模式下,当 接收到起始位后,移位 寄存器接收SDA线上的数据,接收7位后与 自己的地址进行比较。
头或地址不匹配:接口会忽略它并等待下一个起始位。
地址匹配:接口会依次:
● 发出应答脉冲(如果 ACK 位置 1)
● ADDR 位会由硬件置 1 并在 ITEVFEN 位置 1 时生成一个中断。
● 如果 ENDUAL=1,则软件必须读取 DUALF 位状态来核对哪些从地址进行了应答。
在这里插入图片描述
很长的一段,
上一个章节分析的很详细。为什么要设置EV阶段
1。等待上一个状态的结束
2. 下一个阶段的准备
在这里插入图片描述
I2C GPIO初始化

void I2C_GPIO_init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	/*init GPIOA CLK*/
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);


	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	/* config pin to I2c */
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource8,GPIO_AF_I2C1);
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource9,GPIO_AF_I2C1);
}

重点 .GPIO_OType = GPIO_OType_OD;
开漏输出
开漏输出就是不输出电压,控制输出低电平时引脚接地,控制输出高电平时引脚既不输出高电平,也不输出低电平,为高阻态。
SDA,SCK 默认拉高,所以必须使用开漏模式。


void I2C_cfgInit(void)
{

	I2C_InitTypeDef iic_init_struct;


	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
	
	iic_init_struct.I2C_Ack = I2C_Ack_Enable;
	iic_init_struct.I2C_AcknowledgedAddress =I2C_AcknowledgedAddress_7bit;
	iic_init_struct.I2C_ClockSpeed = 100000;
	iic_init_struct.I2C_DutyCycle = I2C_DutyCycle_2;
	iic_init_struct.I2C_Mode =I2C_Mode_I2C;
	iic_init_struct.I2C_OwnAddress1 =  0X0A;
	I2C_Init(I2C1, &iic_init_struct);

	I2C_Cmd(I2C1, ENABLE);

}

总线的初始化非常常规,没有特别的地方。

数据发送
数据的发送 比较复杂
在这里插入图片描述

1.S位发送起始位
EV5事件 SB=1(SB?) SB Start Bit
也就是说发送其实位后,需要读取SB 后再把地址写入数据寄存器
在这里插入图片描述
1.发送起始位,SB自动1.读取SR1 后,切入数据到数据寄存器,SB 清零。
所以需要等待SB为1.
2.写入地址数据到 DR 数据寄存器
3.从机应答ACK(硬件主导)
4。EV6,EV8
EV6发送数据后接收到应答,ADDR=1 表示地址成功发送。
EV8 数据寄存器空,表示数据发送完成
5.写入数据Data1
6.从机应答(硬件)EV8确定数据发送完成

7.EV8_2停止
8.P停止位

库函数版本没有对,I2C全过程进行封装,需要用户一步一步来调用

uint32_t I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite)
{
  I2CTimeout = I2CT_LONG_TIMEOUT;

  while(I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY))  
   {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(4);
  } 
  
  /* Send START condition */
  I2C_GenerateSTART(EEPROM_I2C, ENABLE);
  
  
  I2CTimeout = I2CT_FLAG_TIMEOUT;

  /* Test on EV5 and clear it */
  while(!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT))
  {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(5);
  } 
  
  /* Send EEPROM address for write */
  I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDRESS, I2C_Direction_Transmitter);
  
  I2CTimeout = I2CT_FLAG_TIMEOUT;

  /* Test on EV6 and clear it */
  while(!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) 
  {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(6);
  } 
  /* Send the EEPROM's internal address to write to */    
  I2C_SendData(EEPROM_I2C, WriteAddr);  

  I2CTimeout = I2CT_FLAG_TIMEOUT;

  /* Test on EV8 and clear it */
  while(! I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) 
  {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(7);
  } 
  /* While there is data to be written */
  while(NumByteToWrite--)  
  {
    /* Send the current byte */
    I2C_SendData(EEPROM_I2C, *pBuffer); 

    /* Point to the next byte to be written */
    pBuffer++; 
  
    I2CTimeout = I2CT_FLAG_TIMEOUT;

    /* Test on EV8 and clear it */
    while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
    {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(8);
    } 
  }

  /* Send STOP condition */
  I2C_GenerateSTOP(EEPROM_I2C, ENABLE);
  
  return 1;
}

在这里插入图片描述
所谓事件就是发送过程中硬件的输入条件,硬件执行通信协议需要按照时序和逻辑来发送数据。这些数据需要通信模块以外的部分来提供
所以产生事件。
库函数事件
在这里插入图片描述

stm32f4xx_i2c.h 中定义好事件对应的位 也就是Evx
在这里插入图片描述
使用 库函数 检测到对应事件的发生。

ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)

使用 while等待

while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) 
	{
		/*TimeOutCheck*/
	}

在这里插入图片描述
通过这个结构,可以判断通信的步骤是否完成,以便进行下一部动作。

S -->等待EV5->发送地址->ACK->等待EV6,EV8->发送数据->EV8->ACK 。。。。。

在这里插入图片描述
主接收器的传输序列图
大同小异

主要部分就是 S ,地址,Data ,Wait(EVx)
所以只需要4个 API

S

void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState)

地址

	void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction)

Data

void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data)

Wait(EVx)

while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) 
	{
		/*TimeOutCheck*/
	}
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-12-26 22:21:45  更:2021-12-26 22:22:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 12:51:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码