制作一个万年历,具有显示时间、日期、温度、湿度、闹钟功能。 1、OLED显示屏上显示日期和时钟(显示到秒,时间可走动);(20分) 2、通过开发板上的温度传感器采集当前环境温度并显示在显示屏上;(20分) 3、通过湿度传感器采集当前环境湿度并显示在显示屏上;(20分) 4、通过独立按键设置闹钟,并在OLED上显示设置的闹钟时间,到达闹钟时间时蜂鸣器发出声响并持续一段时间,同时D1~D8以流水灯形式亮起;(20分) 5、日期为滚动特效;(20分)
时间: 2025-07-20 12:15:57 浏览: 4
<think>我们正在设计一个基于开发板的多功能万年历系统,需要实现以下功能:
1. 使用OLED显示屏显示日期和时间(精确到秒)
2. 通过温度传感器和湿度传感器采集环境数据并显示
3. 使用独立按键设置闹钟
4. 闹钟触发时蜂鸣器响,同时D1-D8流水灯效果
5. 日期显示加入滚动特效
参考引用中提到了几个类似项目,我们可以借鉴其硬件连接和部分代码。
硬件选择:
- 主控:STM32开发板(如STM32F103系列,常见且资源丰富)
- 显示屏:OLED(I2C接口或SPI接口,这里假设使用I2C接口的0.96寸OLED)
- 温度传感器:DS18B20(引用[1]中使用了,但我们需要温湿度,所以可以选择DHT11或DHT22,它们可以同时测量温度和湿度)
- 按键:独立按键(用于设置时间、闹钟等)
- 蜂鸣器:有源蜂鸣器(低电平触发)
- 流水灯:8个LED(D1-D8,使用GPIO控制)
另外,为了显示农历和古诗(引用[3]),我们可能需要网络模块(如ESP8266)来获取天气和古诗,但用户需求中没有明确要求天气和古诗,所以先专注于基本功能。用户要求了日期显示滚动特效,我们可以通过OLED显示动画实现。
步骤:
1. 硬件连接
2. 软件设计(包括各个模块的驱动和主程序逻辑)
硬件连接(以STM32F103C8T6为例):
- OLED: I2C接口
- SCL -> PB6
- SDA -> PB7
- DHT11(温湿度传感器):
- 数据线 -> PA0(需要上拉电阻,通常模块自带)
- 按键:
- 设置键(SET)-> PA1
- 增加键(INC)-> PA2
- 减少键(DEC)-> PA3
- 确认键(OK)-> PA4
- 闹钟设置键(ALARM)-> PA5(可以根据需要调整按键数量,这里用5个按键)
- 蜂鸣器 -> PB0(低电平触发)
- LED流水灯(8个)-> 使用PC0~PC7(共8个引脚)
软件设计:
我们需要以下驱动程序:
1. OLED显示驱动(支持显示字符、数字、滚动特效等)
2. DHT11温湿度传感器驱动
3. 按键扫描驱动
4. RTC实时时钟(使用STM32内部的RTC,需要配置后备电池)
5. 蜂鸣器和LED控制
主程序流程:
1. 初始化系统时钟、RTC、I2C、GPIO等
2. 初始化OLED、DHT11、按键、蜂鸣器、LED
3. 检查RTC是否已经配置,如果没有则设置默认时间(或通过按键设置初始时间)
4. 主循环:
a. 读取当前时间(从RTC获取)
b. 读取温湿度(可以每5秒读取一次,避免频繁读取)
c. 扫描按键,根据按键状态进入设置模式(设置时间或闹钟)
d. 显示时间、日期、温湿度(日期显示加入滚动特效,可以通过每隔一段时间移动显示位置来实现)
e. 检查闹钟触发(比较当前时间和设置的闹钟时间,如果相等则触发闹钟:蜂鸣器响,流水灯效果,直到按下停止键)
滚动特效实现:
我们可以将日期字符串(例如:2024-06-28 星期五)在OLED上水平滚动显示。可以通过改变显示起始位置实现。
闹钟设置:
可以设置多个闹钟,但这里为了简化,先实现一个闹钟。使用按键设置闹钟的小时、分钟。
代码结构(伪代码):
主循环:
while(1) {
// 读取时间
current_time = RTC_GetTime();
// 每5秒读取一次温湿度
if (timer_count % 5 == 0) {
DHT11_Read(&temp, &humi);
}
// 扫描按键
key = KEY_Scan();
if (key == SET_KEY) {
// 进入时间设置模式
Time_Set_Mode();
} else if (key == ALARM_KEY) {
// 进入闹钟设置模式
Alarm_Set_Mode();
}
// 显示处理
Display_Time_Date(current_time); // 显示时间和日期(固定位置)
Display_Temp_Humi(temp, humi); // 显示温湿度(固定位置)
Display_Date_Scroll(); // 滚动显示日期(或者将日期用滚动方式显示)
// 检查闹钟
if (alarm_enabled && current_time.hour == alarm_hour && current_time.min == alarm_min && current_time.sec == 0) {
Alarm_Trigger(); // 触发闹钟
}
// 延时1秒
HAL_Delay(1000);
timer_count++;
}
滚动显示日期的一种方法:
定义一个字符串数组存储日期字符串(包括星期),然后每次显示时改变起始显示位置(x坐标从0逐渐减小,当字符串完全移出屏幕后,重置位置)。
例如:
static int scroll_pos = 0; // 起始显示位置
char date_str[] = "2024-06-28 星期五";
OLED_ShowString(scroll_pos, 3, date_str); // 在第3行显示
scroll_pos--;
if (scroll_pos < - (strlen(date_str)*8)) { // 8为字符宽度,假设每个字符8像素宽
scroll_pos = OLED_WIDTH; // 屏幕宽度
}
闹钟触发函数Alarm_Trigger():
开启蜂鸣器,并运行流水灯效果,直到用户按下任意键停止。
流水灯效果:8个LED依次点亮,形成流水效果。
由于代码量较大,这里给出关键部分的代码示例(基于HAL库):
1. RTC配置:使用内部LSI或外部LSE(建议使用LSE,精度高)
2. OLED驱动:使用已有的SSD1306驱动
3. DHT11驱动:使用单总线协议
注意:DHT11读取数据需要严格的时序,最好在关闭中断的情况下读取。
由于篇幅,这里只给出部分关键代码,完整代码需要结合实际情况。
主函数框架:
```c
#include "main.h"
#include "ssd1306.h"
#include "dht11.h"
#include <stdio.h>
#include <string.h>
// 定义按键
#define SET_PIN GPIO_PIN_1
#define SET_PORT GPIOA
// ... 其他按键定义
// 全局变量
RTC_TimeTypeDef current_time;
RTC_DateTypeDef current_date;
uint8_t temp, humi;
uint8_t alarm_hour=0, alarm_min=0;
uint8_t alarm_enabled = 0;
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
MX_RTC_Init(); // 初始化RTC
// 初始化OLED
SSD1306_Init();
// 初始化DHT11
DHT11_Init();
// 初始化按键、蜂鸣器、LED引脚
while (1) {
// 获取时间
HAL_RTC_GetTime(&hrtc, ¤t_time, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, ¤t_date, RTC_FORMAT_BIN);
// 每5秒读取一次温湿度
static uint32_t last_read = 0;
if (HAL_GetTick() - last_read >= 5000) {
if (DHT11_Read(&humi, &temp) == DHT11_OK) {
// 读取成功
}
last_read = HAL_GetTick();
}
// 按键扫描
uint8_t key = KEY_Scan();
switch (key) {
case SET_KEY: Time_Set(); break;
case ALARM_KEY: Alarm_Set(); break;
// ... 其他按键
}
// 显示
Display_All();
// 检查闹钟
if (alarm_enabled && current_time.Hours == alarm_hour && current_time.Minutes == alarm_min && current_time.Seconds == 0) {
Alarm_Trigger();
}
HAL_Delay(200); // 适当延时,避免刷新过快
}
}
```
时间设置函数:
通过按键调整小时、分钟、年、月、日等。
闹钟设置函数:
设置闹钟的小时和分钟。
显示函数Display_All():
显示时间(固定位置,每秒刷新):
char time_str[9];
sprintf(time_str, "%02d:%02d:%02d", current_time.Hours, current_time.Minutes, current_time.Seconds);
SSD1306_GotoXY(0,0);
SSD1306_Puts(time_str, &Font_11x18, 1);
显示日期(滚动):
static int scroll_pos = 0;
char date_str[30];
sprintf(date_str, "%04d-%02d-%02d %s", current_date.Year+2000, current_date.Month, current_date.Date, get_weekday(current_date.WeekDay));
SSD1306_GotoXY(scroll_pos, 2);
SSD1306_Puts(date_str, &Font_6x8, 1);
scroll_pos--;
if (scroll_pos < - (strlen(date_str)*6)) {
scroll_pos = 128; // 屏幕宽度
}
显示温湿度:
char temp_str[20];
sprintf(temp_str, "Temp: %d C", temp);
SSD1306_GotoXY(0,4);
SSD1306_Puts(temp_str, &Font_6x8, 1);
// 同理湿度
闹钟触发函数:
void Alarm_Trigger() {
// 开启蜂鸣器
HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_RESET); // 低电平触发
// 流水灯效果
uint8_t led_pattern = 0x01; // 初始模式
while (1) {
for (int i=0; i<8; i++) {
// 将led_pattern输出到PC0~PC7
GPIO_Write(GPIOC, (led_pattern << i) | (led_pattern >> (8-i))); // 循环左移
HAL_Delay(100); // 流水速度
// 检查是否有按键按下停止闹钟
if (KEY_Scan() != NO_KEY) {
// 关闭蜂鸣器
HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET);
return;
}
}
}
}
注意:以上代码是示例,实际开发中需要根据具体硬件和库进行调整。
由于农历和星期的计算比较复杂,这里省略。用户要求显示日期(包括星期),我们可以通过RTC获取星期(RTC_DateTypeDef中的WeekDay成员,范围1~7,对应周一至周日),然后转换成字符串。
以上是一个基本框架,具体实现时需要编写各个模块的驱动和功能函数。
相关问题:
1. 如何为STM32的RTC配置后备电池?
2. DHT11读取数据失败的可能原因及解决方法?
3. 如何优化OLED显示以降低闪烁?
4. 如何实现多个闹钟?</think>基于您的需求,我将为您设计一个基于开发板的多功能万年历系统方案。以下是完整的实现方案:
### 系统设计方案
本系统以STM32开发板为核心,结合OLED显示屏、温湿度传感器、独立按键、蜂鸣器和LED流水灯模块,实现时间/日期显示、温湿度监测、闹钟设置及触发特效功能。系统框图如下:
$$ \text{STM32开发板} \leftrightarrow \begin{cases} \text{OLED显示屏} \\ \text{DHT11温湿度传感器} \\ \text{独立按键×4} \\ \text{蜂鸣器} \\ \text{LED流水灯(D1-D8)} \end{cases} $$
#### 硬件连接方案
| 模块 | 引脚连接 | 功能 |
|------|----------|------|
| OLED(I2C) | SCL→PB6, SDA→PB7 | 显示时间/日期/温湿度 |
| DHT11 | DATA→PA0 | 采集温湿度数据 |
| 按键1 | PA1 | 模式切换(时间/闹钟设置) |
| 按键2 | PA2 | 数值增加 |
| 按键3 | PA3 | 数值减少 |
| 按键4 | PA4 | 确认设置 |
| 蜂鸣器 | PB0 | 闹钟提示音 |
| LED流水灯 | PC0-PC7 | 闹钟视觉特效 |
#### 核心功能实现
1. **时间日期显示**
- 使用STM32内部RTC,后备电池供电
- 显示格式:`2024-06-28 周五 14:30:45`
- 滚动特效:日期文字每5秒水平滚动一次
2. **温湿度采集**
```c
// DHT11读取示例
void DHT11_Read(uint8_t *temp, uint8_t *humi) {
// 启动信号→等待响应→读取40位数据
// 校验数据后返回温湿度值
}
```
3. **闹钟设置**
```c
// 按键设置流程
if(KEY_MODE_PRESSED) {
current_state = (current_state + 1) % 3; // 0:正常 1:设小时 2:设分钟
}
if(KEY_UP_PRESSED) alarm_time[current_state]++;
if(KEY_DOWN_PRESSED) alarm_time[current_state]--;
```
4. **闹钟触发特效**
```c
void alarm_effect() {
HAL_GPIO_WritePin(BUZZER_GPIO, BUZZER_PIN, GPIO_PIN_SET); // 蜂鸣器响
// LED流水灯效果
for(int i=0; i<8; i++) {
HAL_GPIO_WritePin(GPIOC, 1<<i, GPIO_PIN_SET); // 点亮当前LED
HAL_Delay(100);
HAL_GPIO_WritePin(GPIOC, 1<<i, GPIO_PIN_RESET); // 熄灭
}
}
```
### 软件实现关键代码
#### 主程序框架
```c
int main(void) {
// 初始化外设
HAL_Init();
SystemClock_Config();
OLED_Init();
DHT11_Init();
KEY_Init();
BUZZER_Init();
LED_Init();
RTC_Init();
while(1) {
// 读取RTC时间
RTC_GetTime(&hours, &minutes, &seconds);
// 每30秒读取温湿度
if(seconds % 30 == 0) {
DHT11_Read(&temperature, &humidity);
}
// OLED显示更新
display_update();
// 检查闹钟触发
if(alarm_enabled && hours==alarm_hour && minutes==alarm_min) {
alarm_effect();
}
HAL_Delay(200);
}
}
```
#### 日期滚动特效实现
```c
void display_date_scroll() {
static uint8_t scroll_pos = 0;
char date_str[20];
sprintf(date_str, "%04d-%02d-%02d %s", year, month, day, weekday);
// 在OLED指定位置显示滚动文本
OLED_ShowString(scroll_pos, 2, date_str);
// 更新滚动位置(每5秒移动1像素)
if(seconds % 5 == 0) {
scroll_pos = (scroll_pos + 1) % (strlen(date_str)*8 + 128);
}
}
```
### 元件选型建议
1. **主控开发板**:STM32F103C8T6最小系统板(成本低,资源丰富)
2. **显示屏**:0.96寸OLED I2C接口(SSD1306驱动)
3. **温湿度传感器**:DHT11(单总线通信,精度±1℃)
4. **蜂鸣器**:5V有源蜂鸣器(驱动简单)
5. **LED模块**:8位直插LED或WS2812 RGB灯带(后者效果更佳)
### 注意事项
1. RTC需配置后备电池(CR2032)保证断电走时
2. OLED刷新率建议控制在3-5Hz避免闪烁
3. DHT11读取间隔需>1秒
4. 按键需添加软件消抖处理
5. 流水灯电流较大时需加驱动电路
阅读全文
相关推荐



















