温湿度采集与OLED显示

1. 学习I2C总线通信协议,使用STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集,并将采集的温度-湿度值通过串口输出。具体任务:

1)解释什么是“软件I2C”和“硬件I2C”? 

I2C(Inter-Integrated Circuit)是一种串行通信协议,用于在集成电路之间传输数据。I2C使用两条线:SCL(时钟线)和SDA(数据线),通过主从架构进行通信。STM32F103微控制器支持I2C通信,可以通过软件模拟或硬件外设实现I2C协议。

软件I2C

软件I2C(Software I2C)指的是通过软件代码来模拟I2C通信时序和协议。这种方法不依赖微控制器的硬件I2C外设,而是通过普通的GPIO引脚和定时控制来实现I2C通信。具体来说,软件I2C通常包括以下几个步骤:

  1. 拉低SDA: 模拟起始条件。
  2. 拉低或拉高SCL:控制时钟线以产生时钟脉冲。
  3. 读写SDA:根据需要发送或接收数据位。
  4. 释放SDA:模拟停止条件。

优点

  • 灵活性高,可以用于没有硬件I2C外设的微控制器。
  • 可以在任意GPIO引脚上实现。

缺点

  • 需要占用CPU资源,效率较低。
  • 定时要求高,容易受到中断的影响。

硬件I2C

硬件I2C(Hardware I2C)利用微控制器内部专门的I2C外设模块来实现I2C通信。STM32F103系列微控制器通常内置多个I2C外设,可以直接使用这些外设来控制I2C通信,而无需手动模拟时序。

优点

  • 效率高,由硬件自动处理时序和协议,减少CPU负担。
  • 更加稳定,受外部中断的影响较小。
  • 通常支持更高的I2C总线速度(标准模式、快速模式等)。

缺点

  • 硬件接口的灵活性较低,受限于特定的I2C引脚。
  • 需要通过寄存器配置,学习曲线可能较高。

实现I2C通信并采集AHT20数据

1. 配置I2C外设

首先,需要通过STM32的I2C外设初始化代码配置I2C总线。

#include "stm32f1xx_hal.h"

I2C_HandleTypeDef hi2c1;

void MX_I2C1_Init(void)
{
    hi2c1.Instance = I2C1;
    hi2c1.Init.ClockSpeed = 100000; // 100kHz 标准模式
    hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
    hi2c1.Init.OwnAddress1 = 0;
    hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c1.Init.OwnAddress2 = 0;
    hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    if (HAL_I2C_Init(&hi2c1) != HAL_OK)
    {
        // 初始化错误处理
    }
}
2. AHT20 数据读取函数

编写函数,通过I2C读取AHT20的数据。

#define AHT20_ADDRESS 0x38 << 1 // AHT20 I2C地址,考虑到7位地址格式

uint8_t AHT20_Init(void)
{
    uint8_t init_cmd[] = {0xBE, 0x08, 0x00};
    return HAL_I2C_Master_Transmit(&hi2c1, AHT20_ADDRESS, init_cmd, 3, HAL_MAX_DELAY);
}

uint8_t AHT20_ReadData(uint8_t *data)
{
    uint8_t trigger_measurement_cmd[] = {0xAC, 0x33, 0x00};
    HAL_I2C_Master_Transmit(&hi2c1, AHT20_ADDRESS, trigger_measurement_cmd, 3, HAL_MAX_DELAY);
    HAL_Delay(80); // 延时保证测量完成
    return HAL_I2C_Master_Receive(&hi2c1, AHT20_ADDRESS, data, 6, HAL_MAX_DELAY);
}

 

3. 串口配置与数据输出

配置串口,并通过串口发送读取到的温湿度数据。

UART_HandleTypeDef huart1;

void MX_USART1_UART_Init(void)
{
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 115200;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&huart1) != HAL_OK)
    {
        // 初始化错误处理
    }
}

void Print_Temp_Humidity(float temperature, float humidity)
{
    char buffer[100];
    int len = snprintf(buffer, sizeof(buffer), "Temperature: %.2f C, Humidity: %.2f %%\r\n", temperature, humidity);
    HAL_UART_Transmit(&huart1, (uint8_t *)buffer, len, HAL_MAX_DELAY);
}

 

4. 主循环

在主循环中调用这些函数,周期性地读取并输出温湿度数据。

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_I2C1_Init();
    MX_USART1_UART_Init();

    // 初始化AHT20
    if (AHT20_Init() != HAL_OK)
    {
        // 错误处理
    }

    uint8_t data[6];

    while (1)
    {
        if (AHT20_ReadData(data) == HAL_OK)
        {
            uint32_t raw_temperature = ((uint32_t)data[3] & 0x0F) << 16 | data[4] << 8 | data[5];
            uint32_t raw_humidity = (uint32_t)data[1] << 12 | data[2] << 4 | (data[3] & 0xF0) >> 4;
            
            float temperature = ((float)raw_temperature / 1048576.0) * 200.0 - 50.0;
            float humidity = ((float)raw_humidity / 1048576.0) * 100.0;
            
            Print_Temp_Humidity(temperature, humidity);
        }

        HAL_Delay(2000); // 2秒钟读取一次
    }
}

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

 定期读取温湿度数据

读取传感器数据并进行处理:

// 读取AHT20数据
void AHT20_ReadData(float *temperature, float *humidity)
{
    uint8_t data[7];
    AHT20_StartMeasurement();
    HAL_Delay(80); // 等待测量完成
    
    HAL_I2C_Master_Receive(&hi2c1, AHT20_ADDR, data, 7, HAL_MAX_DELAY);
    
    uint32_t rawHumidity = (data[1] << 12) | (data[2] << 4) | (data[3] >> 4);
    uint32_t rawTemperature = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5];
    
    *humidity = ((float)rawHumidity / 1048576.0) * 100.0;
    *temperature = ((float)rawTemperature / 1048576.0) * 200.0 - 50.0;
}
 显示到OLED显示屏(可选)

使用适当的OLED驱动库来显示数据,这里假设已经初始化OLED显示:

void OLED_DisplayData(float temperature, float humidity)
{
    char buffer[32];
    sprintf(buffer, "Temp: %.2f C", temperature);
    OLED_ShowString(0, 0, buffer);
    sprintf(buffer, "Hum: %.2f %%", humidity);
    OLED_ShowString(0, 16, buffer);
}
通过串口发送数据到上位机

初始化UART并发送数据:

UART_HandleTypeDef huart1;

void MX_USART1_UART_Init(void)
{
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 115200;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&huart1) != HAL_OK)
    {
        // Initialization Error
        Error_Handler();
    }
}

void UART_SendData(float temperature, float humidity)
{
    char buffer[64];
    int len = sprintf(buffer, "Temperature: %.2f C, Humidity: %.2f %%\r\n", temperature, humidity);
    HAL_UART_Transmit(&huart1, (uint8_t*)buffer, len, HAL_MAX_DELAY);
}
主循环

在主循环中,每隔2秒钟采集一次数据,并进行显示和发送:

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_I2C1_Init();
    MX_USART1_UART_Init();
    
    AHT20_Init();
    
    while (1)
    {
        float temperature, humidity;
        AHT20_ReadData(&temperature, &humidity);
        
        OLED_DisplayData(temperature, humidity); // 如果有OLED显示
        UART_SendData(temperature, humidity);
        
        HAL_Delay(2000); // 每隔2秒采样一次
    }
}

作者水平有限,不足之处欢迎指正。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

珏决

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值