STM32:IIC与温湿度传感器(轮询模式)

目录

一.IIC通信原理

二.Cubemx

三.代码实现

1.查阅AHT20数据手册

2.IIC读取与发送函数

3.根据手册写初始化过程,在aht20.c中定义一个初始化函数AHT20_Init

4.根据AHT20数据手册,在aht20.c文件中定义AHT20读取温湿度的函数:AHT20_Read

5.aht20.h文件中实现函数声明

6.main.c文件剩下代码:

四.整体代码:


之前我们学习了STM32中最常用的通信方式:串口,这次,我们来学习另一种常见的通信方式:IIC通信 ,并且使用IIC通信与stm32板上的AHT20传感器进行交互,获取周围环境的温度与湿度。

一.IIC通信原理

除了共地线,还有一条可以传递数据的数据线(SDA:Serial Data)和另一条用于同步时钟脉冲的时钟线(SCL:Serial Clock) 。串口两根线可以同时进行双向通信(全双工通信 ),而IIC的SDA也允许双向通信,但同一时刻只能一端发送,不能同时进行(半双工通信 ),即同一时刻只能进行一个方向的通信 ,为了避免冲突,IIC采用主从模式 ,一台设备为主机,另一条/多台为从机。只能主机先发起通信,从机才能根据主机的指令回复相应的信息。因为一问一答的主从模式,使得IIC可以支持多设备通信,多用于板载小传感器芯片 。像IIC这种支持多个设备进行通信的通信协议,我们称其为总线协议 。在IIC总线上,每个从机都有其唯一的设备地址。IIC选择与异步通信相对的另一种模式------同步通信 ,即主机通过时钟线发送固定频率的脉冲信号,来作为IIC总线上所有设备通信的统一时钟源。

主机在发送开始与结束信号时,时钟线为高电平主机才控制数据线。正常情况下,比如数据发送方为从机,当时钟线为低电平,从机控制数据线设置为高/低电平;当时钟线为高电平时,主机读取数据线刚才设置的电平。按照IIC协议的约定,数据的接收方需要发送一个ACK信号(应答信号)确认自己已经收到数据。

二.Cubemx

1.打开USART2,用于后面串口查看数据

2.设置IIC

3.这次不将代码全部写在main.c文件,,而是专门为AHT20写一下驱动文件(aht20.h+aht20.c)

勾选为每一个外设生成一对.c/.h文件,可以在其它文件中include相应的头文件,就能拿到huart2或hi2c1这类外设操作句柄了。

保存并生成代码后发现生成gpio,i2c,usart的.c和.h文件

4.定义aht20.c与.h文件

aht20.h文件:写#include"i2c.h"(为了使用I2C相关函数)

aht20.c文件:写#include"aht20.h"(包含了i2c.h文件)

三.代码实现

1.查阅AHT20数据手册

2.IIC读取与发送函数

IIC读取函数:(主机接收)

HAL_I2C_Master_Receive(hi2c, DevAddress, pData, Size, Timeout);

第一个参数:外设操作句柄的指针,即hi2c1的指针

第二个参数:读取的从机地址,即宏定义AHT20_ADDRESS

第三个参数:用于接收数据的变量的指针,即&readBuffer

第四个参数:读取多少位数据,按照手册,读一位数据,即为1

第五个参数:超时时间,这里填永久等待,即HAL_MAX_DELAY

因此,该函数为:HAL_I2C_Master_Receive(&hi2c1,AHT20_ADDRESS,&readBuffer,1,HAL_MAX_DELAY);
IIC发送函数:(主机发送)

HAL_I2C_Master_Transmit(hi2c, DevAddress, pData, Size, Timeout);

第一个参数:外设操作句柄的指针,即hi2c1的指针

第二个参数:发送的从机地址,即宏定义AHT20_ADDRESS

第三个参数:用于发送数据的变量的指针,即sendBuffer(数组名为首元素地址)

第四个参数:发送多少位数据,按照手册,发送3字节数据,即为3

第五个参数:超时时间,这里填永久等待,即HAL_MAX_DELAY

因此,该函数为:

HAL_I2C_Master_Transmit(&hi2c1, AHT20_ADDRESS, sendBuffer, 3,HAL_MAX_DELAY)
注意辨别什么时候使用Transmit,什么时候使用Receive(当题目无明显体现谁向谁发送消息时):

命令 / 指令 = 单片机 (主机) 发给传感器 (从机) → Transmit;

读数 / 状态 = 传感器发给单片机 → Receive

3.根据手册写初始化过程,在aht20.c中定义一个初始化函数AHT20_Init

(1)数据手册初始化过程

(2)进行define宏定义,定义一下AHT20的设备地址是0x70

(3)初始化函数

