15. STM32 drives sht35 temperature and humidity sensor

This paper uses analog IIC to drive sht35 temperature and humidity sensor
Stamping point: The IIC pull-up resistor of the purchased module is 10KΩ, which will cause IIC instability, poor anti-interference, and easy to cause timing errors; it is recommended to replace it with 4.7KΩ

1. CubeMx configuration







The rest are default, generate the project

1, us precise delay

Delay_Driver.c

/********************************************** *************************
*file: timer high precision delay
*author:remnant dream
*date:2022.9.26
*note: Note: Users are prohibited from using and changing
    The timer configuration:
Frequency division factor -- 24, period -- 65535
No need to enable interrupt
***************************************************** *********************/
#include "Delay_Driver.h"

/******************************
@function:us delay
@param:us--time to be delayed
@return: void
@date:2022.9.26
@remark:
*******************************/
void Delay_us(unsigned int us)
{<!-- -->
    if(!us){<!-- -->return;}
    us = (us > 6553)?6553:us;
    us *= 10;//Basic is 100ns
    _DelayTIM_Handle.Instance->CNT = 0;
HAL_TIM_Base_Start( & amp;_DelayTIM_Handle);
while(_DelayTIM_Handle.Instance->CNT < us);
HAL_TIM_Base_Stop( & amp;_DelayTIM_Handle);
}

/******************************
@function:ms delay
@param:ms--time to be delayed
@return: void
@date:2022.9.26
@remark:
*******************************/
void Delay_ms(unsigned int ms)
{<!-- -->
    unsigned int i = 0;
    if(!ms){<!-- -->return;}
    while(ms)
    {<!-- -->
        i = (ms < 6)?(ms):6;
        Delay_us(i*1000);
        ms -= i;
    }
}

/******************************
@function:s delay
@param:s--time to be delayed
@return: void
@date:2022.9.26
@remark:
*******************************/
void Delay_s(unsigned int s)
{<!-- -->
    unsigned int i = 0;
    if(!s){<!-- -->return;}
    while(s)
    {<!-- -->
        i = (s < 60)?(s):60;
        Delay_ms(i*1000);
        s -= i;
    }
}

Delay_Driver.h

#ifndef _Delay_Driver_H_
#define _Delay_Driver_H_
#include "tim.h"

#define _DelayTIM_Handle htim17

extern void Delay_us(unsigned int us);
extern void Delay_ms(unsigned int ms);
extern void Delay_s(unsigned int s);

#endif


2. Pin analog IIC communication

IIC_simulate.c

/********************************************** *************************
*file: Simulate IIC file
*author:remnant dream
*date:2023.5.20
*note:V2.0
This file simulates the IIC host, and the functions use the simIIC_StructDef structure entity, which is convenient for multiple peripherals to use
eg:
#define dSHT3X_SDA_CLOCK __HAL_RCC_GPIOB_CLK_ENABLE()
#define dSHT3X_SDA_PORT GPIOB
#define dSHT3X_SDA_PIN GPIO_PIN_3
#define dSHT3X_SCL_CLOCK __HAL_RCC_GPIOB_CLK_ENABLE()
#define dSHT3X_SCL_PORT GPIOB
#define dSHT3X_SCL_PIN GPIO_PIN_4
#define dSHT3X_IIC_ADDRESS 0x44

void SHT3x_GPIO_EnableColock(void)//sht3x initializes the GPIO clock enable function of SDA|SCL of IIC
{
  dSHT3X_SDA_CLOCK;
  dSHT3X_SCL_CLOCK;
}

simIIC_StructDef SHT3X_IIC;//Initialize the IIC structure variable
SHT3X_IIC.SDA_Pin = dSHT3X_SDA_PIN;
SHT3X_IIC.SCL_Pin = dSHT3X_SCL_PIN;
SHT3X_IIC.SDA_GPIO = dSHT3X_SDA_PORT;
SHT3X_IIC.SCL_GPIO = dSHT3X_SCL_PORT;
SHT3X_IIC.GPIO_EnableColock = &SHT3x_GPIO_EnableColock;
SHT3X_IIC.DelayMicrosecond = 1;//IIC speed: 500KHz
SHT3X_IIC.Delay_us = & amp;Delay_us;//External us delay precise function
simIIC_Init(SHT3X_IIC);//Initialize IIC

uint8_t data[6] = {0};
if(simIIC_Read(SHT3X_IIC,data,6,dSHT3X_IIC_ADDRESS) < 0)return -1;//Read 6 bytes of data
if(simIIC_Write(SHT3X_IIC,data,2,dSHT3X_IIC_ADDRESS) < 0) return -1;//write 6 bytes of data
***************************************************** *********************/
#include "IIC_simulate.h"

