15、STM32驱动sht35温湿度传感器

news2024/11/18 15:22:19

本文使用模拟IIC驱动sht35温湿度传感器
踩坑点:购买的模块IIC上拉电阻为10KΩ,会导致IIC不稳定,抗干扰差,容易导致时序错误;建议更换为4.7KΩ

一、CubeMx配置

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
其余默认,生成工程

1、us精确延时

Delay_Driver.c

/**********************************************************************
*file:定时器高精度延时
*author:残梦
*date:2022.9.26
*note:注:用户禁止使用、更改
    该定时器配置:
	分频系数 -- 24,周期 -- 65535
	无需开启中断
**********************************************************************/
#include "Delay_Driver.h"

/******************************
@function:us延时
@param:us--待延时的时间
@return:void
@date:2022.9.26
@remark:
******************************/
void Delay_us(unsigned int us)
{
    if(!us){return;}
    us = (us > 6553)?6553:us;
    us *= 10;//基础是100ns
    _DelayTIM_Handle.Instance->CNT = 0;
	HAL_TIM_Base_Start(&_DelayTIM_Handle);
	while(_DelayTIM_Handle.Instance->CNT < us);
	HAL_TIM_Base_Stop(&_DelayTIM_Handle);
}

/******************************
@function:ms延时
@param:ms--待延时的时间
@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延时
@param:s--待延时的时间
@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、引脚模拟IIC通信

IIC_simulate.c

/**********************************************************************
*file:模拟IIC文件
*author:残梦
*date:2023.5.20
*note:V2.0
本文件模拟IIC主机,函数使用的都是simIIC_StructDef结构体实体,方便多个外设使用
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 初始化IIC的SDA|SCL的GPIO时钟使能函数
{
  dSHT3X_SDA_CLOCK;
  dSHT3X_SCL_CLOCK;
}

simIIC_StructDef SHT3X_IIC;//初始化IIC结构体变量
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速度:500KHz
SHT3X_IIC.Delay_us = &Delay_us;//外部us延时精确函数
simIIC_Init(SHT3X_IIC);//初始化IIC

uint8_t data[6] = {0};
if(simIIC_Read(SHT3X_IIC,data,6,dSHT3X_IIC_ADDRESS) < 0)return -1;//读取6个字节的数据
if(simIIC_Write(SHT3X_IIC,data,2,dSHT3X_IIC_ADDRESS) < 0)return -1;//写入6个字节的数据
**********************************************************************/
#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 方向设置
#define dxPIN_MODE_IN(gpio,pin)     {gpio->MODER &= ~(3<<(pin*2));gpio->MODER |= 0<<(pin*2);}//输入模式
#define dxPIN_MODE_OUT(gpio,pin)    {gpio->MODER &= ~(3<<(pin*2));gpio->MODER |= 1<<(pin*2);}//输出模式

#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:模拟IIC延时函数
@param:
@return:void
@note:
******************************/
static void simIIC_DelayUs(simIIC_StructDef simIIC)
{
    if(simIIC.DelayMicrosecond == 0)return;
    simIIC.Delay_us(simIIC.DelayMicrosecond);
}

/******************************
@function:模拟IIC初始化
@param:simIIC--待初始化的simIIC_StructDef
@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起始信号
@param:simIIC--待初始化的simIIC_StructDef
@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结束信号
@param:simIIC--待初始化的simIIC_StructDef
@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写数据(请勿其他使用)
@param: data--待发送的数据
@return:0--写成功,-1--写失败(从机地址不存在)
@note:不含IIC起始,IIC结束
******************************/
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 & 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读数据(请勿其他使用)
@param: ack:0--应答,1--不应答
@return:读取的数据
@note:不含IIC起始,IIC结束
******************************/
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写数据
@param: data--待发送的数据
        byteNum--数据字节数,不含地址字节
        address--从机地址
@return:0--写成功,-1--写失败(从机地址不存在|数据字节数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;}//地址访问:写
    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读数据
@param: data--读取到的数据
        byteNum--待读取数据字节数,不含地址字节
        address--从机地址
