Files
stc32g128k/Docs/60_coding/mod-sys.md

4.1 KiB
Raw Blame History

编码实现 - 系统核心控制与存储 (Docs/60_coding/mod-sys.md)

本文件对应系统状态机、超时低功耗休眠判断以及断电数据库的具体编码实现。

1. 对应代码源文件

  • App/main.c (系统主逻辑、主状态机切换、10s 超时累加判断)
  • App/config.h (系统状态及数据结构定义)

2. 关键代码片段与逻辑实现

2.1 10秒无操作休眠时序 (Timer1_Isr)

定时器初始化配置为 1msmain.c 中实现。 在 Timer1_Isr (每 10ms 调用一次) 中,当系统非处于休眠(STATE_SLEEP)且非处于报警(STATE_ALARMING/STATE_SOS_EMITTED)状态时,累加无按键操作计数器 inactivity_timer

u16 inactivity_timer = 0;

void Timer1_Isr(void) interrupt 3 {
    // 基础毫秒滴答计数
    ms_tick++;
    
    // 10ms 调度周期
    if (ms_tick % 10 == 0) {
        // 当不是休眠或报警时,进行超时计时累加
        if (current_state != STATE_SLEEP && current_state != STATE_ALARMING && current_state != STATE_SOS_EMITTED) {
            inactivity_timer++;
        }
    }
}

2.2 主循环低功耗检测与状态转换

在主循环 main() 中,不断检查 inactivity_timer 是否达到 1000即 1000 * 10ms = 10 秒):

void main(void) {
    System_Init();
    
    while (1) {
        // 读取按键事件并重置计时器
        if (key_event_buf != KEY_EVENT_NONE) {
            inactivity_timer = 0; // 重置无按键操作计时器
        }
        
        // 如果达到 10 秒无操作,进入低功耗休眠
        if (inactivity_timer >= 1000) {
            inactivity_timer = 0;
            current_state = STATE_SLEEP;
            Enter_Low_Power_Sleep(); // 关屏、拉低 SGM_CTRL、单片机停机
        }
        
        // 轮询解码及其他主状态机业务处理
        // ...
    }
}

2.3 获取出厂唯一 ID (Get_Bracelet_Factory_ID)

从 STC32G 的内置 IDATA RAM 区域 0xF1~0xF7 处读取 7 字节唯一硬件 ID并将其转换为符合 EV1527 的 20 位地址码:

u32 Get_Bracelet_Factory_ID(void) {
    unsigned char idata *p_uid = (unsigned char idata *)0xF1;
    u32 uid = 0;
    
    // 组合后 3 字节并进行 20 位限制
    uid = ((u32)p_uid[4] << 16) | ((u32)p_uid[5] << 8) | p_uid[6];
    uid &= 0x0FFFFF; // 20-bit address range limit for EV1527
    
    if (uid == 0) {
        uid = CLONED_ADDR; // 防错备份
    }
    return uid;
}

2.4 电池采样与充电状态读取实现

在系统模块中,通过硬件 ADC 通道 8 (P0.0) 和数字 I/O (P2.7) 采集电池状态:

  1. ADC 初始化 (ADC_Init)
void ADC_Init(void) {
    P0M1 |= 0x01; P0M0 &= ~0x01; // P0.0 (Pin 29 / BAT_ADC) 配置为高阻输入 (模拟输入模式)
    ADCCFG = 0x2F;               // RESFMT = 1 (右对齐)
    ADC_CONTR |= 0x80;           // 打开 ADC 电源 (ADC_POWER = 1)
}
  1. 读取采样数据与电量百分比计算
u16 Get_ADC_Result(u8 channel) {
    ADC_CONTR = 0x80 | channel;  // 开启电源并选择通道 (channel = 8 对应 P0.0)
    _nop_(); _nop_();
    ADC_CONTR |= 0x40;           // 启动 ADC 转换 (ADC_START = 1)
    while (!(ADC_CONTR & 0x20)); // 等待转换完成 (ADC_FLAG)
    ADC_CONTR &= ~0x20;          // 清除 ADC 标志
    return ((u16)ADC_RES << 8) | ADC_RESL; // 返回 12 位 ADC 转换结果
}

u8 Read_Battery_Percent(void) {
    u16 adc_val = Get_ADC_Result(8); // 读取通道 8 (P0.0)
    
    // 线性百分比转换3.3V (ADC=1279) 对应 0%, 4.2V (ADC=1628) 对应 100%
    if (adc_val <= 1279) {
        return 0;
    } else if (adc_val >= 1628) {
        return 100;
    } else {
        return (u8)((u32)(adc_val - 1279) * 100 / (1628 - 1279));
    }
}
  1. 充电状态读取
// P2.7 (Pin 28 / DET) 在 System_Init 时需配置为高阻输入以进行充电状态检测
bit Is_Charging(void) {
    return (P2 & (1 << 7)) ? 1 : 0; // 读取 P2.7 引脚高电平状态1 表示 USB 接入
}