STM32驱动dht11检测温湿度由OLED12864显示

硬件环境

本次实验所使用的硬件环境如下:

  • STM32F103C8T6开发板

  • DHT11温湿度传感器

  • OLED12864显示屏

  • 杜邦线若干

  • 软件环境
    本次实验所使用的软件环境如下:

  • Keil C51编译器

  • ST-LINK V2下载器

  • ST-LINK Utility软件

实验流程

硬件连接

首先,将STM32F103C8T6开发板、DHT11温湿度传感器和OLED12864显示屏分别连接在一起。

将DHT11温湿度传感器的VCC引脚连接到STM32F103C8T6开发板的5V引脚上。
将DHT11温湿度传感器的GND引脚连接到STM32F103C8T6开发板的GND引脚上。
将DHT11温湿度传感器的DATA引脚连接到STM32F103C8T6开发板的PB0引脚上。
将OLED12864显示屏的SDA引脚连接到STM32F103C8T6开发板的PA6引脚上。
将OLED12864显示屏的SCL引脚连接到STM32F103C8T6开发板的PA7引脚上。
将OLED12864显示屏的VCC引脚连接到STM32F103C8T6开发板的5V引脚上。
将OLED12864显示屏的GND引脚连接到STM32F103C8T6开发板的GND引脚上。

软件编写

DHT11温湿度传感器的驱动
本次实验所使用的DHT11温湿度传感器的驱动程序如下:

#include "dht11.h"

/* 定义DHT11相关的宏 */
#define DHT11_PORT GPIOB
#define DHT11_PIN GPIO_Pin_0

/* 定义DHT11初始化函数 */
void DHT11_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    GPIO_InitStruct.GPIO_Pin = DHT11_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DHT11_PORT, &GPIO_InitStruct);

    GPIO_SetBits(DHT11_PORT, DHT11_PIN);
}

/* 定义延时函数 */
void delay_us(uint32_t us)
{
    uint32_t i;

    while(us--)
    {
        i = 10;
        while(i--);
    }
}

/* 定义读取数据函数 */
uint8_t DHT11_Read_Byte(void)
{
    uint8_t i, byte = 0;

    for(i = 0; i < 8; i++)
    {
        /* 等待50us */
        delay_us(50);

        /* 将DHT11_PIN置为高电平,等待DHT11的响应 */
        GPIO_SetBits(DHT11_PORT, DHT11_PIN);
        delay_us(30);

        /* 判断DHT11的响应是否正确 */
        if(GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN) == RESET)
        {
            /* 等待DHT11拉低总线 */
            delay_us(80);

            /* 判断DHT11拉低总线的时间长短 */
            if(GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN) == SET)
            {
                byte |= (1 << (7 - i));
            }
        }
    }

    return byte;
}

/* 定义读取数据函数 */
uint8_t DHT11_Read_Data(uint8_t *temp, uint8_t *humi)
{
    uint8_t buf[5], i;

    /* 发送起始信号 */
    GPIO_ResetBits(DHT11_PORT, DHT11_PIN);
    delay_ms(18);
    GPIO_SetBits(DHT11_PORT, DHT11_PIN);

    /* 等待DHT11的响应 */
    delay_us(40);

    /* 判断DHT11的响应是否正确 */
    if(GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN) == RESET)
    {
        /* 等待DHT11拉低总线 */
        delay_us(80);

        /* 判断DHT11拉低总线的时间长短 */
        if(GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN) == SET)
        {
            /* 等待DHT11将总线拉高 */
            delay_us(80);

            /* 读取40位数据 */
            for(i = 0; i < 5; i++)
            {
                buf[i] = DHT11_Read_Byte();
            }

            /* 判断校验和是否正确 */
            if
	        ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
	        {
	            *humi = buf[0];
	            *temp = buf[2];
	
	            return 0;
	        }
	    }
	}

return 1;
}

以上是DHT11的驱动程序,通过以上的程序,我们可以将DHT11温湿度传感器的数据读取出来并进行校验,确保数据的正确性。下面是OLED 128x64的驱动程序:

#include "oled.h"
#include "i2c.h"

/* 定义OLED相关的宏 */
#define OLED_I2C_ADDRESS 0x78
#define OLED_CMD_MODE 0x00
#define OLED_DATA_MODE 0x40

/* 定义OLED写入函数 */
void OLED_Write(uint8_t reg, uint8_t data)
{
    uint8_t buf[2];
    buf[0] = reg;
    buf[1] = data;

    HAL_I2C_Master_Transmit(&hi2c1, OLED_I2C_ADDRESS, buf, 2, 1000);
}

