STM32 HAL库教程:I2C串行接口配置

电气特性

I2C(Inter-Integrated Circuit)是一种由飞利浦公司(现恩智浦半导体)开发的串行通信协议,用于连接低速外围设备。I2C总线只需要两根线(SDA:串行数据线,SCL:串行时钟线)就可以实现多个设备之间的数据交换。以下是I2C的主要电气特性:

  1. 两线接口

  2. SDA(Serial Data Line):用于传输数据。(数据线)
  3. SCL(Serial Clock Line):用于同步数据传输。(时钟线)
  4. 多主从结构

  5. I2C总线支持多个主设备和一个或多个从设备。在任何时刻,只有一个主设备控制总线。(不能同时存在多个主设备)
  6. 地址编码

  7. 每个从设备都有唯一的7位或10位地址,主设备通过地址来选择要通信的从设备。
  8. 时钟同步

  9. I2C总线上的所有设备都同步于SCL线上的时钟信号。时钟线由主设备控制
  10. 数据传输速率

  11. 标准模式下,时钟频率可达100 kHz。
  12. 快速模式下,时钟频率可达400 kHz。
  13. 高速模式下,时钟频率可达3.4 MHz。
  14. 起始和停止条件

  15. 数据传输开始于起始条件,结束于停止条件。起始条件是SCL为高电平时,SDA由高电平向低电平跳变;停止条件是SCL为高电平时,SDA由低电平向高电平跳变。
  16. 数据有效性

  17. 数据在SCL为高电平时保持稳定,在SCL为低电平时改变。
  18. 位的表示

  19. I2C使用8位数据传输,每次传输可以是一个字节(8位),也可以是多个字节。
  20. 确认(ACK/NACK)

  21. 每个字节传输后,接收方会通过驱动SDA线至低电平来发送一个确认位(ACK),或者通过不驱动SDA线(保持高电平)来发送一个非确认位(NACK)。

协议

I²C写操作的详细步骤:

  1. 起始条件:主设备通过将SDA线从高电平拉到低电平,同时保持SCL为高电平,然后释放SCL,使其变为低电平,从而产生起始条件。总线在起始条件后处于忙碌状态。

  2. 发送从设备地址:主设备发送从设备的7位或10位地址,后面跟着一个写操作位(即最低位为0)。所有从设备都会接收这个地址,但只有地址匹配的从设备会响应。

  3. 从设备响应:地址匹配的从设备会发送一个确认(ACK)信号,即在第9个时钟周期时,从设备将SDA线拉低。

  4. 发送数据:主设备开始发送数据字节,每个字节后面都跟着一个时钟周期,用于从设备发送ACK信号。主设备可以发送多个字节,直到发送完所有需要的数据。

  5. 停止条件:当主设备发送完所有数据后,它会发出停止条件,即将SDA线从低电平拉到高电平,同时保持SCL为高电平,然后释放SDA线。

  6. 从设备处理数据:从设备在接收到停止条件后,会处理这些数据,例如存储到内部寄存器或EEPROM中。

以下是I²C写过程的时序图表示:

起始条件 -> [设备地址 + W] -> ACK -> [数据1] -> ACK -> [数据2] -> ACK -> ... -> [数据N] -> ACK -> 停止条件

-> 表示时间流动,[] 表示数据字节,R 表示读操作位,ACK 表示主设备发送的确认信号,NACK 表示主设备发送的否定确认信号。

I²C读操作的详细步骤:

  1. 起始条件:主设备通过将SDA线从高电平拉到低电平,同时保持SCL为高电平,然后释放SCL,使其变为低电平,从而产生起始条件。总线在起始条件后处于忙碌状态。

  2. 发送从设备地址:主设备发送从设备的7位或10位地址,后面跟着一个读操作位(即最低位为1)。所有从设备都会接收这个地址,但只有地址匹配的从设备会响应。

  3. 从设备响应:地址匹配的从设备会发送一个确认(ACK)信号,即在第9个时钟周期时,从设备将SDA线拉低。

  4. 读取数据:从设备开始发送数据字节,主设备在每个字节后面通过发送ACK信号来请求更多的数据,或者通过发送NACK信号来结束读取过程。

  5. 停止条件:当主设备完成数据读取后,它会发出停止条件,即将SDA线从低电平拉到高电平,同时保持SCL为高电平,然后释放SDA线。

  6. 主设备处理数据:主设备接收到数据后,可以根据需要进行处理或存储。

