Files
stc32g128k/Drivers/adc.c

172 lines
4.7 KiB
C
Raw Permalink Normal View History

#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 (10) , R16 (22)
* : 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);
}