K1Guitar/APP/app_adc.c

550 lines
14 KiB
C
Raw Permalink 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.

#include "includes.h"
/* ==================== <20>ⲿ<EFBFBD><E2B2BF><EFBFBD><EFBFBD> ==================== */
extern void SendNoteOnMidiEvent(uint8_t Key, uint8_t OnVal);
extern void SendNoteOffMidiEvent(uint8_t Key, uint8_t OffVal);
extern uint8_t get_note_by_channel(uint8_t ch);
extern bool powon;
extern bool InModeFlag;
uint8_t get_note_by_channel(uint8_t ch)
{
switch(ch)
{
case 0: return USE_MIDI.Midi_5; // 5<><35>
case 1: return USE_MIDI.Midi_4; // 4<><34>
case 2: return USE_MIDI.Midi_3; // 3<><33>
case 3: return USE_MIDI.Midi_6; // 6<><36>
case 4: return USE_MIDI.Midi_1; // 1<><31>
case 6: return USE_MIDI.Midi_2; // 2<><32>
default: return 0x3C;
}
}
static uint8_t string_state[7] = {0};
/* <20><>Ƭ״̬<D7B4><CCAC> */
typedef enum {
PICK_STATE_IDLE,
PICK_STATE_DOWN,
PICK_STATE_UP
} pick_state_t;
typedef enum {
PICK_FSM_STATE_IDLE,
PICK_FSM_STATE_DOWN,
PICK_FSM_STATE_UP,
PICK_FSM_STATE_UP_LONG,
} pick_fsm_state_t;
static pick_fsm_state_t pick_fsm = PICK_FSM_STATE_IDLE;
static pick_state_t pick_prev = PICK_STATE_IDLE;
static pick_state_t pick_curr = PICK_STATE_IDLE;
bool pick_hold_up = 0;
static uint32_t pick_hold_tick = 0;
#define PICK_LONG_PRESS_MS 200
static uint8_t key_stable_flag[4] = {0};
bool usb_charging_state = 0;
bool usb_charging_laststate = 0;
/* <20><><EFBFBD><EFBFBD> */
static uint16_t vol_last = 0xFFFF;
uint8_t level = 0;
/* <20><><EFBFBD> */
#define BAT_SAMPLE_COUNT 20
static uint16_t bat_buffer[BAT_SAMPLE_COUNT] = {0};
static uint8_t bat_index = 0;
static uint32_t bat_sum = 0;
uint8_t percentage = 0;
//static uint32_t charge_step_tick = 0;
#define VBAT_MIN_RAW 2520
#define VBAT_MAX_RAW 3528
/* ==================== ͨ<><CDA8>0~4,6<><36><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ==================== */
static void app_adc_string_process(uint8_t channel)
{
uint16_t adc_val = ADC_ReadChannel(ADC_CHANNEL_0) >> 5;
uint8_t vel_out = 80;
if (adc_val >= 127) {
/* δ<><CEB4><EFBFBD><EFBFBD> <20><> Note Off */
if (string_state[channel]) {
string_state[channel] = 0;
//SendNoteOffMidiEvent(get_note_by_channel(channel), 0x00);
}
} else {
/* <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> */
if (adc_val <= 20)
vel_out = 127;
else {
uint16_t delta = adc_val - 20;
vel_out = 127 - delta * 57 / 110;
}
if (!string_state[channel]) {
string_state[channel] = 1;
SendNoteOnMidiEvent(get_note_by_channel(channel), vel_out);
}
}
}
pick_state_t app_adc_get_pick_input(void)
{
uint16_t adc_val = ADC_ReadChannel(ADC_CHANNEL_0);
pick_prev = pick_curr;
if (adc_val <= 1000)
pick_curr = PICK_STATE_DOWN;
else if (adc_val >= 3800)
pick_curr = PICK_STATE_UP;
else
pick_curr = PICK_STATE_IDLE;
return pick_curr;
}
static void app_adc_pick_process(void)
{
pick_state_t curstate = app_adc_get_pick_input();
uint32_t now = rt_tick_get();
uint32_t hold_tick;
switch(pick_fsm)
{
case PICK_FSM_STATE_IDLE:
if(curstate == PICK_STATE_DOWN)
{
pick_hold_tick = now;
pick_fsm = PICK_FSM_STATE_DOWN;
/* 音师:拨片下拨即响(进入 DOWN 触发),不要等复位 */
MainTask_Sendmsg(MSG_ID_BP_KEY,PICK_STATE_DOWN,0,0);
}
if(curstate == PICK_STATE_UP)
{
pick_hold_tick = now;
pick_fsm = PICK_FSM_STATE_UP;
}
break;
case PICK_FSM_STATE_DOWN:
if(curstate != PICK_STATE_DOWN)
{
pick_fsm = PICK_FSM_STATE_IDLE;
}
break;
case PICK_FSM_STATE_UP:
if(curstate != PICK_STATE_UP)
{
pick_fsm = PICK_FSM_STATE_IDLE;
//发送上拨消息
}else
{
hold_tick = now - pick_hold_tick;
if(hold_tick > PICK_LONG_PRESS_MS && !pick_hold_up)
{
pick_hold_up = 1;
pick_fsm = PICK_FSM_STATE_UP_LONG;
//发送长按消息
}
}
break;
case PICK_FSM_STATE_UP_LONG:
/* 长按已发过,等释放回 IDLE */
if(curstate != PICK_STATE_UP)
{
pick_fsm = PICK_FSM_STATE_IDLE;
pick_hold_up = 0;
//发送上拨消息
}
break;
}
}
/* ==================== ADC1 in0~3 ==================== */
static void app_adc_key_process(uint8_t idx)
{
static uint8_t debounce_cnt[4] = {0}; // 每个按键独立消抖计数
uint16_t val = ADC_ReadChannel(ADC_CHANNEL_1);
// 按下判定连续多次采样小于1000
if (val < 1000)
{
if (!key_stable_flag[idx])
{
if (++debounce_cnt[idx] >= 3) // 连续3次满足判定按下
{
key_stable_flag[idx] = 1;
ADC_IN1_KEY_Handle(idx, 1);
debounce_cnt[idx] = 0;
}
}
else
{
debounce_cnt[idx] = 0;
}
}
// 释放判定连续多次采样大于2000
else if (val > 2000)
{
if (key_stable_flag[idx])
{
if (++debounce_cnt[idx] >= 3) // 连续3次满足判定释放
{
key_stable_flag[idx] = 0;
debounce_cnt[idx] = 0;
}
}
else
{
debounce_cnt[idx] = 0;
}
}
// 中间迟滞区间,保持原状态,不做处理
}
/* ==================== ADC1 in4 ==================== */
/* 快速探测 Type-C / USB 是否接入(关机开机路径共用) */
bool app_adc_usb_is_plugged(void)
{
uint16_t val;
BSP_SelectAdcChannel(4); /* E_ADC1_FUNCTION_USB_CHECK */
Delay_us(20);
val = ADC_ReadChannel(ADC_CHANNEL_1) >> 5;
return (val > 80) ? true : false;
}
static void app_adc_charge_process(void)
{
uint16_t val = ADC_ReadChannel(ADC_CHANNEL_1) >> 5;
/* 插入充电阈值80仅状态跳变时执行一次 */
if (val > 80)
{
if (usb_charging_state != 1)
{
usb_charging_state = 1;
usb_charging_laststate = 1;
if (powon)
{
MainTask_Sendmsg(MSG_ID_CHARG, usb_charging_state, usb_charging_laststate, 0);
}
else
{
/* 关机态插电:立即进全屏充电页,勿走开机 Logo */
LOG_I("CHG", "usb plug while soft-off → charge UI");
MainTask_Sendmsg(MSG_ID_POWOFF_CHARG, percentage, usb_charging_state, 0);
}
}
}
/* 拔掉充电阈值40迟滞防抖仅状态跳变时执行一次 */
else if (val < 40)
{
if (usb_charging_state != 0)
{
usb_charging_state = 0;
usb_charging_laststate = 0;
if (powon)
{
MainTask_Sendmsg(MSG_ID_CHARG, usb_charging_state, 1, 0);
}
else
{
/* 通知 UI 熄灭充电页并关主电 */
MainTask_Sendmsg(MSG_ID_POWOFF_CHARG, percentage, 0, 0);
BSP_MainPowerEnable(0);
}
}
}
}
/* ==================== ADC1 in5 ==================== */
static void app_adc_hp_process(void)
{
uint16_t val = ADC_ReadChannel(ADC_CHANNEL_1) >> 5;
if (val > 50) {
MainTask_Sendmsg(MSG_ID_HP_SPK_IN, 1, 0, 0);
} else {
MainTask_Sendmsg(MSG_ID_HP_SPK_IN, 1, 0, 0);
}
}
/* ==================== ADC1 in6 ==================== */
static void app_adc_volume_map_level(uint16_t val)
{
/* 5 格状态栏音量条0=静音5=最大 */
if (val <= 5) level = 0;
else if (val <= 35) level = 1;
else if (val <= 65) level = 2;
else if (val <= 95) level = 3;
else if (val <= 115) level = 4;
else level = 5;
}
void app_adc_sync_volume(uint16_t val)
{
vol_last = val;
app_adc_volume_map_level(val);
}
/* 取当前主音量(复用扫描任务维护的最近一次有效值)。
* 模拟开关同一时刻只选中一路,离开扫描上下文直接重读 ADC 会串到
* 其它通道,故统一走 vol_last未初始化0xFFFF时按静音兜底 */
uint8_t app_adc_get_volume(void)
{
return (vol_last > 127) ? 0 : (uint8_t)vol_last;
}
static void app_adc_volume_process(void)
{
uint16_t val = ADC_ReadChannel(ADC_CHANNEL_1)>>5;
if(abs((int16_t)vol_last - (int16_t)val) > 2)
{
app_adc_sync_volume(val);
MainTask_Sendmsg(MSG_ID_EC_VOL, val, level, 0);
}
}
/* ==================== ADC1 ͨ<><CDA8>7<EFBFBD><37><EFBFBD><EFBFBD><EFBFBD> ==================== */
static bat_state_t bat_state = BAT_IDLE;
static uint32_t bat_last_sample_tick = 0; /* 上次采样时刻 */
static uint32_t bat_state_tick = 0; /* 进当前状态的时刻 */
static uint8_t bat_charge_paused = 0; /* 本次是否暂停了充电 */
static uint8_t bat_poweron_done = 0; /* 开机首采标志 */
static uint8_t bat_sample_cnt = 0; /* SAMPLE 内已采了几个 */
static uint32_t bat_sample_tick = 0; /* SAMPLE 内上次采样的时刻 */
/* ==================== <20><>ʼ<EFBFBD><CABC> ==================== */
void app_adc_init(void)
{
for (int i = 0; i < 7; i++) string_state[i] = 0;
for (int i = 0; i < 4; i++) key_stable_flag[i] = 0;
pick_prev = pick_curr = PICK_STATE_IDLE;
pick_hold_up = 0;
usb_charging_state = 0;
vol_last = 0xFFFF; level = 0;
bat_index = 0; bat_sum = 0; percentage = 0;
for (int i = 0; i < BAT_SAMPLE_COUNT; i++) bat_buffer[i] = 0;
/* 电池状态机复位:下次开机触发首采 */
bat_state = BAT_IDLE;
bat_last_sample_tick = 0;
bat_charge_paused = 0;
bat_poweron_done = 0;
bat_sample_cnt = 0;
bat_sample_tick = 0;
}
/* 采样:读 ADC + 滑动平均 */
static void app_adc_battery_do_sample(void)
{
uint16_t adc_raw = ADC_ReadChannel(ADC_CHANNEL_1);
bat_sum -= bat_buffer[bat_index];
bat_buffer[bat_index] = adc_raw;
bat_sum += bat_buffer[bat_index];
bat_index = (bat_index + 1) % BAT_SAMPLE_COUNT;
}
/* 上报:映射成百分比,变化才发消息 */
static void app_adc_battery_report(void)
{
uint16_t filtered = bat_sum / BAT_SAMPLE_COUNT;
uint8_t pct;
if (filtered < VBAT_MIN_RAW)
pct = 0;
else if (filtered > VBAT_MAX_RAW)
pct = 100;
else
pct = 100 * (filtered - VBAT_MIN_RAW) / (VBAT_MAX_RAW - VBAT_MIN_RAW);
pct = (pct / 10) * 10;
if (pct != percentage) { /* 变化才上报 */
percentage = pct;
if(usb_charging_state && !powon)
{
MainTask_Sendmsg(MSG_ID_POWOFF_CHARG, percentage, usb_charging_state, 0);
}
else
{
MainTask_Sendmsg(MSG_ID_BATTERY_VALUE, percentage, usb_charging_state, 0);
}
}
}
/* 电池采集状态机入口app_adc_scan 每 1ms 调用,状态推进约每 10ms 一次) */
static void app_adc_battery_process(void)
{
uint32_t now = rt_tick_get();
switch (bat_state)
{
case BAT_IDLE:
/* 触发:开机后首采,或距上次 ≥30s */
if (/*powon && */!bat_poweron_done)
{
bat_poweron_done = 1;
bat_state = BAT_START;
}
else if (now - bat_last_sample_tick >= BAT_SAMPLE_INTERVAL_MS)
{
bat_state = BAT_START;
}
break;
case BAT_START:
if (usb_charging_state) /* 充电中:先停充电,采真实电压 */
{
BSP_ChargerEnable(0);
bat_charge_paused = 1;
bat_state_tick = now;
bat_state = BAT_WAIT_CHARGE_OFF;
}
else
{
bat_charge_paused = 0;
bat_state = BAT_SAMPLE;
}
break;
case BAT_WAIT_CHARGE_OFF:
if (now - bat_state_tick >= BAT_CHARGE_OFF_WAIT_MS)
bat_state = BAT_SAMPLE;
break;
case BAT_SAMPLE:
/* 连续采满 BAT_SAMPLE_COUNT 次(间隔 10ms填满滑动平均 buffer */
if (now - bat_sample_tick >= 10)
{
app_adc_battery_do_sample();
bat_sample_cnt++;
bat_sample_tick = now;
}
if (bat_sample_cnt >= BAT_SAMPLE_COUNT)
{
bat_sample_cnt = 0; /* 采满,进入收尾 */
if (bat_charge_paused)
bat_state = BAT_RESTORE_CHARGE;
else
bat_state = BAT_DONE;
}
break;
case BAT_RESTORE_CHARGE:
BSP_ChargerEnable(1); /* 恢复充电 */
bat_charge_paused = 0;
bat_state = BAT_DONE;
break;
case BAT_DONE:
app_adc_battery_report();
bat_last_sample_tick = now;
bat_state = BAT_IDLE;
break;
}
}
void app_adc_scan_all(void)
{
static uint8_t channel = 0;
BSP_SelectAdcChannel(channel);
Delay_us(10);
// adc_in 0
switch (channel)
{
case 0: case 1: case 2: case 3: case 4: case 6:
if(!InModeFlag) break;
app_adc_string_process(channel);
break;
case 7:
if(!InModeFlag) break;
app_adc_pick_process();
break;
}
// adc_in 1
switch (channel)
{
case 0: case 1: case 2: case 3:
if(!InModeFlag) break;
app_adc_key_process(channel);
break;
case 4:
app_adc_charge_process();
break;
case 5:
if(!InModeFlag) break;
app_adc_hp_process();
break;
case 6:
app_adc_volume_process();
break;
case 7:
app_adc_battery_process();
break;
}
if(channel < 8)
{
channel++;
}else
{
channel = 0;
}
}
void app_adc_in1_scan_part(uint8_t channel)
{
BSP_SelectAdcChannel(channel);
Delay_us(10);
// adc_in 1
switch (channel)
{
case 0: case 1: case 2: case 3:
app_adc_key_process(channel);
break;
case 4:
app_adc_charge_process();
break;
case 5:
app_adc_hp_process();
break;
case 6:
app_adc_volume_process();
break;
case 7:
app_adc_battery_process();
break;
}
}