STM32F030硬件I2C代码及解析

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

先说说STM32的I2C:
ST的M3系列还有M4系列的I2C基本上是一致的,但是到M0系列以后,I2C的设计是重新修改过的,所以用起来会比M3和M4系列的好用很多,前面的文章有详细描述过STM32F103的I2C的硬件缺陷,有兴趣的可以看看,接下来讲讲M0系列的硬件I2C。

从我的使用体验上来说,M0系列的I2C用起来比STM32F103的体验感强太多了,少了很多纷繁复杂的EVENT,通信的流程简化了很多,先看看初始化的代码:

void IIC_Init(void)
{
	I2C_InitTypeDef		I2C_InitStructure;
	GPIO_InitTypeDef	GPIO_InitStructure;
	
	//I2C时钟使能
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;	       //复用模式
	GPIO_InitStructure.GPIO_PuPd =  GPIO_PuPd_UP;// GPIO_PuPd_NOPULL
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
	GPIO_Init(GPIOC, &GPIO_InitStructure);

	GPIO_PinAFConfig(GPIOC,GPIO_PinSource5,GPIO_AF_0);//SDA
	GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_0);//SCL
		

	
	//IIC配置
	I2C_InitStructure.I2C_Timing=0x00200002;//0x00210507
	I2C_InitStructure.I2C_AnalogFilter=I2C_AnalogFilter_Enable;
	I2C_InitStructure.I2C_DigitalFilter=4;
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;		//I2C模式
	I2C_InitStructure.I2C_OwnAddress1 =0; //指定自己的地址为七位地址,和从器件不同即可
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;//启用应答	 
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//七位地址模式

	I2C_Init(I2C1, &I2C_InitStructure);
	/* 使能 I2C */
	I2C_Cmd(I2C1, ENABLE);  	

}

IO配置

IO配置为开漏输出,选择复用功能。

TIMING配置

I2C外设寄存器的配置,第一个参数I2C_Timing很多新手朋友可能不知道该怎么设置,原来的时候ST官方有个execl的小工具,选择I2C频率,上升时间和下降时间后,点击计算就可以得到一个值,复制过来填进去就行,如下图(可以在官网找到,名字:I2C_Timing_Configuration_V1.0.1)在这里插入图片描述

后面我发现一个更简单的办法,直接在cubemx上面选择M0的芯片的I2C,配置好对应的设置后会自动生成配置值:在这里插入图片描述

滤波器配置

timing配置完成后是滤波器的配置,模拟滤波器和数字滤波器的作用:
去除总线上的一些噪声干扰。
开启后对总线的影响:
在总线上没有挂负载时,I2C的速度可以根据时钟源选择,超过I2C协议规定的3.4M/s(如此速度下通信,前提是从机能支持),但是当开启数字滤波和模拟滤波后,速度会下降很多。
其他的配置没什么特别要注意的地方,不详细展开。

读EEPROM流程详述

I2C作为主机读写从机数据,从机是EEPROM,只做了简单的读数据操作,当时为了偷懒没有做翻页读的处理(由于当时有很多种型号的EEPROM,读写函数里做了条件编译来兼容不同系列),
EE_TYPE在头文件中的定义如下:

#define A24C01   0x01
#define A24C02   0x02
#define A24C04   0x03
#define A24C08   0x04
#define A24C16   0x05
#define A24C32   0x06
#define A24C64   0x07
#define A24C128  0x08
#define A24C256  0x09
#define A24C512  0x0a
#define A24C1024 0x0b

#define EE_TYPE A24C02
//IIC读取数据函数
void IIC_Read(uint16_t SalveAddr,uint8_t startaddr,uint8_t *buffer,uint8_t Length)
{
	uint8_t i;
	

	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));//检查总线是否繁忙
	
#if (EE_TYPE > A24C16)
	I2C_TransferHandling(I2C1,SalveAddr,2,I2C_SoftEnd_Mode,I2C_Generate_Start_Write);
	
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TXIS)==RESET);//检查TXDR寄存器是否为空
	
	I2C_SendData(I2C1, startaddr>>8);//向总线发送从器件地址	
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TXIS)==RESET);//检查发送是否完成
	 
	I2C_SendData(I2C1,startaddr);
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TC)==RESET);
	
	
#else
	I2C_TransferHandling(I2C1,SalveAddr,1,I2C_SoftEnd_Mode,I2C_Generate_Start_Write);
	
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TXIS)==RESET);//检查TXDR寄存器是否为空
	
	I2C_SendData(I2C1,startaddr);
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TC)==RESET);
#endif
	I2C_TransferHandling(I2C1,SalveAddr,Length,I2C_AutoEnd_Mode, I2C_Generate_Start_Read);//产生一个读的起始信号
	
	for(i=0;i<Length;i++)
	{
		while(I2C_GetFlagStatus(I2C1,I2C_FLAG_RXNE)==RESET);//等待接收完成
		
		buffer[i]=I2C_ReceiveData(I2C1);	
	}
	
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_STOPF)==RESET);//作为主机检测由硬件自己产生的停止信号	
	I2C_ClearFlag(I2C1,I2C_FLAG_STOPF);
}

