/** * @file main.c * @brief BQ25756 裸机充电 Demo(STM32F103VE, StdPeriph) * * 最小可用示例 — 仅需 SysTick + 软 I²C + 串口。 * 每 2s 轮询一次 BQ25756 状态并通过 USART1 打印。 * * 分层:直接调用 bq25756_hal.c 的函数。 * * @note 此文件用于逻辑验证。AI-4 生产固件见 app_charge_task.c (GD32F303 + µC/OS-III)。 */ #include "stm32f10x.h" #include "bq25756_regs.h" #include "soft_i2c.h" #include "bq25756_hal.h" #include /*=========================================================================== * 全局变量 *===========================================================================*/ /** SysTick 毫秒计数器 */ static volatile uint32_t g_ms_ticks = 0; /*=========================================================================== * CE 引脚(PA0, 低电平有效) *===========================================================================*/ /** * @brief 初始化 CE 引脚 — 推挽输出,初始拉高(禁止充电) */ static void CE_GPIO_Init(void) { GPIO_InitTypeDef gpio; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_StructInit(&gpio); gpio.GPIO_Pin = GPIO_Pin_0; gpio.GPIO_Speed = GPIO_Speed_10MHz; gpio.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA, &gpio); GPIO_SetBits(GPIOA, GPIO_Pin_0); } /*=========================================================================== * 调试串口(USART1, PA9/PA10, 115200-8N1) *===========================================================================*/ /** * @brief 初始化 USART1 — 重定向 printf */ static void USART1_Init(void) { GPIO_InitTypeDef gpio; USART_InitTypeDef usart; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); /* TX — PA9 */ GPIO_StructInit(&gpio); gpio.GPIO_Pin = GPIO_Pin_9; gpio.GPIO_Speed = GPIO_Speed_50MHz; gpio.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &gpio); /* RX — PA10 */ GPIO_StructInit(&gpio); gpio.GPIO_Pin = GPIO_Pin_10; gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &gpio); USART_StructInit(&usart); usart.USART_BaudRate = 115200; usart.USART_WordLength = USART_WordLength_8b; usart.USART_StopBits = USART_StopBits_1; usart.USART_Parity = USART_Parity_No; usart.USART_HardwareFlowControl = USART_HardwareFlowControl_None; usart.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_Init(USART1, &usart); USART_Cmd(USART1, ENABLE); } /** * @brief printf 底层输出 — 重定向到 USART1 */ int fputc(int ch, FILE *f) { while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); USART_SendData(USART1, (uint8_t)ch); return ch; } /*=========================================================================== * SysTick 延时 *===========================================================================*/ /** * @brief SysTick 中断 — 每 1ms 递增 g_ms_ticks */ void SysTick_Handler(void) { g_ms_ticks++; } /** * @brief 初始化 SysTick — 1ms 周期 */ static void delay_init(void) { if (SysTick_Config(SystemCoreClock / 1000)) { while (1); } } /** * @brief 毫秒级阻塞延时(SysTick 实现) * * @param ms 延时毫秒数 */ static void delay_ms_st(uint32_t ms) { uint32_t start = g_ms_ticks; while ((g_ms_ticks - start) < ms); } /*=========================================================================== * 调试辅助 *===========================================================================*/ /** * @brief BQ25756 充电状态码 → 可读字符串 * * @param status REG0x21 CHARGE_STAT 位段 (bits 2:0) * @return 状态名字符串(静态,不可释放) */ static const char* charge_state_str(uint8_t status) { /* mask to bits 2:0 */ switch (status & 0x07) { case 0: return "No Charge"; case 1: return "Trickle"; case 2: return "Pre-charge"; case 3: return "Fast CC"; case 4: return "Fast CV"; case 6: return "Top-off"; case 7: return "Done!"; default: return "Unknown"; } } /*=========================================================================== * 主函数 *===========================================================================*/ /** * @brief BQ25756 充电 Demo 入口 * * 流程: * 1. 初始化系统时钟、调试串口、CE 引脚、软 I²C * 2. 检测 BQ25756 是否存在(读取 PART_INFO 寄存器) * 3. 执行 AI-4 初始化序列(14 步寄存器写入) * 4. 启动充电(退出 HIZ → 使能 EN_CHG → 拉低 CE) * 5. 主循环:每 2s 读一次 VBAT/IBAT/VIN + 充电状态 + 故障标记 * * @return 永不返回 */ int main(void) { delay_init(); USART1_Init(); CE_GPIO_Init(); SoftI2C_Init(NULL); printf("\r\n\r\n=== BQ25756 Charging Demo ===\r\n"); /* --- 检测 BQ25756 是否存在 --- */ uint8_t part = SoftI2C_ReadReg(BQ25756_HAL_I2C_ADDR, BQ25756_REG_PART_INFO); if (part != 0x12) { printf("[FAIL] BQ25756 not found! (PART_INFO=0x%02X, expected 0x12)\r\n", part); while (1); } printf("[OK] BQ25756 detected (PART_INFO=0x12)\r\n"); /* --- 初始化 BQ25756 --- */ int ret = BQ25756_AI4_Init(); if (ret != 0) { printf("[FAIL] BQ25756_AI4_Init failed at step %d\r\n", ret); while (1); } printf("[OK] BQ25756 AI-4 init complete (14 steps)\r\n"); /* --- 启动充电 --- */ BQ25756_AI4_StartCharging(); printf("[OK] Charging started\r\n\r\n"); /* --- 主轮询循环 --- */ while (1) { uint8_t status = SoftI2C_ReadReg(BQ25756_HAL_I2C_ADDR, BQ25756_REG_CHARGER_STATUS_1); uint8_t fault = SoftI2C_ReadReg(BQ25756_HAL_I2C_ADDR, BQ25756_REG_FAULT_STATUS); int32_t vbat_mv = bq_read_vbat_mv(); int32_t ibat_ma = bq_read_ibat_ma(); int32_t vin_mv = bq_read_vin_mv(); printf("[%lu ms] ", g_ms_ticks); printf("State=%s ", charge_state_str(status)); printf("VBAT=%ldmV ", (long)vbat_mv); printf("IBAT=%+ldmA ", (long)ibat_ma); printf("VIN=%ldmV ", (long)vin_mv); if (fault) { printf("FAULT: "); if (fault & 0x80) printf("VAC_UV "); if (fault & 0x40) printf("VAC_OV "); if (fault & 0x20) printf("IBAT_OCP "); if (fault & 0x10) printf("VBAT_OVP "); if (fault & 0x08) printf("TSHUT "); if (fault & 0x04) printf("CHG_TMR "); if (fault & 0x02) printf("DRV_SUP "); } printf("\r\n"); bq_reset_wd(); delay_ms_st(2000); } }