STM32使用HAL库通过中断实现非阻塞I2C通讯 解决实际发送错误数据的问题 HAL_I2C_Mem_Write_IT

stm32使用HAL库 使用非阻塞模式 中断完成I2C数据传输

调用HAL_I2C_Mem_Write_IT函数通过中断实现非阻塞I2C通讯

在调试过程中,程序中设定从起始地址0x00开始写入0x11 0x22,在程序debug时,HAL_I2C_Mem_Write_IT函数的形参也是0x11 0x22,结果从逻辑分析仪上看,实际主机向从机发送的是0x8E、0x04,调用读函数HAL_I2C_Mem_Read_IT后,发现写入的数据确实就是0x8E、0x04,出现了设定写入的数据和实际发送的数据不一致,发送错误数据的情况。

目录

24C08

存储大小

设备地址

数据地址

写命令和读命令

STM32G0B1RET6

程序编写


主机为STM32G0B1RET6,从机为24C08

24C08

24C08数据手册参考:

https://www.findic.com/jiage/m24c08-fmn6tp-VXQonm9zm.html#doc_tab

存储大小

8 Kbit (1 Kbyte) of EEPROM,Page size: 16 bytes,共64Page

设备地址

高四位固定为Ah

低四位分别是:

b2:E2,这一位与芯片引脚E2接VCC还是VSS(GND)有关,接VCC时为1,接VSS时为0

A9、A8:将24C08的内存分为4部分:(这里的地址是以byte为单位)

第一部分的地址为0x000-0x0FF,A9 = 0 A8 = 0

第二部分的地址为0x100-0x1FF,A9 = 0 A8 = 1

第三部分的地址为0x200-0x2FF,A9 = 1 A8 = 0

第四部分的地址为0x300-0x3FF,A9 = 1 A8 = 1

实际上A9和A8就是地址的第9和第8位(最低位是第0位)

RW:指读写命令,读命令时,该位为1,写命令时,该位为0

因此,对于24C08硬件引脚E2已接VSS,且硬件引脚WC已接VSS,如果想要向0x000地址写入数据,那么设备地址为0xA0,如果想要从0x000地址读取数据,那么设备地址为0xA1

数据地址

写命令和读命令

①写命令

If the Write Control input is driven High, the Write instruction is not executed and the

accompanying data bytes are not acknowledged.

24C08有写使能引脚,需在硬件上,将写使能引脚接地,才可以写数据

注意:页写入模式允许在单个写入周期内写入最多16个字节,前提是这些字节都位于内存中的同一页面:即最高有效内存地址位A9/A4相同。如果发送的字节数超过页末尾可容纳的字节数,则会发生"滚动",即超出页末尾的字节将从位置0开始写入同一页面。

从时序图上看,例如对于24C08硬件引脚E2已接VSS,且硬件引脚WC已接VSS,如果想要向0x000和0x001地址分别写入数据0x11和0x22,那么先发送设备地址0xA0,再发送数据地址0x00,然后再发送0x11、0x22

②读命令:

从时序图上看,例如对于24C08硬件引脚E2已接VSS,如果想要读取0x000和0x001地址,那么先发送设备地址0xA0,再发送数据地址0x00,然后再发送0xA1,再开始读取两次数据

STM32G0B1RET6

本文使用TI官方NUCLEO-G0B1RE板,相关资料参考以下博文:

NUCLEO-G0B1RE STM32G0B1RET6的学习(1)------STM32CubeIDE的安装、新建工程和配置硬件SPI-CSDN博客

I2C复用PB7和PB6

PB6 ------> I2C1_SCL

PB7 ------> I2C1_SDA

程序编写

cpp 复制代码
void I2C_Test(void)
{

	uint8_t deviceAddr = 0xA0;//设备地址 写0xA0 读0xA1 A2接地 读写页0x00
	uint8_t eepromAddr = 0x00;//读写地址
	uint8_t writeData[2] = {0x11, 0x22};
	static uint8_t readData[2]  = {0x00, 0x00};
	uint8_t writeSize = 2;
	uint8_t readSize = 2;
	static uint8_t a = 0;
	static uint32_t lastTick = 0;

	if(a == 0)
	{
		HAL_I2C_Mem_Write_IT(&hi2c1, deviceAddr, eepromAddr, I2C_MEMADD_SIZE_8BIT, writeData, writeSize);
		a = 1;
	    lastTick = GetTick();
	}
	else if(a == 1)
	{
		if(pastTickMs(lastTick) > 10)//delay10ms
		{
			a = 2;
		}
	}
	else if(a == 2)
	{
		HAL_I2C_Mem_Read_IT(&hi2c1, (deviceAddr+1), eepromAddr, I2C_MEMADD_SIZE_8BIT, readData, readSize);

		a = 3;
	}

}

逻辑分析仪得到的时序图:

写时序:

读时序:

可以看到,设定的writeData[2] = {0x11, 0x22};,但实际发送的却是0x8E和0x04

经过调试后,发现在writeData的定义上,增加static的静态,那么实际发送的数据就是正确的:

cpp 复制代码
static uint8_t writeData[2] = {0x11, 0x22};

逻辑分析仪得到的时序图:

写时序:

读时序:

由于程序是通过中断实现非阻塞I2C通讯,会将数组的地址赋值hi2c->pBuffPtr,而writeData如果定义的是局部非静态数组,那么在函数I2C_Test结束后,这一数组的地址就会被释放掉,因此,想要实现中断非阻塞I2C通讯,那么需将写入数组writeData定义为静态变量。

相关推荐
C.咖.2 小时前
STM32 ——嵌入式 存储系统、时钟系统(F407 系列)
stm32·单片机·嵌入式硬件
d111111111d7 小时前
MPU6050简介(学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习
IT阳晨。16 小时前
【STM32】ADC
stm32·单片机·嵌入式硬件
Wave84520 小时前
STM32_标准库转hal库
stm32·单片机·嵌入式硬件
@曾记否1 天前
瑞控FPVF405飞控开发板硬件功能整理
stm32·嵌入式硬件
小齐勇闯天涯1 天前
STM32--PWM原理机制
stm32·单片机·嵌入式硬件
许商1 天前
【stm32】【CDC】详解
stm32·单片机·嵌入式硬件
权泽谦2 天前
C语言控制台游戏教程:从零实现贪吃蛇(附源码+讲解)
c语言·stm32·游戏
FrozenLove_G2 天前
服务器的BMC内部有系统吗?
stm32·单片机·嵌入式硬件