读数据前先对总线进行BUSY判断,总线电平有变化时,说明处于busy状态,暂时无法操作。
如果总线处于空闲状态,就可以接手总线的控制权,调用I2C_TransferHandling函数向总线上的器件发起寻址,参数中需要确定从器件地址,发送字节数,及达到发送字节数后的结束方式,是否生成起始条件及读写方向。
其中结束方式有三个选项:
软件结束模式:在既定传输字节完成后,TC标志将置位且SCL线低电平将被延展,此时可以执行的操作有两个,一是不放弃总线控制权重新发起start信号,二是通过软件操作手动发送停止位。
自动结束模式:在既定传输字节完成后,硬件自动发送停止位。
重加载模式:当要传输的字节数大于255时,可以选择重加载模式,完成既定传输字节数后,TCR标志将置1,SCL会被延长,向NBYTES中写入一个非0值可以继续传输数据,但是在向NBYTES中写入最后一次传输的字节数之前,必须关闭重加载模式。

由于从器件是EEPROM,在器件地址发送完成后还要发送一次读写地址,此时如果用的从机器件是24c16以下的型号,从机的读写地址就是8位的,如果是24c32以上的,就要发送16位读写地址。读写地址发送完成后判断TC标志表示发送完成,16位地址时,需要在高8位地址发送完成后判断TXIS标志,我理解的TXIS标志置起状态是TXDR寄存器中数据传输到移位寄存器中(此寄存器没有公开到用户手册),并未转化成高低电平到总线时的状态(TC标志未置位),TXIS置起后,可以继续发送低八位地址。

到这里为止,如果通信过程顺利,接下来的操作就是对eeprom具体区域读数,由于上一次调用I2C_TransferHandling选择软件结束模式,且并未发送停止信号,接下来的操作就是调用I2C_TransferHandling,再次发起起始信号,发送从器件地址,将传输方向从写改为读,且确定传输字节数,接下来就是根据既定字节数,由硬件自动发送时钟出去读取数据,根据RXNE标志来接收数据,如果想读取的字节数小于255,可以选择自动结束模式,在传输完成后,自动发出停止信号,也可以选择软件结束(需要在传输完成后配置寄存器发出停止信号),如果接收数据大于255,选择重加载模式,操作方法上文有描述。
接收完成后,需要读取状态寄存器判断主机是否已经发送停止位,此时,一次完整的I2C作为主机读取EEPROM数据的通信过程结束。

写EEPROM流程详述

void IIC_Write(uint16_t SalveAddr,uint8_t startaddr,uint8_t *buffer, uint8_t Length)
{
	uint8_t i;
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));

#if (EE_TYPE > A24C16)	
	I2C_TransferHandling(I2C1,SalveAddr,2,I2C_Reload_Mode,I2C_Generate_Start_Write);
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TXIS)==RESET);//检查TXDR寄存器是否为空
	
	I2C_SendData(I2C1, startaddr>>8);
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TXIS)==RESET);//该位在Reload=1时NBYTES个数数据发送完成后被置1,向NBYTES写入非0数值时被清0
	I2C_SendData(I2C1,startaddr);
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TCR)==RESET);

#else 
	I2C_TransferHandling(I2C1,SalveAddr,1,I2C_Reload_Mode,I2C_Generate_Start_Write);
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TXIS)==RESET);//检查TXDR寄存器是否为空
	
	I2C_SendData(I2C1,startaddr);
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TCR)==RESET);
#endif 
	
	I2C_TransferHandling(I2C1,SalveAddr,Length,I2C_AutoEnd_Mode,I2C_No_StartStop);
	
	for(i=0;i<Length;i++)
	{
		while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TXIS)==RESET);//等待发送寄存器为空
		
		I2C_SendData(I2C1,buffer[i]);	
	}
	
	while(I2C_GetFlagStatus(I2C1,I2C_FLAG_STOPF)==RESET);//作为主机检测由硬件自己产生的停止信号
	
	I2C_ClearFlag(I2C1,I2C_FLAG_STOPF);
}

