stm32——I2C协议

06-01 1260阅读

I2C协议概述


  • I2C协议详解

    概述

    I2C(Inter-Integrated Circuit)协议是由Philips(现NXP)开发的串行通信总线,用于连接微控制器和外围设备(如EEPROM、传感器、ADC/DAC等)。它是一种同步、半双工、多主多从的串行通信协议。

    主要特点

    • 两线制:仅使用两根线进行通信:
      • SCL (Serial Clock Line):串行时钟线(由主设备生成)
      • SDA (Serial Data Line):串行数据线(双向传输)
      • 多主多从:总线上可连接多个主设备和多个从设备
      • 半双工:同一时刻只能单向传输数据
      • 地址寻址:每个从设备有唯一7位或10位地址
      • 开漏输出:SCL和SDA均为开漏输出,需外接上拉电阻(4.7kΩ或10kΩ)
      • 线与逻辑:支持多主设备仲裁

        连接拓扑

        核心原理

        1. 起始条件(Start Condition)

        • SCL高电平时,SDA从高→低跳变
        • 主设备获取总线控制权
          SDA: -----|________
                  |
          SCL: _____|
          

          2. 停止条件(Stop Condition)

          • SCL高电平时,SDA从低→高跳变
          • 主设备释放总线
            SDA: ________|-----
                    |
            SCL: _______|
            

            3. 数据传输

            • 数据在SCL高电平期间保持稳定
            • 数据变化发生在SCL低电平期间
            • 8位数据,MSB(最高位)优先
              SDA: --Bit7--Bit6--...--Bit0--
                    _   _   _   _   _   _   _   _
              SCL: | |_| |_| |_| |_| |_| |_| |_| |
              

              4. 应答机制(ACK/NACK)

              每字节传输后的第9个时钟周期:

              • ACK:接收方拉低SDA(成功接收)
              • NACK:接收方保持SDA高电平(接收失败)
                SDA: ... Bit0 | ACK/NACK
                             _
                SCL: ... Bit0|_| 
                

                5. 地址帧

                • 起始条件后发送
                • 7位地址 + 1位R/W方向位:
                  • R/W=0:主→从写操作
                  • R/W=1:主←从读操作
                  • 地址匹配的从设备回复ACK

                    通信时序

                    写操作时序(主→从)

                    主设备: [START] → [Addr+W] → [Data1] → [Data2] → [STOP]
                    从设备:           [ACK]     → [ACK]     → [ACK]
                    

                    读操作时序(主←从)

                    主设备: [START] → [Addr+R] → [NACK] → [STOP]
                    从设备:           [ACK]     → [Data1] → [Data2]
                    

                    STM32实现(HAL库)

                    初始化流程

                    int main(void) {
                      HAL_Init();                  // 1. HAL库初始化
                      SystemClock_Config();        // 2. 系统时钟配置
                      MX_GPIO_Init();              // 3. GPIO初始化
                      MX_I2C1_Init();              // 4. I2C外设初始化
                      
                      while(1) {
                        // 数据传输操作
                      }
                    }
                    

                    GPIO配置示例

                    static void MX_GPIO_Init(void) {
                      GPIO_InitTypeDef GPIO_InitStruct = {0};
                      
                      __HAL_RCC_GPIOB_CLK_ENABLE();  // 使能GPIOB时钟
                      
                      // 配置PB6(SCL), PB7(SDA)
                      GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
                      GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;  // 开漏复用
                      GPIO_InitStruct.Pull = GPIO_PULLUP;      // 上拉电阻
                      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
                      GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
                      HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
                    }
                    

                    I2C外设配置

                    static void MX_I2C1_Init(void) {
                      hi2c1.Instance = I2C1;
                      hi2c1.Init.Timing = 0x00702999;       // 时序配置(根据时钟计算)
                      hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
                      hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
                      hi2c1.Init.OwnAddress1 = 0;          // 主模式设为0
                      hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
                      hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
                      
                      if (HAL_I2C_Init(&hi2c1) != HAL_OK) {
                        Error_Handler();
                      }
                    }
                    

                    数据传输操作

                    // 写操作示例
                    #define SLAVE_ADDR 0x68 0x00, 0x01, 0x02}; 
                    HAL_I2C_Master_Transmit(&hi2c1, SLAVE_ADDR, txData, 3, 100);
                    // 读操作示例(先写寄存器地址,再读数据)
                    uint8_t regAddr = 0x32;
                    uint8_t rxData[2];
                    HAL_I2C_Master_Transmit(&hi2c1, SLAVE_ADDR, &regAddr, 1, 100);
                    HAL_I2C_Master_Receive(&hi2c1, SLAVE_ADDR, rxData, 2, 100);
                    
                      // 传输完成处理
                    }
                    
                      /* MCU Configuration--------------------------------------------------------*/
                      /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
                      HAL_Init(); // 1. HAL库初始化
                      /* Configure the system clock */
                      SystemClock_Config(); // 2. 系统时钟配置
                      /* Initialize all configured peripherals */
                      MX_GPIO_Init();   // 3. GPIO初始化
                      MX_I2C1_Init();   // 4. I2C外设初始化
                      /* Infinite loop */
                      while (1)
                      {
                        /* Add user code here */
                      }
                    }
                    
                      GPIO_InitTypeDef GPIO_InitStruct = {0};
                      /* GPIO Ports Clock Enable */
                      __HAL_RCC_GPIOB_CLK_ENABLE(); // Enable GPIOB clock (assuming I2C1 uses PB6, PB7)
                      /*Configure GPIO pins : PB6 (SCL), PB7 (SDA) */
                      GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7; // SCL, SDA
                      GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; // Alternate Function Open-Drain (开漏)
                      GPIO_InitStruct.Pull = GPIO_PULLUP; // 上拉电阻 (很重要!)
                      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; // High speed for I2C
                      GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; // Set alternate function to I2C1
                      HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
                    }
                    
                      /* I2C1 parameter configuration*/
                      hi2c1.Instance = I2C1; // 选择I2C1外设
                      // !!! 对于STM32G0/G4/H7等新的I2C,需要配置Timing Register !!!
                      // 这个值需要根据你的系统时钟和I2C速度(如100kHz, 400kHz)通过STM32CubeIDE计算或手册查找
                      // 例如,对于48MHz系统时钟,100kHz I2C,可能是0x10901021UL
                      hi2c1.Init.Timing = 0x00702999; // 这是一个示例值,请根据实际情况配置
                      // 如果是较旧的STM32F系列,可能需要配置以下参数而不是Timing
                      // hi2c1.Init.ClockSpeed = 100000; // 100kHz
                      // hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; // 占空比
                      // hi2c1.Init.OwnAddress1 = 0; // 主设备模式下为0
                      // hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; // 7位地址
                      // hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; // 禁用双地址
                      // hi2c1.Init.OwnAddress2 = 0;
                      // hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; // 禁用通用呼叫
                      // hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; // 禁用时钟延长
                      hi2c1.Init.OwnAddress1 = 0; // 主设备模式下,自身地址通常不重要
                      hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; // 7位地址模式
                      hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
                      hi2c1.Init.OwnAddress2 = 0;
                      hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
                      hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
                      // 调用HAL库函数进行I2C初始化
                      if (HAL_I2C_Init(&hi2c1) != HAL_OK)
                      {
                        Error_Handler(); // 初始化失败,调用错误处理函数
                      }
                      // 使能模拟降噪滤波器(可选,CubeIDE默认开启)
                      if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
                      {
                        Error_Handler();
                      }
                      // 使能数字降噪滤波器(可选,CubeIDE默认开启)
                      if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
                      {
                        Error_Handler();
                      }
                    }
                    0x00, 0x01, 0x02}; // 第一个字节通常是内部寄存器地址,后面是要写入的数据
                    HAL_StatusTypeDef status;
                    // 1. 向从设备写入数据
                    // HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
                    status = HAL_I2C_Master_Transmit(&hi2c1, SLAVE_ADDRESS_WRITE, txData_write, sizeof(txData_write), HAL_MAX_DELAY);
                    if (status != HAL_OK)
                    {
                        // 错误处理,例如:
                        if (status == HAL_ERROR) {
                            // 总线错误,如ACK未收到
                        } else if (status == HAL_TIMEOUT) {
                            // 超时
                        }
                        Error_Handler();
                    }
                    HAL_Delay(10); // 延时等待从设备处理
                    
                        Error_Handler();
                    }
                    HAL_Delay(10);
                    
                        Error_Handler();
                    }
                    // 2. 紧接着,从该从设备读取数据 (HAL库内部会处理重复起始条件)
                    status = HAL_I2C_Master_Receive(&hi2c1, SLAVE_ADDRESS, rxData_reg, sizeof(rxData_reg), HAL_MAX_DELAY);
                    if (status != HAL_OK)
                    {
                        Error_Handler();
                    }
                    HAL_Delay(10);
                    
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码