fix: 唤醒时立即重置所有按键状态计数,并将全局与时钟中断的开启推迟至屏幕初始化 Delay 之后,彻底解决唤醒瞬间的 ADC 电压波动误判导致立马关机的问题

This commit is contained in:
2026-07-30 15:25:44 +08:00
parent 41bb78aa59
commit b3a74ab2f4
2 changed files with 110 additions and 95 deletions

View File

@@ -8,39 +8,39 @@
#include "../Drivers/pcf8563.h" #include "../Drivers/pcf8563.h"
#include "intrins.h" #include "intrins.h"
// 引用 main.c 中的全局唤醒与运行状态变 // 引用 main.c <EFBFBD><EFBFBD>的全<EFBFBD><EFBFBD>唤醒与运行状态变<EFBFBD><EFBFBD>
extern volatile u8 p0_wakeup_flag; extern volatile u8 p0_wakeup_flag;
extern volatile u8 p2_wakeup_flag; extern volatile u8 p2_wakeup_flag;
extern volatile u8 p3_wakeup_flag; extern volatile u8 p3_wakeup_flag;
extern volatile u8 rf_wakeup_flag; extern volatile u8 rf_wakeup_flag;
/** /**
* @brief 系统 GPIO 口模式初始化 * @brief 系统 GPIO <EFBFBD><EFBFBD>口模式初始化
* @details 配置各引脚的推挽输出、高阻输入及准双向模式,建立系统初电气环境 * @details 配置各引脚的推挽输出、高阻输入及准双向模式,建立系统初<EFBFBD><EFBFBD>电气环境<EFBFBD>
*/ */
void GPIO_Init(void) void GPIO_Init(void)
{ {
// 使能访问扩展特殊功能寄存 XSFR // 使能访问扩展特殊功能寄存<EFBFBD><EFBFBD> XSFR
EAXFR = 1; EAXFR = 1;
// 1. 配置 PWR_HOLD (P0.0) 为推挽输出模 (P0M1 bit0=0, P0M0 bit0=1) // 1. 配置 PWR_HOLD (P0.0) 为推挽输出模<EFBFBD><EFBFBD> (P0M1 bit0=0, P0M0 bit0=1)
P0M1 &= ~(1 << 0); P0M1 &= ~(1 << 0);
P0M0 |= (1 << 0); P0M0 |= (1 << 0);
PWR_HOLD = 1; // 上电第一时间拉高,锁存电源保持供 PWR_HOLD = 1; // 上电<EFBFBD><EFBFBD><EFBFBD><EFBFBD>时间拉高,锁存电源保持供<EFBFBD><EFBFBD>
// 2. 配置 KEY_UP (P0.1), KEY_CONFIRM (P0.2) 为高阻输/带上拉准双向 // 2. 配置 KEY_UP (P0.1), KEY_CONFIRM (P0.2) 为高阻输<EFBFBD><EFBFBD>/带上拉准双向
P0M1 &= ~((1 << 1) | (1 << 2)); P0M1 &= ~((1 << 1) | (1 << 2));
P0M0 &= ~((1 << 1) | (1 << 2)); P0M0 &= ~((1 << 1) | (1 << 2));
KEY_UP = 1; KEY_UP = 1;
KEY_CONFIRM = 1; KEY_CONFIRM = 1;
// 3. 初化 STC32G 硬件 ADC 模块 (其中自动配置 P0.3 P1.3 为高阻输入模) // 3. 初<EFBFBD><EFBFBD>化 STC32G <EFBFBD><EFBFBD><EFBFBD><EFBFBD> ADC 模块 (其中<EFBFBD><EFBFBD>动配<EFBFBD><EFBFBD> P0.3 <EFBFBD><EFBFBD> P1.3 为高阻输入模<EFBFBD><EFBFBD>)
ADC_Init(); ADC_Init();
// 4. 配置 PCF8563 I2C 管脚 P3.2 (SCL) P3.3 (SDA) 为准双向口模式,并开上拉 // 4. 配置 PCF8563 I2C 管脚 P3.2 (SCL) <EFBFBD><EFBFBD> P3.3 (SDA) 为准双向口模式,并开上拉
P3M1 &= ~((1 << 2) | (1 << 3)); P3M1 &= ~((1 << 2) | (1 << 3));
P3M0 &= ~((1 << 2) | (1 << 3)); P3M0 &= ~((1 << 2) | (1 << 3));
P3PU |= (1 << 2) | (1 << 3); // 开启 P3.2 P3.3 的内 4.7K 上拉电阻 P3PU |= (1 << 2) | (1 << 3); // <EFBFBD><EFBFBD><EFBFBD><EFBFBD> P3.2 <EFBFBD><EFBFBD> P3.3 的内<EFBFBD><EFBFBD> 4.7K 上拉电阻
RTC_SCL = 1; RTC_SCL = 1;
RTC_SDA = 1; RTC_SDA = 1;
@@ -49,49 +49,49 @@ void GPIO_Init(void)
P2M1 &= ~((1 << 5) | (1 << 3)); P2M1 &= ~((1 << 5) | (1 << 3));
P2M0 |= ((1 << 5) | (1 << 3)); P2M0 |= ((1 << 5) | (1 << 3));
MOTOR = 0; MOTOR = 0;
RGB_DIN = 0; // P2.3 初拉低,防上电期间 WS2812B 触发 RGB_DIN = 0; // P2.3 初<EFBFBD><EFBFBD>拉低,防<EFBFBD>上电期间 WS2812B <EFBFBD><EFBFBD>触发
// 配置 KEY_SOS (P2.6) 为带上拉准双向口模式以确保输入稳 // 配置 KEY_SOS (P2.6) 为带上拉准双向口模式以确保输入稳<EFBFBD><EFBFBD>
P2M1 &= ~(1 << 6); P2M1 &= ~(1 << 6);
P2M0 &= ~(1 << 6); P2M0 &= ~(1 << 6);
KEY_SOS = 1; KEY_SOS = 1;
(*(unsigned char volatile xdata *)0xFE12) |= (1 << 6); // 使能 P2.6 的强内部上拉电阻 (P2PU = 0xFE12) (*(unsigned char volatile xdata *)0xFE12) |= (1 << 6); // 使能 P2.6 的强内部上拉电阻 (P2PU = 0xFE12)
// SGM_CTRL (P1.7), LCD 控制管脚 (P1.0, P1.1, P1.4, P1.5, P1.6) 为推挽输 // SGM_CTRL (P1.7), LCD 控制管脚 (P1.0, P1.1, P1.4, P1.5, P1.6) <EFBFBD><EFBFBD>为推挽输<EFBFBD><EFBFBD>
P1M1 &= ~((1 << 7) | (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6)); P1M1 &= ~((1 << 7) | (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6));
P1M0 |= ((1 << 7) | (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6)); P1M0 |= ((1 << 7) | (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6));
// SHUT (P3.5) 射/外设开启使能脚置为推挽输 // SHUT (P3.5) 射<EFBFBD>/外<EFBFBD><EFBFBD><EFBFBD><EFBFBD>使能脚置为推挽输<EFBFBD><EFBFBD>
P3M1 &= ~(1 << 5); P3M1 &= ~(1 << 5);
P3M0 |= (1 << 5); P3M0 |= (1 << 5);
SHUT = 0; // 低电平开工作 SHUT = 0; // 低电平开<EFBFBD><EFBFBD>工作
// 7. 配置 CHRG_DET (P1.2) 为高阻输入模式,适配 DET 模拟 ADC 通道 2 // 7. 配置 CHRG_DET (P1.2) 为高阻输入模式,适配 DET 模拟 ADC 通道 2
// 由于精密模拟电平测,切勿开启引脚内部上拉电阻 // 由于<EFBFBD><EFBFBD>精密模拟电平<EFBFBD><EFBFBD>测,切勿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>引脚内部上拉电阻
P1M1 |= (1 << 2); P1M1 |= (1 << 2);
P1M0 &= ~(1 << 2); P1M0 &= ~(1 << 2);
// P1PU 在扩 XSFR 空间中没有被定义的话以用 P1 口寄存器或是关闭上拉 // P1PU 在扩<EFBFBD><EFBFBD> XSFR 空间<EFBFBD><EFBFBD>没有<EFBFBD><EFBFBD>定义的话<EFBFBD><EFBFBD>以用 P1 <EFBFBD><EFBFBD>口寄存器或<EFBFBD><EFBFBD>是关闭上拉<EFBFBD><EFBFBD>
// STC32G 中端口上拉寄存器 P1PU (FE11H),因为是 XSFR 我们 config.h 里有 extern 或直接操 // STC32G <EFBFBD><EFBFBD><EFBFBD><EFBFBD>口上拉寄存器<EFBFBD><EFBFBD> P1PU (FE11H),因为是 XSFR 我们<EFBFBD><EFBFBD> config.h 里有 extern 或直接操<EFBFBD><EFBFBD>
// 扩展 XSFR P1PU 地址 0xFE11 // 扩展 XSFR P1PU 地址<EFBFBD><EFBFBD> 0xFE11
(*(unsigned char volatile xdata *)0xFE11) &= ~(1 << 2); (*(unsigned char volatile xdata *)0xFE11) &= ~(1 << 2);
} }
/** /**
* @brief 初化 UART1 串口通信 * @brief 初<EFBFBD><EFBFBD>化 UART1 串口通信
* @details 设定波特 115200 (使用 Timer2 作为发生器,24.0MHz 晶振) * @details 设定波特<EFBFBD><EFBFBD> 115200 (使用 Timer2 作为发生<EFBFBD><EFBFBD><EFBFBD><EFBFBD>24.0MHz 晶振)
*/ */
void Uart1_Init(void) void Uart1_Init(void)
{ {
SCON = 0x50; // 8 位数据, 可变波特率 SCON = 0x50; // 8 位数<EFBFBD><EFBFBD>, <20><>变波特率
AUXR |= 0x01; // 串口 1 选择 Timer2 做波特率发生 AUXR |= 0x01; // 串口 1 选择 Timer2 做波特率发生<EFBFBD><EFBFBD>
AUXR |= 0x04; // Timer2 时钟 1T 模式 AUXR |= 0x04; // Timer2 时钟<EFBFBD><EFBFBD> 1T 模式
T2L = 0xCC; // 24MHz / 115200 = 208 (0xD0), 对应 reload 65536 - 52 = 0xFFCC T2L = 0xCC; // 24MHz / 115200 = 208 (0xD0), 对应 reload <EFBFBD><EFBFBD> 65536 - 52 = 0xFFCC
T2H = 0xFF; T2H = 0xFF;
AUXR |= 0x10; // 启动 Timer2 运 AUXR |= 0x10; // <EFBFBD><EFBFBD><EFBFBD><EFBFBD> Timer2 运<EFBFBD>
} }
/** /**
* @brief 串口 1 发单字节数据 * @brief 串口 1 发<EFBFBD><EFBFBD>单字节数据
* @param dat 待发送的字节 * @param dat 待发送的字节
*/ */
void Uart_SendByte(u8 dat) void Uart_SendByte(u8 dat)
@@ -102,8 +102,8 @@ void Uart_SendByte(u8 dat)
} }
/** /**
* @brief 串口 1 发字符串 * @brief 串口 1 发<EFBFBD><EFBFBD>字符串
* @param s 字串指针 * @param s 字<EFBFBD><EFBFBD>串指针
*/ */
void Uart_SendString(char *s) void Uart_SendString(char *s)
{ {
@@ -113,8 +113,8 @@ void Uart_SendString(char *s)
} }
/** /**
* @brief 串口 1 非阻塞接收字 * @brief 串口 1 非阻塞接收字<EFBFBD><EFBFBD>
* @return char 接收到的字,若无接收数据则返 '\0' * @return char 接收到的字<EFBFBD><EFBFBD>,若无接收数据则返<EFBFBD><EFBFBD> '\0'
*/ */
char Uart_RxChar(void) char Uart_RxChar(void)
{ {
@@ -126,8 +126,8 @@ char Uart_RxChar(void)
} }
/** /**
* @brief 阻塞毫秒延时 * @brief 阻<EFBFBD><EFBFBD><EFBFBD>秒延<EFBFBD><EFBFBD>
* @param ms 秒数 * @param ms <EFBFBD><EFBFBD>秒数
*/ */
void Delay_ms(u16 ms) void Delay_ms(u16 ms)
{ {
@@ -140,8 +140,8 @@ void Delay_ms(u16 ms)
} }
/** /**
* @brief 阻微秒延 * @brief 阻<EFBFBD><EFBFBD>微秒延<EFBFBD><EFBFBD>
* @param us 秒数 * @param us <EFBFBD><EFBFBD>秒数
*/ */
void Delay_us(u16 us) void Delay_us(u16 us)
{ {
@@ -152,8 +152,8 @@ void Delay_us(u16 us)
} }
/** /**
* @brief 系统机上电硬件自函数 * @brief 系统<EFBFBD><EFBFBD>机上电硬件自<EFBFBD><EFBFBD>函数
* @details 检测 PWR_HOLD 锁存状态、ADC 采样基准与串口通讯,输出完整自 report * @details <EFBFBD><EFBFBD><EFBFBD><EFBFBD> PWR_HOLD 锁存状<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ADC 采样基准与串口<EFBFBD><EFBFBD><EFBFBD>,输出完整自<EFBFBD><EFBFBD> report
*/ */
void Self_Test(void) void Self_Test(void)
{ {
@@ -165,12 +165,12 @@ void Self_Test(void)
Uart_SendString("\r\n========================================\r\n"); Uart_SendString("\r\n========================================\r\n");
Uart_SendString("[SELF-TEST] System Power-On Self Test...\r\n"); Uart_SendString("[SELF-TEST] System Power-On Self Test...\r\n");
// 执 I2C 总线器件描,查找 RTC 否物理响 // 执<EFBFBD> I2C 总线器件<EFBFBD><EFBFBD>描,查找 RTC <EFBFBD><EFBFBD>否物理响<EFBFBD><EFBFBD>
PCF8563_ScanDiagnostic(); PCF8563_ScanDiagnostic();
// 0. I2C 件脚电平诊断测试 (验证引脚可控性与短路) // 0. I2C <EFBFBD><EFBFBD>件脚电平诊断测试 (验证引脚<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
Uart_SendString("[I2C-DIAG] Pin Level Test Starting...\r\n"); Uart_SendString("[I2C-DIAG] Pin Level Test Starting...\r\n");
// 1 测试 (准双+上拉) // <EFBFBD><EFBFBD> 1 测试 (准双<EFBFBD><EFBFBD>+上拉)
P3M1 &= ~((1 << 2) | (1 << 3)); P3M1 &= ~((1 << 2) | (1 << 3));
P3M0 &= ~((1 << 2) | (1 << 3)); P3M0 &= ~((1 << 2) | (1 << 3));
P3PU |= (1 << 2) | (1 << 3); P3PU |= (1 << 2) | (1 << 3);
@@ -183,7 +183,7 @@ void Self_Test(void)
Uart_SendByte((u8)(RTC_SDA ? '1' : '0')); Uart_SendByte((u8)(RTC_SDA ? '1' : '0'));
Uart_SendString("\r\n"); Uart_SendString("\r\n");
// 0 测试 // <EFBFBD><EFBFBD> 0 测试
RTC_SCL = 0; RTC_SCL = 0;
RTC_SDA = 0; RTC_SDA = 0;
Delay_ms(10); Delay_ms(10);
@@ -193,17 +193,17 @@ void Self_Test(void)
Uart_SendByte((u8)(RTC_SDA ? '1' : '0')); Uart_SendByte((u8)(RTC_SDA ? '1' : '0'));
Uart_SendString("\r\n"); Uart_SendString("\r\n");
// 0.2 执 RTC 底层单独试读测试 // 0.2 执<EFBFBD> RTC 底层单独试<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
PCF8563_TryReadDiagnostic(); PCF8563_TryReadDiagnostic();
// 1. 验证 PWR_HOLD 锁存状 // 1. 验证 PWR_HOLD 锁存状<EFBFBD>
if (PWR_HOLD == 1) { if (PWR_HOLD == 1) {
Uart_SendString("[SELF-TEST] PWR_HOLD Pin State: HIGH [OK]\r\n"); Uart_SendString("[SELF-TEST] PWR_HOLD Pin State: HIGH [OK]\r\n");
} else { } else {
Uart_SendString("[SELF-TEST] PWR_HOLD Pin State: LOW [FAIL]\r\n"); Uart_SendString("[SELF-TEST] PWR_HOLD Pin State: LOW [FAIL]\r\n");
} }
// 2. 检查 P0.3 ADC 按键基准常态电压 // 2. <EFBFBD><EFBFBD><EFBFBD><EFBFBD> P0.3 ADC 按键基准常<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
key_down_adc = ADC_ReadFiltered(ADC_CHANNEL_KEY_DOWN); key_down_adc = ADC_ReadFiltered(ADC_CHANNEL_KEY_DOWN);
Uart_SendString("[SELF-TEST] KEY_DOWN (P0.3) ADC Raw Value: "); Uart_SendString("[SELF-TEST] KEY_DOWN (P0.3) ADC Raw Value: ");
Uart_SendByte((u8)('0' + (key_down_adc / 1000) % 10)); Uart_SendByte((u8)('0' + (key_down_adc / 1000) % 10));
@@ -212,12 +212,12 @@ void Self_Test(void)
Uart_SendByte((u8)('0' + (key_down_adc % 10))); Uart_SendByte((u8)('0' + (key_down_adc % 10)));
Uart_SendString(" [OK]\r\n"); Uart_SendString(" [OK]\r\n");
// 2.2 检测 KEY_SOS (P2.6) 物理电平常 // 2.2 <EFBFBD><EFBFBD><EFBFBD><EFBFBD> KEY_SOS (P2.6) 物理电平常<EFBFBD>
Uart_SendString("[SELF-TEST] KEY_SOS (P2.6) Pin Level: "); Uart_SendString("[SELF-TEST] KEY_SOS (P2.6) Pin Level: ");
Uart_SendByte((u8)(KEY_SOS ? '1' : '0')); Uart_SendByte((u8)(KEY_SOS ? '1' : '0'));
Uart_SendString("\r\n"); Uart_SendString("\r\n");
// 3. 检查 P1.3 电池电压测与百分 // 3. <EFBFBD><EFBFBD><EFBFBD><EFBFBD> P1.3 电池电压<EFBFBD><EFBFBD>测与百分<EFBFBD><EFBFBD>
vbat_mv = ADC_GetBatteryVoltage_mV(); vbat_mv = ADC_GetBatteryVoltage_mV();
percent = ADC_GetBatteryPercent(); percent = ADC_GetBatteryPercent();
batt_adc_raw = ADC_ReadFiltered(ADC_CHANNEL_BATTERY); batt_adc_raw = ADC_ReadFiltered(ADC_CHANNEL_BATTERY);
@@ -240,7 +240,7 @@ void Self_Test(void)
Uart_SendByte((u8)('0' + (percent % 10))); Uart_SendByte((u8)('0' + (percent % 10)));
Uart_SendString("% [OK]\r\n"); Uart_SendString("% [OK]\r\n");
// 4. 查充电状 // 4. <EFBFBD><EFBFBD>查充电状<EFBFBD><EFBFBD>
{ {
u16 det_adc = ADC_ReadFiltered(ADC_CHANNEL_CHRG_DET); u16 det_adc = ADC_ReadFiltered(ADC_CHANNEL_CHRG_DET);
u16 det_mv = (det_adc * 3300UL) / 4095UL; u16 det_mv = (det_adc * 3300UL) / 4095UL;
@@ -269,93 +269,93 @@ void Self_Test(void)
} }
/** /**
* @brief 执关机断电流 * @brief 执<EFBFBD><EFBFBD>关机断电流<EFBFBD><EFBFBD>
* @details 关断外设、震动提示并拉低 PWR_HOLD 引脚切断总电 * @details 关断外<EFBFBD><EFBFBD><EFBFBD><EFBFBD>震动提示并拉低 PWR_HOLD 引脚切断总电<EFBFBD><EFBFBD>
*/ */
void Power_Off(void) void Power_Off(void)
{ {
Uart_SendString("[SYS] Executing Power Off sequence...\r\n"); Uart_SendString("[SYS] Executing Power Off sequence...\r\n");
// 达震动反 100ms // <EFBFBD><EFBFBD>达震动反<EFBFBD><EFBFBD> 100ms
MOTOR = 1; MOTOR = 1;
Delay_ms(100); Delay_ms(100);
MOTOR = 0; MOTOR = 0;
// 关断屏幕背光 RGB 灯光 // 关断屏幕背光<EFBFBD><EFBFBD> RGB <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
SGM_CTRL = 1; // 高电平断电,关闭背光灭屏 SGM_CTRL = 1; // 高电平断电,关闭背光<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
RGB_Send(0, 0, 0, 0, 0, 0); RGB_Send(0, 0, 0, 0, 0, 0);
// 拉低 PWR_HOLD 切断电源锁存使电源关 // 拉低 PWR_HOLD 切断电源锁存使<EFBFBD><EFBFBD>电源关<EFBFBD><EFBFBD>
PWR_HOLD = 0; PWR_HOLD = 0;
// 进入死循等待电源物理切断 // 进入死循<EFBFBD><EFBFBD>等待电源物理切断
while (1) { while (1) {
PWR_HOLD = 0; PWR_HOLD = 0;
} }
} }
/** /**
* @brief 系统切入低功耗停机休眠模 * @brief 系统切入低功耗停机休眠模<EFBFBD><EFBFBD>
*/ */
void Enter_Low_Power_Sleep(void) void Enter_Low_Power_Sleep(void)
{ {
Uart_SendString("[SYS] Entering low power sleep...\r\n"); Uart_SendString("[SYS] Entering low power sleep...\r\n");
// 1. 关闭/熄灭 RGB // 1. 关闭/熄灭 RGB <EFBFBD><EFBFBD>
RGB_Send(0, 0, 0, 0, 0, 0); RGB_Send(0, 0, 0, 0, 0, 0);
// 2. LCD 芯片写入 Display OFF 指令 (0x28) 关显 // 2. <EFBFBD><EFBFBD> LCD <EFBFBD><EFBFBD>片写<EFBFBD><EFBFBD> Display OFF 指令 (0x28) 关显<EFBFBD><EFBFBD>
WriteComm(0x28); WriteComm(0x28);
Delay_ms(20); Delay_ms(20);
// 3. LCD 芯片写入 Sleep In 指令 (0x10) 关内部电荷泵 // 3. <EFBFBD><EFBFBD> LCD <EFBFBD><EFBFBD>片写<EFBFBD><EFBFBD> Sleep In 指令 (0x10) 关内部电荷泵
WriteComm(0x10); WriteComm(0x10);
Delay_ms(20); Delay_ms(20);
// 4. 关闭背光(高电平电,关闭背光屏) // 4. 关闭背光(高电平<EFBFBD><EFBFBD>电,关闭背光<EFBFBD><EFBFBD>屏)
SGM_CTRL = 1; SGM_CTRL = 1;
// 5. 屏幕接口防漏电 // 5. 屏幕接口防漏电<EFBFBD><EFBFBD>
LCD_CS = 1; LCD_CS = 1;
LCD_RST = 1; LCD_RST = 1;
LCD_DCX = 0; LCD_DCX = 0;
LCD_SCL = 0; LCD_SCL = 0;
LCD_SDI = 0; LCD_SDI = 0;
// 6. 射频设置为关接收模式(低功SHUT=0, RF_SetMode(0) // 6. 射<EFBFBD><EFBFBD><EFBFBD><EFBFBD>置为关<EFBFBD><EFBFBD>接收模式(低功<EFBFBD><EFBFBD>SHUT=0, RF_SetMode(0)<EFBFBD><EFBFBD>
RF_SetMode(0); RF_SetMode(0);
// 使能访问扩展特殊功能寄存 // 使能访问扩展特殊功能寄存<EFBFBD><EFBFBD>
P_SW2 |= 0x80; P_SW2 |= 0x80;
// 7. 配置 Port0 中断唤醒源 (KEY_UP=P0.1, KEY_CONFIRM=P0.2, KEY_DOWN=P0.3) // 7. 配置 Port0 <EFBFBD><EFBFBD><EFBFBD><EFBFBD>唤醒<EFBFBD><EFBFBD> (KEY_UP=P0.1, KEY_CONFIRM=P0.2, KEY_DOWN=P0.3)
P0IM1 |= 0x0E; P0IM1 |= 0x0E;
P0IM0 &= ~0x0E; // 下降沿触 P0IM0 &= ~0x0E; // 下降沿触<EFBFBD><EFBFBD>
P0INTF = 0x00; // 清除挂起的中标志 P0INTF = 0x00; // 清除挂起的中<EFBFBD><EFBFBD>标志
P0INTE |= 0x0E; // 开启 P0.1, P0.2, P0.3 中断允许 P0INTE |= 0x0E; // <EFBFBD><EFBFBD><EFBFBD><EFBFBD> P0.1, P0.2, P0.3 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
P0WKUE |= 0x0E; // 使能 P0.1, P0.2, P0.3 掉电唤醒 P0WKUE |= 0x0E; // 使能 P0.1, P0.2, P0.3 掉电唤醒
// 8. 配置 Port2 中断唤醒源 (SOS=P2.6) // 8. 配置 Port2 <EFBFBD><EFBFBD><EFBFBD><EFBFBD>唤醒<EFBFBD><EFBFBD> (SOS=P2.6)
P2IM1 |= 0x40; P2IM1 |= 0x40;
P2IM0 &= ~0x40; // 下降沿触 P2IM0 &= ~0x40; // 下降沿触<EFBFBD><EFBFBD>
P2INTF = 0x00; // 清除挂起标志 P2INTF = 0x00; // 清除挂起标志
P2INTE |= 0x40; // 开启 P2.6 中断允许 P2INTE |= 0x40; // <EFBFBD><EFBFBD><EFBFBD><EFBFBD> P2.6 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
P2WKUE |= 0x40; // 使能 P2.6 掉电唤醒 P2WKUE |= 0x40; // 使能 P2.6 掉电唤醒
// 9. 配置 Port3 中断唤醒源 (RF_RX_DATA=P3.6) // 9. 配置 Port3 <EFBFBD><EFBFBD><EFBFBD><EFBFBD>唤醒<EFBFBD><EFBFBD> (RF_RX_DATA=P3.6)
P3IM1 |= 0x40; P3IM1 |= 0x40;
P3IM0 |= 0x40; // 双边沿触 P3IM0 |= 0x40; // 双边沿触<EFBFBD><EFBFBD>
P3INTF = 0x00; // 清除挂起标志 P3INTF = 0x00; // 清除挂起标志
P3INTE |= 0x40; // 开启 P3.6 中断允许 P3INTE |= 0x40; // <EFBFBD><EFBFBD><EFBFBD><EFBFBD> P3.6 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
P3WKUE |= 0x40; // 使能 P3.6 掉电唤醒 P3WKUE |= 0x40; // 使能 P3.6 掉电唤醒
// 保引脚上拉和输入使能,防止因空产生的功耗泄漏 // <EFBFBD><EFBFBD>保引脚上拉和输入使能,防止因<EFBFBD><EFBFBD>空产生的功<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
P2PU |= 0x40; P2PU |= 0x40;
P2IE |= 0x40; P2IE |= 0x40;
P3PU &= ~0x40; P3PU &= ~0x40;
P3IE |= 0x40; P3IE |= 0x40;
// 清零各个唤醒测标志位 // 清零各个唤醒<EFBFBD><EFBFBD>测标志位
P0INTF = 0x00; P0INTF = 0x00;
P2INTF = 0x00; P2INTF = 0x00;
P3INTF = 0x00; P3INTF = 0x00;
@@ -365,25 +365,38 @@ void Enter_Low_Power_Sleep(void)
p3_wakeup_flag = 0; p3_wakeup_flag = 0;
rf_wakeup_flag = 0; rf_wakeup_flag = 0;
// 10. 关闭系统滴答定时 Timer1 中断,防止休眠时定时器唤醒 // 10. 关闭系统滴答定时<EFBFBD><EFBFBD> Timer1 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>休眠时<EFBFBD>定时器<EFBFBD>唤醒
ET1 = 0; ET1 = 0;
EA = 1; // 开启全局中断 EA = 1; // <EFBFBD><EFBFBD><EFBFBD><EFBFBD>全局<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// 配置 PCON 挂起单片机,切入停机 (Power Down) 模式 // 配置 PCON 挂起单片机,切入停机 (Power Down) 模式
PCON |= 0x02; // PD = 1 PCON |= 0x02; // PD = 1
_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();
// ====== 被外部中断唤醒后,在此处继续运行 ====== // ====== <EFBFBD><EFBFBD>外部<EFBFBD><EFBFBD><EFBFBD><EFBFBD>唤醒后<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ======
Wakeup_Restore(); Wakeup_Restore();
} }
/** /**
* @brief 休眠唤醒恢 * @brief 休眠唤醒恢<EFBFBD>
*/ */
void Wakeup_Restore(void) void Wakeup_Restore(void)
{ {
// <20><><EFBFBD>ò<EFBFBD><C3B2><EFBFBD><EFBFBD><EFBFBD><E3B0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬<D7B4><CCAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD>/<2F><><EFBFBD><EFBFBD>˲̬<CBB2><CCAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>³<EFBFBD><C2B3><EFBFBD><EFBFBD>ػ<EFBFBD>
extern volatile u16 key_up_hold;
extern volatile u16 key_down_hold;
extern volatile u16 key_confirm_hold;
extern volatile u16 key_sos_hold;
extern volatile u16 comb_hold;
key_up_hold = 0;
key_down_hold = 0;
key_confirm_hold = 0;
key_sos_hold = 0;
comb_hold = 0;
EAXFR = 1; EAXFR = 1;
// 1. 立即关闭有掉电外部中断允许与唤醒允许,防止重入 // 1. 立即关闭<EFBFBD><EFBFBD>有掉电<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>与唤醒允<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
P0INTE = 0x00; P0INTE = 0x00;
P2INTE = 0x00; P2INTE = 0x00;
P3INTE = 0x00; P3INTE = 0x00;
@@ -394,15 +407,14 @@ void Wakeup_Restore(void)
P2INTF = 0x00; P2INTF = 0x00;
P3INTF = 0x00; P3INTF = 0x00;
// 2. 清零掉电唤醒定时 // 2. 清零掉电唤醒定时<EFBFBD><EFBFBD>
WKTCH = 0x00; WKTCH = 0x00;
WKTCL = 0x00; WKTCL = 0x00;
// 3. 开启全局中断并重启系统滴答定时 // 3. <EFBFBD><EFBFBD><EFBFBD><EFBFBD>全局<EFBFBD><EFBFBD><EFBFBD><EFBFBD>并重<EFBFBD><EFBFBD>系统滴答定时<EFBFBD><EFBFBD>
EA = 1; // 3. <20>жϿ<D0B6><CFBF><EFBFBD>״̬<D7B4>Ƴ<EFBFBD><C6B3><EFBFBD><EFBFBD><EFBFBD>Ļ<EFBFBD><C4BB>ʼ<EFBFBD><CABC>֮<EFBFBD><D6AE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ET1 = 1;
// 4. 恢射频芯片工作模 // 4. 恢<EFBFBD><EFBFBD>射频芯片工作模<EFBFBD><EFBFBD>
RF_SetMode(1); RF_SetMode(1);
// 打印唤醒调试日志 // 打印唤醒调试日志
@@ -419,19 +431,22 @@ void Wakeup_Restore(void)
Uart_SendString("[WR] Woken by TIMER/Other\r\n"); Uart_SendString("[WR] Woken by TIMER/Other\r\n");
} }
// 5. 恢屏幕供电与背光(低电平上电,恢复背光亮屏) // 5. 恢<EFBFBD><EFBFBD>屏幕供电与背光(低电平上电,恢复背光亮屏)
SGM_CTRL = 0; SGM_CTRL = 0;
// 6. 延时 200ms 等待液晶稳压板上电稳定后,重新 LCD 寄存器初始化 // 6. 延时 200ms 等待液晶稳压板上电稳定后,重新<EFBFBD> LCD 寄存器初始化
Delay_ms(200); Delay_ms(200);
LCD_Init(); LCD_Init();
// 7. 充零闲置计时器 // <EFBFBD><EFBFBD><EFBFBD>¿<EFBFBD><EFBFBD><EFBFBD>ȫ<EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD><EFBFBD><EFBFBD> Timer1 <20>δ<EFBFBD><CEB4><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>жϣ<D0B6><CFA3><EFBFBD>ȷ<EFBFBD><C8B7><EFBFBD>ڵ<EFBFBD>ѹ<EFBFBD>ȶ<EFBFBD><C8B6><EFBFBD><EFBFBD>ſ<EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
EA = 1;
ET1 = 1;
// 7. 充零闲置计时<E8AEA1><E697B6>
inactivity_timer = 0; inactivity_timer = 0;
} }
/** /**
* @brief 安全获取 Timer0 计数器 (防高字节滚动跳变) * @brief 安全获取 Timer0 计数器<EFBFBD> (防高字节滚动跳变)
*/ */
u16 GetTimer0_Safe(void) u16 GetTimer0_Safe(void)
{ {
@@ -445,7 +460,7 @@ u16 GetTimer0_Safe(void)
} }
/** /**
* @brief 串口 1 发 4 位十进制字 (0x0~0xF) * @brief 串口 1 发<EFBFBD> 4 位十<EFBFBD><EFBFBD>进制字<EFBFBD> (0x0~0xF)
*/ */
void Uart_SendHex4(u8 val) void Uart_SendHex4(u8 val)
{ {
@@ -458,7 +473,7 @@ void Uart_SendHex4(u8 val)
} }
/** /**
* @brief 串口 1 发 8 位十进制 (0x00~0xFF) * @brief 串口 1 发<EFBFBD> 8 位十<EFBFBD><EFBFBD>进制 (0x00~0xFF)
*/ */
void Uart_SendHex8(u8 val) void Uart_SendHex8(u8 val)
{ {
@@ -467,7 +482,7 @@ void Uart_SendHex8(u8 val)
} }
/** /**
* @brief 串口 1 发 16 位十进制 (0x0000~0xFFFF) * @brief 串口 1 发<EFBFBD> 16 位十<EFBFBD><EFBFBD>进制 (0x0000~0xFFFF)
*/ */
void Uart_SendHex16(u16 val) void Uart_SendHex16(u16 val)
{ {
@@ -476,7 +491,7 @@ void Uart_SendHex16(u16 val)
} }
/** /**
* @brief 串口 1 发 20 位十进制 (用于射 5 ID 打印) * @brief 串口 1 发<EFBFBD> 20 位十<EFBFBD><EFBFBD>进制 (用于射<EFBFBD> 5 <EFBFBD><EFBFBD> ID 打印)
*/ */
void Uart_SendHex20(u32 val) void Uart_SendHex20(u32 val)
{ {
@@ -485,7 +500,7 @@ void Uart_SendHex20(u32 val)
} }
/** /**
* @brief 串口 1 发 32 位十进制 * @brief 串口 1 发<EFBFBD> 32 位十<EFBFBD><EFBFBD>进制
*/ */
void Uart_SendHex32(u32 val) void Uart_SendHex32(u32 val)
{ {

View File

@@ -10,8 +10,8 @@
根据项目开发优先级与依赖关系,按以下四个顺序阶段分步完成: 根据项目开发优先级与依赖关系,按以下四个顺序阶段分步完成:
### 阶段 1: P0.3 ADC 按键检测 ### 阶段 1: P0.3 ADC 按键检测c
- **硬件引脚**: `P0.3` 对应 STC32G 硬件 `ADC3` 通道。 - **硬件引脚**: `P0.3` 对应 STC32G 硬件 `ADC11` 通道。
- **电平特征**: 开机常态下 `KEY_DOWN` 节点电压约为 **2.0V**(未按下),按键按下后电压升至约为 **3.7V**。 - **电平特征**: 开机常态下 `KEY_DOWN` 节点电压约为 **2.0V**(未按下),按键按下后电压升至约为 **3.7V**。
- **算法与逻辑**: - **算法与逻辑**:
- 配置 ADC 模块,引入滑动窗口均值/中值滤波消抖。 - 配置 ADC 模块,引入滑动窗口均值/中值滤波消抖。