作为主机写EEPROM的操作流程类似,但是不需要修改传输方向,所以在第一次寻址时使用重加载模式,在8位或16位读写地址发送完成后,不重新生成起始信号,直接再次写入NBYTES,开始写入数据操作,由于该函数中我既定的传输字节数小于255,所以在该次传输开始前将模式修改成自动结束模式。
然后就是开始发送数据,后续结束流程和读EEPROM操作时类似。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: STM32F446是意法半导体(STMicroelectronics)推出的一款基于ARM Cortex-M4内核的高性能微控制器。它具有丰富的外设资源,其中包括一种被广泛应用的串行通信接口I2C(Inter-Integrated Circuit)。下面是关于STM32F446的I2C例程的简要介绍。 STM32F446的I2C例程是基于I2C外设的软件库函数的示例代码。该例程演示了如何使用I2C进行数据传输和通信。 一般而言,使用I2C进行数据传输主要包括以下几个步骤: 1. 设置I2C外设的参数:配置I2C总线速率、模式等,可以使用STM32提供的I2C库函数进行设置。 2. 初始化I2C外设:初始化I2C硬件资源,包括引脚和时钟等,可以使用STM32提供的I2C库函数进行初始化。 3. 配置I2C从设备:设置I2C从设备的地址和其他相关参数,以便I2C主设备能够与其进行通信。 4. 发送数据:使用I2C主设备发送数据到从设备。可以使用STM32提供的I2C库函数完成。 5. 接收数据:使用I2C主设备接收从设备发送的数据。同样可以使用STM32提供的I2C库函数完成。 6. 处理数据:根据具体应用需求对接收到的数据进行处理,例如解析、转换等。 7. 关闭I2C外设:在完成数据传输后,关闭I2C外设以释放相关资源,可以使用STM32提供的I2C库函数进行关闭。 以上步骤仅是一个基本的流程,在实际应用中可能会根据需求进行更多的配置和处理。 总的来说,STM32F446的I2C例程提供了一个示例,展示了如何使用STM32提供的库函数来实现I2C通信的基本操作。这些例程可以作为开发者学习和使用I2C的参考,帮助他们快速上手和开发自己的应用。 ### 回答2: 在STM32F446微控制器上使用I2C(Inter-Integrated Circuit)总线进行通信的例程如下: 1. 首先,需要在STM32CubeMX软件中选择I2C总线的引脚,并使能I2C外设。具体选择哪些引脚以及使能外设的操作可以根据硬件连接和需求来确定。 2. 在代码中,首先需要包含相应的头文件,例如stm32f4xx_hal.h和stm32f4xx_hal_i2c.h。 3. 然后,需要对I2C外设进行初始化。可以使用HAL_I2C_Init()函数来完成初始化操作。在初始化过程中,需要设置I2C的时钟频率、I2C模式、地址模式等参数。 4. 接下来,可以使用HAL_I2C_Master_Transmit()函数进行主设备的发送数据操作。该函数的参数包括I2C外设的句柄、从设备地址、待发送的数据缓冲区和数据长度。 5. 若要接收数据,可以使用HAL_I2C_Master_Receive()函数进行主设备的接收数据操作。该函数的参数和HAL_I2C_Master_Transmit()函数类似。 6. 如果要进行高级的I2C操作,例如使用DMA进行数据传输或者使用中断机制,可以查阅相关的参考文档和例程,并进行相应的配置和编程。 7. 最后,在使用完成I2C总线后,需要调用HAL_I2C_DeInit()函数来关闭I2C外设。 以上是使用STM32F446微控制器进行I2C通信的简要步骤和说明。具体的实现代码可以根据具体应用和使用的开发环境进行编写。 ### 回答3: STM32F446是意法半导体(STMicroelectronics)推出的一款高性能32位内核的微控制器系列。它具有丰富的外设接口,包括多个I2C总线接口。下面我将简要介绍STM32F446的I2C例程。 I2C(Inter-Integrated Circuit)是一种串行通信接口,可用于多个器件之间的通信。STM32F446的I2C控制器由硬件支持,可以通过配置寄存器来实现不同模式的通信。 在编写STM32F446的I2C例程时,我们需要进行如下步骤: 1. 初始化I2C控制器:通过设置I2C相关寄存器,如I2C_CR1、I2C_CR2等,来配置I2C的工作模式、时钟频率等参数。 2. 选择I2C模式:STM32F446的I2C控制器支持主模式和从模式。主模式用于发送命令和读取数据,从模式用于接收命令和发送数据。 3. 配置设备地址和寄存器地址:在主模式下,我们需要配置要通信的从设备地址和要访问的寄存器地址。 4. 发送和接收数据:根据需要,我们可以通过调用适当的函数来发送和接收数据。例如,使用I2C_TransmitData()函数发送数据,使用I2C_ReceiveData()函数接收数据。 5. 处理中断和错误:在I2C通信过程中,可能出现中断和错误。我们需要正确处理这些中断和错误,以确保通信的完整性和准确性。 总之,编写STM32F446的I2C例程需要配置I2C控制器、选择模式、配置地址、发送和接收数据,并处理中断和错误。在理解了I2C的基本原理和STM32F446的硬件架构后,我们可以根据具体的应用需求,编写出适用的I2C例程。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值