Adds KEY_EVENT_SECOND_TICK, generated once per real second from Clock_IncMS() via a new second_tick_flag and pushed through the normal event queue, so every foreground App's onEvent() receives it and decides independently whether to act. Removes the old global inactivity_timer (60s sleep from anywhere) entirely. HomeApp now accumulates its own idle-second counter and sleeps after 10s idle specifically while on the home screen; MenuApp's existing 10s auto-close is converted from onRun() polling to the same tick+reset pattern for consistency. Any non-tick key event resets each app's own counter to 0.
510 lines
16 KiB
C
510 lines
16 KiB
C
#include "system.h"
|
||
#include "rgb.h"
|
||
#include "ui.h"
|
||
#include "clock.h"
|
||
#include "../Drivers/lcd.h"
|
||
#include "../Drivers/rf.h"
|
||
#include "../Drivers/adc.h"
|
||
#include "../Drivers/pcf8563.h"
|
||
#include "intrins.h"
|
||
|
||
// 引用 main.c 中的全局唤醒与运行状态变量
|
||
extern volatile u8 p0_wakeup_flag;
|
||
extern volatile u8 p2_wakeup_flag;
|
||
extern volatile u8 p3_wakeup_flag;
|
||
extern volatile u8 rf_wakeup_flag;
|
||
|
||
/**
|
||
* @brief 系统 GPIO 端口模式初始化
|
||
* @details 配置各引脚的推挽输出、高阻输入及准双向模式,建立系统初始电气环境。
|
||
*/
|
||
void GPIO_Init(void)
|
||
{
|
||
// 使能访问扩展特殊功能寄存器 XSFR
|
||
EAXFR = 1;
|
||
|
||
// 1. 配置 PWR_HOLD (P0.0) 为推挽输出模式 (P0M1 bit0=0, P0M0 bit0=1)
|
||
P0M1 &= ~(1 << 0);
|
||
P0M0 |= (1 << 0);
|
||
PWR_HOLD = 1; // 上电第一时间拉高,锁存电源保持供电
|
||
|
||
// 2. 配置 KEY_UP (P0.1), KEY_CONFIRM (P0.2) 为高阻输入/带上拉准双向
|
||
P0M1 &= ~((1 << 1) | (1 << 2));
|
||
P0M0 &= ~((1 << 1) | (1 << 2));
|
||
KEY_UP = 1;
|
||
KEY_CONFIRM = 1;
|
||
|
||
// 3. 初始化 STC32G 硬件 ADC 模块 (其中自动配置 P0.3 和 P1.3 为高阻输入模式)
|
||
ADC_Init();
|
||
|
||
// 4. 配置 PCF8563 I2C 管脚 P3.2 (SCL) 与 P3.3 (SDA) 为准双向口模式,并开上拉
|
||
P3M1 &= ~((1 << 2) | (1 << 3));
|
||
P3M0 &= ~((1 << 2) | (1 << 3));
|
||
P3PU |= (1 << 2) | (1 << 3); // 开启 P3.2 与 P3.3 的内部 4.7K 上拉电阻
|
||
RTC_SCL = 1;
|
||
RTC_SDA = 1;
|
||
|
||
// 5. 配置推挽输出引脚:
|
||
// MOTOR (P2.5), RGB_DIN (P2.3) -> P2M1 bit5,3=0; P2M0 bit5,3=1
|
||
P2M1 &= ~((1 << 5) | (1 << 3));
|
||
P2M0 |= ((1 << 5) | (1 << 3));
|
||
MOTOR = 0;
|
||
RGB_DIN = 0; // P2.3 初始拉低,防止上电期间 WS2812B 误触发
|
||
|
||
// 配置 KEY_SOS (P2.6) 为带上拉准双向口模式以确保输入稳定
|
||
P2M1 &= ~(1 << 6);
|
||
P2M0 &= ~(1 << 6);
|
||
KEY_SOS = 1;
|
||
(*(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) 置为推挽输出
|
||
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));
|
||
SGM_CTRL = 1; // 背光从上电第一刻起就确定关闭 (LEDA=1),避免推挽模式生效前电平不确定造成瞬间闪烁
|
||
|
||
|
||
|
||
// SHUT (P3.5) 射频/外设开启使能脚置为推挽输出
|
||
P3M1 &= ~(1 << 5);
|
||
P3M0 |= (1 << 5);
|
||
SHUT = 0; // 低电平开启工作
|
||
|
||
// 7. 配置 CHRG_DET (P1.2) 为高阻输入模式,适配 DET 模拟 ADC 通道 2
|
||
// 由于是精密模拟电平检测,切勿开启引脚内部上拉电阻
|
||
P1M1 |= (1 << 2);
|
||
P1M0 &= ~(1 << 2);
|
||
// P1PU 在扩展 XSFR 空间中没有被定义的话可以用 P1 端口寄存器或者是关闭上拉,
|
||
// STC32G 中端口上拉寄存器是 P1PU (FE11H),因为是 XSFR 我们在 config.h 里有 extern 或直接操作
|
||
// 扩展 XSFR P1PU 地址为 0xFE11
|
||
(*(unsigned char volatile xdata *)0xFE11) &= ~(1 << 2);
|
||
}
|
||
|
||
/**
|
||
* @brief 初始化 UART1 串口通信
|
||
* @details 设定波特率 115200 (使用 Timer2 作为发生器,24.0MHz 晶振)
|
||
*/
|
||
void Uart1_Init(void)
|
||
{
|
||
SCON = 0x50; // 8 位数据, 可变波特率
|
||
AUXR |= 0x01; // 串口 1 选择 Timer2 做波特率发生器
|
||
AUXR |= 0x04; // Timer2 时钟为 1T 模式
|
||
T2L = 0xCC; // 24MHz / 115200 = 208 (0xD0), 对应 reload 值 65536 - 52 = 0xFFCC
|
||
T2H = 0xFF;
|
||
AUXR |= 0x10; // 启动 Timer2 运行
|
||
}
|
||
|
||
/**
|
||
* @brief 串口 1 发送单字节数据
|
||
* @param dat 待发送的字节
|
||
*/
|
||
void Uart_SendByte(u8 dat)
|
||
{
|
||
SBUF = dat;
|
||
while (!TI);
|
||
TI = 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 串口 1 发送字符串
|
||
* @param s 字符串指针
|
||
*/
|
||
void Uart_SendString(char *s)
|
||
{
|
||
while (*s) {
|
||
Uart_SendByte(*s++);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 串口 1 非阻塞接收字符
|
||
* @return char 接收到的字符,若无接收数据则返回 '\0'
|
||
*/
|
||
char Uart_RxChar(void)
|
||
{
|
||
if (RI) {
|
||
RI = 0;
|
||
return SBUF;
|
||
}
|
||
return '\0';
|
||
}
|
||
|
||
/**
|
||
* @brief 阻塞毫秒延时
|
||
* @param ms 毫秒数
|
||
*/
|
||
void Delay_ms(u16 ms)
|
||
{
|
||
u16 i, j;
|
||
for (i = 0; i < ms; i++) {
|
||
for (j = 0; j < 2000; j++) {
|
||
_nop_();
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 阻塞微秒延时
|
||
* @param us 微秒数
|
||
*/
|
||
void Delay_us(u16 us)
|
||
{
|
||
u16 i;
|
||
for (i = 0; i < us; i++) {
|
||
_nop_(); _nop_(); _nop_(); _nop_();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 系统开机上电硬件自检函数
|
||
* @details 检测 PWR_HOLD 锁存状态、ADC 采样基准与串口通讯,输出完整自检 report
|
||
*/
|
||
void Self_Test(void)
|
||
{
|
||
u16 key_down_adc;
|
||
u16 vbat_mv;
|
||
u16 batt_adc_raw;
|
||
u8 percent;
|
||
|
||
Uart_SendString("\r\n========================================\r\n");
|
||
Uart_SendString("[SELF-TEST] System Power-On Self Test...\r\n");
|
||
|
||
// 执行 I2C 总线器件扫描,查找 RTC 是否物理响应
|
||
PCF8563_ScanDiagnostic();
|
||
|
||
// 0. I2C 硬件脚电平诊断测试 (验证引脚可控性与短路)
|
||
Uart_SendString("[I2C-DIAG] Pin Level Test Starting...\r\n");
|
||
// 写 1 测试 (准双向+上拉)
|
||
P3M1 &= ~((1 << 2) | (1 << 3));
|
||
P3M0 &= ~((1 << 2) | (1 << 3));
|
||
P3PU |= (1 << 2) | (1 << 3);
|
||
RTC_SCL = 1;
|
||
RTC_SDA = 1;
|
||
Delay_ms(10);
|
||
Uart_SendString("[I2C-DIAG] Write SCL=1, SDA=1 -> Real Level: SCL=");
|
||
Uart_SendByte((u8)(RTC_SCL ? '1' : '0'));
|
||
Uart_SendString(", SDA=");
|
||
Uart_SendByte((u8)(RTC_SDA ? '1' : '0'));
|
||
Uart_SendString("\r\n");
|
||
|
||
// 写 0 测试
|
||
RTC_SCL = 0;
|
||
RTC_SDA = 0;
|
||
Delay_ms(10);
|
||
Uart_SendString("[I2C-DIAG] Write SCL=0, SDA=0 -> Real Level: SCL=");
|
||
Uart_SendByte((u8)(RTC_SCL ? '1' : '0'));
|
||
Uart_SendString(", SDA=");
|
||
Uart_SendByte((u8)(RTC_SDA ? '1' : '0'));
|
||
Uart_SendString("\r\n");
|
||
|
||
// 0.2 执行 RTC 底层单独试读测试
|
||
PCF8563_TryReadDiagnostic();
|
||
|
||
// 1. 验证 PWR_HOLD 锁存状态
|
||
if (PWR_HOLD == 1) {
|
||
Uart_SendString("[SELF-TEST] PWR_HOLD Pin State: HIGH [OK]\r\n");
|
||
} else {
|
||
Uart_SendString("[SELF-TEST] PWR_HOLD Pin State: LOW [FAIL]\r\n");
|
||
}
|
||
|
||
// 2. 检查 P0.3 ADC 按键基准常态电压
|
||
key_down_adc = ADC_ReadFiltered(ADC_CHANNEL_KEY_DOWN);
|
||
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 / 100) % 10));
|
||
Uart_SendByte((u8)('0' + (key_down_adc / 10) % 10));
|
||
Uart_SendByte((u8)('0' + (key_down_adc % 10)));
|
||
Uart_SendString(" [OK]\r\n");
|
||
|
||
// 2.2 检测 KEY_SOS (P2.6) 物理电平常态
|
||
Uart_SendString("[SELF-TEST] KEY_SOS (P2.6) Pin Level: ");
|
||
Uart_SendByte((u8)(KEY_SOS ? '1' : '0'));
|
||
Uart_SendString("\r\n");
|
||
|
||
// 3. 检查 P1.3 电池电压检测与百分比
|
||
vbat_mv = ADC_GetBatteryVoltage_mV();
|
||
percent = ADC_GetBatteryPercent();
|
||
batt_adc_raw = ADC_ReadFiltered(ADC_CHANNEL_BATTERY);
|
||
|
||
Uart_SendString("[SELF-TEST] Battery Raw ADC: ");
|
||
Uart_SendByte((u8)('0' + (batt_adc_raw / 1000) % 10));
|
||
Uart_SendByte((u8)('0' + (batt_adc_raw / 100) % 10));
|
||
Uart_SendByte((u8)('0' + (batt_adc_raw / 10) % 10));
|
||
Uart_SendByte((u8)('0' + (batt_adc_raw % 10)));
|
||
|
||
Uart_SendString(" -> Voltage: ");
|
||
Uart_SendByte((u8)('0' + (vbat_mv / 1000) % 10));
|
||
Uart_SendByte('.');
|
||
Uart_SendByte((u8)('0' + (vbat_mv / 100) % 10));
|
||
Uart_SendByte((u8)('0' + (vbat_mv / 10) % 10));
|
||
|
||
Uart_SendString(" V, Capacity: ");
|
||
Uart_SendByte((u8)('0' + (percent / 100) % 10));
|
||
Uart_SendByte((u8)('0' + (percent / 10) % 10));
|
||
Uart_SendByte((u8)('0' + (percent % 10)));
|
||
Uart_SendString("% [OK]\r\n");
|
||
|
||
// 4. 检查充电状态
|
||
{
|
||
u16 det_adc = ADC_ReadFiltered(ADC_CHANNEL_CHRG_DET);
|
||
u16 det_mv = (det_adc * 3300UL) / 4095UL;
|
||
Uart_SendString("[SELF-TEST] CHRG_DET (P1.2) ADC: ");
|
||
Uart_SendByte((u8)('0' + (det_adc / 1000) % 10));
|
||
Uart_SendByte((u8)('0' + (det_adc / 100) % 10));
|
||
Uart_SendByte((u8)('0' + (det_adc / 10) % 10));
|
||
Uart_SendByte((u8)('0' + (det_adc % 10)));
|
||
Uart_SendString(" -> Voltage: ");
|
||
Uart_SendByte((u8)('0' + (det_mv / 1000) % 10));
|
||
Uart_SendByte('.');
|
||
Uart_SendByte((u8)('0' + (det_mv / 100) % 10));
|
||
Uart_SendByte((u8)('0' + (det_mv / 10) % 10));
|
||
Uart_SendString(" V -> ");
|
||
if (det_mv >= 800 && det_mv <= 1800) {
|
||
Uart_SendString("CHARGING [OK]\r\n");
|
||
} else if (det_mv >= 2200 && det_mv <= 2800) {
|
||
Uart_SendString("FULLY CHARGED [OK]\r\n");
|
||
} else {
|
||
Uart_SendString("NOT CHARGING [OK]\r\n");
|
||
}
|
||
}
|
||
|
||
Uart_SendString("[SELF-TEST] Self Test Completed Successfully!\r\n");
|
||
Uart_SendString("========================================\r\n\r\n");
|
||
}
|
||
|
||
/**
|
||
* @brief 执行关机断电流程
|
||
* @details 关断外设、震动提示并拉低 PWR_HOLD 引脚切断总电源
|
||
*/
|
||
void Power_Off(void)
|
||
{
|
||
Uart_SendString("[SYS] Executing Power Off sequence...\r\n");
|
||
|
||
// 马达震动反馈 100ms
|
||
MOTOR = 1;
|
||
Delay_ms(100);
|
||
MOTOR = 0;
|
||
|
||
// 关断屏幕背光与 RGB 灯光
|
||
SGM_CTRL = 1; // 高电平断电,关闭背光灭屏
|
||
RGB_Send(0, 0, 0, 0, 0, 0);
|
||
|
||
// 拉低 PWR_HOLD 切断电源锁存使总电源关闭
|
||
PWR_HOLD = 0;
|
||
|
||
// 进入死循环等待电源物理切断
|
||
while (1) {
|
||
PWR_HOLD = 0;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 系统切入低功耗停机休眠模式
|
||
*/
|
||
void Enter_Low_Power_Sleep(void)
|
||
{
|
||
Uart_SendString("[SYS] Entering low power sleep...\r\n");
|
||
|
||
// 1. 关闭/熄灭 RGB 灯
|
||
RGB_Send(0, 0, 0, 0, 0, 0);
|
||
|
||
// 2. 向 LCD 芯片写入 Display OFF 指令 (0x28) 关显示
|
||
WriteComm(0x28);
|
||
Delay_ms(20);
|
||
|
||
// 3. 向 LCD 芯片写入 Sleep In 指令 (0x10) 关内部电荷泵
|
||
WriteComm(0x10);
|
||
Delay_ms(20);
|
||
|
||
// 4. 关闭背光(高电平断电,关闭背光灭屏)
|
||
SGM_CTRL = 1;
|
||
|
||
// 5. 屏幕接口防漏电处理
|
||
LCD_CS = 1;
|
||
LCD_RST = 1;
|
||
LCD_DCX = 0;
|
||
LCD_SCL = 0;
|
||
LCD_SDI = 0;
|
||
|
||
// 6. 射频设置为关闭接收模式(低功耗,SHUT=0, RF_SetMode(0))
|
||
RF_SetMode(0);
|
||
|
||
// 使能访问扩展特殊功能寄存器
|
||
P_SW2 |= 0x80;
|
||
|
||
// 7. 配置 Port0 中断唤醒源 (KEY_UP=P0.1, KEY_CONFIRM=P0.2, KEY_DOWN=P0.3)
|
||
P0IM1 |= 0x0E;
|
||
P0IM0 &= ~0x0E; // 下降沿触发
|
||
P0INTF = 0x00; // 清除挂起的中断标志
|
||
P0INTE |= 0x0E; // 开启 P0.1, P0.2, P0.3 中断允许
|
||
P0WKUE |= 0x0E; // 使能 P0.1, P0.2, P0.3 掉电唤醒
|
||
|
||
// 8. 配置 Port2 中断唤醒源 (SOS=P2.6)
|
||
P2IM1 |= 0x40;
|
||
P2IM0 &= ~0x40; // 下降沿触发
|
||
P2INTF = 0x00; // 清除挂起标志
|
||
P2INTE |= 0x40; // 开启 P2.6 中断允许
|
||
P2WKUE |= 0x40; // 使能 P2.6 掉电唤醒
|
||
|
||
// 9. 配置 Port3 掉电唤醒源 (RF_RX_DATA=P3.6)
|
||
// RF_HandleEdgeInterrupt() 用软件乒乓单边沿切换模拟双边沿触发,运行期间 P3IM0 会在
|
||
// 上升沿/下降沿之间动态翻转;如果休眠前不重新固定它,进入 Power Down 那一刻 P3IM0
|
||
// 具体停在哪个方向是不确定的,可能导致唤醒不了或唤醒延迟。根据《STC32G 技术手册》
|
||
// 15.1.3 节真值表,PxIM1/PxIM0 的四种模式里只有下降沿(0,0)和上升沿(0,1)两种边沿模式
|
||
// 标注支持掉电唤醒,高/低电平两种模式都不支持——所以这里没有改成电平触发,而是强制
|
||
// 固定为上升沿 (与 RF_Init() 开机时的初始配置一致),确保休眠那一刻处于一个明确的、
|
||
// 手册标注支持唤醒的状态;唤醒后 P3IM0 就停在上升沿,与开机状态相同,解码状态机从
|
||
// 一个已知状态重新开始,不需要额外恢复。
|
||
P3IM1 &= ~0x40;
|
||
P3IM0 |= 0x40; // (0,1) 上升沿触发
|
||
P3INTF = 0x00; // 清除挂起标志
|
||
P3WKUE |= 0x40; // 使能 P3.6 掉电唤醒
|
||
|
||
// 确保引脚上拉和输入使能,防止因浮空产生的功耗泄漏
|
||
P2PU |= 0x40;
|
||
P2IE |= 0x40;
|
||
P3PU &= ~0x40;
|
||
P3IE |= 0x40;
|
||
|
||
// 清零各个唤醒检测标志位
|
||
P0INTF = 0x00;
|
||
P2INTF = 0x00;
|
||
P3INTF = 0x00;
|
||
|
||
p0_wakeup_flag = 0;
|
||
p2_wakeup_flag = 0;
|
||
p3_wakeup_flag = 0;
|
||
rf_wakeup_flag = 0;
|
||
|
||
// 10. 关闭系统滴答定时器 Timer1 与 RF 时间戳基准 Timer0 的中断,防止休眠时被定时器误唤醒
|
||
// (Power Down 模式下主振荡器本应整体停振,Timer0/1 都会随之停止计数;这里仍显式关闭
|
||
// 中断允许作为防御性保险,与 ET1 的处理方式保持一致)
|
||
ET0 = 0;
|
||
ET1 = 0;
|
||
EA = 1; // 开启全局中断
|
||
|
||
// 配置 PCON 挂起单片机,切入停机 (Power Down) 模式
|
||
PCON |= 0x02; // PD = 1
|
||
_nop_(); _nop_(); _nop_(); _nop_();
|
||
|
||
// ====== 被外部中断唤醒后,在此处继续运行 ======
|
||
Wakeup_Restore();
|
||
}
|
||
|
||
/**
|
||
* @brief 休眠唤醒恢复
|
||
*/
|
||
void Wakeup_Restore(void)
|
||
{
|
||
EAXFR = 1;
|
||
// 1. 立即关闭 P0/P2 掉电外部中断允许与全部唤醒允许,防止重入;
|
||
// P3INTE 的 P3.6 位不清零 —— 该中断常态用于正常运行期间的 RF 边沿解码,唤醒后仍需保持开启
|
||
P0INTE = 0x00;
|
||
P2INTE = 0x00;
|
||
P3INTE = 0x40;
|
||
// P3.6 的悬空钳位已改用内部下拉 (P3PD,在 RF_Init() 里一次性永久开启,Power Down 期间
|
||
// SFR 状态保持不变,无需在这里重新配置);此处不再恢复上拉,避免上拉与下拉同时使能相互打架
|
||
|
||
P0WKUE = 0x00;
|
||
P2WKUE = 0x00;
|
||
P3WKUE = 0x00;
|
||
P0INTF = 0x00;
|
||
P2INTF = 0x00;
|
||
P3INTF = 0x00;
|
||
|
||
// 2. 清零掉电唤醒定时器
|
||
WKTCH = 0x00;
|
||
WKTCL = 0x00;
|
||
|
||
// 3. 开启全局中断并重启系统滴答定时器 Timer1 与 RF 时间戳基准 Timer0
|
||
EA = 1;
|
||
ET0 = 1;
|
||
ET1 = 1;
|
||
|
||
// 4. 恢复射频芯片工作模式
|
||
RF_SetMode(1);
|
||
|
||
// 打印唤醒调试日志
|
||
if ((p0_wakeup_flag & 0x0E) || (p2_wakeup_flag & 0x40)) {
|
||
Uart_SendString("[WR] Woken by KEY (P0=");
|
||
Uart_SendHex8(p0_wakeup_flag);
|
||
Uart_SendString(", P2=");
|
||
Uart_SendHex8(p2_wakeup_flag);
|
||
Uart_SendString(")\r\n");
|
||
} else if ((p3_wakeup_flag & 0x40) || rf_wakeup_flag) {
|
||
rf_wakeup_flag = 1;
|
||
Uart_SendString("[WR] Woken by RF (P3.6)!\r\n");
|
||
} else {
|
||
Uart_SendString("[WR] Woken by TIMER/Other\r\n");
|
||
}
|
||
|
||
// 5. 恢复屏幕供电与背光(低电平上电,恢复背光亮屏)
|
||
SGM_CTRL = 0;
|
||
|
||
// 6. 延时 200ms 等待液晶稳压板上电稳定后,重新对 LCD 寄存器初始化
|
||
Delay_ms(200);
|
||
LCD_Init();
|
||
}
|
||
|
||
/**
|
||
* @brief 安全获取 Timer0 计数器值 (防高字节滚动跳变)
|
||
*/
|
||
u16 GetTimer0_Safe(void)
|
||
{
|
||
u8 high1, high2, low;
|
||
do {
|
||
high1 = TH0;
|
||
low = TL0;
|
||
high2 = TH0;
|
||
} while (high1 != high2);
|
||
return (((u16)high1 << 8) | low);
|
||
}
|
||
|
||
/**
|
||
* @brief 串口 1 发送 4 位十六进制字符 (0x0~0xF)
|
||
*/
|
||
void Uart_SendHex4(u8 val)
|
||
{
|
||
val &= 0x0F;
|
||
if (val < 10) {
|
||
Uart_SendByte('0' + val);
|
||
} else {
|
||
Uart_SendByte('A' + (val - 10));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 串口 1 发送 8 位十六进制 (0x00~0xFF)
|
||
*/
|
||
void Uart_SendHex8(u8 val)
|
||
{
|
||
Uart_SendHex4(val >> 4);
|
||
Uart_SendHex4(val);
|
||
}
|
||
|
||
/**
|
||
* @brief 串口 1 发送 16 位十六进制 (0x0000~0xFFFF)
|
||
*/
|
||
void Uart_SendHex16(u16 val)
|
||
{
|
||
Uart_SendHex8((u8)(val >> 8));
|
||
Uart_SendHex8((u8)val);
|
||
}
|
||
|
||
/**
|
||
* @brief 串口 1 发送 20 位十六进制 (用于射频 5 位 ID 打印)
|
||
*/
|
||
void Uart_SendHex20(u32 val)
|
||
{
|
||
Uart_SendHex4((u8)(val >> 16));
|
||
Uart_SendHex16((u16)val);
|
||
}
|
||
|
||
/**
|
||
* @brief 串口 1 发送 32 位十六进制
|
||
*/
|
||
void Uart_SendHex32(u32 val)
|
||
{
|
||
Uart_SendHex16((u16)(val >> 16));
|
||
Uart_SendHex16((u16)val);
|
||
}
|