STM32_HAL_I2C_串行接口

电气特性

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

  1. 两线接口

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

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

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

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

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

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

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

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

    • 每个字节传输后,接收方会通过驱动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

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

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

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

有哪些函数

  1. 初始化和去初始化

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

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

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

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

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

    • HAL_I2C_IsDeviceReady():检查指定地址的从设备是否就绪。
    • HAL_I2C_Mem_Write():向从设备的内存写入数据。
    • 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通信中,从机与从机之间不能直接进行通信,所有的数据传输都需要通过主机来控制。

相关推荐

  1. stm32_HAL_串口不定长数据接收发送

    2024-06-08 18:50:02       18 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-08 18:50:02       5 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-08 18:50:02       5 阅读
  3. 在Django里面运行非项目文件

    2024-06-08 18:50:02       4 阅读
  4. Python语言-面向对象

    2024-06-08 18:50:02       6 阅读

热门阅读

  1. mybatisplus QueryWrapper or 写法

    2024-06-08 18:50:02       20 阅读
  2. window.clearInterval(timer) 清除定时器

    2024-06-08 18:50:02       17 阅读
  3. Docker

    Docker

    2024-06-08 18:50:02      16 阅读
  4. Redis命令使用示例(一)

    2024-06-08 18:50:02       18 阅读
  5. Ansible——user模块

    2024-06-08 18:50:02       18 阅读
  6. SD-WAN加速跨国服务器访问

    2024-06-08 18:50:02       17 阅读
  7. Spring Boot中实现规则引擎源码教程

    2024-06-08 18:50:02       14 阅读
  8. android:text 总为大写字母的原因

    2024-06-08 18:50:02       13 阅读
  9. input只允许输入数字

    2024-06-08 18:50:02       17 阅读
  10. 数据结构汇总学习(ing)

    2024-06-08 18:50:02       15 阅读
  11. 注解 - @RequestBody

    2024-06-08 18:50:02       16 阅读