前言

网上有些人说STM32的硬件I2C使用起来有问题,我用起来一点问题都没有,下面大致说一下最近做这个的心得

CubeMX设置

软件采用最新的CubeMX和SDK生成,芯片型号STM32F107RC
首先时钟使用常规的72M,这部分配置很多芯片都一样

I2C的配置也是普普通通,保持默认就好,不使用DMA传输

I2C初始化代码

以下代码由CubeMX自动生成,在用户代码区(USER CODE)添加了解除写保护WR的代码,除此之外没有其它修改

void MX_I2C1_Init(void)
{hi2c1.Instance = I2C1;hi2c1.Init.ClockSpeed = 100000;hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;hi2c1.Init.OwnAddress1 = 0;hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;hi2c1.Init.OwnAddress2 = 0;hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;if (HAL_I2C_Init(&hi2c1) != HAL_OK){Error_Handler();}}void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(i2cHandle->Instance==I2C1){/* USER CODE BEGIN I2C1_MspInit 0 *//* USER CODE END I2C1_MspInit 0 */__HAL_RCC_GPIOB_CLK_ENABLE();/**I2C1 GPIO Configuration    PB6     ------> I2C1_SCLPB7     ------> I2C1_SDA */GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/* I2C1 clock enable */__HAL_RCC_I2C1_CLK_ENABLE();/* I2C1 interrupt Init */HAL_NVIC_SetPriority(I2C1_EV_IRQn, 5, 0);HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);HAL_NVIC_SetPriority(I2C1_ER_IRQn, 5, 0);HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);/* USER CODE BEGIN I2C1_MspInit 1 */GPIO_InitStruct.Pin = GPIO_PIN_4;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_PULLDOWN;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);  //DISABLE wr/* USER CODE END I2C1_MspInit 1 */}
}

从设备读写

一般的EEPROM,像AT24C02这种小容量的设备,地址都只需要8位,页大小一般是16字节一个页
而像AT24C32C、AT24C64C这种32K、64K字节的大容量EEPROM,8位地址是不够的,使用了16位地址,页大小在这两个器件中也变成了32字节
正是由于容量的不同,导致代码上需要做差异化处理,才能正确读取EEPROM芯片

以下代码可以参考,写的时候无法跨页,因此写大量数据的时候,只能一页一页的写,两次写之间保证5MS的间隔
读没有跨页的影响,可以一次性把全部数据读出来,但是要注意,读和写之间,是要有5MS的间隔的,否则读不到数据。也就是说每次写完,延迟5MS,就能保证后续的程序没有问题。

