无垠的广袤 发表于 2025-5-20 01:58

【STM32C092RC 测评】AHT10 温湿度 OLED 显示

# 【STM32C092RC 测评】AHT10 温湿度 OLED 显示

本文介绍了 Nucleo-STM32C092 开发板通过硬件 IIC 与 AHT10 和 OLED 通信,采集环境温湿度、串口打印并实时显示在 OLED 的项目设计,制成 DIY 温湿度计。

## 项目方案

- 使用 STM32CubeMX 创建工程,配置 IIC 和 UART;
- STM32CubeIDE 代码编译和工程调试、固件上传;
- 实现基于 AHT10 传感器的环境温湿度的数据采集、串口打印和 OLED 实时显示。

## 工程创建

使用 STM32CubeMX 快速创建工程。

- 打开 `STM32CubeMX` 软件,新建 ST 板卡工程,搜索 `NUCLEO-C092RC` 选中目标板卡,开始工程,选择默认外设配置(注意不使用 BSP 板级支持包);
- 时钟配置:采用默认设置,系统时钟频率 12MHz;
- `Pinout & Configuration` 标签下选择 `Connectivity` - 使能 `USART2` - 选择 `Asynchronous` 异步通信模式;
- `Pinout & Configuration` 标签下选择 `I2C1` - 使能 `I2C1` - 注意到 GPIO 对应 PA9 (SCL) 和 PA10 (SDA);
- `Pinout & Configuration` 标签下选择 `I2C2` - 使能 `I2C2` - 注意到 GPIO 对应 PA7 (SCL) 和 PA6 (SDA);

> 这里可以仅开启一个 IIC 实现复用。
- 配置完成后,进入 `Project Manager` 标签栏,进行项目命名、保存路径设置、编译器选择等操作;
- 点击 `Generate Code` 按钮,使用 **STM32CubeIDE** 或 Keil 打开目标工程;
- 编译工程,`0 error, 0 warning` .

## 硬件连接

### AHT10

| AHT10 引脚 | NUCLEO-C092RC 引脚 |
| :--------- | :----------------- |
| VCC      | 3.3V               |
| GND      | GND                |
| SDA      | PA10 (I2C1_SDA)    |
| SCL      | PA9 (I2C1_SCL)   |

### OLED

| OLED 引脚 | NUCLEO-C092RC 引脚 |
| :-------- | :----------------- |
| GND       | GND                |
| VCC       | 3.3V               |
| SCL       | PA10 (I2C2_SCL)    |
| SDA       | PA9 (I2C2_SDA)   |

### 实物连接

!(data/attachment/forum/202505/20/015658n38fbv35572b2rp2.jpg "oled_aht10_display.jpg")


## 工程代码