#define dxSET_PIN(GPIOx,Pin) GPIOx->BSRR = Pin //pin set 1
#define dxRESET_PIN(GPIOx,Pin) GPIOx->BSRR = ((uint32_t)Pin << 16u) //pin set 0
#define dxREAD_PIN(GPIOx,Pin) (GPIOx->IDR & Pin)?1:0
#define dxSET_LEVEL_PIN(gpio,pin,level) if(level){<!-- -->dxSET_PIN(gpio,pin);}else dxRESET_PIN(gpio,pin)

//IO direction setting
#define dxPIN_MODE_IN(gpio,pin) {<!-- -->gpio->MODER & amp;= ~(3<<(pin*2));gpio->MODER |= 0<<(pin*2) ;}//input mode
#define dxPIN_MODE_OUT(gpio,pin) {<!-- -->gpio->MODER & amp;= ~(3<<(pin*2));gpio->MODER |= 1<<(pin*2) ;}//output mode

#define dIIC_SCL(simIIC,x) dxSET_LEVEL_PIN(simIIC.SCL_GPIO,simIIC.SCL_Pin,x)
#define dIIC_SDA(simIIC,x) dxSET_LEVEL_PIN(simIIC.SDA_GPIO,simIIC.SDA_Pin,x)
#define dIIC_SDA_IN(simIIC) dxPIN_MODE_IN(simIIC.SDA_GPIO,simIIC.SDA_Pin)
#define dIIC_SDA_OUT(simIIC) dxPIN_MODE_OUT(simIIC.SDA_GPIO,simIIC.SDA_Pin)
#define dIIC_SDA_READ(simIIC) dxREAD_PIN(simIIC.SDA_GPIO,simIIC.SDA_Pin)

static void simIIC_DelayUs(simIIC_StructDef simIIC);

/******************************
@function: Simulate IIC delay function
@param:
@return: void
@note:
*******************************/
static void simIIC_DelayUs(simIIC_StructDef simIIC)
{<!-- -->
    if(simIIC. DelayMicrosecond == 0) return;
    simIIC.Delay_us(simIIC.DelayMicrosecond);
}

/******************************
@function: Simulate IIC initialization
@param: simIIC-- simIIC_StructDef to be initialized
@return: void
@note:
*******************************/
void simIIC_Init(simIIC_StructDef simIIC)
{<!-- -->
    GPIO_InitTypeDef GPIO_InitStruct = {<!-- -->0};

    simIIC.GPIO_EnableColock();
    GPIO_InitStruct.Pin = simIIC.SDA_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct. Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(simIIC.SDA_GPIO, &GPIO_InitStruct);
    GPIO_InitStruct.Pin = simIIC.SCL_Pin;
    HAL_GPIO_Init(simIIC.SCL_GPIO, &GPIO_InitStruct);
    dIIC_SCL(simIIC,1);
    dIIC_SDA(simIIC,1);
}

/******************************
@function: IIC start signal
@param: simIIC-- simIIC_StructDef to be initialized
@return: void
@note:
*******************************/
void simIIC_Start(simIIC_StructDef simIIC)
{<!-- -->
    dIIC_SDA_OUT(simIIC);
    dIIC_SDA(simIIC,1);
    dIIC_SCL(simIIC,1);
    simIIC_DelayUs(simIIC);
    dIIC_SDA(simIIC,0);
    simIIC_DelayUs(simIIC);
    dIIC_SCL(simIIC,0);
}

/******************************
@function: IIC end signal
@param: simIIC-- simIIC_StructDef to be initialized
@return: void
@note:
*******************************/
void simIIC_Stop(simIIC_StructDef simIIC)
{<!-- -->
    dIIC_SCL(simIIC,0);
    dIIC_SDA(simIIC,0);
    simIIC_DelayUs(simIIC);

    dIIC_SCL(simIIC,1);
    simIIC_DelayUs(simIIC);
    dIIC_SDA(simIIC,1);
    simIIC_DelayUs(simIIC);
}

