Files
stc32g128k/App/system.c

328 lines
7.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "system.h"
#include "rgb.h"
#include "ui.h"
#include "../Drivers/lcd.h"
void GPIO_Init(void)
{
IE = 0x00;
IE2 = 0x00;
TCON = 0x00;
TMOD &= 0xF0;
TR0 = 0;
ET0 = 0;
AUXR = 0x00;
INTCLKO = 0x00;
P_SW1 = 0x00;
P_SW2 = 0x80; // 开启 EAXFR=1允许访问 P0PU/P2PU/P0INTE/P2INTE 等扩展 SFR 寄存器
P_SW3 = 0x00;
// 配置 P0.0 (BAT_ADC) 为高阻输入模式
P0M1 |= (1 << 0);
P0M0 &= ~(1 << 0);
// 配置 P0.1 (KEY_UP), P0.2 (KEY_CONFIRM), P0.3 (KEY_DOWN) 为准双向口模式并置 1
P0M1 &= ~((1 << 1) | (1 << 2) | (1 << 3));
P0M0 &= ~((1 << 1) | (1 << 2) | (1 << 3));
KEY_UP = 1;
KEY_CONFIRM = 1;
KEY_DOWN = 1;
// 配置 P2.3 (RGB_DIN) 为推挽输出模式
P2M1 &= ~(1 << 3);
P2M0 |= (1 << 3);
RGB_DIN = 0;
// 配置 P2.5 (MOTOR) 为推挽输出模式
P2M1 &= ~(1 << 5);
P2M0 |= (1 << 5);
MOTOR = 0;
// 配置 P2.6 (KEY_SOS) 为准双向口模式并置 1
P2M1 &= ~(1 << 6);
P2M0 &= ~(1 << 6);
KEY_SOS = 1;
// 配置 P2.2 (SHUT) 为推挽输出模式
P2M1 &= ~(1 << 2);
P2M0 |= (1 << 2);
SHUT = 1; // 默认拉高开启射频接收芯片工作
// 开启按键引脚 P0.1, P0.2, P0.3 和 P2.6 的内部上拉电阻,避免引脚抖动误唤醒
P0PU |= 0x0E;
P2PU |= 0x40;
// 配置 P2.7 (DET) 为高阻输入模式
P2M1 |= (1 << 7);
P2M0 &= ~(1 << 7);
// 配置 P3.0 (TXD), P3.1 (RXD) 和 P3.4 (SGM_CTRL)
P3M1 &= ~((1 << 0) | (1 << 1) | (1 << 4));
P3M0 &= ~(1 << 0);
P3M0 |= ((1 << 1) | (1 << 4));
}
void Delay_ms(u16 ms)
{
u16 i, j;
for (i = 0; i < ms; i++)
for (j = 12000; j > 0; j--);
}
void Delay10us(void)
{
unsigned char data i;
_nop_();
i = 30;
while (--i);
}
u16 GetTimer0_Safe(void)
{
u8 h1, l, h2;
do {
h1 = TH0;
l = TL0;
h2 = TH0;
} while (h1 != h2);
return ((u16)h1 << 8) | l;
}
void Delay_us(u16 us)
{
u16 ticks = (u16)((u32)us * (MAIN_Fosc / 1000000UL) / 12UL);
TL0 = 0;
TH0 = 0;
TR0 = 1;
while (GetTimer0_Safe() < ticks);
TR0 = 0;
}
void Uart1_Init(void)
{
u16 reload = (u16)(65536UL - (MAIN_Fosc / 4 / 115200UL));
SCON = 0x50;
AUXR |= 0x01;
AUXR |= 0x04;
T2L = (u8)reload;
T2H = (u8)(reload >> 8);
AUXR |= 0x10;
TI = 0;
}
void Uart_SendByte(u8 dat)
{
REN = 0;
SBUF = dat;
while (!TI);
TI = 0;
RI = 0;
REN = 1;
}
void Uart_SendString(char *s)
{
REN = 0;
while (*s) {
SBUF = *s++;
while (!TI);
TI = 0;
}
RI = 0;
REN = 1;
}
char Uart_RxChar(void)
{
if (RI) {
char c = SBUF;
RI = 0;
return c;
}
return 0;
}
void Uart_SendHex4(u8 val)
{
val &= 0x0F;
if (val < 10)
Uart_SendByte((u8)('0' + val));
else
Uart_SendByte((u8)('A' + (val - 10)));
}
void Uart_SendHex8(u8 val)
{
Uart_SendHex4(val >> 4);
Uart_SendHex4(val);
}
void Uart_SendHex20(u32 val)
{
Uart_SendHex4((u8)(val >> 16));
Uart_SendHex8((u8)(val >> 8));
Uart_SendHex8((u8)val);
}
void Uart_SendHex32(u32 val)
{
Uart_SendHex8((u8)(val >> 24));
Uart_SendHex8((u8)(val >> 16));
Uart_SendHex8((u8)(val >> 8));
Uart_SendHex8((u8)val);
}
void Uart_SendHex16(u16 val)
{
Uart_SendHex8((u8)(val >> 8));
Uart_SendHex8((u8)val);
}
void FormatHex(u32 val, char *buf)
{
u8 i;
buf[0] = 'A'; buf[1] = 'D'; buf[2] = 'D'; buf[3] = 'R'; buf[4] = ':';
buf[5] = ' '; buf[6] = '0'; buf[7] = 'x';
for (i = 0; i < 5; i++) {
u8 nibble = (val >> (4 * (4 - i))) & 0x0F;
if (nibble < 10)
buf[8 + i] = '0' + nibble;
else
buf[8 + i] = 'A' + (nibble - 10);
}
buf[13] = '\0';
}
void Enter_Low_Power_Sleep(void)
{
// 串口打印进入休眠提示
Uart_SendString("[SYS] Entering low power sleep...\r\n");
// 1. 熄灭 FCOB 双幻彩灯条
RGB_Send(0, 0, 0, 0, 0, 0);
// 2. 向屏幕发送 Display OFF (0x28) 彻底关闭像素发光显示
WriteComm(0x28);
Delay_ms(20);
// 3. AMOLED 屏控制器写入 Sleep In (0x10) 睡眠指令
WriteComm(0x10);
Delay_ms(20);
// 4. 拉低 SGM_CTRL 彻底断开 SGM3833 负压升压芯片的供电
SGM_CTRL = 0;
// 5. 将 AMOLED 控制总线所有 IO 拉低,以防由于 IO 寄生二极管对屏幕倒灌电导致常亮
LCD_CS = 0;
LCD_RST = 0;
LCD_DCX = 0;
LCD_SCL = 0;
LCD_SDI = 0;
// 6. 休眠状态下不能关闭接收芯片,保持 SHUT 为高电平 (1) 工作状态
SHUT = 1;
// 确保开启扩展寄存器访问 (EAXFR = 1),以便能正确配置端口唤醒使能扩展寄存器
P_SW2 |= 0x80;
// 7. 配置 P0.1, P0.2, P0.3 为 低电平触发 唤醒
P0IM1 |= 0x0E;
P0IM0 &= ~0x0E;
P0INTE |= 0x0E;
// 8. 配置 P2.6 (KEY_SOS) 为 低电平触发 唤醒
P2IM1 |= 0x40;
P2IM0 &= ~0x40;
P2INTE |= 0x40;
// ===== 配置端口掉电唤醒使能寄存器 PxWKUE =====
P0WKUE |= 0x0E; // 使使能 P0.1/P0.2/P0.3 掉电唤醒
P2WKUE |= 0x40; // 使使能 P2.6 掉电唤醒
// 9. 不允许外部中断 2 (RF_RX_DATA) 沿触发唤醒源
EX2 = 0;
// 10. 清除端口中断的悬挂/标志位,防误触
P0INTF = 0x00;
P2INTF = 0x00;
// 11. 关闭 Timer1 中断,保持 EA=1 让端口中断能唤醒
ET1 = 0;
EA = 1;
// 12. 写入 PCON 掉电模式位,使 MCU 进入深度 Power-Down 挂起状态
Uart_SendString("[SYS] Entering Power-Down mode...\r\n");
PCON |= 0x02; // PD = 1
_nop_();
_nop_();
_nop_();
_nop_();
// 13. 唤醒并执行完 ISR 后CPU 从这里继续执行
Wakeup_Restore();
}
void Wakeup_Restore(void)
{
u8 p0_flag;
u8 p2_flag;
// 确保 EAXFR=1 才能访问扩展 SFR (P0INTF/P2INTF/P0INTE/P2INTE)
EAXFR = 1;
// [诊断] 在清除标志位之前先读取,判断唤醒来源
p0_flag = P0INTF;
p2_flag = P2INTF;
// 1. 立即禁用端口中断和唤醒,防止继续触发
P0INTE = 0x00;
P2INTE = 0x00;
P0WKUE = 0x00; // 清除 P0 唤醒允许
P2WKUE = 0x00; // 清除 P2 唤醒允许
P0INTF = 0x00;
P2INTF = 0x00;
EX2 = 0;
// 1b. 关闭掉电唤醒定时器
WKTCH = 0x00;
WKTCL = 0x00;
// 2. 重新开启全局中断与 Timer1 中断
EA = 1;
ET1 = 1;
// [诊断] 打印唤醒来源
if (p0_flag & 0x0E) {
Uart_SendString("[WR] Woken by KEY P0 (P0INTF=0x");
Uart_SendHex8(p0_flag);
Uart_SendString(")\r\n");
} else if (p2_flag & 0x40) {
Uart_SendString("[WR] Woken by KEY P2 (P2INTF=0x");
Uart_SendHex8(p2_flag);
Uart_SendString(")\r\n");
} else {
Uart_SendString("[WR] Woken by TIMER (no key flag)\r\n");
}
// 3. 保持 SHUT 开启射频接收芯片工作
SHUT = 1;
// 4. 拉高 SGM_CTRL 并发送脉冲使能 SGM3833 升压
SGM_CTRL = 1;
SGM_SendPulse(27);
// 5. 等待负压电轨充分稳定
Delay_ms(200);
// 6. 重做屏控制器 RM69310 寄存器组的初始化
LCD_Init();
// 7. 重置闲置倒计时
inactivity_timer = 0;
// 8. 直接绘制时钟界面(绕过 AppManager 早期返回保护)
current_state = STATE_NORMAL;
UI_ShowClockPage(current_state, current_hour, current_min);
Uart_SendString("[SYS] Wakeup restored!\r\n");
}