`aht10.h` 和 `aht10.c` 的代码详见帖子:[【STM32C092RC 测评】AHT10 温湿度串口打印](https://bbs.21ic.com/icview-3454688-1-1.html) .

### oled.h

```c++
#ifndef __OLED_H__
#define __OLED_H__

#include "stm32c0xx_hal.h"


#define   OLED_GPIO_CLK_ENABLE()         __HAL_RCC_GPIOA_CLK_ENABLE()

#define   GPIOx_OLED_PORT               GPIOB
#define   OLED_SCK_PIN                  GPIO_PIN_6
#define   OLED_SCK_ON()               HAL_GPIO_WritePin(GPIOx_OLED_PORT, OLED_SCK_PIN, GPIO_PIN_SET)
#define   OLED_SCK_OFF()                HAL_GPIO_WritePin(GPIOx_OLED_PORT, OLED_SCK_PIN, GPIO_PIN_RESET)
#define   OLED_SCK_TOGGLE()             HAL_GPIO_TogglePin(GPIOx_OLED_PORT, OLED_SCK_PIN)
#define   OLED_SDA_PIN                  GPIO_PIN_7
#define   OLED_SDA_ON()               HAL_GPIO_WritePin(GPIOx_OLED_PORT, OLED_SDA_PIN, GPIO_PIN_SET)
#define   OLED_SDA_OFF()                HAL_GPIO_WritePin(GPIOx_OLED_PORT, OLED_SDA_PIN, GPIO_PIN_RESET)
#define   OLED_SDA_TOGGLE()             HAL_GPIO_TogglePin(GPIOx_OLED_PORT, OLED_SDA_PIN)


void WriteCmd(void);
void OLED_WR_CMD(uint8_t cmd);
void OLED_WR_DATA(uint8_t data);
void OLED_Init(void);
void OLED_Clear(void);
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Set_Pos(uint8_t x, uint8_t y);
void OLED_On(void);
void OLED_ShowNum(uint8_t x,uint8_t y,unsigned int num,uint8_t len,uint8_t size2, uint8_t Color_Turn);
void OLED_ShowDecimal(uint8_t x,uint8_t y,float num,uint8_t z_len,uint8_t f_len,uint8_t size2, uint8_t Color_Turn);
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t Char_Size, uint8_t Color_Turn);
void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t Char_Size, uint8_t Color_Turn);
void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no, uint8_t Color_Turn);
void OLED_DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t *BMP,uint8_t Color_Turn);
void OLED_DrawGIF(uint8_t x0, uint8_ty0, uint8_tx1, uint8_t y1, uint8_tk, int m, unsigned char GIF[]);
void OLED_HorizontalShift(uint8_t direction);
void OLED_Some_HorizontalShift(uint8_t direction,uint8_t start,uint8_t end);
void OLED_VerticalAndHorizontalShift(uint8_t direction);
void OLED_DisplayMode(uint8_t mode);
void OLED_IntensityControl(uint8_t intensity);
void OLED_ClearLinePart(uint8_t line, uint8_t start, uint8_t end);

#endif
```

### oled.c

```c++
/*
* ======================
* ref: https://blog.csdn.net/m0_46295154/article/details/139970968
* ======================
*/
#include "oled.h"
#include "i2c.h"
#include "oledfont.h"

uint8_t CMD_Data[]={
0xAE, 0x00, 0x10, 0x40, 0xB0, 0x81, 0xFF, 0xA1, 0xA6, 0xA8, 0x3F,

0xC8, 0xD3, 0x00, 0xD5, 0x80, 0xD8, 0x05, 0xD9, 0xF1, 0xDA, 0x12,

0xD8, 0x30, 0x8D, 0x14, 0xAF};      //初始化命令


void WriteCmd(void)
{
        uint8_t i = 0;
        for(i=0; i<27; i++)
        {
                HAL_I2C_Mem_Write(&hi2c2 ,0x78,0x00,I2C_MEMADD_SIZE_8BIT,CMD_Data+i,1,0x100);
        }
}

/**
* @function: void OLED_WR_CMD(uint8_t cmd)
* @description: 向设备写控制命令
* @param {uint8_t} cmd 芯片手册规定的命令
* @return {*}
*/
void OLED_WR_CMD(uint8_t cmd)
{
        HAL_I2C_Mem_Write(&hi2c2 ,0x78,0x00,I2C_MEMADD_SIZE_8BIT,&cmd,1,0x100);
}

/**
* @function: void OLED_WR_DATA(uint8_t data)
* @description: 向设备写控制数据
* @param {uint8_t} data 数据
* @return {*}
*/
void OLED_WR_DATA(uint8_t data)
{
        HAL_I2C_Mem_Write(&hi2c2 ,0x78,0x40,I2C_MEMADD_SIZE_8BIT,&data,1,0x100);
}

/**
* @function: void OLED_Init(void)
* @description: OLED初始化
* @return {*}
*/
void OLED_Init(void)
{
        HAL_Delay(200);

        WriteCmd();
}

/**
* @function: OLED_Clear(void)
* @description: 清屏,整个屏幕的像素点都是关闭的
* @return {*}
*/
void OLED_Clear(void)
{
        uint8_t i,n;
        for(i=0;i<8;i++)
        {
                OLED_WR_CMD(0xb0+i);
                OLED_WR_CMD (0x00);
                OLED_WR_CMD (0x10);
                for(n=0;n<132;n++)
                        OLED_WR_DATA(0);
        }
}

/**
* @function: void OLED_Display_On(void)
* @description: 更新显示
* @return {*}
*/
void OLED_Display_On(void)
{
        OLED_WR_CMD(0X8D);//SET DCDC命令
        OLED_WR_CMD(0X14);//DCDC ON
        OLED_WR_CMD(0XAF);//DISPLAY ON
}

/**
* @function: void OLED_Display_Off(void)
* @description: 关闭OLED显示
* @return {*}
*/
void OLED_Display_Off(void)
{
        OLED_WR_CMD(0X8D);//SET DCDC命令
        OLED_WR_CMD(0X10);//DCDC OFF
        OLED_WR_CMD(0XAE);//DISPLAY OFF
}

/**
* @function: void OLED_Set_Pos(uint8_t x, uint8_t y)
* @description: 坐标设置
* @param {uint8_t} x,y
* @return {*}
*/
void OLED_Set_Pos(uint8_t x, uint8_t y)
{
        OLED_WR_CMD(0xb0+y);
        OLED_WR_CMD(((x&0xf0)>>4)|0x10);
        OLED_WR_CMD(x&0x0f);
}

/**
* @function: void OLED_On(void)
* @description: 更新显示
* @return {*}
*/
void OLED_On(void)
{
        uint8_t i,n;
        for(i=0;i<8;i++)
        {
                OLED_WR_CMD(0xb0+i);    //设置页地址(0~7)
                OLED_WR_CMD(0x00);      //设置显示位置—列低地址
                OLED_WR_CMD(0x10);      //设置显示位置—列高地址
                for(n=0;n<128;n++)
                        OLED_WR_DATA(1);
        } //更新显示
}

/**
* @function: unsigned int oled_pow(uint8_t m,uint8_t n)
* @description: m^n函数
* @param {uint8_t} m,n
* @return {unsigned int} result
*/
unsigned int oled_pow(uint8_t m,uint8_t n)
{
        unsigned int result=1;
        while(n--)result*=m;
        return result;
}
//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式        0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNum(uint8_t x,uint8_t y,unsigned int num,uint8_t len,uint8_t size2, uint8_t Color_Turn)
{
        uint8_t t,temp;
        uint8_t enshow=0;
        for(t=0;t<len;t++)
        {
                temp=(num/oled_pow(10,len-t-1))%10;
                if(enshow==0&&t<(len-1))
                {
                        if(temp==0)
                        {
                                OLED_ShowChar(x+(size2/2)*t,y,' ',size2, Color_Turn);
                                continue;
                        }
                        else
                                enshow=1;
                }
               OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2, Color_Turn);
        }
}

/**
* @function: void OLED_Showdecimal(uint8_t x,uint8_t y,float num,uint8_t z_len,uint8_t f_len,uint8_t size2, uint8_t Color_Turn)
* @description: 显示正负浮点数
* @param {uint8_t} x待显示的数字起始横坐标,x:0~126
* @param {uint8_t} y待显示的数字起始纵坐标, y:0~7,若选择字体大小为16,则两行数字之间需要间隔2,若选择字体大小为12,间隔1
* @param {float} num:输入的浮点型数据
* @param {uint8_t } z_ len:整数部分的位数
* @param {uint8_t } f_len: 小数部分的位数
* @param {uint8_t} size2:输入的数据大小,选择 16/12,16为8X16,12为6x8
* @param {uint8_t} Color_Turn是否反相显示(1反相、0不反相)
* @return {*}
*/
void OLED_ShowDecimal(uint8_t x,uint8_t y,float num,uint8_t z_len,uint8_t f_len,uint8_t size2, uint8_t Color_Turn)
{
        uint8_t t,temp,i=0;//i为负数标志位
        uint8_t enshow;
        int z_temp,f_temp;
        if(num<0)
        {
                z_len+=1;
                i=1;
                num=-num;
        }
        z_temp=(int)num;
        //整数部分
        for(t=0;t<z_len;t++)
        {
                temp=(z_temp/oled_pow(10,z_len-t-1))%10;
                if(enshow==0 && t<(z_len-1))
                {
                        if(temp==0)
                        {
                                OLED_ShowChar(x+(size2/2)*t,y,' ',size2, Color_Turn);
                                continue;
                        }
                        else
                        enshow=1;
                }
                OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2, Color_Turn);
        }
        //小数点
        OLED_ShowChar(x+(size2/2)*(z_len),y,'.',size2, Color_Turn);

        f_temp=(int)((num-z_temp)*(oled_pow(10,f_len)));
//小数部分
        for(t=0;t<f_len;t++)
        {
                temp=(f_temp/oled_pow(10,f_len-t-1))%10;
                OLED_ShowChar(x+(size2/2)*(t+z_len)+5,y,temp+'0',size2, Color_Turn);
        }
        if(i==1)//如果为负,就将最前的一位赋值‘-’
        {
                OLED_ShowChar(x,y,'-',size2, Color_Turn);
                i=0;
        }
}

/**
* @function: void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t Char_Size,uint8_t Color_Turn)
* @description: 在OLED12864特定位置开始显示一个字符
* @param {uint8_t} x字符开始显示的横坐标 0~127
* @param {uint8_t} y字符开始显示的纵坐标 0~63
* @param {uint8_t} chr待显示的字符
* @param {uint8_t} Char_Size待显示字符的字体大小,选择字体 16/12
* @param {uint8_t} Color_Turn是否反相显示(1反相、0不反相)
* @return {*}
*/
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t Char_Size, uint8_t Color_Turn)
{
        unsigned char c=0,i=0;
                c=chr-' ';//得到偏移后的值
                if(x>128-1){x=0;y=y+2;}
                if(Char_Size ==16)
                {
                        OLED_Set_Pos(x,y);
                        for(i=0;i<8;i++)
                        {
                                if(Color_Turn)
                                        OLED_WR_DATA(~F8X16);
                                else
                                        OLED_WR_DATA(F8X16);
                        }
                        //OLED_WR_DATA(F8X16);
                        OLED_Set_Pos(x,y+1);
                        for(i=0;i<8;i++)
                        {
                                if(Color_Turn)
                                        OLED_WR_DATA(~F8X16);
                                else
                                        OLED_WR_DATA(F8X16);
                        }
                        //OLED_WR_DATA(F8X16);
                }
                else
                {
                                OLED_Set_Pos(x,y);
                                for(i=0;i<6;i++)
                                {
                                        if(Color_Turn)
                                                OLED_WR_DATA(~F6x8);
                                        else
                                                OLED_WR_DATA(F6x8);
                                }
                                //OLED_WR_DATA(F6x8);

                }
}

/**
* @function: void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *chr, uint8_tChar_Size, uint8_t Color_Turn)
* @description: 在OLED12864特定位置开始显示字符串
* @param {uint8_t} x待显示字符串的开始横坐标x:0~127
* @param {uint8_t} y待显示字符串的开始纵坐标 y:0~7,若选择字体大小为16,则两行数字之间需要间隔2,若选择字体大小为12,间隔1
* @param {uint8_t} *chr待显示的字符串
* @param {uint8_t} Char_Size待显示字符串的字体大小,选择字体 16/12,16为8X16,12为6x8
* @param {uint8_t} Color_Turn是否反相显示(1反相、0不反相)
* @return {*}
*/
void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t Char_Size, uint8_t Color_Turn)
{
        uint8_t j=0;
        while (chr!='\0')
        {
                OLED_ShowChar(x,y,chr,Char_Size, Color_Turn);
                if (Char_Size ==12) //6X8的字体列加6,显示下一个字符
                        x += 6;
                else//8X16的字体列加8,显示下一个字符
                        x += 8;
                if (x > 122 && Char_Size==12) //TextSize6x8如果一行不够显示了,从下一行继续显示
                {
                        x = 0;
                        y++;
                }
                if (x > 120 && Char_Size== 16) //TextSize8x16如果一行不够显示了,从下一行继续显示
                {
                        x = 0;
                        y+=2;
                }
                j++;
        }
}

/**
* @function: void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no, uint8_t Color_Turn)
* @description: 在OLED特定位置开始显示16X16汉字
* @param {uint8_t} x待显示的汉字起始横坐标x: 0~112,两列汉字之间需要间隔16
* @param {uint8_t} y待显示的汉字起始纵坐标 y: 0~6 , 两行汉字之间需要间隔2
* @param {uint8_t} no待显示的汉字编号
* @param {uint8_t} Color_Turn是否反相显示(1反相、0不反相)
* @return {*}
*/
void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no, uint8_t Color_Turn)
{
        uint8_t t=0;
        OLED_Set_Pos(x,y);
    for(t=0;t<16;t++)
    {
            if (Color_Turn)
                    OLED_WR_DATA(~Hzk); //显示汉字的上半部分
            else
                    OLED_WR_DATA(Hzk); //显示汉字的上半部分
    }
        OLED_Set_Pos(x,y+1);
    for(t=0;t<16;t++)
    {
            if (Color_Turn)
                    OLED_WR_DATA(~Hzk); //显示汉字的上半部分
            else
                    OLED_WR_DATA(Hzk);//显示汉字的上半部分

    }
}

/**
* @function: void OLED_DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t *BMP,uint8_t Color_Turn)
* @description: 在OLED特定区域显示BMP图片
* @param {uint8_t} x0图像开始显示横坐标x0:0~127
* @param {uint8_t} y0图像开始显示纵坐标y0:0~7
* @param {uint8_t} x1图像结束显示横坐标x1:1~128
* @param {uint8_t} y1图像结束显示纵坐标y1:1~8
* @param {uint8_t} *BMP待显示的图像数据
* @param {uint8_t} Color_Turn是否反相显示(1反相、0不反相)
* @return {*}
*/
void OLED_DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t *BMP,uint8_t Color_Turn)
{
   uint32_t j = 0;
   uint8_t x = 0, y = 0;

if(y1%8==0)
                y = y1/8;
else
                y = y1/8 + 1;
        for(y=y0;y<y1;y++)
        {
                OLED_Set_Pos(x0,y);
    for(x=x0;x<x1;x++)
                {
                        if (Color_Turn)
                                OLED_WR_DATA(~BMP);//显示反相图片
                        else
                                OLED_WR_DATA(BMP);//显示图片

                }
        }
}

/*
        @brief                        显示动图
        @param                        x0:起始列地址
                                y0:起始页地址
                                x1:终止列地址
                                y1:终止页地址
                                k: 帧个数
                                m: 单帧数组大小
                                BMP[]:存放动图代码的数组
        @retval                        无
*/
void OLED_DrawGIF(uint8_t x0, uint8_ty0, uint8_tx1, uint8_t y1, uint8_tk, int m, unsigned char GIF[])
{
        unsigned int j=0; //定义变量
        unsigned char x,y,i; //定义变量

        if(y1%8==0) y=y1/8;   //判断终止页是否为8的整数倍
       else y=y1/8+1;
        for (i=0;i<k;i++) //从第一帧开始画
        {
                j = 0;
                for(y=y0;y<y1;y++) //从起始页开始,画到终止页
                {
                        OLED_Set_Pos(x0,y);//在页的起始列开始画

                        for(x=x0;x<x1;x++) //画x1 - x0 列
                          {
                                                OLED_WR_DATA(GIF);                //画图片的点
                          }
                }
        }
}



/**
* @function: void OLED_HorizontalShift(uint8_t direction)
* @description: 屏幕内容水平全屏滚动播放
* @param {uint8_t} direction                        LEFT           0x27           RIGHT0x26
* @return {*}
*/
void OLED_HorizontalShift(uint8_t direction)

{
        OLED_WR_CMD(0x2e);//停止滚动
        OLED_WR_CMD(direction);//设置滚动方向
        OLED_WR_CMD(0x00);//虚拟字节设置,默认为0x00
        OLED_WR_CMD(0x00);//设置开始页地址
        OLED_WR_CMD(0x07);//设置每个滚动步骤之间的时间间隔的帧频
    //0x00-5帧, 0x01-64帧, 0x02-128帧, 0x03-256帧, 0x04-3帧, 0x05-4帧, 0x06-25帧, 0x07-2帧,
        OLED_WR_CMD(0x07);//设置结束页地址
        OLED_WR_CMD(0x00);//虚拟字节设置,默认为0x00
        OLED_WR_CMD(0xff);//虚拟字节设置,默认为0xff
        OLED_WR_CMD(0x2f);//开启滚动-0x2f,禁用滚动-0x2e,禁用需要重写数据
}

/**
* @function: void OLED_Some_HorizontalShift(uint8_t direction,uint8_t start,uint8_t end)
* @description: 屏幕部分内容水平滚动播放
* @param {uint8_t} direction                        LEFT           0x27           RIGHT0x26
* @param {uint8_t} start 开始页地址0x00~0x07
* @param {uint8_t} end结束页地址0x01~0x07
* @return {*}
*/
void OLED_Some_HorizontalShift(uint8_t direction,uint8_t start,uint8_t end)
{
        OLED_WR_CMD(0x2e);//停止滚动
        OLED_WR_CMD(direction);//设置滚动方向
        OLED_WR_CMD(0x00);//虚拟字节设置,默认为0x00
        OLED_WR_CMD(start);//设置开始页地址
        OLED_WR_CMD(0x07);//设置每个滚动步骤之间的时间间隔的帧频,0x07即滚动速度2帧
        OLED_WR_CMD(end);//设置结束页地址
        OLED_WR_CMD(0x00);//虚拟字节设置,默认为0x00
        OLED_WR_CMD(0xff);//虚拟字节设置,默认为0xff
        OLED_WR_CMD(0x2f);//开启滚动-0x2f,禁用滚动-0x2e,禁用需要重写数据

}

/**
* @function: void OLED_VerticalAndHorizontalShift(uint8_t direction)
* @description: 屏幕内容垂直水平全屏滚动播放
* @param {uint8_t} direction                                右上滚动       0x29
*                                                            左上滚动   0x2A
* @return {*}
*/
void OLED_VerticalAndHorizontalShift(uint8_t direction)
{
        OLED_WR_CMD(0x2e);//停止滚动
        OLED_WR_CMD(direction);//设置滚动方向
        OLED_WR_CMD(0x01);//虚拟字节设置
        OLED_WR_CMD(0x00);//设置开始页地址
        OLED_WR_CMD(0x07);//设置每个滚动步骤之间的时间间隔的帧频,即滚动速度
        OLED_WR_CMD(0x07);//设置结束页地址
        OLED_WR_CMD(0x01);//垂直滚动偏移量
        OLED_WR_CMD(0x00);//虚拟字节设置,默认为0x00
        OLED_WR_CMD(0xff);//虚拟字节设置,默认为0xff
        OLED_WR_CMD(0x2f);//开启滚动-0x2f,禁用滚动-0x2e,禁用需要重写数据
}

/**
* @function: void OLED_DisplayMode(uint8_t mode)
* @description: 屏幕内容取反显示
* @param {uint8_t} direction                        ON        0xA7,
*                                                          OFF        0xA6        默认此模式,设置像素点亮
* @return {*}
*/
void OLED_DisplayMode(uint8_t mode)
{
        OLED_WR_CMD(mode);
}

/**
* @function: void OLED_IntensityControl(uint8_t intensity)
* @description: 屏幕亮度调节
* @param{uint8_t} intensity        0x00~0xFF,RESET=0x7F
* @return {*}
*/
void OLED_IntensityControl(uint8_t intensity)
{
        OLED_WR_CMD(0x81);
        OLED_WR_CMD(intensity);
}

/**
* @brief清除OLED上指定行的部分内容
* @paramline: 行号(0-7)
* @paramstart: 起始列(0-127)
* @paramend: 结束列(0-127)
* @retval None
*/
void OLED_ClearLinePart(uint8_t line, uint8_t start, uint8_t end)
{
    uint8_t i;

    // 参数检查
    if(line > 7) return;
    if(start > end) { uint8_t tmp = start; start = end; end = tmp; }
    if(start > 127) start = 127;
    if(end > 127) end = 127;

    OLED_Set_Pos(start, line);
    for(i = start; i <= end; i++) {
      OLED_WR_DATA(0x00);
    }
}
```

### main.c

```c++
#include "main.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"

/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <string.h>
#include "aht10.h"
#include "oled.h"
/* USER CODE END Includes */

void SystemClock_Config(void);

int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
MX_I2C2_Init();
MX_USART2_UART_Init();

if(AHT10_Init() != 0)
{
          HAL_UART_Transmit(&huart2, (uint8_t*)"AHT11 Init Failed!\r\n", 19, 100);
          while(1);
}

char msg;
float temp, humi;
        OLED_Init();
        OLED_Clear();
        OLED_ShowString(0,0,"Temperature:",16,1);
        OLED_ShowString(100,2,"C",16,0);
        OLED_ShowString(0,4,"Humidity:",16,1);
        OLED_ShowString(100,6,"%",16,0);

while (1)
{
      uint8_t ret = AHT10_ReadData(&temp, &humi);
      if(ret == 0)
      {
          sprintf(msg, "Temp: %.1f C, Humi: %.1f %%\r\n", temp, humi);
          OLED_ClearLinePart(2, 45, 99);
          OLED_ClearLinePart(3, 45, 99);
          OLED_ShowDecimal(45,2,temp,2,2,16,0);
          OLED_ClearLinePart(6, 45, 99);
          OLED_ClearLinePart(7, 45, 99);
          OLED_ShowDecimal(45,6,humi,2,2,16,0);
      }
      else
      {
          sprintf(msg, "Error: %d\r\n", ret);
      }
      HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), 100);
      HAL_Delay(500);
}
/* USER CODE END 3 */
}
```

编译程序,连接开发板并运行程序,可实现固件上传和程序自动执行。

## 效果演示

OLED 显示温湿度

!(data/attachment/forum/202505/20/015736iyyx22yjjer8x1u8.gif "oled_aht10_display.gif")


同时串口打印温湿度数据

!(data/attachment/forum/202505/20/015751ktzs9gkgg185a17t.gif "oled_aht10_print.gif")


## 总结

本文介绍了 Nucleo-STM32C092 开发板通过硬件 IIC 与 AHT10 和 OLED 通信,采集环境温湿度、串口打印并实时显示在 OLED 的项目设计,实现了 DIY 温湿度计。这项工作为相关产品的开发和设计提供了参考。

页: [1]
查看完整版本: 【STM32C092RC 测评】AHT10 温湿度 OLED 显示