@return:0--读成功,-1--读失败(从机地址不存在|读取错误)
@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;}//地址访问:读
    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引脚
    uint32_t SCL_Pin;//SCL引脚
    GPIO_TypeDef  *SDA_GPIO;//SDA端口
    GPIO_TypeDef  *SCL_GPIO;//SCL端口
    void (*GPIO_EnableColock)(void);//使能SDA、SCL的GPIO时钟函数,用户定义:eg:void SHT3x_GPIO_EnableColock(void)
    unsigned short int DelayMicrosecond;//IIC延时时间,频率接近1/(2*DelayMicrosecond) * 1000000;为0时不予延时;注意IIC实际延时会稍大于此时间,因为还有引脚翻转时间消耗
    void (*Delay_us)(unsigned int us);//微秒延时精确函数,用户定义:eg:void Delay_us(unsigned int us)
}simIIC_StructDef;

typedef enum
{
    simIIC_ACK = 0, //IIC应答
    simIIC_NACK = 1 //IIC不应答
}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温湿度传感器驱动
sht3x_Driver.c

/**********************************************************************
*file:sht3x温湿度传感器驱动
*author:残梦
*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校验,CRC多项式为:x^8+x^5+x^4+1,即0x31
@param:DAT 要校验的数据
@return:校验码
@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:发送两个字节数据
@param:MSB 高8位;LSB 低8位
@return:-1--写失败,0--成功
@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;
}

/*软件复位SHT3x*/
static void SHT3x_SoftReset(void)
{
  SHT3x_WriteByte(0x30,0xA2);    //重新初始化SHT3x
}

/******************************
@function:sht3x 初始化IIC的SDA|SCL的GPIO时钟使能函数
@param:void
@return:void
@note:
******************************/
void SHT3x_GPIO_EnableColock(void)
{
  dSHT3X_SDA_CLOCK;
  dSHT3X_SCL_CLOCK;
}

