STM32——IIC详解

目录

1、I2C协议简介

 2、IIC的结构

2.1、外部结构

2.2、stm32——IIC的内部结构(寄存器以及时钟等)

3、IIC的时序

 ​编辑

4、stm32作为主机发送器的时序图(重点) 

5、附上代码(还有不理解的可以评论)


1、I2C协议简介

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

I2C只有一跟数据总线 SDA(Serial Data Line),串行数据总线,只能一位一位的发送数据,属于串行通信,采用半双工通信

半双工通信:可以实现双向的通信,但不能在两个方向上同时进行,必须轮流交替进行,其实也可以理解成一种可以切换方向的单工通信,同一时刻必须只能一个方向传输,只需一根数据线.
对于I2C通讯协议把它分为物理层和协议层物理层规定通讯系统中具有机械、电子功能部分的特性(硬件部分),确保原始数据在物理媒体的传输。协议层主要规定通讯逻辑,统一收发双方的数据打包、解包标准(软件层面)
摘采自博主:rivencode     原文链接:https://blog.csdn.net/k666499436/article/details/124686559

 2、IIC的结构

2.1、外部结构

STM32——IIC详解_第1张图片

还是继续看这个图 

  1. 首先,这是一个支持多个设备的总线,可以看见,被分为了主控器(主机)外围器件(从机);支持多个主机和多个从机
  2. 一个IIC只有两条线路;一条SDA(双向的数据线)、一条SCL(串行时钟线);也就是一条控制数据的收发,一条传输数据
  3. 传输的过程中呢;遵循主从机制:既然都是挂载在同一条IIC总线上的设备,为什么还要区分主机和从机呢??区别又是什么呢??

主从机制:

                区别:主机可以控制SCL(时钟线),也可以收发数据

                           从机也可以收发数据、但是只能读取SCL(时钟线)

                原因:首先一些模块在使用的过程中,他并不需要在意自己什么时候收发数据,只需要 

                           机械的进行收发数据操作,所以从机的出现就可以不用在意从机的时钟线

-------------------------------原因仅代表个人观点;个人看来应该是从设备以及控制方面来考虑的结果 

2.2、stm32——IIC的内部结构(寄存器以及时钟等)

STM32——IIC详解_第2张图片

怎么说呢,这个其实没什么好讲的,stm32芯片手册已经讲的很清楚的,我只是强调一下这个结构图的重要性而已;而且呢只有看明白这个图了,才会明白为什么要这样配置(ADC之类的这种结构体更重要)

3、IIC的时序

 STM32——IIC详解_第3张图片

 IIC作为标准时序;标准的含义便是通用的,都知道的,固定的对吧??所以IIC的时序呢是不需要我们自己去设计也不能自己设计的;我们需要的是明白IIC的时序,在不同的状态SCL代表什么SDA怎么传输数据的

首先

  1. SCL空闲状态:高电平
  2. IIC通信的起始条件:在SCL高电平时,SDA从高切换为低电平
  3. IIC通信的停止条件:在SCL高电平时,SDA从低切换为高电平
  4. IIC传输:一个时钟传输一个数据(SCL拉高一次,SDA传输一个数据)
  5. 传输顺序:高位先行
  6. 传输数据的定义:从机设备地址(一般是7位)+一位读写位+数据位(数据位没有限制)
  7. 规定:每传输8位,有一个应答位(stm32用事件实现)
  8. 发送放发ACK接收方回复ACK便可以继续传输数据;NACK便结束(主机发送停止信号)

4、stm32作为主机发送器的时序图(重点) 

STM32——IIC详解_第4张图片

咱们结合上面讲的IIC时序来理解stm32定义的IIC主发送器的序列图 

首先 序列是发送的,事件均在stm32内部

s:起始条件

EV5:一个事件,代表要开始发送数据了

地址:从机的地址(准确来说应该是7位的从机地址加读写位(这个好像也没讲,就是代表你是接

收的还是发送的))

A:ACK应答位

EV6:地址发送完毕,而且应答了ACK

EV8_1:数据开始发送(不用我们捕获)

EV8:数据正在发送

p:停止条件

5、附上代码(还有不理解的可以评论)

#include "stm32f10x.h"                  // Device header
#include "my_iic.h"

#define I2C_ADDRESS 0x78//我自己的设备地址

//发送一个数据
void my_send1(u8 addr, u8 data)
{
	I2C_GenerateSTART(I2C2,ENABLE);
	while(SUCCESS != I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT));
	
	I2C_Send7bitAddress(I2C2,I2C_ADDRESS,I2C_Direction_Transmitter);
	while(SUCCESS != I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

	I2C_SendData(I2C2,addr);
	while(SUCCESS != I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING))
	
	I2C_SendData(I2C2,data);
	while(SUCCESS != I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED));	
	
	I2C_GenerateSTOP(I2C2,ENABLE);
}

void My_IIC_Init(void)
{
  // 1. 时钟使能
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE); // 使能I2C2时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 使能GPIOB时钟

  // 2. GPIO配置 (SCL在PB10,SDA在PB11)
	GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 开漏输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  // 3. I2C初始化
	I2C_InitTypeDef I2C_InitStructure;
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; // 标准模式
  I2C_InitStructure.I2C_OwnAddress1 = 0x00; // 自己的I2C地址 (可根据需要修改)
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  I2C_InitStructure.I2C_ClockSpeed = 50000; // 50kHz
  I2C_Init(I2C1, &I2C_InitStructure);

  // 4. I2C使能
  I2C_Cmd(I2C1, ENABLE);


}

你可能感兴趣的:(嵌入式,stm32,嵌入式硬件,单片机)