/******************************
@function: IIC write data (do not use it otherwise)
@param: data--data to be sent
@return: 0--write success, -1--write failure (slave address does not exist)
@note: Does not contain IIC start, IIC end
*******************************/
signed int simIIC_WriteOneByte(simIIC_StructDef simIIC, unsigned char data)
{<!-- -->
    unsigned char ack = 0, mask = 0;

    dIIC_SDA_OUT(simIIC);
    for(mask=0x80;mask != 0;mask >>= 1)
    {<!-- -->
        dIIC_SDA(simIIC,((mask & amp; data) ? 1 : 0));
        simIIC_DelayUs(simIIC);
        dIIC_SCL(simIIC,1);
        simIIC_DelayUs(simIIC);
        dIIC_SCL(simIIC,0);
    }
    dIIC_SDA(simIIC,1);
    dIIC_SDA_IN(simIIC);
    simIIC_DelayUs(simIIC);
    dIIC_SCL(simIIC,1);
    simIIC_DelayUs(simIIC);
    ack = dIIC_SDA_READ(simIIC);
    dIIC_SCL(simIIC,0);
    dIIC_SDA_OUT(simIIC);

    return (ack? -1:0);
}

/******************************
@function: IIC read data (do not use it otherwise)
@param: ack: 0--answer, 1--no answer
@return: the data read
@note: Does not contain IIC start, IIC end
*******************************/
unsigned char simIIC_ReadOneByte(simIIC_StructDef simIIC, simIIC_xACK_EnumDef ack)
{<!-- -->
    unsigned char mask = 0, data = 0;

    dIIC_SDA(simIIC,1);
    dIIC_SDA_IN(simIIC);
    for(mask=0x80;mask != 0;mask >>= 1)
    {<!-- -->
        simIIC_DelayUs(simIIC);
        dIIC_SCL(simIIC,1);
        simIIC_DelayUs(simIIC);
        data |= ((dIIC_SDA_READ(simIIC))?mask:0);
        dIIC_SCL(simIIC,0);
    }
    dIIC_SDA_OUT(simIIC);
    dIIC_SDA(simIIC,ack);
    simIIC_DelayUs(simIIC);
    dIIC_SCL(simIIC,1);
    simIIC_DelayUs(simIIC);
    dIIC_SCL(simIIC,0);

    return data;
}

/******************************
@function: IIC write data
@param: data--data to be sent
        byteNum - the number of data bytes, excluding address bytes
        address--slave address
@return: 0--write success, -1--write failure (slave address does not exist | data bytes 0)
@note:
*******************************/
signed int simIIC_Write(simIIC_StructDef simIIC, unsigned char *data, unsigned int byteNum, unsigned char address)
{<!-- -->
    unsigned int pos = 0;
    if(byteNum == 0) return -1;

    simIIC_Start(simIIC);
    if(simIIC_WriteOneByte(simIIC,address << 1) < 0){<!-- -->simIIC_Stop(simIIC);return -1;}//address access: write
    for(pos=0;pos < byteNum;pos + + ){<!-- -->if(simIIC_WriteOneByte(simIIC,data[pos]) < 0){<!-- -->simIIC_Stop(simIIC);return -1;}}
    simIIC_Stop(simIIC);
    return 0;
}

/******************************
@function: IIC read data
@param: data-- the read data
        byteNum--the number of data bytes to be read, excluding address bytes
        address--slave address
@return: 0--read successfully, -1--read failed (slave address does not exist | read error)
@note:
*******************************/
signed int simIIC_Read(simIIC_StructDef simIIC, unsigned char *data, unsigned int byteNum, unsigned char address)
{<!-- -->
    unsigned int pos = 0;
    if(byteNum == 0) return -1;
    address = (address << 1) | 0x01;

    simIIC_Start(simIIC);
    if(simIIC_WriteOneByte(simIIC,address) < 0){<!-- -->simIIC_Stop(simIIC);return -1;}//address access: read
    for(pos=0;pos < byteNum;pos + + ){<!-- -->data[pos] = simIIC_ReadOneByte(simIIC,(pos == (byteNum-1))?simIIC_NACK:simIIC_ACK);}
    simIIC_Stop(simIIC);
    return 0;
}

IIC_simulate.h

#ifndef _IIC_simulate_H_
#define _IIC_simulate_H_
#include "gpio.h"

typedef struct
{<!-- -->
    uint32_t SDA_Pin;//SDA pin
    uint32_t SCL_Pin;//SCL pin
    GPIO_TypeDef *SDA_GPIO;//SDA port
    GPIO_TypeDef *SCL_GPIO;//SCL port
    void (*GPIO_EnableColock)(void);//Enable the GPIO clock function of SDA and SCL, user-defined: eg:void SHT3x_GPIO_EnableColock(void)
    unsigned short int DelayMicrosecond;//IIC delay time, the frequency is close to 1/(2*DelayMicrosecond) * 1000000; when it is 0, there is no delay; note that the actual delay of IIC will be slightly longer than this time, because there is still a pin flip time consume
    void (*Delay_us)(unsigned int us);//microsecond delay precise function, user-defined: eg:void Delay_us(unsigned int us)
} simIIC_StructDef;

