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

123 lines
4.3 KiB
Markdown
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.

# 编码实现 - 系统核心控制与存储 (Docs/60_coding/mod-sys.md)
本文件对应系统控制与存储的具体编码实现细节。只包含手环代码实现。
## 1. 对应代码源文件
* [App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c) (系统主循环、定时器中断、IAP 存取)
* [App/config.h](file:///c:/workfile/105/stc32g12k128/App/config.h) (系统状态及数据结构定义)
## 2. 关键代码片段与逻辑实现
### 2.1 定时器 1 中断服务 (Timer1_Isr)
定时器初始化配置为 1ms`main.c` 中第 190~250 行左右实现。
`Timer1_Isr` 里,我们累加 `ms_tick`。当累加到 1000 时,重置 `ms_tick = 0`,自增 `current_sec`。若秒达 60则自增 `current_min` 并置位 `clock_updated = 1` 通知主循环在下一个周期重绘时钟画面。
### 2.2 IAP 读写细节
`main.c` 中通过 IAP 寄存器控制读写。
```c
void IAP_EraseSector(u16 addr) {
IAP_CMD = 3; // 扇区擦除
IAP_ADDRL = addr & 0xFF;
IAP_ADDRH = addr >> 8;
IAP_TRIG = 0x5A; // 触发
IAP_TRIG = 0xA5;
_nop_();
}
```
- 主动擦除与写字节前必须先调用使能,写完后调用 `IAP_Disable()` 避免误写入损坏配置。
- 数据库保存在末尾扇区 `0xFE0000`(大小为 512 字节)。
### 2.3 获取出厂唯一 ID (Get_Bracelet_Factory_ID)
从 STC32G 的内置 IDATA RAM 区域 `0xF1~0xF7` 处读取 7 字节唯一硬件 ID并将其转换为符合 EV1527 的 20 位地址码:
```c
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 传感器自定义名称拼接与写入 (Add_Sensor)
`Add_Sensor(u32 addr, u8 type, u8 suffix_idx)` 中,系统预设 7 类传感器名前缀:
```c
char *code sensor_prefixes[7] = {
"PORTE", "PIR", "FUMEE", "URGENCE", "GAZ", "INOND.", "VIBRA."
};
```
在写入时,手动拼接前缀和两位数字 `suffix_idx` 后缀:
```c
void Add_Sensor(u32 addr, u8 type, u8 suffix_idx) {
u8 slot = ...; // 检索空槽或匹配历史ID
char *prefix = sensor_prefixes[type];
u8 len = 0;
// 拷贝前缀
while (prefix[len] != '\0' && len < 11) {
sensor_list[slot].name_gbk[len] = prefix[len];
len++;
}
sensor_list[slot].name_gbk[len++] = ' ';
sensor_list[slot].name_gbk[len++] = '0' + (suffix_idx / 10);
sensor_list[slot].name_gbk[len++] = '0' + (suffix_idx % 10);
sensor_list[slot].name_gbk[len] = '\0';
Save_Database();
}
### 2.5 电池采样与充电状态读取实现
在系统模块中,通过硬件 ADC 通道 8 (P0.0) 和数字 I/O (P2.7) 采集电池状态:
1. **ADC 初始化 (ADC_Init)**
```c
void ADC_Init(void) {
P0M1 |= 0x01; P0M0 &= ~0x01; // P0.0 配置为高阻输入 (模拟输入模式)
ADCCFG = 0x2F; // RESFMT = 1 (右对齐), ADC 时钟配置为 SYSCLK / 2 / 16
ADC_CONTR |= 0x80; // 打开 ADC 电源 (ADC_POWER = 1)
}
```
2. **读取采样数据与电量百分比计算**
```c
u16 Get_ADC_Result(u8 channel) {
ADC_CONTR = 0x80 | channel; // 开启电源并选择通道
_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));
}
}
```
3. **充电状态读取**
```c
// P2.7 在 System_Init 时需配置为高阻输入以进行充电状态检测
bit Is_Charging(void) {
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 -->
```