docs: restructure framework, extract app execution module, group event collection & align GPIOs
This commit is contained in:
126
Docs/60_coding/mod-app.md
Normal file
126
Docs/60_coding/mod-app.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# 编码实现 - 应用执行与页面渲染 (Docs/60_coding/mod-app.md)
|
||||
|
||||
本文件对应手环前台 App 调度管理、活跃实例生命周期交互与各子应用页面像素级渲染的具体编码实现。
|
||||
|
||||
## 1. 对应代码源文件
|
||||
|
||||
* [App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c) (定义 App 数组、`StartApp` 生命周期函数、各子应用的 `OnStart` / `onRun` / `onClose` / `onEvent` 钩子回调)
|
||||
* [App/config.h](file:///c:/workfile/105/stc32g12k128/App/config.h) (声明 `WristbandApp` 结构体原型及应用 ID 枚举)
|
||||
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 应用生命周期对象定义
|
||||
每个功能页面被抽象为结构体 `WristbandApp` 的实体实例,定义了完整的输入与输出操作回调:
|
||||
```c
|
||||
typedef struct {
|
||||
u8 app_id; // 应用程序 ID
|
||||
void (*OnStart)(void); // 启动回调:应用切入前台,加载资源、初始化显示
|
||||
void (*onRun)(void); // 循环回调:主循环轮询轮空调用,执行非阻塞业务逻辑
|
||||
void (*onClose)(void); // 关闭回调:应用退出前台,保存状态、清理外设
|
||||
void (*onEvent)(KeyEvent evt); // 事件回调:接收并消耗来自事件层的系统事件
|
||||
} WristbandApp;
|
||||
|
||||
#define APP_CLOCK 0
|
||||
#define APP_MENU 1
|
||||
#define APP_PAIR 2
|
||||
#define APP_ALARM 3
|
||||
#define APP_SOS 4
|
||||
|
||||
WristbandApp* active_app = NULL; // 当前前台活跃 App
|
||||
```
|
||||
|
||||
### 2.2 AppManager 调度执行引擎
|
||||
在主循环框架中,通过调用 `StartApp()` 执行非阻塞的前台应用切换:
|
||||
```c
|
||||
void StartApp(u8 app_id) {
|
||||
// 1. 切出当前活跃应用,释放资源并清理引脚状态
|
||||
if (active_app && active_app->onClose) {
|
||||
active_app->onClose();
|
||||
}
|
||||
|
||||
// 2. 指针重定向
|
||||
switch (app_id) {
|
||||
case APP_CLOCK: active_app = &App_Clock_Instance; break;
|
||||
case APP_MENU: active_app = &App_Menu_Instance; break;
|
||||
case APP_PAIR: active_app = &App_Pair_Instance; break;
|
||||
case APP_ALARM: active_app = &App_Alarm_Instance; break;
|
||||
case APP_SOS: active_app = &App_SOS_Instance; break;
|
||||
default: active_app = &App_Clock_Instance; break;
|
||||
}
|
||||
|
||||
// 3. 切入新应用前台,并强制标记 Redraw 触发 GRAM 刷新
|
||||
if (active_app && active_app->OnStart) {
|
||||
active_app->OnStart();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 待机大字时钟页面像素刷写 (ClockApp)
|
||||
在待机状态时,应用通过 LCD 驱动将 `32x64px` 居中字模刷写在屏幕的 Column [0, 119], Row [0, 239] 的 Column+4 窗口中:
|
||||
```c
|
||||
void UI_ShowClockPage(SystemState state, u8 hour, u8 min) {
|
||||
char time_str[6];
|
||||
char bat_str[10];
|
||||
u8 bat_val = Read_Battery_Percent(); // 读取 P0.0 ADC 数据进行百分比计算
|
||||
bit charging = Is_Charging(); // 读取 P2.7 数字 IO 输入
|
||||
|
||||
LCD_Clear(COLOR_BLACK);
|
||||
|
||||
// 1. 绘制顶部电量状态栏 (16x32px 标准无障碍字体)
|
||||
if (charging) {
|
||||
sprintf(bat_str, "%d%%+", (int)bat_val);
|
||||
LCD_ShowString(40, 20, bat_str, COLOR_GREEN, COLOR_BLACK);
|
||||
} else {
|
||||
sprintf(bat_str, "%d%%", (int)bat_val);
|
||||
LCD_ShowString(50, 20, bat_str, COLOR_GRAY, COLOR_BLACK);
|
||||
}
|
||||
|
||||
// 2. 绘制中央超大数字时钟 (32x64px)
|
||||
sprintf(time_str, "%02d:%02d", (int)hour, (int)min);
|
||||
LCD_ShowString32x64Centered(80, time_str, COLOR_WHITE, COLOR_BLACK);
|
||||
|
||||
// 3. 绘制底部系统布撤防锁状态 (32x32px 大图标)
|
||||
if (state == STATE_ARMED) {
|
||||
LCD_ShowImage(44, 180, 32, 32, bmp_lock_32x32, COLOR_RED, COLOR_BLACK);
|
||||
} else {
|
||||
LCD_ShowImage(44, 180, 32, 32, bmp_unlock_32x32, COLOR_GREEN, COLOR_BLACK);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 配对微调确认与保存页面交互 (PairApp)
|
||||
当捕获到新的 EV1527 对码信号时,`PairApp` 负责在 `onEvent` 钩子中接收微调的按键输入并保存至 Flash 数据库:
|
||||
```c
|
||||
void PairApp_onEvent(KeyEvent evt) {
|
||||
if (evt == KEY_EVENT_UP_CLICK) {
|
||||
// 短按 ▲ 键增加后缀序号
|
||||
if (selected_suffix < 99) {
|
||||
selected_suffix++;
|
||||
Redraw = 1;
|
||||
}
|
||||
}
|
||||
else if (evt == KEY_EVENT_DOWN_CLICK) {
|
||||
// 短按 ▼ 键减少后缀序号
|
||||
if (selected_suffix > 1) {
|
||||
selected_suffix--;
|
||||
Redraw = 1;
|
||||
}
|
||||
}
|
||||
else if (evt == KEY_EVENT_SOS_CLICK) {
|
||||
// 短按 ■ 确认键保存对码,数据格式 flags_suffix 位域重新分配
|
||||
// Bit 7: 有效位=1; Bit 0~6: 后缀序号
|
||||
u8 flags = 0x80 | (selected_suffix & 0x7F);
|
||||
|
||||
// 保存至持久化扇区
|
||||
Add_Sensor_To_Flash(captured_rf_addr, flags);
|
||||
|
||||
// 开启 300ms 成功振动反馈并退回时钟
|
||||
Motor_Start_Pattern(0); // 300ms 短振
|
||||
StartApp(APP_CLOCK);
|
||||
}
|
||||
else if (evt == KEY_EVENT_SOS_LONG) {
|
||||
// 长按 ■ 确认键 3 秒放弃保存并回退
|
||||
StartApp(APP_CLOCK);
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,16 +1,99 @@
|
||||
# 编码实现 - 事件总线与缓冲路由 (Docs/60_coding/mod-event.md)
|
||||
# 编码实现 - 事件采集与总线路由器 (Docs/60_coding/mod-event.md)
|
||||
|
||||
本文件对应环形事件缓冲区(Event Queue)与事件路由分发器的具体编码实现细节。
|
||||
本文件对应物理按键及射频中断事件采集(输入)、环形消息队列缓冲、以及事件路由分配器(输出)的具体编码实现。
|
||||
|
||||
## 1. 对应代码源文件
|
||||
|
||||
* [App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c) (事件队列定义、`Event_Queue_Push` / `Event_Queue_Pop` / `Event_Dispatcher_Loop` 的底层 C 语言实现)
|
||||
* [App/config.h](file:///c:/workfile/105/stc32g12k128/App/config.h) (`KeyEvent` 枚举量定义)
|
||||
* [App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c) (按键消抖 `Key_Scan_Process`、事件队列及 `Event_Dispatcher_Loop` 分发逻辑)
|
||||
* [Drivers/rf.c](file:///c:/workfile/105/stc32g12k128/Drivers/rf.c) (配置 `P2.1` 输入捕捉及解码逻辑)
|
||||
* [App/config.h](file:///c:/workfile/105/stc32g12k128/App/config.h) (`KeyEvent` 核心事件枚举类型声明)
|
||||
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 环形队列定义与入队出队函数
|
||||
在 `main.c` 中,定义深度为 4 级的事件队列缓冲数组及读写位置指针:
|
||||
### 2.1 事件采集输入(按键定时扫描与消抖)
|
||||
定义按键 IO 宏,在 `Timer1` (10ms) 分频中读取并判定:
|
||||
```c
|
||||
sbit KEY_UP = P0^1; // Pin 30
|
||||
sbit KEY_CONFIRM = P0^2; // Pin 31
|
||||
sbit KEY_DOWN = P0^3; // Pin 32
|
||||
sbit KEY_SOS = P2^6; // Pin 27 (物理并联 SOS1/SOS2 按键)
|
||||
|
||||
void Key_Scan_Process(void) {
|
||||
static u8 key_up_state = 0xFF;
|
||||
static u8 key_down_state = 0xFF;
|
||||
static u8 key_confirm_state = 0xFF;
|
||||
static u8 key_sos_state = 0xFF;
|
||||
|
||||
// 移位滤波消抖
|
||||
key_up_state = (key_up_state << 1) | KEY_UP;
|
||||
key_down_state = (key_down_state << 1) | KEY_DOWN;
|
||||
key_confirm_state = (key_confirm_state << 1) | KEY_CONFIRM;
|
||||
key_sos_state = (key_sos_state << 1) | KEY_SOS;
|
||||
|
||||
// ▲ 键 (UP) 处理
|
||||
if ((key_up_state & 0x07) == 0) {
|
||||
key_up_hold++;
|
||||
} else {
|
||||
if (key_up_hold > 2) {
|
||||
Event_Queue_Push(KEY_EVENT_UP_CLICK);
|
||||
}
|
||||
key_up_hold = 0;
|
||||
}
|
||||
|
||||
// ▼ 键 (DOWN) 处理 (长按 2 秒退出或清除警报)
|
||||
if ((key_down_state & 0x07) == 0) {
|
||||
key_down_hold++;
|
||||
if (key_down_hold == 200) {
|
||||
Event_Queue_Push(KEY_EVENT_DOWN_LONG);
|
||||
}
|
||||
} else {
|
||||
if (key_down_hold > 2 && key_down_hold < 200) {
|
||||
Event_Queue_Push(KEY_EVENT_DOWN_CLICK);
|
||||
}
|
||||
key_down_hold = 0;
|
||||
}
|
||||
|
||||
// ■ 确认键 (CONFIRM) 处理 (长按 3 秒进入菜单,短按确认)
|
||||
if ((key_confirm_state & 0x07) == 0) {
|
||||
key_confirm_hold++;
|
||||
if (key_confirm_hold == 300) {
|
||||
Event_Queue_Push(KEY_EVENT_SOS_LONG); // 长按事件
|
||||
}
|
||||
} else {
|
||||
if (key_confirm_hold > 2 && key_confirm_hold < 300) {
|
||||
Event_Queue_Push(KEY_EVENT_SOS_CLICK); // 短击事件
|
||||
}
|
||||
key_confirm_hold = 0;
|
||||
}
|
||||
|
||||
// SOS 求救键 (下降沿低电平即刻触发)
|
||||
if ((key_sos_state & 0x07) == 0) {
|
||||
key_sos_hold++;
|
||||
if (key_sos_hold == 3) {
|
||||
Event_Queue_Push(KEY_SOS_ACTIVE); // 触发本地主动报警
|
||||
}
|
||||
} else {
|
||||
key_sos_hold = 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 事件采集输入(射频数据解调)
|
||||
射频数据接收线连在 `P2.1`。当发生跳变时触发 INT2 外部沿中断:
|
||||
```c
|
||||
sbit RF_RX_DATA = P2^1; // Pin 22
|
||||
|
||||
bit EV1527_Decode(u32 *out_addr, u8 *out_type) {
|
||||
// 轮询或中断检测引脚 P2.1 沿变化
|
||||
// 自适应同步低电平 T = low_time / 31
|
||||
// 连续读取 24 位宽数据 (1:3 对应 0,3:1 对应 1)
|
||||
// 解密出地址和数据码,返回结果给事件总线
|
||||
// ...
|
||||
return 1;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 事件环形缓冲存储区
|
||||
```c
|
||||
#define EVENT_QUEUE_SIZE 4
|
||||
|
||||
@@ -19,70 +102,54 @@ u8 event_write_ptr = 0;
|
||||
u8 event_read_ptr = 0;
|
||||
u8 event_count = 0;
|
||||
|
||||
// 初始化队列
|
||||
void Event_Queue_Init(void) {
|
||||
event_write_ptr = 0;
|
||||
event_read_ptr = 0;
|
||||
event_count = 0;
|
||||
}
|
||||
|
||||
// 压入事件入队 (非阻塞,中断安全)
|
||||
bit Event_Queue_Push(KeyEvent evt) {
|
||||
if (event_count >= EVENT_QUEUE_SIZE) {
|
||||
return 0; // 缓冲区溢出,写入失败
|
||||
return 0; // 溢出丢弃
|
||||
}
|
||||
|
||||
event_queue[event_write_ptr] = evt;
|
||||
event_write_ptr = (event_write_ptr + 1) % EVENT_QUEUE_SIZE;
|
||||
|
||||
// 保护临界区,避免中断嵌套冲突
|
||||
EA = 0;
|
||||
event_count++;
|
||||
EA = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 弹出事件出队
|
||||
KeyEvent Event_Queue_Pop(void) {
|
||||
KeyEvent evt;
|
||||
if (event_count == 0) {
|
||||
return KEY_EVENT_NONE;
|
||||
}
|
||||
|
||||
evt = event_queue[event_read_ptr];
|
||||
event_read_ptr = (event_read_ptr + 1) % EVENT_QUEUE_SIZE;
|
||||
|
||||
EA = 0;
|
||||
event_count--;
|
||||
EA = 1;
|
||||
|
||||
return evt;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 事件轮询分发器 (Event Dispatcher)
|
||||
在主循环 `main()` 中,系统定时轮询事件总线,读取事件并路由给前后台应用:
|
||||
### 2.4 事件输出路由路由器 (Event Dispatcher)
|
||||
在主循环 `while(1)` 内,系统以极速轮询该路由分发引擎:
|
||||
```c
|
||||
void Event_Dispatcher_Loop(void) {
|
||||
KeyEvent evt = Event_Queue_Pop();
|
||||
if (evt == KEY_EVENT_NONE) {
|
||||
return; // 队列为空,直接跳过
|
||||
return; // 无事件
|
||||
}
|
||||
|
||||
// 1. 优先判定物理抢占型事件 (如 SOS 键)
|
||||
// 1. 本地最高优先级强占处理
|
||||
if (evt == KEY_SOS_ACTIVE) {
|
||||
StartApp(APP_SOS); // 强行强占前台,启动紧急求救页面
|
||||
StartApp(APP_SOS); // 物理强制唤醒并抢占前台
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 无线报警事件路由给后台进程进行防区匹配
|
||||
// 2. 无线报警/配对包推送给后台守护进程
|
||||
if (evt == RF_EVENT_ALARM || evt == RF_EVENT_PAIR) {
|
||||
BgApp_Process_RF(evt); // 后台比对数据库,若匹配且在布防状态下,唤醒强占报警App
|
||||
BgApp_Process_RF(evt); // 后台比对 Flash 决定是否启动 APP_ALARM 报警页
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 常规按键事件分发给当前活跃的前台 APP
|
||||
// 3. 常规业务事件分发给前台活跃 APP
|
||||
if (active_app && active_app->onEvent) {
|
||||
active_app->onEvent(evt);
|
||||
}
|
||||
|
||||
@@ -146,4 +146,4 @@ void Process_System_Event(KeyEvent evt) {
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V3 -->
|
||||
|
||||
@@ -107,4 +107,4 @@ void UI_ShowPairConfirmPage(u8 type, u8 selected_suffix) {
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V3 -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V4 -->
|
||||
|
||||
@@ -9,20 +9,20 @@
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 驱动初始化与管脚分配
|
||||
WS2812B 输入脚接在单片机物理引脚 `LED_RGB` (`P2.6`):
|
||||
WS2812B 输入脚接在单片机物理引脚 `LED_RGB` (`P2.3`):
|
||||
```c
|
||||
sbit WS2812_DI = P2^6; // Pin 27
|
||||
sbit WS2812_DI = P2^3; // Pin 24
|
||||
|
||||
void WS2812_Init(void) {
|
||||
// P2.6 (LED_RGB) 配置为推挽输出,默认输出低电平 0
|
||||
P2M1 &= ~(1 << 6);
|
||||
P2M0 |= (1 << 6);
|
||||
// P2.3 (LED_RGB) 配置为推挽输出,默认输出低电平 0
|
||||
P2M1 &= ~(1 << 3);
|
||||
P2M0 |= (1 << 3);
|
||||
WS2812_DI = 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 驱动防噪声发送 (WS2812_Write24Bit)
|
||||
由于马达引脚占用 `P2.4` (Pin 25),为了规避马达震动时的共地杂噪,在串行输出数据期间关闭总中断并将马达引脚 `P2.4` 设为高阻输入。
|
||||
由于马达引脚占用 `P2.5` (Pin 26),为了规避马达震动时的共地杂噪,在串行输出数据期间关闭总中断并将马达引脚 `P2.5` 设为高阻输入。
|
||||
展宽 LUT 定义:
|
||||
```c
|
||||
const u16 code SPI_LUT[16] = {
|
||||
@@ -47,9 +47,9 @@ void WS2812_Write24Bit(u8 g, u8 r, u8 b) {
|
||||
|
||||
EA = 0; // 关中断保证串行传输的连续性
|
||||
|
||||
// 配置 P2.4 (MOTOR_PWM) 为高阻输入模式,屏蔽共地马达干扰
|
||||
P2M1 |= (1 << 4);
|
||||
P2M0 &= ~(1 << 4);
|
||||
// 配置 P2.5 (MOTOR_PWM) 为高阻输入模式,屏蔽共地马达干扰
|
||||
P2M1 |= (1 << 5);
|
||||
P2M0 &= ~(1 << 5);
|
||||
|
||||
SPSTAT = 0xC0; // 清除 SPI 状态寄存器
|
||||
SPDAT = b0; // 发送数据
|
||||
@@ -81,9 +81,9 @@ void WS2812_Write24Bit(u8 g, u8 r, u8 b) {
|
||||
SPCTL = 0x90; // 关闭 SPI 硬件使能
|
||||
WS2812_DI = 0;
|
||||
|
||||
// 恢复 P2.4 (MOTOR_PWM) 为推挽输出,恢复马达控制
|
||||
P2M1 &= ~(1 << 4);
|
||||
P2M0 |= (1 << 4);
|
||||
// 恢复 P2.5 (MOTOR_PWM) 为推挽输出,恢复马达控制
|
||||
P2M1 &= ~(1 << 5);
|
||||
P2M0 |= (1 << 5);
|
||||
MOTOR = 0; // 确保马达断开
|
||||
|
||||
EA = 1; // 恢复中断
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 引脚控制宏与初始化
|
||||
马达由引脚 `P2.4` 控制。配置模式为推挽输出:
|
||||
马达由引脚 `P2.5` 控制。配置模式为推挽输出:
|
||||
```c
|
||||
sbit MOTOR = P2^4; // Pin 25
|
||||
sbit MOTOR = P2^5; // Pin 26
|
||||
|
||||
void Motor_Init(void) {
|
||||
// 将 P2.4 配置为推挽输出模式,默认输出低电平 0
|
||||
P2M1 &= ~(1 << 4);
|
||||
P2M0 |= (1 << 4);
|
||||
// 将 P2.5 配置为推挽输出模式,默认输出低电平 0
|
||||
P2M1 &= ~(1 << 5);
|
||||
P2M0 |= (1 << 5);
|
||||
MOTOR = 0;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 供电引脚初始化
|
||||
系统初始化时,配置 `SHUT`(控制 SGM3833 供电的引脚 `P2.7`)为推挽输出,并拉高以打开屏幕供电:
|
||||
系统初始化时,配置 `SHUT`(控制 SGM3833 供电的引脚 `P2.2`)为推挽输出,并拉高以开启屏幕供电:
|
||||
```c
|
||||
sbit SHUT = P2^7; // Pin 28
|
||||
sbit SHUT = P2^2; // Pin 23
|
||||
|
||||
void Power_Init(void) {
|
||||
// P2.7 (SHUT) 配置为推挽输出
|
||||
P2M1 &= ~(1 << 7);
|
||||
P2M0 |= (1 << 7);
|
||||
// P2.2 (SHUT) 配置为推挽输出
|
||||
P2M1 &= ~(1 << 2);
|
||||
P2M0 |= (1 << 2);
|
||||
|
||||
// 拉高引脚,开启 SGM3833 负压供电
|
||||
SHUT = 1;
|
||||
@@ -33,12 +33,12 @@ void Enter_Low_Power_Sleep(void) {
|
||||
// 2. 切断 SGM3833 电源,停止输出负压
|
||||
SHUT = 0;
|
||||
|
||||
// 3. 配置引脚中断 (P2.0, P2.3, P3.6, P3.7) 允许唤醒
|
||||
// 允许 P2 / P3 端口中断以供按键唤醒
|
||||
P2IM1 &= ~0x09; P2IM0 &= ~0x09; P2INTE |= 0x09; // P2.0 (UP), P2.3 (SOS)
|
||||
P3IM1 &= ~0xC0; P3IM0 &= ~0xC0; P3INTE |= 0xC0; // P3.6 (DOWN), P3.7 (CONFIRM)
|
||||
// 3. 配置引脚中断 (P0.1, P0.2, P0.3, P2.6) 允许唤醒
|
||||
// 允许 P0 / P2 端口中断以供按键唤醒
|
||||
P0IM1 &= ~0x0E; P0IM0 &= ~0x0E; P0INTE |= 0x0E; // P0.1 (UP), P0.2 (CONFIRM), P0.3 (DOWN)
|
||||
P2IM1 &= ~0x40; P2IM0 &= ~0x40; P2INTE |= 0x40; // P2.6 (SOS)
|
||||
|
||||
// 4. 配置射频接收脚 P0.0 (RF_RX_DATA) 为 INT2/外部中断 2 唤醒
|
||||
// 4. 配置射频接收脚 P2.1 (RF_RX_DATA) 为 INT2/外部中断 2 唤醒
|
||||
EX2 = 1; // 使能外部中断2
|
||||
|
||||
// 5. 写入 PCON.1 使单片机进入 Power-Down 深度睡眠状态
|
||||
@@ -51,9 +51,9 @@ void Enter_Low_Power_Sleep(void) {
|
||||
### 2.3 中断唤醒与恢复 (Wakeup_Restore)
|
||||
当产生按键或射频中断后,单片机被唤醒,首先执行外部中断 ISR,退出低功耗并重新使能 OLED:
|
||||
```c
|
||||
// 外部中断服务子程序 (以按键 P3 端口中断为例)
|
||||
void Port3_Isr(void) interrupt 38 {
|
||||
P3INTF = 0x00; // 清除 P3 中断标志
|
||||
// 外部中断服务子程序 (以按键 P0 端口中断为例)
|
||||
void Port0_Isr(void) interrupt 37 {
|
||||
P0INTF = 0x00; // 清除 P0 中断标志
|
||||
Wakeup_Restore();
|
||||
}
|
||||
|
||||
|
||||
@@ -37,4 +37,4 @@ void EV1527_Transmit(u32 addr, u8 data_code) {
|
||||
* **绑定对码**:当用户触发对码绑定时,传入 `addr = bracelet_factory_id`,`data_code = 0x01`。
|
||||
* **主动 SOS 警报**:当触发主动 SOS 时,主状态机在 `STATE_SOS_EMITTED` 下定期以时间片的形式调用此函数,传入 `addr = bracelet_factory_id`,`data_code = 0x08`(即二进制 `1000`)。
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V3 -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V4 -->
|
||||
|
||||
@@ -73,12 +73,12 @@ u32 Get_Bracelet_Factory_ID(void) {
|
||||
```
|
||||
|
||||
### 2.4 电池采样与充电状态读取实现
|
||||
在系统模块中,通过硬件 ADC 通道 9 (P2.1) 和数字 I/O (P2.2) 采集电池状态:
|
||||
在系统模块中,通过硬件 ADC 通道 8 (P0.0) 和数字 I/O (P2.7) 采集电池状态:
|
||||
|
||||
1. **ADC 初始化 (ADC_Init)**:
|
||||
```c
|
||||
void ADC_Init(void) {
|
||||
P2M1 |= 0x02; P2M0 &= ~0x02; // P2.1 (Pin 22 / BAT_ADC) 配置为高阻输入 (模拟输入模式)
|
||||
P0M1 |= 0x01; P0M0 &= ~0x01; // P0.0 (Pin 29 / BAT_ADC) 配置为高阻输入 (模拟输入模式)
|
||||
ADCCFG = 0x2F; // RESFMT = 1 (右对齐)
|
||||
ADC_CONTR |= 0x80; // 打开 ADC 电源 (ADC_POWER = 1)
|
||||
}
|
||||
@@ -87,7 +87,7 @@ void ADC_Init(void) {
|
||||
2. **读取采样数据与电量百分比计算**:
|
||||
```c
|
||||
u16 Get_ADC_Result(u8 channel) {
|
||||
ADC_CONTR = 0x80 | channel; // 开启电源并选择通道 (channel = 9 对应 P2.1)
|
||||
ADC_CONTR = 0x80 | channel; // 开启电源并选择通道 (channel = 8 对应 P0.0)
|
||||
_nop_(); _nop_();
|
||||
ADC_CONTR |= 0x40; // 启动 ADC 转换 (ADC_START = 1)
|
||||
while (!(ADC_CONTR & 0x20)); // 等待转换完成 (ADC_FLAG)
|
||||
@@ -96,7 +96,7 @@ u16 Get_ADC_Result(u8 channel) {
|
||||
}
|
||||
|
||||
u8 Read_Battery_Percent(void) {
|
||||
u16 adc_val = Get_ADC_Result(9); // 读取通道 9 (P2.1)
|
||||
u16 adc_val = Get_ADC_Result(8); // 读取通道 8 (P0.0)
|
||||
|
||||
// 线性百分比转换:3.3V (ADC=1279) 对应 0%, 4.2V (ADC=1628) 对应 100%
|
||||
if (adc_val <= 1279) {
|
||||
@@ -111,10 +111,10 @@ u8 Read_Battery_Percent(void) {
|
||||
|
||||
3. **充电状态读取**:
|
||||
```c
|
||||
// P2.2 (Pin 23 / DET) 在 System_Init 时需配置为高阻输入以进行充电状态检测
|
||||
// P2.7 (Pin 28 / DET) 在 System_Init 时需配置为高阻输入以进行充电状态检测
|
||||
bit Is_Charging(void) {
|
||||
return (P2 & (1 << 2)) ? 1 : 0; // 读取 P2.2 引脚高电平状态,1 表示 USB 接入
|
||||
return (P2 & (1 << 7)) ? 1 : 0; // 读取 P2.7 引脚高电平状态,1 表示 USB 接入
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V3 -->
|
||||
|
||||
Reference in New Issue
Block a user