379 lines
9.5 KiB
C
379 lines
9.5 KiB
C
#include "system.h"
|
||
#include "rgb.h"
|
||
#include "ui.h"
|
||
#include "clock.h"
|
||
#include "../Drivers/lcd.h"
|
||
#include "../Drivers/rf.h"
|
||
#include "intrins.h"
|
||
|
||
// 引用外部定义在 main.c 中的掉电外部唤醒事件状态暂存标志
|
||
extern volatile u8 p0_wakeup_flag; // P0 端口按键中断唤醒标志
|
||
extern volatile u8 p2_wakeup_flag; // P2 端口按键中断唤醒标志
|
||
extern volatile u8 p3_wakeup_flag; // P3 端口射频中断唤醒标志
|
||
extern volatile u8 rf_wakeup_flag; // 射频接收中断唤醒标志
|
||
|
||
/**
|
||
* @brief 系统 GPIO 端口工作模式初始化配置
|
||
*/
|
||
void GPIO_Init(void)
|
||
{
|
||
// EAXFR = 1 允许访问扩展特殊功能寄存器 (XSFR)
|
||
EAXFR = 1;
|
||
|
||
// 1. 配置 P0.1 (KEY_UP), P0.2 (KEY_CONFIRM), P0.3 (KEY_DOWN) 物理按键引脚为准双向口模式 (M1=0, M0=0)
|
||
P0M1 &= ~0x0E;
|
||
P0M0 &= ~0x0E;
|
||
KEY_UP = 1;
|
||
KEY_CONFIRM = 1;
|
||
KEY_DOWN = 1;
|
||
|
||
// 2. 配置 P1.3 (BAT_ADC) 电池电压采样引脚为高阻输入模式 (M1=1, M0=0)
|
||
P1M1 |= (1 << 3);
|
||
P1M0 &= ~(1 << 3);
|
||
|
||
// 3. 配置 P5.4 (DET) 充电器插入检测引脚为高阻输入模式 (M1=1, M0=0)
|
||
P5M1 |= (1 << 4);
|
||
P5M0 &= ~(1 << 4);
|
||
|
||
// 4. 配置 P2.5 (MOTOR) 振动马达驱动引脚为推挽输出模式 (M1=0, M0=1)
|
||
P2M1 &= ~(1 << 5);
|
||
P2M0 |= (1 << 5);
|
||
MOTOR = 0; // 默认静止不震动
|
||
|
||
// 5. 配置 P2.6 (KEY_SOS) 物理求救按键引脚为准双向口模式并置 1 (M1=0, M0=0)
|
||
P2M1 &= ~(1 << 6);
|
||
P2M0 &= ~(1 << 6);
|
||
KEY_SOS = 1;
|
||
|
||
// 6. 配置 P3.5 (SHUT) 射频芯片使能引脚为推挽输出模式 (M1=0, M0=1)
|
||
P3M1 &= ~(1 << 5);
|
||
P3M0 |= (1 << 5);
|
||
SHUT = 1; // 默认拉高使能开启,允许无线芯片运行
|
||
|
||
// 7. 配置 P1.7 (SGM_CTRL / LEDA) 为推挽输出模式 (M1=0, M0=1)
|
||
// PMOS 背光控制:低电平 (0) 导通发光,高电平 (1) 截止熄灭
|
||
P1M1 &= ~(1 << 7);
|
||
P1M0 |= (1 << 7);
|
||
SGM_CTRL = 1; // 初始设为高电平 (关闭背光),由 LCD_Init 初始化完成后开启
|
||
|
||
// 8. 配置 P0.1, P0.2, P0.3 和 P2.6 的内部上拉电阻,避免引脚浮空抖动误唤醒
|
||
P0PU |= 0x0E; // 开启 P0.1/P0.2/P0.3 上拉
|
||
P2PU |= 0x40; // 开启 P2.6 上拉
|
||
|
||
// 9. 配置 P3.0 (UART1_RXD - 输入) 和 P3.1 (UART1_TXD - 输出) 为相应模式
|
||
P3M1 &= ~((1 << 0) | (1 << 1));
|
||
P3M0 &= ~(1 << 0); // RXD 设为准双向
|
||
P3M0 |= (1 << 1); // TXD 设为推挽输出
|
||
}
|
||
|
||
/**
|
||
* @brief 阻塞式毫秒级延时函数 (基于 CPU 频率估算环路次数)
|
||
* @param ms 延迟毫秒数
|
||
*/
|
||
void Delay_ms(u16 ms)
|
||
{
|
||
u16 i, j;
|
||
for (i = 0; i < ms; i++)
|
||
// 24MHz 晶振下,双重循环实现约 1ms 延迟
|
||
for (j = 12000; j > 0; j--);
|
||
}
|
||
|
||
/**
|
||
* @brief 精确的 10 微秒延时函数 (利用 8051 指令循环时间)
|
||
*/
|
||
void Delay10us(void)
|
||
{
|
||
unsigned char data i;
|
||
_nop_();
|
||
i = 30; // 循环常数
|
||
while (--i);
|
||
}
|
||
|
||
/**
|
||
* @brief 阻塞式微秒级延时函数
|
||
* @param us 延迟微秒数
|
||
*/
|
||
void Delay_us(u16 us)
|
||
{
|
||
u16 i;
|
||
for(i = 0; i < us; i++)
|
||
{
|
||
_nop_(); _nop_(); _nop_(); _nop_();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 获取安全的 Timer0 计数器值
|
||
*/
|
||
u16 GetTimer0_Safe(void)
|
||
{
|
||
u8 th, tl;
|
||
do {
|
||
th = TH0;
|
||
tl = TL0;
|
||
} while (th != TH0); // 消除高低字节溢出读取不同步误差
|
||
return ((u16)th << 8) | tl;
|
||
}
|
||
|
||
/**
|
||
* @brief 初始化 UART1 (串口 1) 用于调试输出与指令接收
|
||
*/
|
||
void Uart1_Init(void)
|
||
{
|
||
SCON = 0x50; // 8位数据, 可变波特率
|
||
T2L = 0xCC; // 1T模式,波特率 115200 对应的重载值底位 (24MHz)
|
||
T2H = 0xFF; // 波特率重载值高位
|
||
AUXR |= 0x14; // 定时器 2 设为 1T 模式并启动定时器 2
|
||
AUXR |= 0x01; // 串口 1 选择定时器 2 作为波特率发生器
|
||
ES = 1; // 开启串口 1 中断允许
|
||
}
|
||
|
||
/**
|
||
* @brief 串口 1 发送 1 字节数据
|
||
*/
|
||
void Uart_SendByte(u8 dat)
|
||
{
|
||
SBUF = dat;
|
||
while (!TI); // 等待发送中断标志置位
|
||
TI = 0; // 清除发送标志
|
||
}
|
||
|
||
/**
|
||
* @brief 串口 1 发送以 ' |