cpp 复制代码
//初始化
void AHT20_Init()
{
	uint8_t readBuffer;//用于接收状态信息
	HAL_Delay(40);//按照手册先延时40ms
	HAL_I2C_Master_Receive(&hi2c1,AHT20_ADDRESS,&readBuffer,1,HAL_MAX_DELAY);
	if((readBuffer & 0x08) == 0x00)
	{
		uint8_t sendBuffer[3] = {0xBE, 0x08, 0x00};
		HAL_I2C_Master_Transmit(&hi2c1, AHT20_ADDRESS, sendBuffer,3 , HAL_MAX_DELAY);
	}
}

4.根据AHT20数据手册,在aht20.c文件中定义AHT20读取温湿度的函数:AHT20_Read

(1)数据手册:

(2)AHT20_Read函数:

cpp 复制代码
void AHT20_Read(float* Temperature, float* Humidity)
{
	uint8_t sendBuffer[3] = {0xAC, 0x33, 0x00};
	uint8_t readBuffer[6] = {0};

	HAL_I2C_Master_Transmit_(&hi2c1, AHT20_ADDRESS, sendBuffer, 3, HAL_MAX_DELAY);
	HAL_Delay(75);
	HAL_I2C_Master_Receive_IT(&hi2c1, AHT20_ADDRESS, readBuffer,6, HAL_MAX_DELAY);

	if((readBuffer[0] & 0x80) == 0x00)
	{
		uint32_t data = 0;
		//注意类型转化:uint8_t->uint32_t
		data = ((uint32_t)readBuffer[3] >> 4 ) + ((uint32_t)readBuffer[2] << 4) + ((uint32_t)readBuffer[1] << 12);
		*Humidity = data* 100.0f / ( 1<<20 ) ;//注意要乘100.0f,保证运算结果为小数

		data = (((uint32_t)readBuffer[3] & 0x0F) << 16) + ((uint32_t)readBuffer[4] << 8) + (uint32_t)readBuffer[5];
		*Temperature = data * 200.0f / (1 << 20) - 50;
	}
}

5.aht20.h文件中实现函数声明

(1)在aht20.h文件中对刚才定义的函数进行声明

cpp 复制代码
void AHT20_Init();

void AHT20_Read(float* Temperature, float* Humidity);

6.main.c文件剩下代码:

(1)在main.c文件中引入aht20.h,stdio.h和string.h头文件

(2)在main函数中初始化,同时引入3个变量

(3)在while循环中写入读取温湿度函数,且把文字 + 数字拼成字符串存进message数组中,

注意:由于stm32CubeIDE没有启用编译器对浮点数输出的支持,按照报错指示来解决该问题

最后通过串口发送函数HAL_UART_Transmit发送出来

cpp 复制代码
AHT20_Read(&temperature, &humidity);
sprintf(message, "温度:%.lf ℃,湿度:%.lf %%\r\n",temperature,humidity);
//注意强制类型转化:
HAL_UART_Transmit(&huart2, (uint8_t*)message, strlen(message), HAL_MAX_DELAY);
HAL_Delay(1000);

四.整体代码:

1.aht20.h

cpp 复制代码
/*
 * aht20.h
 *
 *  Created on: May 24, 2026
 *      Author: 25306
 */

#ifndef INC_AHT20_H_
#define INC_AHT20_H_

#include "i2c.h"

void AHT20_Init();

void AHT20_Read(float* Temperature, float* Humidity);

//void AHT20_Measure();
//
//void AHT20_Get();
//
//void AHT20_Analysis(float* Temperature, float* Humidity);
#endif /* INC_AHT20_H_ */

2.aht20.c

cpp 复制代码
/*
 * aht20.c
 *
 *  Created on: May 24, 2026
 *      Author: 25306
 */
#include"aht20.h"

#define AHT20_ADDRESS 0x70

//uint8_t readBuffer[6] = {0};

//初始化
void AHT20_Init()
{
	uint8_t readBuffer;//用于接收状态信息
	HAL_Delay(40);//按照手册先延时40ms
	HAL_I2C_Master_Receive(&hi2c1,AHT20_ADDRESS,&readBuffer,1,HAL_MAX_DELAY);
	if((readBuffer & 0x08) == 0x00)
	{
		uint8_t sendBuffer[3] = {0xBE, 0x08, 0x00};
		HAL_I2C_Master_Transmit(&hi2c1, AHT20_ADDRESS, sendBuffer,3 , HAL_MAX_DELAY);
	}
}

