本文使用模拟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>© 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