温湿度采集与OLED显示

一、原理

1.I2C总线通信协议

I2C(Inter-Integrated Circuit)总线是一种由飞利浦公司(现NXP半导体)开发的一种多主多从的串行通信协议,用于连接低速外围设备。I2C总线仅需两根线——串行数据线(SDA)和串行时钟线(SCL)——就可以在连接于总线上的设备之间进行信息传输。

2.硬件I2C

硬件I2C是指微控制器内置的I2C模块,该模块专门用于处理I2C协议的所有细节,包括起始位、停止位、数据传输、时钟信号以及应答信号的生成。使用硬件I2C时,开发者通常只需要通过硬件寄存器配置I2C模块的参数(如时钟速度、设备地址等),然后通过硬件I2C模块提供的接口进行数据的读写操作。硬件I2C的优点是速度快、效率高,不需要占用CPU资源来模拟时序,因此在处理高速或大量数据传输时更为可靠。

3.软件I2C

软件I2C,又称为模拟I2C,是通过微控制器的通用输入输出(GPIO)引脚,由软件程序模拟I2C协议的时序来实现的。在软件I2C中,开发者需要编写代码来控制SDA和SCL引脚的电平变化,以模拟出I2C通信所需的起始位、停止位、数据位和时钟信号。软件I2C的优势在于灵活性高,可以在没有硬件I2C模块的微控制器上实现I2C通信,或者在硬件I2C模块被占用时作为一种替代方案。但是,软件I2C通常速度较慢,且会占用CPU资源,可能在处理高速或实时性要求高的应用时不够理想。

4.对比

硬件I2C通常更快,因为它由专用的硬件电路处理,而软件I2C受限于CPU的速度和可用资源。
硬件I2C不需要CPU资源来模拟时序,而软件I2C需要CPU不断控制GPIO引脚的状态。
软件I2C可以在任何具有GPIO功能的微控制器上实现,而硬件I2C需要微控制器具备I2C硬件模块。
硬件I2C在处理复杂的通信协议时更为可靠,因为它不受其他程序任务的影响。

二、编程实现:每隔2秒钟采集一次温湿度数据,显示到OLED上,同时通过串口发送到上位机的“串口助手”软件。

1.STM32CubeMX配置

RCC:
![[bb70ce82bf7abe4af568f7489f2a9c7.png]]

USART1:
![[Pasted image 20240623233533.png]]

SYS:
![[Pasted image 20240623233931.png]]

GPIO:
![[Pasted image 20240623233956.png]]

12C1:
![[Pasted image 20240623234116.png]]

Clock:
![[Pasted image 20240623234220.png]]

2.代码

下载AHT20芯片代码
http://www.aosong.com/class-36-2.html

3.Keil代码修改

AHT20-21_DEMO_V1_3.h:

#ifndef AHT20_DEMO
#define AHT20_DEMO

#include “main.h”

void Delay_N10us(uint32_t t);//延时函数
void SensorDelay_us(uint32_t t);//延时函数
void Delay_4us(void); //延时函数
void Delay_5us(void); //延时函数
void Delay_1ms(uint32_t t);
void AHT20_Clock_Init(void); //延时函数
void SDA_Pin_Output_High(void) ; //将PB15配置为输出 , 并设置为高电平, PB15作为I2C的SDA
void SDA_Pin_Output_Low(void); //将P15配置为输出 并设置为低电平
void SDA_Pin_IN_FLOATING(void); //SDA配置为浮空输入
void SCL_Pin_Output_High(void); //SCL输出高电平,P14作为I2C的SCL
void SCL_Pin_Output_Low(void); //SCL输出低电平
void Init_I2C_Sensor_Port(void); //初始化I2C接口,输出为高电平
void I2C_Start(void); //I2C主机发送START信号
void AHT20_WR_Byte(uint8_t Byte); //往AHT20写一个字节
uint8_t AHT20_RD_Byte(void);//从AHT20读取一个字节
uint8_t Receive_ACK(void); //看AHT20是否有回复ACK
void Send_ACK(void) ; //主机回复ACK信号
void Send_NOT_ACK(void); //主机不回复ACK
void Stop_I2C(void); //一条协议结束
uint8_t AHT20_Read_Status(void);//读取AHT20的状态寄存器
uint8_t AHT20_Read_Cal_Enable(void); //查询cal enable位有没有使能
void AHT20_SendAC(void); //向AHT20发送AC命令
uint8_t Calc_CRC8(uint8_t *message,uint8_t Num);
void AHT20_Read_CTdata(uint32_t *ct); //没有CRC校验,直接读取AHT20的温度和湿度数据
void AHT20_Read_CTdata_crc(uint32_t *ct); //CRC校验后,读取AHT20的温度和湿度数据
void AHT20_Init(void); //初始化AHT20
void JH_Reset_REG(uint8_t addr);///重置寄存器
void AHT20_Start_Init(void);///上电初始化进入正常测量状态
#endif

main:

#include “main.h”
#include “dma.h”
#include “i2c.h”
#include “usart.h”
#include “gpio.h”
#include<stdio.h>
#include “AHT20-21_DEMO_V1_3.h”

void SystemClock_Config(void);

int fputc(int ch,FILE *f)

{
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);
//等待发送结束
while(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_TC)!=SET){
}

return ch;

}

int main(void)
{
/* USER CODE BEGIN 1 */
uint32_t CT_data[2]={0,0};
volatile int c1,t1;

Delay_1ms(500);

HAL_Init();

SystemClock_Config();

MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();

//初始化AHT20
AHT20_Init();
Delay_1ms(500);

while (1)
{
/* USER CODE END WHILE */
AHT20_Read_CTdata(CT_data); //不经过CRC校验,直接读取AHT20的温度和湿度数据 推荐每隔大于1S读一次
//AHT20_Read_CTdata_crc(CT_data); //crc校验后,读取AHT20的温度和湿度数据

	c1 = CT_data[0]*1000/1024/1024;  //计算得到湿度值c1(放大了10倍)
	t1 = CT_data[1]*2000/1024/1024-500;//计算得到温度值t1(放大了10倍)
	printf("正在检测");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	printf("\r\n");
	HAL_Delay(1000);
	printf("温度:%d%d.%d",t1/100,(t1/10)%10,t1%10);
	printf("湿度:%d%d.%d",c1/100,(c1/10)%10,c1%10);
	printf("\r\n");
	printf("等待");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	HAL_Delay(100);
	printf(".");
	printf("\r\n");
	HAL_Delay(1000);

/* 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 */
    }

4.串口打印

![[Pasted image 20240623234956.png]]

  • 9
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值