【STM32L496】使用HAL库实现I2C写入/读取数据(M24C32)

I2C原理与配置

IIC原理超详细讲解—值得一看
【嵌入式硬件芯片开发笔记】EEPROM芯片M24C32配置流程
STM32硬件I2C与软件模拟I2C超详解

M24C32芯片了解

实现通信功能的芯片为M24C32,对此,芯片手册上第一页就有对其概括描述。

Automotive 32-Kbit serial I²C bus EEPROM with 1 MHz clock

启动/停止条件:当串行时钟(SCL)位于高电平状态,串行数据(SDA)位于下降沿时,M24C32开始接收数据;串行数据(SDA)位于上升沿时,M24C32停止接收数据。
数据输入:SCL上升沿时SDA进行采样。SDA必须在SCL的上升沿期间保持稳定,且当SCL被驱动为低电平时,SDA才改变电平状态。
设备寻址:设备选择代码由一个4位设备类型标识符和一个3位芯片使能地址(E2、E1、E0)组成,设备类型标识符中,1010b为选择存储器(to select the memory),1011b为选择标识页(to select the Identification page)。
在一条I2C总线上最多可连接8个存储器设备。每个片上使能输入(E2、E1、E0)上都有一个唯一的3位代码;当收到设备选择代码时,只有当芯片使能地址与E2、E1、E0输入解码值相同时,存储器设备才会响应。
第八位是读写位,1=read,0=write.
设备寻址表

读操作

看到Current Address Read这行,它是一次读当前地址数据的过程。在开始信号发出后,主设备会发出一个7位片选信号,第八位是设备读/写模式,ACK是从设备应答信号,当从设备发来一个应答信号时,主设备会发送数据,数据传输完成后,从设备不需要发应答信号,最后是主设备发送停止位结束这一次的读操作。Random Address Read是随机地址读操作,而后面的Sequential Current Read就是按顺序读了。Random Address ReadSequential Random Read模式下,需要设备发送地址才能读,所以有两次发送地址的序列。
Read operations
读指令后,若总线发送额外的时钟脉冲并确认每个传输的数据字节,则设备可按顺序输出下一字节。若终止字节流,总线必须不确认最后一个字节,并且必须生成一个停止条件。
读模式下确认:对于所有读指令,设备在发送每个字节后,在第9位时间内等待一个确认标识符,若总线主设备不发送确认(主驱动器SDA在第9位时间为高),则设备终止数据传输并进入待机模式。

写操作

看到Byte Wirte这行,它是一次写操作过程。在开始信号发出后,主设备会发出一个7位片选信号,第八位是设备读/写模式,ACK是从设备应答信号,当从设备发来一个应答信号时,主设备会给从设备发送一个字节地址,如果从设备发来应答信号,主设备此时会再发一次字节地址,当从设备应答后,主设备才会发送数据,数据传输完成后,从设备发来应答信号,最后是主设备发送停止位结束这一次的写操作。Page Write是连续写操作,前面的发片选和地址和Byte Write一样,不一样的是主设备会一直发数据。
Write operations

HAL库配置及初始化

根据原理图和芯片手册配置相关参数
M24C32引脚图

引脚配置参数配置
配置完成后,会生成一个i2c的句柄,当我们需要对i2c进行读写等操作时,对hi2c取地址,它就会调用HAL库中的寄存器回调,然后实现i2c规范中的功能(比如说init、status、mode、errcode这种)。

I2C_HandleTypeDef hi2c1;

部分代码

一开始列出的大概框架如下。

int i2c_write(const unsigned char *pwbuf, const unsigned short wbuflen);

int i2c_read(unsigned char *prBuf, const unsigned short *rbuflen);

void main(void)
{
	//write
	unsigned short wBuflen = 128;
	unsigned char wBuf[wBuflen] = {0};
	for(unsigned char i =0 ;i<wBuflen;i++)
	{
		wBuf[i] = i;
	}	
	int wret = i2c_write(wBuf, wBuflen);

	//read
	unsigned char rBuf[128] = {0};
	unsigned short rlen = 128;
	int rret = i2c_read(rBuf, rlen);
}

因为之前设置的是七位设备地址(第八位是读写位),所以在读写时需要左移一位,HAL库中I2C的读写存储器比较方便,只需要调用HAL_I2C_Mem_WriteHAL_I2C_Mem_Read函数即可。

int i2c_write(uint8_t devadd,uint16_t memadd,uint16_t memsize,uint8_t *pwbuf, const unsigned short wbuflen)
{
	devadd = (devadd<<1)&0xFF;
	if(pwbuf != NULL || wbuflen != 0)
	{
		if(HAL_I2C_Mem_Write(&hi2c1,devadd,memadd,memsize,pwbuf, wbuflen,0xFFFF)==HAL_OK)
		{
			return 1;
		}
	}
	else
	{
		return 0;
	}
}

