Notas de estudio de STM32CubeMX (9) -Uso de la interfaz I2C

1. Introducción a I2C

El bus I2C (Inter-Integrated Circuit, Inter-Integrated Circuit) es un bus en serie desarrollado por Philips Philip Company. Se trata de dos buses seriales, que constan de una línea de datos (SDA) y una línea de reloj (SDL). Se pueden conectar varios dispositivos I2C al bus I2C y cada dispositivo tiene una identificación de dirección única. Solo puede haber un dispositivo maestro a la vez y los demás son dispositivos esclavos. Por lo general, la MCU se controla como dispositivo maestro y los periféricos se utilizan como dispositivos esclavos.

Los periféricos I2C de STM32 se pueden utilizar como maestros y esclavos de comunicación, admiten velocidades de 100 Kbit / sy 400 Kbit / s, admiten direcciones de dispositivos de 7 y 10 bits, admiten transmisión de datos DMA y tienen una función de verificación de datos. Sus periféricos I2C también son compatibles con el protocolo SMBus 2.0. El protocolo SMBus es similar al I2C y se utiliza principalmente en la gestión de baterías de ordenadores portátiles.

2. Distribución de pines

El chip STM32 tiene múltiples periféricos I2C, y sus señales de comunicación I2C se dirigen a diferentes pines GPIO, que deben configurarse en estos pines designados cuando se utilizan.PB8 PB9 为重映射。

Tres, chip EEPROM

El modelo de chip EEPROM en la placa de desarrollo: AT24C02 . La serie AT24C son EEPROM de tipo COMS en serie introducidas por ATMEL Company de los Estados Unidos. Los dos últimos dígitos del modelo de chip indican la capacidad del chip, por ejemplo, ATC24C02 es 2K. En el diagrama de pines, A0, A1 y A2 son pines de dirección del dispositivo, GND es tierra, VCC es fuente de alimentación positiva, WP es protección contra escritura, SCL es línea de reloj serial y SDA es línea de datos serial.

El pin WP en el chip EEPROM tiene una función de protección contra escritura. Cuando el nivel del pin es alto, la escritura de datos está prohibida. Cuando el pin está en un nivel bajo, se pueden escribir datos. Lo conectamos a tierra directamente y no usamos la función de protección contra escritura.

La dirección del dispositivo AT24Cxx es la siguiente, los primeros cuatro bits son fijos 1010y A2 ~ A0 están determinados por el nivel de pin . El módulo de placa AT24Cxx EEPROM está conectado a tierra de forma predeterminada. A2 ~ A0 son 000, el último bit R / W representa operaciones de lectura y escritura. Dado que a menudo es una comunicación I2C cuando se conectan con un lector de direcciones para formar una dirección de 8 bits, y cuando el bit R / W0 , indica una dirección de escritura, más una dirección de 7 bits, un valor al 0xA0que a menudo se hace referencia " escribir dirección "dispositivo I2C; cuando el bit R / W1 , indica que la dirección de lectura, junto con la dirección de 7 bits, un valor 0xA1, que a menudo se denomina" dirección de lectura ".

4. Nueva construcción

1. Abra el software STM32CubeMX y haga clic en "Nuevo proyecto"

2. Elija MCU y paquete

3. Configure los
ajustes de reloj RCC, seleccione HSE (reloj externo de alta velocidad),

seleccione Configuración de reloj para resonador de cristal / cerámica (oscilador de cristal / resonador de cerámica) , configure el reloj del sistema SYSCLK a 72MHz,
modifique el valor de HCLK a 72, y presiona Enter. Modifica automáticamente todas las configuraciones

4. Es
un paso muy importante configurar el modo de depuración ; de lo contrario, la
configuración SYS del depurador no se reconocerá después del primer programa de programación , seleccione Depurar como cable serial

Cinco, I2C1

5.1 Configuración de parámetros

En la configuración Connectivityseleccionada I2C1, seleccione el I2Ccircuito integrado

I2C sin modificación de la configuración predeterminada. Solo tenga en cuenta que I2C es el modo estándar y la velocidad de transmisión I2C (Velocidad de reloj I2C) es 100KHz.

5.2 Generar código

Nombres de elementos de ruta y

selección de entrada de elementos de un entorno de desarrollo de aplicaciones IDE MDK-ARM V5

cada periférico genera un ’.c/.h’archivo separado ,
no un gancho: Todo el código de inicialización se genera en main.c
verificado: archivo de código de inicialización generado en el periférico asociado. Por ejemplo, el código de inicialización GPIO se genera en gpio.c.

