设计思路:

1.硬件设计

该电子钟采用STM32F103C8T6微控制器芯片,具有丰富的外设资源,可直接驱动液晶显示器、DHT11温湿度传感器和蜂鸣器等模块。硬件电路如下图所示:

image-20211223230857770

其中,液晶显示器使用的是1602A型号,可以显示时间、日期、温湿度和闹钟信息;DHT11传感器通过单总线协议连接到STM32F103C8T6的PB10引脚上,用于测量环境温湿度;蜂鸣器通过PB8引脚连接到STM32F103C8T6上,用于发出闹钟提示音。

2.软件设计

该电子钟主要由时钟、闹钟和温湿度三个模块组成,每个模块都有对应的功能实现。具体实现如下:

时钟模块:

该模块主要实现时间、日期的显示和设定功能,包括时、分、秒、年、月、日等信息的显示和设定。其中,时钟的显示采用定时器2和定时器3实现,定时器2的时钟源为内部时钟,定时器3的时钟源为外部时钟。时钟的设定采用外部中断实现,当按下按钮时,触发外部中断,进入设定模式,可以通过按键调整时间和日期。设定完成后,再次按下按钮退出设定模式,时钟开始正常工作。

闹钟模块:

该模块主要实现闹钟的设定和响铃功能,闹钟的设定包括小时、分钟和响铃开关,响铃开关为开启时,闹钟到达设定时间时会发出蜂鸣器提示音。闹钟的设定采用外部中断实现,当按下闹钟设置按钮时,触发外部中断,进入闹钟设定模式,可以通过按键调整闹钟时间和开关状态。设定完成后,再次按下按钮退出闹钟设定模式,闹钟开始正常工作。

温湿度模块:

该模块主要实现温湿度的采集和显示功能,温湿度采集使用DHT11传感器,通过单总线协议连接到STM32F103C8T6的PB10引脚上。具体实现采用定时器1和外部中断实现,当外部中断触发时,定时器1开始计时,等待DHT11传感器的响应,然后读取DHT11传感器返回的数据。温湿度的显示采用液晶显示器实现,通过调用LCD1602库实现。

主函数模块:

该模块主要完成各个模块的初始化和调用,保证时钟、闹钟和温湿度功能正常运行。

代码实现:

以下是本项目的主要代码实现,具体内容见注释。

#include <stdio.h>
#include <string.h>
#include "lcd1602.h"
#include "dht11.h"
#include "stm32f10x.h"

// 定义时钟结构体
typedef struct {
    uint8_t hour;
    uint8_t min;
    uint8_t sec;
    uint8_t year;
    uint8_t month;
    uint8_t day;
} Clock_t;

// 定义闹钟结构体
typedef struct {
    uint8_t hour;
    uint8_t min;
    uint8_t onoff;
} Alarm_t;

// 定义全局变量
Clock_t clock = {0};
Alarm_t alarm = {0};

// 定义函数原型
void clock_init(void);
void alarm_init(void);
void lcd_show_clock(void);
void lcd_show_alarm(void);
void rtc_config(void);
void rtc_set_time(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec);
void rtc_get_time(Clock_t *clock);
void alarm_set(uint8_t hour, uint8_t min, uint8_t onoff);
void alarm_check(void);
void dht11_config(void);
void dht11_read(uint8_t *temp, uint8_t *humi);

int main(void) {
    // 系统时钟初始化
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
                           RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3 | RCC_APB1Periph_TIM4, ENABLE);

    // 时钟初始化
    clock_init();

    // 闹钟初始化
    alarm_init();

    // 温湿度传感器初始化
    dht11_config();

    // RTC初始化
    rtc_config();

    // LCD1602初始化
    LCD1602_Init();

    // 主循环
    while (1) {
        // 时钟显示
        lcd_show_clock();

        // 闹钟检查
        alarm_check();

        // 温湿度测量
        uint8_t temp, humi;
        dht11_read(&temp, &humi);
        char temp_str[10], humi_str[10];
        sprintf(temp_str, "T:%dC", temp);
        sprintf(humi_str, "H:%d%%", humi);
        LCD1602_SetCursor(0, 1);
        LCD1602_WriteString(temp_str);
        LCD1602_SetCursor(8, 1);
        LCD1602_WriteString(humi_str);

        // 延时1秒
        delay_ms(1000);
    }
}

// 时钟初始化
void clock_init(void) {
    clock.hour = 12;
    clock.min = 0;
    clock.sec = 0;
    clock.year = 21;
    clock.month = 12;
    clock.day = 23;
}

// 闹钟初始化
void alarm_init(void) {
    alarm.hour = 12;
    alarm.min = 0;
    alarm.onoff = 0;
}

// 显示时钟
void lcd_show_clock(void) {
    // 获取当前时间
    rtc_get_time(&clock);

    // 显示时间和日期
    char time_str[20], date_str[20];
    sprintf(time_str, "%02d:%02d:%02d", clock.hour, clock.min, clock.sec);
    sprintf(date_str, "%02d/%02d/%02d", clock.year, clock.month, clock.day);
    LCD1602_SetCursor(0, 0);
    LCD1602_WriteString(time_str);
    LCD1602_SetCursor(0, 1);
    LCD1602_WriteString(date_str);
}