int i2c_read(uint8_t devadd,uint16_t memadd,uint16_t memsize,uint8_t *prbuf, const unsigned short rbuflen)
{
	devadd = (devadd<<1)&0xFF;
	
	if(prbuf != NULL || rbuflen != 0)
	{
		if(HAL_I2C_Mem_Read(&hi2c1, devadd, memadd,memsize, prbuf,rbuflen,0xFFFF)==HAL_OK)
		{
			return 1;
		}
	}
	else
	{
		return 0;
	}
}

这两个函数在stm32l4xx_hal_i2c.c文件下

HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress,
                                    uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress,
                                   uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)

实际实现示例,当i2c开始写的时候,因为是一个字一个字地写,所以存储器地址每次加i,即0x0000+i,并且需要延迟一会,否则太快了芯片来不及存数据。
读就直接读,从0x0000开始读。

void I2C_ReadorWrite(uint8_t flag)
{
	if(flag == 1)
	{
		//write
		unsigned char i;
		uint8_t dat=0;
		if(HAL_I2C_IsDeviceReady(&hi2c1,M24C32_ADD<<1,2,0x00ff)==HAL_OK)
		{
			i=0;
		}
		unsigned short wBuflen = 128;
		for(i = 0;i<wBuflen;i++)//i2c clear
		{
			dat=0;
			i2c_write(M24C32_ADD,0x0000+i,I2C_MEMADD_SIZE_16BIT,&dat,1);
			delay_ms(10);
		}	
		for(i = 0;i<wBuflen;i++)//i2c write
		{
			dat=i;
			i2c_write(M24C32_ADD,0x0000+i,I2C_MEMADD_SIZE_16BIT,&dat,1);
			delay_ms(10);
		}	
	}
	else if(flag == 0)
	{
		//read
		unsigned char rBuf[128] = {0};
		unsigned short rlen = 128;
		i2c_read(M24C32_ADD,0x0000,I2C_MEMADD_SIZE_16BIT,rBuf,rlen);
//	for(i=0;i<rlen;i++)
//	{
//		printf("rBuf[%d] = %02X \n",i,rBuf[i]);
//	}
		//uint16_t re_dat=0;
		//i2c_write(M24C32_ADD,0x0000,I2C_MEMADD_SIZE_16BIT,&dat,1);
		//delay_ms(55);

		//i2c_write(M24C32_ADD,0x0000,I2C_MEMADD_SIZE_16BIT,&dat,1);
		//delay_ms(50);
		//i2c_read(M24C32_ADD,0x0000,I2C_MEMADD_SIZE_16BIT,&re_dat,1);
	}
}

遇到的问题

要了解手头这个芯片的i2c地址位数,一般都是7位,在读写时不能忘记移位。
在存储数据时记得调用delay,否则会出现输出的数据有漏掉的情况。
除了这个EEPROM芯片还有一个LP87702芯片的,在熟悉中。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32 HAL I2C库是一种用于STM32微控制器的库集合,用于实现I2C总线通信协议。该库集成了STM32微控制器所有的I2C控制器寄存器,提供了更为简单易用的API接口,方便开发人员进行I2C总线通信开发。 STM32 HAL I2C库的主要特点包括以下几点: 1. 支持多种I2C模式:包括标准模式(100Kbps)、快速模式(400Kbps)和高速模式(1Mbps)等。 2. 支持多个I2C从机设备:可以连接多个从机设备,并分别进行读写操作。 3. 提供了简单易懂的API接口:开发人员可以使用简单的函数调用实现I2C总线设备的初始化、读写操作等。 4. 提供了中断和DMA两种数据传输方式:可以根据实际应用场景选择适合的数据传输方式。 5. 支持主机和从机模式切换:可以在运行过程中切换主机和从机模式。 总之,STM32 HAL I2C库是一种非常实用的工具,可以帮助开发人员快速方便地进行STM32微控制器的I2C总线通信开发。无论是在工业自动化、智能家居、医疗设备等领域,都有着广泛的应用。 ### 回答2: STM32 HAL I2C库是为STM32微控制器设计的一个硬件抽象层库,可以方便地实现I2C总线的读写操作。I2C(Inter-Integrated Circuit)总线是一种串行通信总线,常用于连接微控制器、传感器、模拟转换器等设备。在使用I2C通信时,我们需要设置一些参数,如设备地址、传输模式、传输速率等。STM32 HAL I2C库封装了这些设置,在使用前,只需要初始化相关参数即可。 在STM32 HAL I2C库中,我们可以使用一些常用的函数,如I2C_Init()、I2C_Mem_Write()、I2C_Mem_Read()等。其中,I2C_Init()函数用于初始化I2C总线,设置传输模式、速率等参数;I2C_Mem_Write()和I2C_Mem_Read()函数用于在指定的设备地址下,读写指定的寄存器。 此外,STM32 HAL I2C库还提供了一些高级函数,如I2C_Master_Transmit()、I2C_Master_Receive()、I2C_Slave_Transmit()、I2C_Slave_Receive()等,可以方便地实现主从模式的通信。 总之,STM32 HAL I2C库提供了方便快捷的API接口,简化了I2C总线操作过程,使得开发者可以更加专注于应用程序的开发。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值