/**
* 当地日出日落时间获取程序
* 功能:检测并返回当地实际日出日落时间,未确认时使用默认值(6:00/18:00)
* 适用于32位单片机
*/
#include <stdint.h>
#include <stdbool.h>
// 时间结构体(时分秒)
typedef struct {
uint8_t hour;
uint8_t minute;
uint8_t second;
} Time;
// 配置参数
#define DEFAULT_SUNRISE_HOUR 6 // 默认日出小时
#define DEFAULT_SUNSET_HOUR 18 // 默认日落小时
#define STABLE_THRESHOLD 30 // 状态稳定阈值(秒)
#define WINDOW_SIZE_HOUR 2 // 检测窗口大小(小时)
#define MAX_CLOUDY_DAYS 3 // 最大连续阴天天数
// 检测器状态标志(位域)
typedef struct {
uint8_t sunrise_confirmed : 1; // 日出时间已确认
uint8_t sunset_confirmed : 1; // 日落时间已确认
uint8_t in_sunrise_window : 1; // 在日出检测窗口内
uint8_t in_sunset_window : 1; // 在日落检测窗口内
uint8_t valid_weather : 1; // 天气有效
} DetectorFlags;
// 检测器结构体
typedef struct {
// 时间与状态
Time current_time; // 当前时间
bool has_sunlight; // 当前阳光状态
bool last_valid_sunlight; // 上一次有效阳光状态
// 实际时间存储
Time actual_sunrise; // 实际日出时间
Time actual_sunset; // 实际日落时间
// 状态与计数器
DetectorFlags flags; // 状态标志
uint8_t consecutive_state_count;// 连续相同状态计数(秒)
uint8_t consecutive_cloudy_days;// 连续阴天天数
uint8_t daily_state_changes; // 当日状态变化次数
// 检测窗口
uint16_t sunrise_window_start; // 日出窗口开始(分钟)
uint16_t sunrise_window_end; // 日出窗口结束(分钟)
uint16_t sunset_window_start; // 日落窗口开始(分钟)
uint16_t sunset_window_end; // 日落窗口结束(分钟)
uint8_t last_window_check_hour; // 上次窗口检查小时
} SunTimeDetector;
/**
* @brief 初始化检测器
* @param detector 检测器实例
*/
void SunTimeDetector_Init(SunTimeDetector *detector) {
// 初始化默认时间
detector->actual_sunrise.hour = DEFAULT_SUNRISE_HOUR;
detector->actual_sunrise.minute = 0;
detector->actual_sunrise.second = 0;
detector->actual_sunset.hour = DEFAULT_SUNSET_HOUR;
detector->actual_sunset.minute = 0;
detector->actual_sunset.second = 0;
// 初始化状态
detector->current_time.hour = 0;
detector->current_time.minute = 0;
detector->current_time.second = 0;
detector->has_sunlight = false;
detector->last_valid_sunlight = false;
// 初始化标志位
detector->flags.sunrise_confirmed = false;
detector->flags.sunset_confirmed = false;
detector->flags.in_sunrise_window = false;
detector->flags.in_sunset_window = false;
detector->flags.valid_weather = true;
// 初始化计数器
detector->consecutive_state_count = 0;
detector->consecutive_cloudy_days = 0;
detector->daily_state_changes = 0;
detector->last_window_check_hour = 0xFF; // 无效值
// 初始化窗口
detector->sunrise_window_start = (DEFAULT_SUNRISE_HOUR - WINDOW_SIZE_HOUR) * 60;
detector->sunrise_window_end = (DEFAULT_SUNRISE_HOUR + WINDOW_SIZE_HOUR) * 60;
detector->sunset_window_start = (DEFAULT_SUNSET_HOUR - WINDOW_SIZE_HOUR) * 60;
detector->sunset_window_end = (DEFAULT_SUNSET_HOUR + WINDOW_SIZE_HOUR) * 60;
}
/**
* @brief 更新检测窗口
* @param detector 检测器实例
*/
static void update_windows(SunTimeDetector *detector) {
// 每小时更新一次窗口
if (detector->current_time.hour == detector->last_window_check_hour) {
return;
}
detector->last_window_check_hour = detector->current_time.hour;
uint16_t current_min = detector->current_time.hour * 60 + detector->current_time.minute;
// 计算窗口(使用当前确认的时间或默认时间)
uint8_t sunrise_hour = detector->flags.sunrise_confirmed ?
detector->actual_sunrise.hour : DEFAULT_SUNRISE_HOUR;
uint8_t sunset_hour = detector->flags.sunset_confirmed ?
detector->actual_sunset.hour : DEFAULT_SUNSET_HOUR;
detector->sunrise_window_start = (sunrise_hour - WINDOW_SIZE_HOUR) * 60;
detector->sunrise_window_end = (sunrise_hour + WINDOW_SIZE_HOUR) * 60;
detector->sunset_window_start = (sunset_hour - WINDOW_SIZE_HOUR) * 60;
detector->sunset_window_end = (sunset_hour + WINDOW_SIZE_HOUR) * 60;
// 更新窗口状态
detector->flags.in_sunrise_window = (current_min >= detector->sunrise_window_start &&
current_min < detector->sunrise_window_end);
detector->flags.in_sunset_window = (current_min >= detector->sunset_window_start &&
current_min < detector->sunset_window_end);
}
/**
* @brief 评估天气有效性
* @param detector 检测器实例
*/
static void evaluate_weather(SunTimeDetector *detector) {
uint16_t current_min = detector->current_time.hour * 60 + detector->current_time.minute;
uint16_t sunrise_min = detector->actual_sunrise.hour * 60 + detector->actual_sunrise.minute;
uint16_t sunset_min = detector->actual_sunset.hour * 60 + detector->actual_sunset.minute;
bool is_daytime = (current_min > sunrise_min && current_min < sunset_min);
// 检查状态是否符合预期(白天有阳光,黑夜无阳光)
bool state_normal = (is_daytime && detector->has_sunlight) ||
(!is_daytime && !detector->has_sunlight);
// 检查状态变化次数是否合理
bool changes_normal = (detector->daily_state_changes <= 4);
detector->flags.valid_weather = state_normal && changes_normal;
}
/**
* @brief 每日重置
* @param detector 检测器实例
*/
void SunTimeDetector_DailyReset(SunTimeDetector *detector) {
evaluate_weather(detector);
// 更新连续阴天天数
if (!detector->flags.valid_weather ||
(!detector->flags.sunrise_confirmed && !detector->flags.sunset_confirmed)) {
detector->consecutive_cloudy_days++;
} else {
detector->consecutive_cloudy_days = 0;
}
// 极端天气下重置确认状态
if (detector->consecutive_cloudy_days >= MAX_CLOUDY_DAYS) {
// 保持已确认的时间,不重置为默认值
detector->flags.valid_weather = false;
}
// 重置每日标志
detector->daily_state_changes = 0;
detector->consecutive_state_count = 0;
// 保留已确认的日出日落时间,不重置
}
/**
* @brief 更新检测器状态
* @param detector 检测器实例
* @param new_time 当前时间
* @param new_sunlight 当前阳光状态
*/
void SunTimeDetector_Update(SunTimeDetector *detector, Time new_time, bool new_sunlight) {
detector->current_time = new_time;
// 更新检测窗口
update_windows(detector);
// 极端天气下不更新确认状态
if (detector->consecutive_cloudy_days >= MAX_CLOUDY_DAYS) {
return;
}
// 处理阳光状态变化
if (new_sunlight != detector->has_sunlight) {
detector->consecutive_state_count = 1;
detector->has_sunlight = new_sunlight;
detector->daily_state_changes++;
} else {
if (detector->consecutive_state_count < STABLE_THRESHOLD) {
detector->consecutive_state_count++;
}
}
// 状态未稳定,不处理
if (detector->consecutive_state_count < STABLE_THRESHOLD) {
return;
}
// 检查有效状态变化
bool state_changed = (detector->last_valid_sunlight != detector->has_sunlight);
if (state_changed) {
detector->last_valid_sunlight = detector->has_sunlight;
// 检测日出:窗口内、未确认、阳光从无到有、天气有效
if (detector->flags.in_sunrise_window && !detector->flags.sunrise_confirmed &&
detector->has_sunlight && detector->flags.valid_weather) {
detector->actual_sunrise = new_time; // 记录实际日出时间
detector->flags.sunrise_confirmed = true;
}
// 检测日落:窗口内、未确认、阳光从有到无、天气有效
if (detector->flags.in_sunset_window && !detector->flags.sunset_confirmed &&
!detector->has_sunlight && detector->flags.valid_weather) {
detector->actual_sunset = new_time; // 记录实际日落时间
detector->flags.sunset_confirmed = true;
}
}
}
/**
* @brief 获取当地日出时间
* @param detector 检测器实例
* @return 日出时间(未确认时返回6:00)
*/
Time SunTimeDetector_GetSunrise(SunTimeDetector *detector) {
return detector->actual_sunrise;
}
/**
* @brief 获取当地日落时间
* @param detector 检测器实例
* @return 日落时间(未确认时返回18:00)
*/
Time SunTimeDetector_GetSunset(SunTimeDetector *detector) {
return detector->actual_sunset;
}
// ------------------------------
// 示例使用代码
// ------------------------------
#include "rtc.h" // RTC驱动
#include "light_sensor.h" // 光线传感器驱动
#include "delay.h" // 延时函数
// 全局检测器实例
SunTimeDetector sunDetector;
void main(void) {
// 初始化
RTC_Init();
LightSensor_Init();
SunTimeDetector_Init(&sunDetector);
while (1) {
// 获取当前时间
Time current_time = RTC_GetTime();
// 检查是否需要每日重置(凌晨0:00-0:05)
if (current_time.hour == 0 && current_time.minute < 5) {
SunTimeDetector_DailyReset(&sunDetector);
}
// 获取阳光状态
bool has_sunlight = LightSensor_Read();
// 更新检测器
SunTimeDetector_Update(&sunDetector, current_time, has_sunlight);
// 获取并使用日出日落时间
Time sunrise = SunTimeDetector_GetSunrise(&sunDetector);//日出时间
Time sunset = SunTimeDetector_GetSunset(&sunDetector);//日落时间
sunrise.hour;
sunrise.minute;
sunrise.second;
// 示例:打印时间(实际应用中可用于控制逻辑)
// printf("日出: %02d:%02d, 日落: %02d:%02d\n",
// sunrise.hour, sunrise.minute,
// sunset.hour, sunset.minute);
// 延时1秒
Delay_MS(1000);
}
}
基于RTC和光线传感器的日出日落检测算法
最新推荐文章于 2025-12-15 21:11:20 发布
2万+

被折叠的 条评论
为什么被折叠?



