设计思路:

  1. 硬件部分:

(1)主控芯片:选择STM32F411微控制器芯片。

(2)温湿度传感器:选择DHT11温湿度传感器。

(3)时钟芯片:选择DS3231时钟芯片。

(4)显示模块:选择OLED显示模块。

(5)按键模块:选择4个按键模块。

  1. 软件部分:

(1)温湿度采集:通过DHT11传感器采集温湿度数据,并通过串口发送给PC机。

(2)时钟功能:使用DS3231时钟芯片实现时钟功能,包括时间显示、时间设置、闹钟功能等。

(3)显示功能:使用OLED显示模块显示温湿度、时间、闹钟等信息。

(4)按键功能:通过按键模块实现对时钟、闹钟、温湿度等功能的设置和控制。

(5)串口通信:通过串口与PC机进行通信,将温湿度数据发送给PC机。

设计步骤:

  1. 硬件连接

将DHT11传感器、DS3231时钟芯片、OLED显示模块和按键模块连接到STM32F411微控制器芯片上,具体连接方式可参考各模块的数据手册。

  1. 软件设计

(1)温湿度采集

使用STM32F411的GPIO口读取DHT11传感器的数据,计算得到温湿度值,然后使用串口将温湿度数据发送给PC机。具体代码如下:

//DHT11读取数据函数
void DHT11_ReadData(void)
{
    uint8_t i=0;
    uint8_t buf[5]={0};
    uint8_t check_sum=0;

    DHT11_Data_Out();   //数据线输出
    DHT11_Data_Low();   //数据线拉低
    delay_ms(20);       //延时20ms
    DHT11_Data_High();  //数据线拉高
    delay_us(30);       //延时30us
    DHT11_Data_In();    //数据线输入
    while(DHT11_Data_Read());//等待DHT11响应
    while(!DHT11_Data_Read());//等待DHT11响应结束
    while(DHT11_Data_Read());//等待DHT11数据传输开始

    for(i=0;i<5;i++)    //读取5个字节的数据
    {
        buf[i]=0;
        for(uint8_t j=0;j<8;j++) //读取每个字节的8位数据
        {
            while(!DHT11_Data_Read());//等待DHT11数据位变化
            delay_us(40);           //延时40us
            if(DHT11_Data_Read())   //如果数据位为1
            {
                buf[i]|=(1<<(7-j)); //将数据位写入buf数组
            }
            while(DHT11_Data_Read());//等待数据位变化
        }
    }

    check_sum=buf[0]+buf[1]+buf[2]+buf[3]; //计算校验和
    if(check_sum==buf[4])   //校验和正确
    {
        temperature=buf[2]; //温度值存储在buf[2]中
        humidity=buf[0];    //湿度值存储在buf[0]中
    }
}

//串口发送温湿度数据函数
void Send_Temp_Hum(void)
{
    uint8_t temp_buf[10]={0};
    sprintf((char *)temp_buf,"Temp:%d,Hum:%d\r\n",temperature,humidity);
    HAL_UART_Transmit(&huart1,temp_buf,strlen((char *)temp_buf),0xff);
}

(2)时钟功能

使用DS3231时钟芯片实现时钟功能,包括时间显示、时间设置、闹钟功能等。具体代码如下:

//时钟初始化函数
void RTC_Init(void)
{
    RTC_TimeTypeDef RTC_TimeStruct;
    RTC_DateTypeDef RTC_DateStruct;

    //开启PWR以及BKP备份区域
    __HAL_RCC_PWR_CLK_ENABLE();
    HAL_PWR_EnableBkUpAccess();

    //检查是否第一次上电
    if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR0)!=0x32F2)   //第一次上电
    {
        //初始化时钟时间
        RTC_TimeStruct.Hours=0x12;
        RTC_TimeStruct.Minutes=0x00;
        RTC_TimeStruct.Seconds=0x00;
        RTC_TimeStruct.TimeFormat=RTC_HOURFORMAT12_PM;
        RTC_TimeStruct.DayLightSaving=RTC_DAYLIGHTSAVING_NONE;
        RTC_TimeStruct.StoreOperation=RTC_STOREOPERATION_RESET;
        HAL_RTC_SetTime(&hrtc,&RTC_TimeStruct,RTC_FORMAT_BIN);

        //初始化时钟日期
        RTC_DateStruct.Date=0x01;
        RTC_DateStruct.Month=0x01;
        RTC_DateStruct.Year=0x00;
        RTC_DateStruct.WeekDay=RTC_WEEKDAY_MONDAY;
        HAL_RTC_SetDate(&hrtc,&RTC_DateStruct,RTC_FORMAT_BIN);

        //备份区域写入标志
        HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0,0x32F2);
    }
}