typedef enum
{<!-- -->
    simIIC_ACK = 0, //IIC response
    simIIC_NACK = 1 //IIC does not respond
} simIIC_xACK_EnumDef;

void simIIC_Init(simIIC_StructDef simIIC);
void simIIC_Start(simIIC_StructDef simIIC);
void simIIC_Stop(simIIC_StructDef simIIC);
signed int simIIC_WriteOneByte(simIIC_StructDef simIIC, unsigned char data);
unsigned char simIIC_ReadOneByte(simIIC_StructDef simIIC,simIIC_xACK_EnumDef ack);
signed int simIIC_Write(simIIC_StructDef simIIC, unsigned char *data, unsigned int byteNum, unsigned char address);
signed int simIIC_Read(simIIC_StructDef simIIC, unsigned char *data, unsigned int byteNum, unsigned char address);

#endif

3. sht3x temperature and humidity sensor driver
sht3x_Driver.c

/********************************************** *************************
*file: sht3x temperature and humidity sensor driver
*author:remnant dream
*date:2023.5.22
*note:
***************************************************** *********************/
#include "sht3x_Driver.h"
#include "IIC_simulate.h"
#include "Delay_Driver.h"

#define dSHT3X_SDA_CLOCK __HAL_RCC_GPIOB_CLK_ENABLE()
#define dSHT3X_SDA_PORT GPIOB
#define dSHT3X_SDA_PIN GPIO_PIN_3
#define dSHT3X_SCL_CLOCK __HAL_RCC_GPIOB_CLK_ENABLE()
#define dSHT3X_SCL_PORT GPIOB
#define dSHT3X_SCL_PIN GPIO_PIN_4

#define dSHT3X_IIC_ADDRESS 0x44

static simIIC_StructDef SHT3X_IIC;

static uint8_t SHT3x_CRC_CAL(uint16_t DAT);
static int SHT3x_WriteByte(uint8_t MSB,uint8_t LSB);
static void SHT3x_SoftReset(void);

/******************************
@function: CRC check, CRC polynomial is: x^8 + x^5 + x^4 + 1, which is 0x31
@param:DAT The data to be verified
@return: check code
@note:
*******************************/
static uint8_t SHT3x_CRC_CAL(uint16_t DAT)
{<!-- -->
uint8_t i,t,temp;
uint8_t CRC_BYTE;

CRC_BYTE = 0xFF;
temp = (DAT>>8) & 0xFF;

for(t = 0; t < 2; t ++ )
{<!-- -->
CRC_BYTE ^= temp;
for(i = 0;i < 8;i ++ )
{<!-- -->
if(CRC_BYTE & 0x80)
{<!-- -->
CRC_BYTE <<= 1;
CRC_BYTE ^= 0x31;
}
else
{<!-- -->
CRC_BYTE <<= 1;
}
}

if(t == 0)
{<!-- -->
temp = DAT & 0xFF;
}
}

return CRC_BYTE;
}

/******************************
@function: Send two bytes of data
@param: MSB high 8 bits; LSB low 8 bits
@return: -1--write failed, 0--success
@note:
*******************************/
static int SHT3x_WriteByte(uint8_t MSB, uint8_t LSB)
{<!-- -->
  uint8_t data[2] = {<!-- -->0};
  data[0] = MSB; data[1] = LSB;
  return (simIIC_Write(SHT3X_IIC,data,2,dSHT3X_IIC_ADDRESS) < 0) ? -1 : 0;
}

/*software reset SHT3x*/
static void SHT3x_SoftReset(void)
{<!-- -->
  SHT3x_WriteByte(0x30,0xA2); //Reinitialize SHT3x
}

/******************************
@function:sht3x Initialize the SDA|SCL GPIO clock enable function of IIC
@param: void
@return: void
@note:
*******************************/
void SHT3x_GPIO_EnableColock(void)
{<!-- -->
  dSHT3X_SDA_CLOCK;
  dSHT3X_SCL_CLOCK;
}