void AHT20_Read(float* Temperature, float* Humidity)
{
	uint8_t sendBuffer[3] = {0xAC, 0x33, 0x00};
	uint8_t readBuffer[6] = {0};

	HAL_I2C_Master_Transmit(&hi2c1, AHT20_ADDRESS, sendBuffer, 3,HAL_MAX_DELAY);
	HAL_Delay(75);
	HAL_I2C_Master_Receive(&hi2c1, AHT20_ADDRESS, readBuffer,6,HAL_MAX_DELAY );

	if((readBuffer[0] & 0x80) == 0x00)
	{
		uint32_t data = 0;
		//注意类型转化:uint8_t->uint32_t
		data = ((uint32_t)readBuffer[3] >> 4 ) + ((uint32_t)readBuffer[2] << 4) + ((uint32_t)readBuffer[1] << 12);
		*Humidity = data* 100.0f / ( 1<<20 ) ;//注意要乘100.0f,保证运算结果为小数

		data = (((uint32_t)readBuffer[3] & 0x0F) << 16) + ((uint32_t)readBuffer[4] << 8) + (uint32_t)readBuffer[5];
		*Temperature = data * 200.0f / (1 << 20) - 50;
	}
}

//void AHT20_Measure()
//{
//	static uint8_t sendBuffer[3] = { 0xAC, 0X33, 0X00 };
//	HAL_I2C_Master_Transmit_DMA(&hi2c1, AHT20_ADDRESS, sendBuffer, 3);
//}
//
//void AHT20_Get()
//{
//	HAL_I2C_Master_Receive_DMA(&hi2c1, AHT20_ADDRESS, readBuffer, 6);
//}
//
//void AHT20_Analysis(float* Temperature, float* Humidity)
//{
//	if((readBuffer[0] & 0x80) == 0x00)
//		{
//			uint32_t data = 0;
//			data = ((uint32_t)readBuffer[3] >> 4 ) + ((uint32_t)readBuffer[2] << 4) + ((uint32_t)readBuffer[1] << 12);
//			*Humidity = data* 100.0f / ( 1<<20 ) ;
//
//			data = (((uint32_t)readBuffer[3] & 0x0F) << 16) + ((uint32_t)readBuffer[4] << 8) + (uint32_t)readBuffer[5];
//			*Temperature = data * 200.0f / (1 << 20) - 50;
//		}
//}

3.main.c

cpp 复制代码
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2026 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 */
#include "aht20.h"
#include <stdio.h>
#include<string.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 */
//0:初始状态 发送测量命令  1:正在发送测量命令 2:测量命令发送完成,等待75毫秒后读取AHT20数据
//3:读取中 4:读取完成,解析并展示数据然后恢复到初始状态
uint8_t aht20State = 0;
/* 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_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  AHT20_Init();

  float temperature, humidity;
  char message[50];
  /* USER CODE END 2 */

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

//	  if(aht20State == 0)
//	  {
//		  AHT20_Measure();
//		  aht20State = 1;
//	  }else if(aht20State == 2){
//		  HAL_Delay(75);
//		  AHT20_Get();
//		  aht20State = 3;
//	  }else if(aht20State == 4){
//		  AHT20_Analysis(&temperature, &humidity);
//		  sprintf(message,"温度:%.lf℃, 湿度:%.lf %%\r\n",temperature,humidity);
//		  HAL_UART_Transmit(&huart2,(uint8_t*)message, strlen(message), HAL_MAX_DELAY);
//
//		  HAL_Delay(1000);
//		  aht20State = 0;
//	  }
	  AHT20_Read(&temperature, &humidity);
	  sprintf(message, "温度:%.lf ℃,湿度:%.lf %%\r\n",temperature,humidity);
	  HAL_UART_Transmit(&huart2, (uint8_t*)message, strlen(message), HAL_MAX_DELAY);//注意强制类型转化

	  HAL_Delay(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_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  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_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != 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 */
相关推荐
项目題供诗1 小时前
STM32-编码器接口测速(十七)
stm32·单片机·嵌入式硬件
嵌入式小站1 小时前
STM32 零基础可移植教程 19:I2C 读写寄存器,先读一个设备 ID
stm32·单片机·嵌入式硬件
minglie11 小时前
zynq用普通网口在局域网同步
单片机
weixin_467182281 小时前
Arduino进阶二|自定义类库保姆级教程(从零手写属于自己的传感器类库+完整源码)
c语言·c++·单片机·嵌入式硬件·arduino·c++面向对象·diy库文件
清风6666662 小时前
基于单片机的64位多模式流水灯控制系统设计
单片机·毕业设计·课程设计·期末大作业
进击的横打2 小时前
【车载开发系列】热敏电阻与上下拉电阻
单片机·嵌入式硬件
XINVRY-FPGA2 小时前
XCKU035-2FBVA676I AMD Xilinx Kintex UltraScale FPGA
arm开发·嵌入式硬件·网络安全·fpga开发·硬件工程·信号处理·fpga
崇山峻岭之间3 小时前
单片机USB虚拟串口实验
单片机·嵌入式硬件
崇山峻岭之间3 小时前
单片机USB U盘实验
单片机·嵌入式硬件