/* 定义OLED初始化函数 */
void OLED_Init(void)
{
    /* 复位OLED */
    HAL_GPIO_WritePin(OLED_RST_GPIO_Port, OLED_RST_Pin, GPIO_PIN_SET);
    HAL_Delay(100);
    HAL_GPIO_WritePin(OLED_RST_GPIO_Port, OLED_RST_Pin, GPIO_PIN_RESET);
    HAL_Delay(100);
    HAL_GPIO_WritePin(OLED_RST_GPIO_Port, OLED_RST_Pin, GPIO_PIN_SET);

    /* 设置OLED显示参数 */
    OLED_Write(OLED_CMD_MODE, 0xAE); // 关闭OLED显示
    OLED_Write(OLED_CMD_MODE, 0xD5); // 设置时钟分频因子,震荡频率
    OLED_Write(OLED_CMD_MODE, 0x80); // 分频因子=1,震荡频率=1000Hz
    OLED_Write(OLED_CMD_MODE, 0xA8); // 设置驱动路数
    OLED_Write(OLED_CMD_MODE, 0x3F); // 默认值0x3F(1/64)
    OLED_Write(OLED_CMD_MODE, 0xD3); // 设置显示偏移
    OLED_Write(OLED_CMD_MODE, 0x00); // 默认值0x00
    OLED_Write(OLED_CMD_MODE, 0x40); // 设置显示开始行 [5:0],默认值0
    OLED_Write(OLED_CMD_MODE, 0x8D); // 电荷泵设置
    OLED_Write(OLED_CMD_MODE, 0x14); // bit2,开启/关闭
    OLED_Write(OLED_CMD_MODE, 0x20); // 设置内存地址模式
    OLED_Write(OLED_CMD_MODE, 0x02); // 默认值0x02,水平地址模式
    OLED_Write(OLED_CMD_MODE, 0xA1); // 设置段重映射,bit0=0,左右反转
    OLED_Write(OLED_CMD_MODE, 0xC8); // 设置行重映射,bit3=0,上下反转
    OLED_Write(OLED_CMD_MODE, 0xDA); // 设置COM硬件引脚配置
    OLED_Write(OLED_CMD_MODE, 0x12); // bit5=1,使能COM左右反转

    /* 清空OLED显示 */
    OLED_Clear();
}

/* 定义OLED清屏函数 */
void OLED_Clear(void)
{
    uint8_t i, j;

    for (i = 0; i < 8; i++)
    {
        OLED_Write(OLED_CMD_MODE, 0xB0 + i); // 设置页地址
        OLED_Write(OLED_CMD_MODE, 0x00); // 设置列地址的高位
	    OLED_Write(OLED_CMD_MODE, 0x10); // 设置列地址的低位
	    for (j = 0; j < 128; j++)
	    {
	        OLED_Write(OLED_DATA_MODE, 0x00); // 清空列数据
	    }
	}       
}

/* 定义OLED显示字符函数 */
void OLED_ShowChar(uint8_t x, uint8_t y, char ch)
{
uint8_t i, j;
ch = ch - ' '; // 获取字模偏移量
if (x > 120 || y > 56) // 判断是否越界
    return;

for (i = 0; i < 6; i++)
{
    uint8_t byte = Font6x8[ch][i];
    for (j = 0; j < 8; j++)
    {
        if ((byte >> j) & 0x01) // 判断是否需要点亮
        {
            OLED_DrawPixel(x + i, y + j, OLED_PIXEL_ON);
        }
        else
        {
            OLED_DrawPixel(x + i, y + j, OLED_PIXEL_OFF);
        }
    }
}
}

/* 定义OLED画点函数 */
void OLED_DrawPixel(uint8_t x, uint8_t y, uint8_t pixel)
{
uint8_t page = y / 8; // 获取所在页地址
uint8_t column = x; // 获取所在列地址
uint8_t data;
OLED_Write(OLED_CMD_MODE, 0xB0 + page); // 设置页地址
OLED_Write(OLED_CMD_MODE, (column >> 4) | 0x10); // 设置列地址的高位
OLED_Write(OLED_CMD_MODE, column & 0x0F); // 设置列地址的低位

data = OLED_ReadByte(); // 读取原来的数据
if (pixel == OLED_PIXEL_ON)
{
    data |= 1 << (y % 8); // 点亮像素
}
else
{
    data &= ~(1 << (y % 8)); // 关闭像素
}
OLED_Write(OLED_DATA_MODE, data); // 写入新数据
}

/* 定义OLED读取一个字节的函数 */
uint8_t OLED_ReadByte(void)
{
uint8_t data;
HAL_I2C_Master_Receive(&hi2c1, OLED_I2C_ADDRESS, &data, 1, 1000);

return data;
}



完整代码实现

上述代码只是OLED12864显示屏的部分驱动程序,完整代码如下:

#include "dht11.h"
#include "oled12864.h"

int main(void)
{
    uint8_t temp, humi;
    char str_temp[10], str_humi[10];

    DHT11_Init();
    OLED_Init();
    OLED_Clear();
    OLED_ShowString(0, 0, "DHT11 Test:");
    OLED_ShowString(0, 2, "Temp:");
    OLED_ShowString(0, 4, "Humi:");

    while(1)
    {
        if(DHT11_Read_Data(&temp, &humi) == SUCCESS)
        {
            OLED_ShowString(48, 2, str_temp);
            OLED_ShowString(48, 4, str_humi);
            delay_ms(1000);
        }
    }
    return 0;
}

在主函数中,我们先调用DHT11_Init()和OLED_Init()函数来初始化DHT11温湿度传感器和OLED12864显示屏。然后调用OLED_Clear()函数来清屏,并使用OLED_ShowString()函数在OLED屏幕上显示“DHT11 Test:”、“Temp:”和“Humi:”这几个字符串。

之后进入while循环,在循环中调用DHT11_Read_Data()函数来读取温湿度数据,如果读取成功,则将温度和湿度数据转换成字符串格式,并通过OLED_ShowString()函数显示在屏幕上。

在这个示例代码中,我们仅仅显示了温度和湿度数据,并没有将其存储到外部存储器中。如果需要将数据存储到外部存储器中,可以使用SPI、I2C等接口来控制外部存储器,将数据写入其中。

总结

本文介绍了如何使用STM32驱动DHT11温湿度传感器,并通过OLED12864显示屏将读取到的温湿度数据实时显示在屏幕上。在实现过程中,我们需要理解DHT11传感器的工作原理和通信协议,掌握STM32的GPIO控制和定时器中断等技术,并能够使用OLED12864显示屏的驱动程序来控制显示屏。通过本文的学习,我们可以深入理解嵌入式系统中传感器的应用,为以后的项目开发奠定坚实的基础。

你可能感兴趣的:(stm32,单片机,嵌入式硬件)