你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32CubeMX的I2C总线经验分享

[复制链接]
攻城狮Melo 发布时间:2023-7-1 19:09
1.I2C总线及AT24C02芯片
1.1 I2C总线简介
I2C(Inter-Integrated Circuit)总线是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。是由数据线SDA和时钟线SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,高速I2C总线一般可达400kbps以上。下面从物理层和协议层两方面来了解I2C:
I2C物理层:可连接多个I2C通讯设备,支持多个通讯主机和从机;每个连接到总线的设备都有一个独立的地址,主机利用这个地址进行不同设备之间的访问;总线通过上拉电阻接到电源,当I2C设备空闲时会输出高阻态;多主机同时使用总线时,利用仲裁方式觉得由哪个设备占用总线;有三种传输模式,标准模式(100kbit/s)、快速模式(400kbit/s)、高速模式(3.4Mbit/s 多数I2C设备不支持);连接到相同总线的I2C数量受最大电容400pF限制

微信图片_20230701190856.png

I2C协议层:I2C总线在传送数据的过程中共有三种类型信号,在这些信号中,起始信号是必需的,结束和应答信号可以不要;I2C总线寻址按照从机地址可分为7位和10位(寻址字节)寻址两种,D7~D1位组成从机的地址,D0位是数据传送方向(0表示主机向从机写数据/1表示主机由从机读数据)


  • 开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据
  • 结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据

  • 应答信号:接收数据的IC在接收到8位数据后,向发送数据的IC发出特定的低电平脉冲,表示已经收到数据。CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若为收到应答性,判断为受控单元故障


微信图片_20230701190853.png


1.2 AT24C02芯片简介
AT24C02是一个2K位串行CMOS,内部含有256个字节,此芯片具有I2C通讯接口,芯片内保存的数据在掉电的情况下不丢失(EEPROM),常用于存放比较重要的数据。本实验使用的是SOP-8封装的AT24C02芯片,其引脚说明见下图

微信图片_20230701190849.png

AT24C02芯片的器件地址为7位,高4位固定为1010,低3位有上表中的A0/A1/A2引脚的电平决定,还有一位(最低位R/W)用来选择读写方向。本实验中A0/A1/A2引脚接在GND上了,因此器件地址为1010000;加上最低位的读写方向位后,写器件地址为10100000(0xA0),读器件地址为10100001(0xA1)

微信图片_20230701190846.png


下图为AT24C02的总线时序图和时间参数

微信图片_20230701190842.png

微信图片_20230701190839.png


2.硬件设计
D1指示灯用来提示系统运行状态,K_UP按键用来控制24C02的数据写入,K_DOWN按键用来控制24C02的数据读取,数据的写入与读取信息通过串口1打印出来


  • 指示灯D1
  • USART1串口
  • AT24C02

  • K_UP和K_DOWN按键


微信图片_20230701190835.png


3.软件设计
3.1 STM32CubeMX设置
➡️ RCC设置外接HSE,时钟设置为72M
➡️ PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
➡️ USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位
➡️ PA0设置为GPIO输入模式、下拉模式;PE3设置为GPIO输入模式、上拉模式
➡️ 激活I2C2,选择标准传输模式,选择7位寻址地址,其余默认设置
➡️输入工程名,选择路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码

微信图片_20230701190831.png