/******************************
@function:sht3x初始化
@param:void
@return:-1--初始化失败,0--成功
@note:设定周期数据采集模式(每秒10次,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速度:500KHz
  SHT3X_IIC.Delay_us = &Delay_us;
  simIIC_Init(SHT3X_IIC);
  SHT3x_SoftReset();
  xreturn = SHT3x_WriteByte(0X27,0X21);//周期数据采集模式(每秒10次,Medium Repeatability)

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

/******************************
@function:读取SHT3x数据
@param:*Hum 湿度,*Temp 温度
@return:-1--失败,0--成功
@note:读取周期小于设定周期时,读取会错误;当前设定周期100ms,首次读取会错误
******************************/
int ReadSHT3x(float *Hum,float *Temp)
{
  uint16_t HumData = 0,TempData = 0,HumCRC = 0,TempCRC = 0;//声明变量存放读取的数据
  uint8_t data[6] = {0};

  if(SHT3x_WriteByte(0XE0,0X00) < 0) return -1;   //发送指令,获取数据,周期数据采集模式用
  if(simIIC_Read(SHT3X_IIC,data,6,dSHT3X_IIC_ADDRESS) < 0)return -1;
  TempData = ((uint16_t)data[0] << 8) | (uint16_t)data[1];//温度高8位数据|温度低8位数据
  TempCRC = data[2];//温度CRC校验数据
  HumData = ((uint16_t)data[3] << 8) | (uint16_t)data[4];//湿度高8位数据|湿度低8位数据
  HumCRC = data[5];//湿度CRC校验数据

  if((SHT3x_CRC_CAL(HumData) != HumCRC) || (SHT3x_CRC_CAL(TempData) !=TempCRC)) return -1;//对接收到数据进行CRC校验
  *Hum = (float)HumData*100.0f/(65536-1);           //将接收的16位二进制数据转换为10进制湿度数据
  *Temp = (float)TempData*175.0f/(65536-1)-45.0f;   //将接收的16位二进制数据转换为10进制温度数据
  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、温湿度读取main.c

main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&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(&Hum,&Temp) < 0){printf("error\n");}
    else printf("%.2fRH %.2f℃\n",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 buses 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\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

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

5、结果、IIC波形

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
完整工程及资料:
链接:https://pan.baidu.com/s/1fZVBOykei0jTcVZT9ijiTQ
提取码:gvgc

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/563216.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023年电子、通信与控制工程国际会议(SECCE 2023)

会议简介 Brief Introduction 2023年电子、通信与控制工程国际会议(SECCE 2023) 会议时间&#xff1a;2023年8月11日-13日 召开地点&#xff1a;韩国济州岛 大会官网&#xff1a;www.isecce.org 2023年电子、通信与控制工程国际会议(SECCE 2023)将围绕“电子、通信与控制工程”…

Spring Boot 整合流程引擎 Flowable(附源码地址)

一、导入依赖 flowable依赖&#xff1a; <dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>6.7.2</version> </dependency>pom.xml: <?xml version"1…

驱动页面性能优化的3个有效策略

目录 引言 背景 前端性能优化 测试视角的解法 性能问题的发现 性能数据的采集 性能指标的确定 性能问题的分析 如何衡量性能问题严重性 分析性能瓶颈-分析思路 分析结论关键思路 引言 测试通过发现、分析、验证三板斧&#xff0c;驱动推进页面性能优化快速有效&…

关注 | 蛙色元宇宙,正式成为XRMA联盟成员单位

中国虚拟现实与元宇宙产业峰会&#xff0c;2023年3月22日于杭州圆满结束&#xff0c;在杭州市人民政府、浙江省经济和信息化厅指导&#xff0c;由杭州市经济和信息化局、杭州市西湖区人民政府主办&#xff0c;中国信息通信研究院承办。 蛙色元宇宙作为元宇宙的领先企业之一&…

【AI面试】CrossEntropy Loss 、Balanced Cross Entropy、 Dice Loss 和 Focal Loss 横评对比

样本不均衡问题一直是深度学习领域一个不可忽略的问题&#xff0c;常说的长尾效应&#xff0c;说的就是这个问题。一类占据了主导地位&#xff0c;导致其他类无论怎么优化&#xff0c;都不能好转。 无论是纯纯的分类任务&#xff0c;还是稍微复杂一些的目标检测任务和分割任务…

关于java在成员/全局变量上不同类型赋值遇到的问题(值传递)

一个疑惑 文件简介回答参考文献 文件简介 class ss{static class Student{int id;String name; /*public Student(int id, String name) {this.id id;this.name name;}*/public int getId() {return id;}public void setId(int id) {this.id id;}public String getName() {…

数字人入门文章速览

语音驱动三维人脸方法 OPPO 数字人语音驱动面部技术实践 【万字长文】虚拟人漫谈 Blendshape学习笔记 人脸重建速览&#xff0c;从3DMM到表情驱动动画 功能强大的python包&#xff08;四&#xff09;&#xff1a;OpenCV 从Blendshapes到Animoji 3D人脸重建算法汇总 一、3D人脸重…

windows 10 安装k8s环境 Kubernetes

主要命令有 1. iwr https://chocolatey.org/install.ps1 -UseBasicParsing | iex 2. choco install minikube 3. minikube start 4. minikube dashboard 使用管理员运行 PowerShell 执行下面这条命令 iwr https://chocolatey.org/install.ps1 -UseBasicParsing | iex choc…

开源赋能 普惠未来|铜锁/Tongsuo诚邀您参与2023开放原子全球开源峰会

铜锁/Tongsuo是一个提供现代密码学算法和安全通信协议的开源基础密码库&#xff0c;为存储、网络、密钥管理、隐私计算、区块链等诸多业务场景提供底层的密码学基础能力&#xff0c;实现数据在传输、使用、存储等过程中的私密性、完整性和可认证性&#xff0c;为数据生命周期中…

Linux:web基础与HTTP协议

Linux&#xff1a;web基础与HTTP协议 一、域名概述1.1 域名的概念1.2 域名空间结构1.3 域名注册 二、网页的概念2.1 网页2.2 网站2.3 主页2.4 网页2 三、HTML概述3.1 HTML概述3.2 HTML文档结构3.3 HTML 基本标签 四、web概述4.1 web概述4.2 Web1.0 vs Web2.04.3 静态网页4.3.1 …

【挑战自己】软件测试的7个级别,做到3级已经超越80%测试人

有人说&#xff1a;软件测试就是最low的点点点工作。 有人说&#xff1a;测试工作职位薪水到一定程度只能原地踏步无法提升 也有人说&#xff1a;测试行业相对于开发来说技术性很低&#xff0c;容易被取代。 这其实是对测试行业最大的误解。测试可深可浅&#xff0c;可窄可广…

QDir拼接路径解决各种斜杠问题

一般在项目中经常需要组合路径,与其他程序进行相互调用传递消息通信。 经常可能因为多加斜杠、少加斜杠等问题导致很多问题。 为了解决这些问题,我们可以使用QDir来完成路径的拼接,不直接拼接字符串。 QDir的静态方法QDir::cleanPath() 是为了规范化路径名的,在使用QDir组…

Unity第三方分享(微信)插件ShareSDK使用简记

Unity第三方分享&#xff08;微信&#xff09;插件ShareSDK使用简记 微信分享遇到的问题记录 链接官方链接参考链接 微信分享 官方文档&#xff1a;MobTech集成文档-MobTech 下载地址&#xff1a;GitHub - MobClub/New-Unity-For-ShareSDK: New sample of ShareSDK for Unity,…

ChatGPT:你真的了解网络安全吗?浅谈攻击防御进行时之网络安全新防御

ChatGPT&#xff1a;你真的了解网络安全吗&#xff1f;浅谈网络安全攻击防御进行时 网络安全新防御1. 针对人工智能2. 针对5G和物联网3. 针对云安全4.针对社交工程5. 针对加密技术6. 针对多层次的安全控制 总结 ChatGPT&#xff08;全名&#xff1a;Chat Generative Pre-traine…

去除氟离子的最好办法,矿井水现场氟离子超标RO浓水除氟

一、产品介绍 氟化物选择吸附树脂 Tulsimer CH-87 是一款去除水溶液中氟离子的专用的凝胶型选择性离子交换树脂。它是具有氟化物选择性官能团的交联聚苯乙烯共聚物架构的树脂。 去除氟离子的能力可以达到 1ppm 以下的水平。中性至碱性的PH范围内有较好的工作效率&#xff0c;并…

保姆级别!!!--全网绝对教你会!!教你如何使用MQTTFX连接阿里云平台中的设备----下期告诉你如何创建!

本期需要下载的软件 MQttfx安装包&#xff0c;本人打包的-嵌入式文档类资源-CSDN文库 目录 第一步&#xff1a;建造阿里云设备 这个可以先忽略建造步骤&#xff0c;下期将提供步骤。 第二步&#xff1a;下载mqttfx软件 第三步&#xff1a;填写密钥信息进行连接 查看三元…

如何显示物品词缀?

UE5 插件开发指南 前言0 什么是物品词缀?1 如何动态显示物品词缀?前言 读到这里读者应该已经知道如何解析这个题目了,拆分为如下问题: (1)什么是物品词缀? (2)如何动态显示? 0 什么是物品词缀? 首先要知道什么是物品词缀,如下图所示,物品词缀就是用来描述物品属性的…

助力服务智能医疗检测,基于yolov5开发构建结直肠息肉检测系统,实践训练n/s/m不同量级模型,对比性能结果

将人工智能技术应用于众多的生活真实场景中是一件很有前景的事情&#xff0c;在我前面的博文中已经有不少的相关的开发实践&#xff0c;应用于医学领域也是一个非常重要的细分分支领域&#xff0c;在前面的博文中也有一些实践&#xff0c;感兴趣的话可以自行移步阅读。 《服务…

无需公网IP,快速远程登录家里的威联通NAS

文章目录 前言1. 威联通安装cpolar内网穿透2. 内网穿透2.1 创建隧道2.2 测试公网远程访问 3. 配置固定二级子域名3.1 保留二级子域名3.2 配置二级子域名 4. 使用固定二级子域名远程访问 转载自cpolar内网穿透的文章&#xff1a;无需公网IP&#xff0c;在外远程访问威联通QNAP|N…

『 MySQL篇 』:MySQL 事务特性

目录 一 . 什么是事务&#xff1f; 二. 事务的操作 ​三. 事务的四大特性 四 . 并发事务可能产生的问题 五 . 数据库的隔离级别 一 . 什么是事务&#xff1f; 从概念上来讲&#xff0c;事务是一个有限的数据库操作序列构成&#xff0c;这些操作要么全部执行&#xff0c…