Haga clic en GENERAR CÓDIGO para generar código

5.3 Agregar variables globales

En main.c head Agregue la dirección de escritura 0xA0, la dirección de lectura 0xA1, el búfer de escritura WriteBuffery el búfer de lectura ReadBuffer.

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */
#define ADDR_24LCxx_Write 0xA0
#define ADDR_24LCxx_Read 0xA1
#define BufferSize 256
uint8_t WriteBuffer[BufferSize] = {
    
    0};
uint8_t ReadBuffer[BufferSize] = {
    
    0};
/* USER CODE END PV */

5.4 Agregar funciones de escritura y lectura

/**
  * @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_USART1_UART_Init();
  MX_I2C1_Init();
  /* USER CODE BEGIN 2 */
  printf("\r\n***************I2C Example*******************************\r\n");
  uint8_t i;
  uint8_t j;
  for(i = 0; i < 256; i++)
  {
    
    
    WriteBuffer[i] = i;    /* WriteBuffer init */
    printf("0x%02X ", WriteBuffer[i]);
    if(i % 16 == 15)
    {
    
        
      printf("\n\r");
    }
  }
  /* wrinte date to EEPROM */
  for (j = 0; j < 32; j++)
  {
    
    
    if(HAL_I2C_Mem_Write(&hi2c1, ADDR_24LCxx_Write, 8*j, I2C_MEMADD_SIZE_8BIT, WriteBuffer+8*j, 8, 100) == HAL_OK)
    {
    
    
      printf("\r\n EEPROM 24C02 Write Test OK \r\n");
    }
    else
    {
    
    
      printf("\r\n EEPROM 24C02 Write Test False \r\n");
    }
  } 
  /* read date from EEPROM */
  HAL_I2C_Mem_Read(&hi2c1, ADDR_24LCxx_Read, 0, I2C_MEMADD_SIZE_8BIT, ReadBuffer, BufferSize, 1000);
  for(i = 0; i < 256; i++)
  {
    
    
    printf("0x%02X  ",ReadBuffer[i]);
    if(i%16 == 15)    
    {
    
    
      printf("\n\r");
    }
  }
    
  if(memcmp(WriteBuffer,ReadBuffer,BufferSize) == 0 ) /* check date */
  {
    
    
    printf("\r\n EEPROM 24C02 Read Test OK\r\n");
  }
  else
  {
    
    
    printf("\r\n EEPROM 24C02 Read Test False\r\n");
  }

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    
    
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

Inicialice la caché de datos de escritura en el programa. Luego llame a la HAL_I2C_Mem_Write()función para escribir datos en la EEPROM. Juzgue si la operación de escritura es correcta según el valor de retorno de la función. La descripción de la función de escritura en memoria se puede encontrar en I2C.

  • El primer parámetro es el identificador de operación I2C.
  • El segundo parámetro es la dirección del dispositivo de operación de escritura EEPROM.
  • El tercer parámetro es la dirección de memoria.
  • El cuarto parámetro es la longitud de la dirección de memoria y la longitud de la memoria EEPROM es de 8 bits.
  • El quinto parámetro es la dirección inicial del búfer de datos.
  • El sexto parámetro es el tamaño de los datos transmitidos.AT24C02 型号的芯片页写入时序最多可以一次 发送 8 个数据(即 n = 8 ),该值也称为页大小,某些型号的芯片每个页写入时序最多可传输 16 个数据。
  • El séptimo parámetro es el tiempo de espera de la operación.