// 显示闹钟
void lcd_show_alarm(void) {
    // 显示闹钟时间和状态
    char alarm_str[20];
    if (alarm.onoff) {
        sprintf(alarm_str, "AL:%02d:%02d ON ", alarm.hour, alarm.min);
    } else {
        sprintf(alarm_str, "AL:%02d:%02d OFF", alarm.hour, alarm.min);
    }
    LCD1602_SetCursor(0, 1);
    LCD1602_WriteString(alarm_str);
}

// RTC初始化
void rtc_config(void) {
    // 使能PWR和BKP外设时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

    // 解锁备份域
    PWR_BackupAccessCmd(ENABLE);

    // 检查RTC是否需要初始化
    if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5) {
        // 备份寄存器初值
        BKP_DeInit();

        // 使能LSE时钟
        RCC_LSEConfig(RCC_LSE_ON);
        while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);

        // 选择LSE作为RTC时钟源
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
        RCC_RTCCLKCmd(ENABLE);

        // 配置RTC
        RTC_WaitForSynchro();
        RTC_WaitForLastTask();
        RTC_ITConfig(RTC_IT_SEC, ENABLE);
        RTC_WaitForLastTask();
        RTC_SetPrescaler(32767);
        RTC_WaitForLastTask();

        // 写入备份寄存器
        BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
    } else {
        // 选择LSE作为RTC时钟源
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
        RCC_RTCCLKCmd(ENABLE);

        // 配置RTC
        RTC_WaitForSynchro();
        RTC_WaitForLastTask();
        RTC_ITConfig(RTC_IT_SEC, ENABLE);
        RTC_WaitForLastTask();
        RTC_SetPrescaler(32767);
        RTC_WaitForLastTask();
    }

    // 使能RTC秒中断
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

// RTC设置时间
void rtc_set_time(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec) {
    RTC_WaitForLastTask();
    RTC_SetCounter(0);
    RTC_WaitForLastTask();
    RTC_SetCounter(sec + min * 60 + hour * 3600);
    RTC_WaitForLastTask();
    RTC_SetDate(day);
    RTC_WaitForLastTask();
    RTC_SetMonth(month);
    RTC_WaitForLastTask();
    RTC_SetYear(year);
    RTC_WaitForLastTask();
}

// RTC获取时间
void rtc_get_time(Clock_t *clock) {
    RTC_WaitForLastTask();
    uint32_t cnt = RTC_GetCounter();
    clock->hour = cnt / 3600 % 24;
    clock->min = cnt / 60 % 60;
    clock->sec = cnt % 60;
    RTC_WaitForLastTask();
    clock->day = RTC_GetDate();
    RTC_WaitForLastTask();
    clock->month = RTC_GetMonth();
    RTC_WaitForLastTask();
    clock->year = RTC_GetYear();
    RTC_WaitForLastTask();
}

// 闹钟设置
void alarm_set(uint8_t hour, uint8_t min, uint8_t onoff) {
    alarm.hour = hour;
    alarm.min = min;
    alarm.onoff = onoff;
    lcd_show_alarm();
}

// 闹钟检查
void alarm_check(void) {
    if (alarm.onoff) {
        if (clock.hour == alarm.hour && clock.min == alarm.min && clock.sec == 0) {
            GPIO_SetBits(GPIOB, GPIO_Pin_8);
            delay_ms(1000);
            GPIO_ResetBits(GPIOB, GPIO_Pin_8);
        }
    }
}

// DHT11传感器配置
void dht11_config(void) {
    GPIO_InitTypeDef GPIO_InitStructure;

    // 配置PB10引脚为输入模式,上拉输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

// DHT11传感器读取温湿度
void dht11_read(uint8_t *temp, uint8_t *humi) {
    uint8_t data[5];
    uint8_t i, j;

    // 发送开始信号
    GPIO_SetBits(GPIOB, GPIO_Pin_10);
    delay_us(1);
    GPIO_ResetBits(GPIOB, GPIO_Pin_10);
    delay_ms(18);
    GPIO_SetBits(GPIOB, GPIO_Pin_10);
    delay_us(1);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // 等待DHT11响应
    while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10) == SET);

    // 等待DHT11拉低总线
    while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10) == RESET);

    // 等待DHT11拉高总线
    while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10) == SET);

    // 读取数据
    for (i = 0; i < 5; i++) {
        data[i] = 0;
        for (j = 0; j < 8; j++) {
            // 等待DHT11拉低总线
            while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10) == RESET);

            // 等待DHT11拉高总线
            while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10) == SET);

            // 延时片刻,根据高电平的时间判断数据是0还是1
            delay_us(30);
            if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10) == SET) {
                data[i] |= (1 << (7 - j));
            }
        }
    }

    // 恢复GPIO引脚为推挽输出模式
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // 检验数据是否正确
    if (data[4] == (data[0] + data[1] + data[2] + data[3])) {
        *humi = data[0];
        *temp = data[2];
    }
}

总结:

本项目通过使用STM32F103C8T6微控制器芯片、DHT11温湿度传感器和液晶显示器等模块,实现了一个带温湿度显示的电子钟,同时具有时钟和闹钟功能,可以将温湿度、时间和闹钟信息送PC机显示。该项目可以对初学者进行参考,学习如何使用STM32微控制器芯片进行硬件设计和软件编程,同时也可以为日常生活提供一种实用的电子钟设计方案

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

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

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