基于RTC和光线传感器的日出日落检测算法

/**
 * 当地日出日落时间获取程序
 * 功能:检测并返回当地实际日出日落时间,未确认时使用默认值(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);
    }
}
    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值