以下是I²C读过程的时序图表示:

起始条件 -> [设备地址 + R] -> ACK -> [数据1] -> ACK -> [数据2] -> ACK -> ... -> [数据N] -> NACK -> 停止条件

-> 表示时间流动,[] 表示数据字节,R 表示读操作位,ACK 表示主设备发送的确认信号,NACK 表示主设备发送的否定确认信号。

I 2 C的功能框图

STM32CudeMX 

  • Master  features  主模式特性

  • Slave  features  从模式特性

    1. Byte

    2. 一个字节(Byte)通常包含8位(bit),这是计算机中最小的可寻址的存储单元。
    3. 字节是大多数计算机体系结构中的基本数据单位,用于表示字符、数字和其他数据类型。
    4. 在不同的上下文中,字节可以表示不同的含义,例如在数据通信中,它通常指的是传输的一个数据单元。
    5. Half Word

    6. 半字(Half Word)通常包含16位(bit),即2个字节。
    7. 在16位或更宽的处理器中,半字可能是处理器可以同时处理的数据单位之一。
    8. 在一些编程语言和操作系统中,半字用于指定数据类型的大小,例如短整型(short)在某些体系结构上可能是16位的。
    9. Word

    10. 一个字(Word)的大小取决于具体的处理器架构,但通常是16位、32位或64位。
    11. 在32位处理器中,一个字通常是32位,即4个字节。
    12. 在64位处理器中,一个字可能是64位,即8个字节。
    13. 字是许多处理器的主要数据单位,用于表示整数、指针和内存地址。

    有哪些函数

    1. 初始化和去初始化

    2. HAL_I2C_Init():初始化I2C外设。
    3. HAL_I2C_DeInit():去初始化I2C外设。
    4. 配置

    5. HAL_I2C_Config():配置I2C的一些参数,如时钟速度、地址等。
    6. 数据传输

    7. HAL_I2C_Master_Transmit():作为主设备发送数据到从设备。
    8. HAL_I2C_Master_Receive():作为主设备从从设备接收数据。
    9. HAL_I2C_Slave_Transmit():作为从设备发送数据到主设备。
    10. HAL_I2C_Slave_Receive():作为从设备从主设备接收数据。
    11. 状态和错误处理

    12. HAL_I2C_GetState():获取I2C外设的当前状态。
    13. HAL_I2C_GetError():获取I2C的错误代码。
    14. 中断处理

    15. HAL_I2C_IRQHandler():I2C中断处理函数。
    16. HAL_I2C_MasterTxCpltCallback():主设备发送完成回调函数。
    17. HAL_I2C_MasterRxCpltCallback():主设备接收完成回调函数。
    18. HAL_I2C_SlaveTxCpltCallback():从设备发送完成回调函数。
    19. HAL_I2C_SlaveRxCpltCallback():从设备接收完成回调函数。
    20. 其他功能

    21. HAL_I2C_IsDeviceReady():检查指定地址的从设备是否就绪。
    22. HAL_I2C_Mem_Write():向从设备的内存写入数据。
    23. HAL_I2C_Mem_Read():从从设备的内存读取数据。

    代码编写

    检查指定地址的从设备是否就绪。

    /* USER CODE BEGIN Header */
    /**
      ******************************************************************************
      * @file           : main.c
      * @brief          : Main program body
      ******************************************************************************
      * @attention
      *
      * Copyright (c) 2024 STMicroelectronics.
      * All rights reserved.
      *
      * This software is licensed under terms that can be found in the LICENSE file
      * in the root directory of this software component.
      * If no LICENSE file comes with this software, it is provided AS-IS.
      *
      ******************************************************************************
      */
    /* USER CODE END Header */
    /* Includes ------------------------------------------------------------------*/
    #include "main.h"
    #include "dma.h"
    #include "i2c.h"
    #include "usart.h"
    #include "gpio.h"
    
    /* Private includes ----------------------------------------------------------*/
    /* USER CODE BEGIN Includes */
    
    /* USER CODE END Includes */
    
    /* Private typedef -----------------------------------------------------------*/
    /* USER CODE BEGIN PTD */
    
    /* USER CODE END PTD */
    
    /* Private define ------------------------------------------------------------*/
    /* USER CODE BEGIN PD */
    
    /* USER CODE END PD */
    
    /* Private macro -------------------------------------------------------------*/
    /* USER CODE BEGIN PM */
    
    /* USER CODE END PM */
    
    /* Private variables ---------------------------------------------------------*/
    
    /* USER CODE BEGIN PV */
    
    /* USER CODE END PV */
    
    /* Private function prototypes -----------------------------------------------*/
    void SystemClock_Config(void);
    /* USER CODE BEGIN PFP */
    
    /* USER CODE END PFP */
    
    /* Private user code ---------------------------------------------------------*/
    /* USER CODE BEGIN 0 */
    
    /* USER CODE END 0 */
    
    /**
      * @brief  The application entry point.
      * @retval int
      */
    int main(void)
    {
    
      /* USER CODE BEGIN 1 */
    
      /* USER CODE END 1 */
    
      /* MCU Configuration--------------------------------------------------------*/
    
      /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
      HAL_Init();
    
      /* USER CODE BEGIN Init */
    
      /* USER CODE END Init */
    
      /* Configure the system clock */
      SystemClock_Config();
    
      /* USER CODE BEGIN SysInit */
    
      /* USER CODE END SysInit */
    
      /* Initialize all configured peripherals */
      MX_GPIO_Init();
      MX_DMA_Init();
      MX_I2C1_Init();
      MX_USART1_UART_Init();
      /* USER CODE BEGIN 2 */
    char I2c_Data[9]={"AA"};
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
    		if(HAL_I2C_IsDeviceReady(&hi2c1,0x78,2,500)==HAL_OK){
    				HAL_UART_Transmit(&huart1,(uint8_t*)I2c_Data,9,1000);
    		}else{
    				char a[]={"null"};
    				HAL_UART_Transmit(&huart1,(uint8_t*)a,5,1000);
    		}
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */
      }
      /* USER CODE END 3 */
    }
    
    /**
      * @brief System Clock Configuration
      * @retval None
      */
    void SystemClock_Config(void)
    {
      RCC_OscInitTypeDef RCC_OscInitStruct = {0};
      RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
      /** Initializes the RCC Oscillators according to the specified parameters
      * in the RCC_OscInitTypeDef structure.
      */
      RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
      RCC_OscInitStruct.HSEState = RCC_HSE_ON;
      RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
      RCC_OscInitStruct.HSIState = RCC_HSI_ON;
      RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
      RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
      RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
      if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
      {
        Error_Handler();
      }
    
      /** Initializes the CPU, AHB and APB buses clocks
      */
      RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                                  |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
      RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
      RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
      RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
      RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
      if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
      {
        Error_Handler();
      }
    }
    
    /* USER CODE BEGIN 4 */
    
    /* USER CODE END 4 */
    
    /**
      * @brief  This function is executed in case of error occurrence.
      * @retval None
      */
    void Error_Handler(void)
    {
      /* USER CODE BEGIN Error_Handler_Debug */
      /* User can add his own implementation to report the HAL error return state */
      __disable_irq();
      while (1)
      {
      }
      /* USER CODE END Error_Handler_Debug */
    }
    
    #ifdef  USE_FULL_ASSERT
    /**
      * @brief  Reports the name of the source file and the source line number
      *         where the assert_param error has occurred.
      * @param  file: pointer to the source file name
      * @param  line: assert_param error line source number
      * @retval None
      */
    void assert_failed(uint8_t *file, uint32_t line)
    {
      /* USER CODE BEGIN 6 */
      /* User can add his own implementation to report the file name and line number,
         ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
      /* USER CODE END 6 */
    }
    #endif /* USE_FULL_ASSERT */
    

    注意 

    在I2C(Inter-Integrated Circuit)总线协议中,通常有一个主机(master)和多个从机(slave)。按照I2C协议的设计,所有的数据传输都是在主机控制下进行的。也就是说,在标准的I2C通信中,从机与从机之间不能直接进行通信,所有的数据传输都需要通过主机来控制。

    作者:快秃头的码农

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32 HAL库教程:I2C串行接口配置

    发表回复