//时钟显示函数
void RTC_ShowTime(void)
{
    RTC_TimeTypeDef RTC_TimeStruct;
    RTC_DateTypeDef RTC_DateStruct;
    char time_buf[20]={0};

    HAL_RTC_GetTime(&hrtc,&RTC_TimeStruct,RTC_FORMAT_BIN);
    HAL_RTC_GetDate(&hrtc,&RTC_DateStruct,RTC_FORMAT_BIN);

    sprintf(time_buf,"%02d:%02d:%02d %s",RTC_TimeStruct.Hours,RTC_TimeStruct.Minutes,RTC_TimeStruct.Seconds,RTC_TimeStruct.TimeFormat?"PM":"AM");
    OLED_ShowString(0,0,(uint8_t *)time_buf);
    sprintf(time_buf,"20%02d-%02d-%02d %s",RTC_DateStruct.Year,RTC_DateStruct.Month,RTC_DateStruct.Date,Week[RTC_DateStruct.WeekDay]);
    OLED_ShowString(0,16,(uint8_t *)time_buf);
}

//时钟设置函数
void RTC_SetTime(uint8_t hour,uint8_t min,uint8_t sec,uint8_t am_pm)
{
    RTC_TimeTypeDef RTC_TimeStruct;

    RTC_TimeStruct.Hours=hour;
    RTC_TimeStruct.Minutes=min;
    RTC_TimeStruct.Seconds=sec;
    RTC_TimeStruct.TimeFormat=am_pm;
    RTC_TimeStruct.DayLightSaving=RTC_DAYLIGHTSAVING_NONE;
    RTC_TimeStruct.StoreOperation=RTC_STOREOPERATION_RESET;
    HAL_RTC_SetTime(&hrtc,&RTC_TimeStruct,RTC_FORMAT_BIN);
}

//闹钟设置函数
void RTC_SetAlarm(uint8_t hour,uint8_t min,uint8_t sec,uint8_t am_pm)
{
    RTC_AlarmTypeDef RTC_AlarmStruct;

    RTC_AlarmStruct.AlarmTime.Hours=hour;
    RTC_AlarmStruct.AlarmTime.Minutes=min;
    RTC_AlarmStruct.AlarmTime.Seconds=sec;
    RTC_AlarmStruct.AlarmTime.TimeFormat=am_pm;
    RTC_AlarmStruct.AlarmDateWeekDay=RTC_WEEKDAY_MONDAY;
    RTC_AlarmStruct.AlarmMask=RTC_ALARMMASK_DATEWEEKDAY;
    RTC_AlarmStruct.AlarmSubSecondMask=RTC_ALARMSUBSECONDMASK_ALL;
    RTC_AlarmStruct.Alarm=RTC_ALARM_A;
    HAL_RTC_SetAlarm_IT(&hrtc,&RTC_AlarmStruct,RTC_FORMAT_BIN);
}

(3)显示功能

使用OLED显示模块显示温湿度、时间、闹钟等信息。具体代码如下:

//OLED初始化函数
void OLED_Init(void)
{
    OLED_WR_Byte(0xAE,OLED_CMD);    //关闭显示
    OLED_WR_Byte(0xD5,OLED_CMD);    //设置时钟分频因子,震荡频率
    OLED_WR_Byte(80,OLED_CMD);      //设置分频因子
    OLED_WR_Byte(0xA8,OLED_CMD);    //设置驱动路数
    OLED_WR_Byte(0X3F,OLED_CMD);    //默认0X3F(1/64)
    OLED_WR_Byte(0xD3,OLED_CMD);    //设置显示偏移
    OLED_WR_Byte(0X00,OLED_CMD);    //默认为0

    OLED_WR_Byte(0x40,OLED_CMD);    //设置显示开始行 [5:0]
    OLED_WR_Byte(0xA1,OLED_CMD);    //设置列地址映射
    OLED_WR_Byte(0xC8,OLED_CMD);    //设置COM扫描方式
    OLED_WR_Byte(0xDA,OLED_CMD);    //设置COM硬件引脚配置
    OLED_WR_Byte(0x12,OLED_CMD);    //默认0X12

    OLED_WR_Byte(0x81,OLED_CMD);    //对比度设置
    OLED_WR_Byte(0xFF,OLED_CMD);    //1~255 (对比度值,越大越亮)

    OLED_WR_Byte(0xD9,OLED_CMD);    //设置预充电周期
    OLED_WR_Byte(0xF1,OLED_CMD);    //默认0x22(1个时钟周期,0x22=34时钟周期)

    OLED_WR_Byte(0xDB,OLED_CMD);    //设置VCOMH 电压倍率
    OLED_WR_Byte(0x40,OLED_CMD);    //默认0X20,0.77xVcc

    OLED_WR_Byte(0xA4,OLED_CMD);    //设置全局显示开启[0x00关,0x01开]
    OLED_WR_Byte(0xA6,OLED_CMD);    //设置显示方式[0xa6白底黑字,0xa7黑底白字]
    OLED_WR_Byte(0xAF,OLED_CMD);    //开启显示
    OLED_Clear();
}