/******************************
@function: sht3x initialization
@param: void
@return: -1--initialization failed, 0--success
@note: Set the periodic data collection mode (10 times per second, Medium Repeatability)
*******************************/
int SHT3x_Init(void)
{<!-- -->
  int xreturn = 0;

  SHT3X_IIC.SDA_Pin = dSHT3X_SDA_PIN;
  SHT3X_IIC.SCL_Pin = dSHT3X_SCL_PIN;
  SHT3X_IIC.SDA_GPIO = dSHT3X_SDA_PORT;
  SHT3X_IIC.SCL_GPIO = dSHT3X_SCL_PORT;
  SHT3X_IIC.GPIO_EnableColock = &SHT3x_GPIO_EnableColock;
  SHT3X_IIC.DelayMicrosecond = 1;//IIC speed: 500KHz
  SHT3X_IIC.Delay_us = &Delay_us;
  simIIC_Init(SHT3X_IIC);
  SHT3x_SoftReset();
  xreturn = SHT3x_WriteByte(0X27,0X21);//periodic data acquisition mode (10 times per second, Medium Repeatability)

  float Hum = 0.0f,Temp = 0.0f;
  ReadSHT3x( & amp; Hum, & amp; Temp);
  return xreturn;
}

/******************************
@function: read SHT3x data
@param: *Hum humidity, *Temp temperature
@return: -1--failure, 0--success
@note: When the reading period is less than the setting period, the reading will be wrong; the current setting period is 100ms, and the first reading will be wrong
*******************************/
int ReadSHT3x(float *Hum, float *Temp)
{<!-- -->
  uint16_t HumData = 0,TempData = 0,HumCRC = 0,TempCRC = 0;//declare variables to store the read data
  uint8_t data[6] = {<!-- -->0};

  if(SHT3x_WriteByte(0XE0,0X00) < 0) return -1; //Send command, get data, for periodic data acquisition mode
  if(simIIC_Read(SHT3X_IIC,data,6,dSHT3X_IIC_ADDRESS) < 0) return -1;
  TempData = ((uint16_t)data[0] << 8) | (uint16_t)data[1];//Temperature high 8-bit data | temperature low 8-bit data
  TempCRC = data[2];//Temperature CRC check data
  HumData = ((uint16_t)data[3] << 8) | (uint16_t)data[4];//High humidity 8-bit data | Humidity low 8-bit data
  HumCRC = data[5];//humidity CRC check data

  if((SHT3x_CRC_CAL(HumData) != HumCRC) || (SHT3x_CRC_CAL(TempData) !=TempCRC)) return -1;//Check the received data by CRC
  *Hum = (float)HumData*100.0f/(65536-1); //Convert the received 16-bit binary data into decimal humidity data
  *Temp = (float)TempData*175.0f/(65536-1)-45.0f; //Convert the received 16-bit binary data into decimal temperature data
  return 0;
}

sht3x_Driver.h

#ifndef _sht3x_Driver_H_
#define _sht3x_Driver_H_
#include "main.h"

int SHT3x_Init(void);
int ReadSHT3x(float *Hum, float *Temp);

#endif

4. Read temperature and humidity main.c

main.c

/* USER CODE BEGIN Header */
/**
  ***************************************************** *****************************
  * @file : main.c
  * @brief : Main program body
  ***************************************************** *****************************
  * @attention
  *
  * <h2><center> & amp;copy; Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  * opensource.org/licenses/BSD-3-Clause
  *
  ***************************************************** *****************************
  */
/* USER CODE END Header */
/* Includes ----------------------------------------------- -------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ---------------------------------------------- ------------*/
/* USER CODE BEGIN Includes */
#include "IIC_simulate.h"
#include "Delay_Driver.h"
#include "sht3x_Driver.h"
/* 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 */
float Hum = 0.0f,Temp = 0.0f;
/* 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_USART1_UART_Init();
  MX_TIM17_Init();
  /* USER CODE BEGIN 2 */
  SHT3x_Init();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {<!-- -->
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    HAL_Delay(1000);
    if(ReadSHT3x( & amp;Hum, & amp;Temp) < 0){<!-- -->printf("error\\
");}
    else printf("%.2fRH %.2f℃\\
",Hum,Temp);
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{<!-- -->
  RCC_OscInitTypeDef RCC_OscInitStruct = {<!-- -->0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {<!-- -->0};

  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {<!-- -->}
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 60;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig( & RCC_OscInitStruct) != HAL_OK)
  {<!-- -->
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB bus clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

  if (HAL_RCC_ClockConfig( & RCC_ClkInitStruct, FLASH_LATENCY_4) != 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\\
", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

5. Results, IIC waveform




Complete project and information:
Link: https://pan.baidu.com/s/1fZVBOykei0jTcVZT9ijiTQ
Extraction code: gvgc