/** * app_charge_task.c — AI-4 充电管理任务(µC/OS-III) * * 集成充电状态机 + BQ25756 I2C 驱动 * * 任务结构: * ChargeTask (prio 5): * 每 200ms: 读 BQ25756 ADC → 输入状态机 → 执行 BQ25756 寄存器操作 * 每 10s: 复位 BQ25756 看门狗 * * AdcTask (prio 4): * 采集 NTC ADC → 转换为温度值 → 全局变量供 ChargeTask 读取 */ #include "board_config.h" #include "bq25756_regs.h" #include "bq_i2c_opt.h" #include "bq_verified_ops.h" #include "charge_sm.h" #include /*=========================================================================== * 全局变量 *===========================================================================*/ static int32_t g_vbat_mv = 0; /* 电池电压 mV */ static int32_t g_ibat_ma = 0; /* 充电电流 mA */ static int8_t g_temp_c = 25; /* NTC 温度 °C(默认 25 表示无读数)*/ /*=========================================================================== * NTC 温度计算(103AT, 10kΩ, β=3435K) *===========================================================================*/ /** * @brief 从 NTC ADC 原始值计算温度 * @param adc_val: 12-bit ADC 值 (0~4095) * @return 温度 °C */ static int8_t ntc_adc_to_temp(uint16_t adc_val) { /* 分压公式:V_ntc = Vref × R_ntc / (R_ntc + R_pullup) * ADC = 4095 × R_ntc / (R_ntc + 10000) * 反推: R_ntc = 10000 × ADC / (4095 - ADC) * * 简化:查表或近似公式 * 103AT β=3435K, R25=10kΩ * T = 1 / (1/298.15 + ln(R_ntc/10000)/3435) - 273.15 */ if (adc_val >= 4090) return -40; /* 开路 */ if (adc_val <= 5) return 125; /* 短路 */ float r_ntc = (float)(10000UL * adc_val) / (4095.0f - (float)adc_val); float temp_k = 1.0f / (1.0f/298.15f + logf(r_ntc/10000.0f)/3435.0f); float temp_c = temp_k - 273.15f; return (int8_t)(temp_c + 0.5f); /* 四舍五入 */ } /*=========================================================================== * 充电管理任务(优先级 5) *===========================================================================*/ static void ChargeTask(void *p_arg) { ChargeSM sm; ChargeSM_InitDefault(&sm); /* AI-4: 7S/2A/NTC/50°C/0°C */ OS_ERR err; uint32_t wd_timer = 0; while (1) { /* --- 采集数据 --- */ g_vbat_mv = BQ25756_ReadVBAT_mV(); g_ibat_ma = BQ25756_ReadIBAT_mA(); /* g_temp_c 由 AdcTask 更新 */ /* --- 输入状态机 --- */ ChargeSM_Decision d = ChargeSM_Run(&sm, g_vbat_mv, g_ibat_ma, g_temp_c); /* --- 执行决策 --- */ switch (d.action) { case SM_ACTION_SET_PRECHG: BQ25756_WritePrechargeCurrent(d.target_current_ma); BQ25756_SetEN_CHG(1); BQ_CE_LOW(); break; case SM_ACTION_SET_CC: BQ25756_WriteChargeCurrent(d.target_current_ma); BQ25756_SetEN_CHG(1); BQ_CE_LOW(); break; case SM_ACTION_STOP: BQ25756_SetEN_CHG(0); BQ_CE_HIGH(); break; case SM_ACTION_RESTART: BQ25756_WriteChargeCurrent(d.target_current_ma); BQ25756_SetEN_CHG(1); BQ_CE_LOW(); break; case SM_ACTION_NONE: default: break; } /* --- 看门狗复位(每 10s)--- */ wd_timer += CHARGE_TASK_PERIOD_MS; if (wd_timer >= WD_RESET_PERIOD_MS) { BQ25756_ResetWD(); wd_timer = 0; } /* --- 调试输出 --- */ if (d.action != SM_ACTION_NONE) { printf("[CHG] %s | VBAT=%ldmV IBAT=%ldmA TEMP=%dC | %s", ChargeSM_StateStr(sm.state), (long)g_vbat_mv, (long)g_ibat_ma, (int)g_temp_c, d.reason); } /* 休眠 200ms */ OSTimeDlyHMSM(0, 0, 0, CHARGE_TASK_PERIOD_MS, OS_OPT_TIME_DLY, &err); } } /*=========================================================================== * ADC 采样任务(优先级 4,比充电任务高一级) *===========================================================================*/ static OS_TCB AdcTaskTCB; static CPU_STK AdcTaskStk[ADC_TASK_STACK_SIZE]; /* NTC ADC 配置 */ static void ntc_adc_init(void) { /* GD32F303 ADC0 + GPIO PA3 */ rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_ADC0); gpio_init(NTC_ADC_PORT, GPIO_MODE_AIN, GPIO_OSPEED_2MHZ, NTC_ADC_PIN); adc_deinit(NTC_ADC_PERIPH); adc_channel_length_config(NTC_ADC_PERIPH, ADC_REGULAR_CHANNEL, 1); adc_regular_channel_config(NTC_ADC_PERIPH, 0, NTC_ADC_CHANNEL, ADC_SAMPLETIME_239POINT5); adc_external_trigger_source_config(NTC_ADC_PERIPH, ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE); adc_data_alignment_config(NTC_ADC_PERIPH, ADC_DATAALIGN_RIGHT); adc_resolution_config(NTC_ADC_PERIPH, ADC_RESOLUTION_12B); adc_enable(NTC_ADC_PERIPH); adc_calibration_enable(NTC_ADC_PERIPH); } static void AdcTask(void *p_arg) { OS_ERR err; ntc_adc_init(); while (1) { /* 读 NTC ADC */ adc_software_trigger_enable(NTC_ADC_PERIPH, ADC_REGULAR_CHANNEL); while (!adc_flag_get(NTC_ADC_PERIPH, ADC_FLAG_EOC)); uint16_t adc_val = adc_regular_data_read(NTC_ADC_PERIPH); g_temp_c = ntc_adc_to_temp(adc_val); /* 每 500ms 采样一次 */ OSTimeDlyHMSM(0, 0, 0, 500, OS_OPT_TIME_DLY, &err); } } /*=========================================================================== * 系统初始化入口 *===========================================================================*/ void App_Charge_Init(void) { OS_ERR err; /* --- 硬件初始化 --- */ /* I2C */ I2C_Bus bus = { .instance = BQ_I2C_PERIPH, .scl_port = BQ_I2C_SCL_PORT, .scl_pin = BQ_I2C_SCL_PIN, .sda_port = BQ_I2C_SDA_PORT, .sda_pin = BQ_I2C_SDA_PIN, .speed = BQ_I2C_SPEED, }; BQ_I2C_Init(&bus); /* CE 引脚 */ rcu_periph_clock_enable(RCU_GPIOA); gpio_init(BQ_CE_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_2MHZ, BQ_CE_PIN); BQ_CE_HIGH(); /* 初始拉高,禁止充电 */ /* PG 引脚(可选) */ gpio_init(BQ_PG_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_2MHZ, BQ_PG_PIN); /* --- BQ25756 初始化 --- */ int ret = BQ25756_AI4_Init(); if (ret != 0) { printf("[ERROR] BQ25756 init failed, step %d", ret); return; } printf("[OK] BQ25756 AI-4 init complete"); /* --- 创建任务 --- */ OSTaskCreate((OS_TCB *)&ChargeTaskTCB, (CPU_CHAR *)"Charge", (OS_TASK_PTR )ChargeTask, (void *)0, (OS_PRIO )CHARGE_TASK_PRIO, (CPU_STK *)ChargeTaskStk, (CPU_STK_SIZE )CHARGE_TASK_STACK_SIZE / 10, (CPU_STK_SIZE )CHARGE_TASK_STACK_SIZE, (OS_MSG_QTY )0, (OS_TICK )0, (void *)0, (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), (OS_ERR *)&err); OSTaskCreate((OS_TCB *)&AdcTaskTCB, (CPU_CHAR *)"ADC", (OS_TASK_PTR )AdcTask, (void *)0, (OS_PRIO )ADC_TASK_PRIO, (CPU_STK *)AdcTaskStk, (CPU_STK_SIZE )ADC_TASK_STACK_SIZE / 10, (CPU_STK_SIZE )ADC_TASK_STACK_SIZE, (OS_MSG_QTY )0, (OS_TICK )0, (void *)0, (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), (OS_ERR *)&err); printf("[OK] Charge + ADC tasks created"); }