feat: 校准电池电压与ADC2充电检测,重构RGB为Bitbang翻转驱动,并修复RTC晶振起振问题
This commit is contained in:
171
Drivers/adc.c
Normal file
171
Drivers/adc.c
Normal file
@@ -0,0 +1,171 @@
|
||||
#include "adc.h"
|
||||
#include "../App/system.h"
|
||||
|
||||
/**
|
||||
* @brief 初始化 STC32G 硬件 ADC 模块
|
||||
* @details 配置 P0.3 (KEY_DOWN) 与 P1.3 (BATT_ADC) 为高阻输入模式,
|
||||
* 上电开启 ADC 内部电源并配置结果对齐格式为右对齐。
|
||||
*/
|
||||
void ADC_Init(void)
|
||||
{
|
||||
// 1. 配置 P0.3 和 P1.3 引脚模式为高阻输入 (M1=1, M0=0)
|
||||
P0M1 |= (1 << 3);
|
||||
P0M0 &= ~(1 << 3);
|
||||
|
||||
P1M1 |= (1 << 3);
|
||||
P1M0 &= ~(1 << 3);
|
||||
|
||||
// 配置 P1.2 (CHRG_DET / ADC2) 为高阻输入模式
|
||||
P1M1 |= (1 << 2);
|
||||
P1M0 &= ~(1 << 2);
|
||||
|
||||
// 2. 开启 ADC 模块主电源 (ADC_POWER = 1)
|
||||
ADC_POWER = 1;
|
||||
|
||||
// 3. 配置 ADCCFG 寄存器:
|
||||
// RESFMT (bit 5) = 1: 转换结果右对齐 (ADC_RES 存高4位, ADC_RESL 存低8位)
|
||||
// 底部 4 位 SPEED: 设置 ADC 转换工作时钟频率 (0x0F 表示最快速度)
|
||||
ADCCFG = 0x2F;
|
||||
|
||||
// 4. 软启动延迟,等待 ADC 模块内部电源稳定
|
||||
Delay_ms(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 单次读取指定 ADC 通道的原始 12 位转换结果
|
||||
* @param channel ADC 通道号 (0~15)
|
||||
* @return u16 12 位 ADC 采样原始值 (0 ~ 4095)
|
||||
*/
|
||||
u16 ADC_ReadRaw(u8 channel)
|
||||
{
|
||||
u16 adc_val = 0;
|
||||
|
||||
// 选择指定通道并保持电源开启
|
||||
ADC_CONTR = (ADC_CONTR & 0xF0) | (channel & 0x0F);
|
||||
|
||||
// 延时等待通道切换电容充放电稳定
|
||||
Delay_us(10);
|
||||
|
||||
// 启动 A/D 转换
|
||||
ADC_START = 1;
|
||||
|
||||
// 阻塞等待转换结束 (ADC_FLAG 置 1)
|
||||
while (!ADC_FLAG);
|
||||
|
||||
// 清除转换完成标志
|
||||
ADC_FLAG = 0;
|
||||
|
||||
// 读取 12 位右对齐结果 (ADC_RES 取低 4 位,结合 ADC_RESL 构成 12 位数据)
|
||||
adc_val = ((u16)(ADC_RES & 0x0F) << 8) | ADC_RESL;
|
||||
|
||||
return adc_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 5 次采样排序取中值滤波算法
|
||||
* @param channel ADC 通道号 (0~15)
|
||||
* @return u16 滤波后的 12 位 ADC 采样结果
|
||||
*/
|
||||
u16 ADC_ReadFiltered(u8 channel)
|
||||
{
|
||||
u16 buf[5];
|
||||
u8 i, j;
|
||||
u16 temp;
|
||||
|
||||
// 连续采集 5 次数据
|
||||
for (i = 0; i < 5; i++) {
|
||||
buf[i] = ADC_ReadRaw(channel);
|
||||
}
|
||||
|
||||
// 冒泡排序法进行升序排列
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = 0; j < 4 - i; j++) {
|
||||
if (buf[j] > buf[j + 1]) {
|
||||
temp = buf[j];
|
||||
buf[j] = buf[j + 1];
|
||||
buf[j + 1] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 取中间第 3 个值 (索引 2) 作为有效滤波输出,有效去除偶然性噪声尖峰
|
||||
return buf[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检测 USB 充电是否插入
|
||||
* @return bit 0=未充电, 1=充电中
|
||||
* @note TP4054 CHRG 开漏输出:
|
||||
* - 未充电/充满:CHRG 为高阻(被内部上拉拉高)
|
||||
* - 充电中:CHRG 为低电平
|
||||
* 返回值 1 表示正在充电,0 表示未充电或充满。
|
||||
*/
|
||||
bit Is_Charging(void)
|
||||
{
|
||||
u32 val = ADC_ReadFiltered(ADC_CHANNEL_CHRG_DET);
|
||||
u32 det_mv = (val * 3300UL) / 4095UL;
|
||||
|
||||
// 0.8V ~ 1.8V (800mV ~ 1800mV):正在充电
|
||||
if (det_mv >= 800 && det_mv <= 1800) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检测 KEY_DOWN (P0.3) 按键电平是否按下
|
||||
* @details KEY_DOWN 节点未按下时电压约 2.0V,按下后升至约 3.7V。
|
||||
* @return bit 1: 按下, 0: 常态未按下
|
||||
*/
|
||||
bit ADC_IsKeyDown(void)
|
||||
{
|
||||
u16 val = ADC_ReadFiltered(ADC_CHANNEL_KEY_DOWN);
|
||||
// 若采样值超过阈值 KEY_DOWN_ADC_THRESHOLD (3300),判定为按键被按下
|
||||
if (val > KEY_DOWN_ADC_THRESHOLD) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取 P1.3 电池分压计算得出的实际电池电压值 (单位: mV)
|
||||
* @details 硬件电阻分压电路: R15 (10kΩ) 上拉, R16 (22kΩ) 下拉。
|
||||
* 分压公式: V_node = V_bat * (22 / 32) => V_bat = V_node * (32 / 22)
|
||||
* 根据 ADC 采样: V_node(mV) = adc_val * 3300 / 4095
|
||||
* 真实电池电压 V_bat(mV) = (adc_val * 3300 * 32) / (4095 * 22)
|
||||
* @return u16 电池总电压 (mV, 例如 3850 代表 3.85V)
|
||||
*/
|
||||
u16 ADC_GetBatteryVoltage_mV(void)
|
||||
{
|
||||
u32 adc_val = ADC_ReadFiltered(ADC_CHANNEL_BATTERY);
|
||||
u32 vbat_mv;
|
||||
|
||||
// 经用户实测校准:
|
||||
// 当电池真实电压为 4.0V (4000mV) 时,10k/22k 分压点万用表实测为 2.7V,单片机读取的过滤 ADC 原值约为 2357。
|
||||
// 换算公式:V_bat(mV) = adc_val * 4000 / 2357
|
||||
vbat_mv = (adc_val * 4000UL) / 2357UL;
|
||||
|
||||
return (u16)vbat_mv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算电池剩余电量百分比 (0% ~ 100%)
|
||||
* @details 锂电池标准电压区间定义:
|
||||
* 4.20V (4200mV) 对应 100%
|
||||
* 3.30V (3300mV) 对应 0%
|
||||
* @return u8 电量百分比 (0 ~ 100)
|
||||
*/
|
||||
u8 ADC_GetBatteryPercent(void)
|
||||
{
|
||||
u16 vbat = ADC_GetBatteryVoltage_mV();
|
||||
|
||||
if (vbat >= 4200) {
|
||||
return 100;
|
||||
}
|
||||
if (vbat <= 3300) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 线性百分比换算: percent = (vbat - 3300) * 100 / (4200 - 3300)
|
||||
return (u8)(((u32)(vbat - 3300) * 100UL) / 900UL);
|
||||
}
|
||||
Reference in New Issue
Block a user