//#define I2C_MEMADD_SIZE        I2C_MEMADD_SIZE_8BIT            //小容量EEPROM芯片8位地址用此参数
#define I2C_MEMADD_SIZE     I2C_MEMADD_SIZE_16BIT       //大容量EEPROM芯片16位地址用此参数
#define ADDR_AT24C02_Write 0xA0     //EEPROM I2C写地址
#define ADDR_AT24C02_Read 0xA0+1   //EEPROM I2C读地址typedef enum SYS_PARA_ENUM {LOCAL_IP = 0,UDP_LOCAL_PORT,UDP_PC_PORT,NETMASK,GATEWAY,SERVER_IP,SERVER_PORT,VERSION,SN_NUM,   //16字节SENSOR_TYPE = SN_NUM + 4,SENSOR_DATA_TYPE,SENSOR_INTERVAL,SYS_PARA_MAX,     //end
}sys_para_e;//请注意,为了方便flash读写操作,此处的每一项均设为uint32_t类型
//如果不为uint32_t类型,则flash_write函数将出现错误
typedef struct SYS_PARA_TYPE {uint32_t local_ip;            //本机IP,大端模式uint32_t udp_local_port;  //本机端口号uint32_t udp_pc_port;        //PC端口号uint32_t netmask;            //本机子网掩码,大端模式uint32_t gateway;           //本机网关,大端模式uint32_t server_ip;           //服务器IP,大端模式uint32_t server_port;        //服务器端口号uint32_t version;           //stm32软件版本号uint32_t sn_num[4];         //SN号   5 6 7 8uint32_t sensor_type;        //传感器类型 9uint32_t sensor_data_type; //传感器数据类型uint32_t sensor_interval;  //传感器采集时间间隔
}sys_para_t;/* -----------------------------------------------------------------------------
函数名:     i2c_write
作者:      glx
日期:      2020-11-10
功能:      数据写入eeprom
输入参数:    pData:数据指针
返回值:     类型:HAL_StatusTypeDefHAL_OK:操作成功HAL_ERROR:操作失败
修改记录:
------------------------------------------------------------------------------*/
HAL_StatusTypeDef i2c_write(void *pData)
{HAL_StatusTypeDef ret = HAL_ERROR;uint8_t i, page, pageSize;uint8_t *p = (uint8_t *)pData;if(pData != NULL){if(I2C_MEMADD_SIZE == I2C_MEMADD_SIZE_8BIT){pageSize = 16;           //一页16字节,不能跨页写page = SYS_PARA_MAX/4;}else if(I2C_MEMADD_SIZE == I2C_MEMADD_SIZE_16BIT){pageSize = 32;            //一页32字节,不能跨页写page = SYS_PARA_MAX/8;}//写完整的页for(i = 0; i<page; i++){ret = HAL_I2C_Mem_Write(&hi2c1, ADDR_AT24C02_Write, i*pageSize, I2C_MEMADD_SIZE, p, pageSize, 100);p += pageSize;if(ret != HAL_OK){printf("I2C_Write Sys Para write error\r\n");return HAL_ERROR;}HAL_Delay(5);}//写残缺的页if(SYS_PARA_MAX > (page*4))   {ret = HAL_I2C_Mem_Write(&hi2c1, ADDR_AT24C02_Write, i*pageSize, I2C_MEMADD_SIZE, p, 4*SYS_PARA_MAX-pageSize*page, 100);if(ret != HAL_OK){printf("I2C_Write Sys Para write error\r\n");return HAL_ERROR;}HAL_Delay(5);}}else{printf("I2C_Write pData NULL\r\n");return HAL_ERROR;}return HAL_OK;
}/* -----------------------------------------------------------------------------
函数名:     i2c_read
作者:      glx
日期:      2020-11-10
功能:      读取eeprom数据
输入参数:    pData:数据指针
返回值:     类型:HAL_StatusTypeDefHAL_OK:操作成功HAL_ERROR:操作失败
修改记录:
------------------------------------------------------------------------------*/
HAL_StatusTypeDef i2c_read(void *pData)
{HAL_StatusTypeDef ret = HAL_ERROR;if(pData != NULL){ret = HAL_I2C_Mem_Read(&hi2c1, ADDR_AT24C02_Read, 0, I2C_MEMADD_SIZE, (uint8_t *)pData, SYS_PARA_MAX*4, 100);if(ret != HAL_OK){printf("I2C_Read Sys Para read error\r\n");return HAL_ERROR;}     }else{printf("I2C_Read pData NULL\r\n");return HAL_ERROR;}return HAL_OK;
}

读写的代码


//用于保存系统参数
sys_para_t sys_para = {0};
//用于保存系统默认参数
sys_para_t default_para = {.local_ip = 107<<24 | 10<<16 | 168<<8 | 192,.udp_local_port = 18080,.udp_pc_port = 18081,.netmask = 0<<24 | 255<<16 | 255<<8 | 255,.gateway = 1<<24 | 10<<16 | 168<<8 | 192,.server_ip = 9<<24 | 10<<16 | 168<<8 | 192,.server_port = 18082,.version = 20201124,.sn_num[0] = 0xffffffff,.sn_num[1] = 0xffffffff,.sn_num[2] = 0xffffffff,.sn_num[3] = 0xffffffff,.sensor_type = SENSOR_DOOR,.sensor_data_type = SENSOR_DATA_GPIO,.sensor_interval = 1000,
};i2c_read(&sys_para);
i2c_write(&default_para);

STM32硬件I2C的一点心得(AT24C32C和AT24C64C)相关推荐

  1. stm32硬件I2C测试例程,亲测可用

    对于stm32的硬件I2C确实有不尽人意的地方.但是还是可以实现的,毕竟使用stm32的硬件I2C确实比使用IO口来模拟简单的多.下面的程序代码是使用stm32F03ZET6的I2C1(PB6,PB7 ...

  2. STM8/STM32硬件I2C读取APDS9930程序代码

    STM的硬件I2C一直被各种吐槽,实际上只是用起来比较复杂而已,难点主要是在作为Master时的数据接收上,作为Slave时的数据发送没难度,正常用.重点是要真正掌握它里面设计的那个Data shif ...

  3. STM32 硬件i2c作为从机总是卡死

    调试i2c从机的时候,配置都注册,就是主机读到我的从机的时候就会卡死.摸索了好几天最后发现是clock no stretch mode 没有enable.真是醉了,完全是按照官方例程配置的. 如果cl ...

  4. STM32硬件I2C与软件模拟I2C超详解

    ✅作者简介:嵌入式入坑者,与大家一起加油,希望文章能够帮助各位!!!!

  5. STM32单片机硬件I2C驱动程序(查询方式)

    本文章原始地址:http://feotech.com/?p=69 本程序主要用于驱动STM32单片机芯片的硬件I2C寄存器,实现通过使用芯片自带的I2C寄存器进行数据的发送与接收. 本例程中采用I2C ...

  6. STM32单片机硬件I2C驱动程序(软件轮询方式)---摘自:FeoTech

    感谢原作者:FeoTech   原文网址:http://feotech.com/?p=69 本程序主要用于驱动STM32单片机芯片的硬件I2C寄存器,实现通过使用芯片自带的I2C寄存器进行数据的发送与 ...

  7. STM32单片机硬件I2C读取AHT10温湿度传感器数据

    STM32使用硬件IIC读取AHT10温湿度传感器的数据并显示在0.96寸OLED屏上. 我用的单片机是STM32F103C8T6,程序用的是ST标准库写的. STM32使用硬件I2C读取SHTC3温 ...

  8. STM32F10x_硬件I2C读写EEPROM(标准外设库版本)

    Ⅰ.写在前面 上一篇文章是"STM32F10x_模拟I2C读写EEPROM",讲述使用IO口模拟I2C总线通信,对EEPROM(AT24Xxx)进行读写操作的过程. 上一篇文章主要 ...

  9. STM32F10x_硬件I2C主从通信(轮询发送,中断接收)

    推荐 分享一个大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到人工智能的队伍中来!http://www.captainbed.net/strongerhuang Ⅰ.写在前面 ...

最新文章

  1. Netty实现自定义协议
  2. Android Studio 上Activity的互相切换
  3. MongoDB副本集同步原理
  4. 线程休眠 java 1615477264
  5. bubbleSort 冒泡排序
  6. 比较两个数组,输出不重复的数组
  7. javase基本配置(jdk)
  8. mysql存储ip地址_MySQL怎样存储IP地址
  9. 定义一个Employee类,排序
  10. python交通调查数据处理_python 小型交通调查后的数据处理(数车)
  11. 我的世界会员特效在服务器显示,腐竹教你在游戏中制作登录提示效果
  12. [置顶]       jBPM4工作流开发实战 之 第二部分 jBPM4开发入门
  13. 本地mongochef连接其他计算机上的数据库认证失败解决方法
  14. 爬虫爬出来的数据不全_Web Scraper教程(二)爬虫入门之当当畅销书爬取
  15. 互联网寒冬,那些不怕失业的程序员们,都有什么技能?
  16. pyqt5 PDM下载工具 Persepolis Download Manager 记录
  17. MIP 和 MinIP
  18. Axure 设计App界面
  19. 区块链开发如何选择底层平台和开发语言?
  20. 解决Git报错: warning: LF will be replaced by CRLF in ** 的原因及解决办法

热门文章

  1. 域名解析产品——HTTPDNS使用教程
  2. 在线九宫切图(九宫格切图)工具
  3. Tomcat配置和部署
  4. py2exe找不到Python的解决方法
  5. 可靠性设计原则1000条
  6. Matlab的residuez和residue的区别,举例
  7. Word交叉引用怎么才能只引用编号项
  8. 英飞凌硅麦可以接收到超声波吗?
  9. 大端与小端字节数据详解
  10. 【阿朱洞察】中国大数据行业的下一步走向