3.2 MDK-ARM软件编程
➡️ 在i2c.c文件下可以看到I2C初始化函数
  1. void MX_I2C2_Init(void){
  2.   hi2c2.Instance = I2C2;
  3.   hi2c2.Init.ClockSpeed = 100000;
  4.   hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2;
  5.   hi2c2.Init.OwnAddress1 = 0;
  6.   hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  7.   hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  8.   hi2c2.Init.OwnAddress2 = 0;
  9.   hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  10.   hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  11.   if (HAL_I2C_Init(&hi2c2) != HAL_OK){
  12.     Error_Handler();
  13.   }
  14. }

  15. void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle){
  16.   GPIO_InitTypeDef GPIO_InitStruct = {0};
  17.   if(i2cHandle->Instance==I2C2){
  18.     __HAL_RCC_GPIOB_CLK_ENABLE();
  19.     /**I2C2 GPIO Configuration   
  20.     PB10     ------> I2C2_SCL
  21.     PB11     ------> I2C2_SDA*/
  22.     GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
  23.     GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
  24.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  25.     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  26.     /* I2C2 clock enable */
  27.     /*网上看到很多资料说此处的I2C时钟初始化函数应该放在GPIO
  28.       初始化之前,但是这里没有调整也能够正常读写EEPROM*/
  29.     __HAL_RCC_I2C2_CLK_ENABLE();       
  30.   }
复制代码
➡️ 创建按键驱动文件key.c 和相关头文件key.h,参考[color=var(--weui-LINK)]按键输入例程
➡️ 创建AT24C02驱动文件24cxx.c和24cxx.h
  1. #define ADDR_24CXX_WRITE 0XA0
  2. #define ADDR_24CXX_READ  0XA1
  3. void AT24CXX_Init(void){
  4.   MX_I2C2_Init();       
  5.   while(AT24CXX_Check()){
  6.     printf("AT24C02 Checked Failed!\r\n");
  7.     HAL_Delay(500);
  8.   }
  9.   printf("AT24C02 Checked Sucessed!\r\n");
  10. }

  11. uint8_t AT24CXX_Check(void){
  12.   uint8_t temp;
  13.   HAL_I2C_Mem_Read(&hi2c2,ADDR_24CXX_READ,255,I2C_MEMADD_SIZE_8BIT,&temp,1,0xff);                                  
  14.   if(temp==0x36)       
  15.     return 0;                  
  16.   else{
  17.     uint8_t data = 0x36;
  18.     HAL_I2C_Mem_Write(&hi2c2,ADDR_24CXX_WRITE,255,I2C_MEMADD_SIZE_8BIT,&data,1,0xff);
  19.     HAL_I2C_Mem_Read(&hi2c2,ADDR_24CXX_READ,255,I2C_MEMADD_SIZE_8BIT,&temp,1,0xff);          
  20.     if(temp==0x36)       
  21.       return 0;
  22.   }
  23.   return 1;                                                                                          
  24. }
复制代码

➡️ 在main.c文件下编写I2C测试代码

AT24C02的2Kbit分为32页,每页8个字节。而EEPROM也可以按页写入,本例使用了按页写入的方式,分32次写入。注意每次写入完毕需要延时5ms,是AT24C02芯片的要求;读取数据没有页的限制,可以一次全部读取256个字节

  1. /* USER CODE BEGIN PV */
  2. #define ADDR_24CXX_WRITE 0XA0
  3. #define ADDR_24CXX_READ  0XA1
  4. uint8_t WriteBuf[256];
  5. uint8_t ReadBuf[256];
  6. uint16_t i,j;
  7. /* USER CODE END PV */
  8. int main(void){
  9.   uint8_t key;
  10.   HAL_Init();
  11.   SystemClock_Config();
  12.   MX_GPIO_Init();
  13.   MX_I2C2_Init();
  14.   MX_USART1_UART_Init();
  15.   /* USER CODE BEGIN 2 */
  16.   AT24CXX_Init(void);
  17.   printf("\r\n*********STM32CubeMX I2C AT24C02 Example*********\r\n");
  18.   for(i = 0;i < 256; i++){         //初始化写数据缓冲区
  19.     WriteBuf[i] = i;
  20.   }
  21.   /* USER CODE END 2 */
  22.   while (1){
  23.     key = KEY_Scan(0);
  24.     if(key == KEY_UP_PRES){
  25.       for(j = 0;j < 32;j++){        //按页写入EEPROM,分32次写入
  26.         if(HAL_I2C_Mem_Write(&hi2c2,ADDR_24CXX_WRITE,8*j,I2C_MEMADD_SIZE_8BIT,WriteBuf+8*j,8,0xFF) == HAL_OK){
  27.           printf("\r\nEEPROM 24C02 Write Test OK!\r\n");
  28.           HAL_Delay(5);
  29.         }
  30.         else{
  31.           printf("\r\nEEPROM 24C02 Write Test False!\r\n");
  32.           HAL_Delay(5);                                       
  33.         }
  34.       }
  35.     }
  36.     //EEPROM读取没有页限制,可以一次读取256个字节       
  37.     if(key == KEY_DOWN_PRES){       
  38.       HAL_I2C_Mem_Read(&hi2c2,ADDR_24CXX_READ,0,I2C_MEMADD_SIZE_8BIT,ReadBuf,256,0xFF);
  39.       for(i=0;i<256;i++){
  40.         printf("0x%02X ",ReadBuf[i]);
  41.       }
  42.       //通过内存比较,判断读取和写入的数据是否相同       
  43.       if(memcmp(WriteBuf,ReadBuf,256) == 0){       
  44.         printf("\r\nEEPROM 24C02 Read Test OK!\r\n");
  45.       }
  46.       else{
  47.         printf("\r\nEEPROM 24C02 Read Test False!\r\n");
  48.       }
  49.     }
  50.        
  51.     HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
  52.     HAL_Delay(500);
  53.   }
  54. }
复制代码

4.下载验证
编译无误下载到开发板后,可以看到D1指示灯不断闪烁,当按下K_UP按键后数据写入到24C02芯片内,当按下K_DOWN按键后读取24C02芯片的值,同时串口打印出相应信息

微信图片_20230701190826.png


转载自:嵌入式攻城狮


如有侵权请联系删除


收藏 评论0 发布时间:2023-7-1 19:09

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版