采用学过的STM32微控制器芯片设计一个带温湿度显示的电子钟。该电子钟可以通过DHT11温湿度传感器采集并显示测量到的温湿度。同时该电子钟具有时钟和闹钟功能可以将温湿度、时间和闹钟信息送PC机显示
。
设计思路:
1.硬件设计
该电子钟采用STM32F103C8T6微控制器芯片,具有丰富的外设资源,可直接驱动液晶显示器、DHT11温湿度传感器和蜂鸣器等模块。硬件电路如下图所示:

其中,液晶显示器使用的是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微控制器芯片进行硬件设计和软件编程,同时也可以为日常生活提供一种实用的电子钟设计方案
原文地址: https://www.cveoy.top/t/topic/hqZC 著作权归作者所有。请勿转载和采集!