/**
  * @brief  Write an amount of data in blocking mode to a specific memory address
  * @param  hi2c Pointer to a I2C_HandleTypeDef structure that contains
  *                the configuration information for the specified I2C.
  * @param  DevAddress Target device address: The device 7 bits address value
  *         in datasheet must be shifted to the left before calling the interface
  * @param  MemAddress Internal memory address
  * @param  MemAddSize Size of internal memory address
  * @param  pData Pointer to data buffer
  * @param  Size Amount of data to be sent
  * @param  Timeout Timeout duration
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress,
                                    uint16_t MemAddress, uint16_t MemAddSize,
                                    uint8_t *pData, uint16_t Size, uint32_t Timeout)


Llame a la HAL_I2C_Mem_Read()función para leer los datos en EEPROM que acaba de escribir. HAL_I2C_Mem_Read()La función se describe a continuación.

  • El primer parámetro es el identificador de operación I2C.
  • El segundo parámetro es la dirección del dispositivo de operación de lectura EEPROM.
  • El tercer parámetro es la dirección de memoria.
  • El cuarto parámetro es la longitud de la dirección de memoria.
  • El quinto parámetro es la dirección de inicio del almacenamiento de datos de lectura.
  • El sexto parámetro es el tamaño de los datos transmitidos.
  • El séptimo parámetro es el tiempo de espera de la operación.
/**
  * @brief  Read an amount of data in blocking mode from a specific memory address
  * @param  hi2c Pointer to a I2C_HandleTypeDef structure that contains
  *                the configuration information for the specified I2C.
  * @param  DevAddress Target device address: The device 7 bits address value
  *         in datasheet must be shifted to the left before calling the interface
  * @param  MemAddress Internal memory address
  * @param  MemAddSize Size of internal memory address
  * @param  pData Pointer to data buffer
  * @param  Size Amount of data to be sent
  * @param  Timeout Timeout duration
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress,
                                  uint16_t MemAddress, uint16_t MemAddSize, 
                                  uint8_t *pData, uint16_t Size, uint32_t Timeout)

Finalmente, el programa llama a la memcmp()función para determinar si dos cachés leen y escriben consistencia de datos. memcmp()Si más regiones de memoria son iguales, que es la función de biblioteca estándar, el encabezado de main.cadición frontal string.h.

5.5 Ver impresión

Vista de la función de impresión del puerto serie Notas de estudio de STM32CubeMX (6) -Uso del puerto serie USART

5.6 Comparación de la biblioteca HAL y el código de biblioteca estándar

STM32CubeMX usa el código generado por la biblioteca HAL:

/**
  * @brief I2C1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_I2C1_Init(void)
{
    
    

  /* USER CODE BEGIN I2C1_Init 0 */

  /* USER CODE END I2C1_Init 0 */

  /* USER CODE BEGIN I2C1_Init 1 */

  /* USER CODE END I2C1_Init 1 */
  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();
  }
  /* USER CODE BEGIN I2C1_Init 2 */

  /* USER CODE END I2C1_Init 2 */
}

HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);

Utilice el código de biblioteca estándar STM32:

/**
  * @brief  I2C I/O配置
  * @param  无
  * @retval 无
  */
static void I2C_GPIO_Config(void)
{
    
    
  GPIO_InitTypeDef  GPIO_InitStructure; 

	/* 使能与 I2C 有关的时钟 */
	EEPROM_I2C_APBxClock_FUN ( EEPROM_I2C_CLK, ENABLE );
	EEPROM_I2C_GPIO_APBxClock_FUN ( EEPROM_I2C_GPIO_CLK, ENABLE );
	
    
  /* I2C_SCL、I2C_SDA*/
  GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SCL_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;	       // 开漏输出
  GPIO_Init(EEPROM_I2C_SCL_PORT, &GPIO_InitStructure);
	
  GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SDA_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;	       // 开漏输出
  GPIO_Init(EEPROM_I2C_SDA_PORT, &GPIO_InitStructure);		
}

/**
  * @brief  I2C 工作模式配置
  * @param  无
  * @retval 无
  */
static void I2C_Mode_Config(void)
{
    
    
  I2C_InitTypeDef  I2C_InitStructure; 

  /* I2C 配置 */
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	
	/* 高电平数据稳定,低电平数据变化 SCL 时钟线的占空比 */
  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	
  I2C_InitStructure.I2C_OwnAddress1 =I2Cx_OWN_ADDRESS7; 
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;
	 
	/* I2C的寻址模式 */
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	
	/* 通信速率 */
  I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;
  
	/* I2C 初始化 */
  I2C_Init(EEPROM_I2Cx, &I2C_InitStructure);
  
	/* 使能 I2C */
  I2C_Cmd(EEPROM_I2Cx, ENABLE);   
}

void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);
void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data);
uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);

Seis, asuntos que necesitan atención

El código de usuario se agregará USER CODE BEGIN Ny USER CODE END Nentre, de lo contrario, el próximo uso después de que STM32CubeMX vuelva a generar el código, se eliminará.


Escrito por Leung el 26 de enero de 2021

• Referencia: Tutorial 9 de la serie STM32CubeMX: Circuito interintegrado (I2C)
    [STM32Cube_13] Utilice hardware I2C para leer y escribir EEPROM (AT24C02)

Supongo que te gusta

Origin blog.csdn.net/qq_36347513/article/details/113180162
Recomendado
Clasificación