//OLED清屏函数
void OLED_Clear(void)
{
    uint8_t i,j;
    for(i=0;i<8;i++)
    {
        OLED_WR_Byte(0xb0+i,OLED_CMD);
        OLED_WR_Byte(0x00,OLED_CMD);
        OLED_WR_Byte(0x10,OLED_CMD);
        for(j=0;j<128;j++)
        {
            OLED_WR_Byte(0,OLED_DATA);
        }
    }
}

//OLED显示字符串函数
void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *str)
{
    uint8_t c=0,i=0,j=0;
    while (str[j]!='\0')
    {
        c=str[j]-32;
        if(x>128-1)
        {
            x=0;
            y++;
        }
        if(y>8-1)
        {
            y=x=0;
            OLED_Clear();
        }
        OLED_Set_Pos(x,y);
        for(i=0;i<6;i++)
        {
            OLED_WR_Byte(F6x8[c][i],OLED_DATA);
        }
        x+=6;
        j++;
    }
}

//OLED设置坐标函数
void OLED_Set_Pos(uint8_t x,uint8_t y)
{
    OLED_WR_Byte(0xb0+y,OLED_CMD);
    OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
    OLED_WR_Byte((x&0x0f)|0x01,OLED_CMD);
}

(4)按键功能

使用4个按键模块实现对时钟、闹钟、温湿度等功能的设置和控制。具体代码如下:

//按键扫描函数
void Key_Scan(void)
{
    static uint8_t key_up=1;
    if(key_up&&(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==0))
    {
        key_up=0;
        Key1_Press();
    }
    else if(key_up&&(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==0))
    {
        key_up=0;
        Key2_Press();
    }
    else if(key_up&&(HAL_GPIO_ReadPin(KEY3_GPIO_Port,KEY3_Pin)==0))
    {
        key_up=0;
        Key3_Press();
    }
    else if(key_up&&(HAL_GPIO_ReadPin(KEY4_GPIO_Port,KEY4_Pin)==0))
    {
        key_up=0;
        Key4_Press();
    }
    else if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)&&HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)&&HAL_GPIO_ReadPin(KEY3_GPIO_Port,KEY3_Pin)&&HAL_GPIO_ReadPin(KEY4_GPIO_Port,KEY4_Pin))
    {
        key_up=1;
    }
}

//按键1功能函数
void Key1_Press(void)
{
    if(!menu_flag)
    {
        RTC_ShowTime();
        menu_flag=1;
    }
    else
    {
        menu_flag=0;
    }
}

//按键2功能函数
void Key2_Press(void)
{
    if(menu_flag)
    {
        if(menu_index==0)
        {
            menu_index=3;
        }
        else
        {
            menu_index--;
        }
    }
}

//按键3功能函数
void Key3_Press(void)
{
    if(menu_flag)
    {
        if(menu_index==3)
        {
            menu_index=0;
        }
        else
        {
            menu_index++;
        }
    }
}

//按键4功能函数
void Key4_Press(void)
{
    if(menu_flag)
    {
        switch(menu_index)
        {
            case 0:     //时间设置
                menu_time_flag=1;
                break;
            case 1:     //闹钟设置
                menu_alarm_flag=1;
                break;
            case 2:     //温湿度设置
                break;
            case 3:     //退出菜单
                menu_flag=0;
                break;
            default:
                break;
        }
    }
}

(5)串口通信

使用串口与PC机进行通信,将温湿度数据发送给PC机。具体代码如下:

//串口发送温湿度数据函数
void Send_Temp_Hum(void)
{
    uint8_t temp_buf[10]={0};
    sprintf((char *)temp_buf,"Temp:%d,Hum:%d\r\n",temperature,humidity);
    HAL_UART_Transmit(&huart1,temp_buf,strlen((char *)temp_buf),0xff);
}
  1. 整体流程

(1)初始化各模块,包括DHT11传感器、DS3231时钟芯片、OLED显示模块和按键模块。

(2)循环读取DHT11传感器的温湿度数据,并通过串口发送给PC机。

(3)循环显示时钟时间和日期。

(4)按键扫描,根据按键功能设置时钟、闹钟、温湿度等信息。

(5)定时器中断处理闹钟功能。

  1. 结束语

通过STM32F411微控制器芯片设计一个带温湿度显示的电子钟。该电子钟可以通过DHT11温湿度传感器采集并显示测量到的温湿度。同时该电子钟具有时钟和闹钟功能,可以将温湿度、时间和闹钟信息送PC机显示。该电子钟可以应用于家庭或办公室等场合,为人们提供准确的时间和温湿度信息

通过STM32F411微控制器芯片设计一个带温湿度显示的电子钟。该电子钟可以通过DHT11温湿度传感器采集并显示测量到的温湿度。同时该电子钟具有时钟和闹钟功能可以将温湿度、时间和闹钟信息送PC机显示

原文地址: https://www.cveoy.top/t/topic/hq15 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录