K1Guitar/APP/app_adc.c

550 lines
14 KiB
C
Raw Normal View History

#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_last0xFFFF */
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;
}
}