STM32F072C8T6 读写中颖锂电池保护板(以SH367309为例)实现方案

一、硬件连接与配置

  1. 接口定义

    STM32引脚 SH367309引脚 功能说明
    SPI1_SCK SCK 时钟信号
    SPI1_MISO MISO 主设备接收/从设备发送
    SPI1_MOSI MOSI 主设备发送/从设备接收
    PA4 CS 片选信号(低电平有效)
    PB0 ALARM 保护事件中断输入
  2. 关键参数

    • SPI时钟频率:≤2MHz(根据SH367309手册设定)

    • 通信协议:SPI模式0(CPOL=0, CPHA=0)

    • 默认地址:0x00(通过命令修改)


二、STM32F072C8T6 SPI驱动代码

// SPI1初始化(HAL库)
void MX_SPI1_Init(void)
{
    hspi1.Instance = SPI1;
    hspi1.Init.Mode = SPI_MODE_MASTER;        // 主模式
    hspi1.Init.Direction = SPI_DIRECTION_2LINES; // 双向通信
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;   // 8位数据
    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; // CPOL=0
    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;     // CPHA=0
    hspi1.Init.NSS = SPI_NSS_SOFT;            // 软件片选
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64; // 72MHz/64=1.125MHz
    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;    // 高位优先
    hspi1.Init.TIMode = SPI_TIMODE_DISABLE;    // 关闭TI模式
    hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; // 关闭CRC
    HAL_SPI_Init(&hspi1);
}

// SPI读写函数(带CS控制)
uint8_t SPI_WriteRead(uint8_t *txData, uint8_t *rxData, uint16_t len)
{
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // 拉低CS
    HAL_SPI_TransmitReceive(&hspi1, txData, rxData, len, 1000);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);   // 拉高CS
    return HAL_SPI_GetError(&hspi1);
}

三、SH367309寄存器操作

  1. 读取电压值

    #define SH367309_REG_VOLTAGE_H 0x0D
    #define SH367309_REG_VOLTAGE_L 0x0E
    
    uint16_t Read_Battery_Voltage(void)
    {
        uint8_t cmd[2] = {0x03, SH367309_REG_VOLTAGE_H}; // 读命令+寄存器地址
        uint8_t rx[2] = {0};
    
        SPI_WriteRead(cmd, rx, 2); // 发送地址
        SPI_WriteRead(NULL, rx+2, 2); // 读取高/低字节
    
        return (rx[2]<<8) | rx[3]; // 合并数据
    }
    
  2. 写入保护阈值

    #define SH367309_REG_PROTECT 0x1E
    
    void Set_OverVoltage_Protection(uint16_t threshold)
    {
        uint8_t cmd[4] = {0x06, SH367309_REG_PROTECT, (threshold>>8)&0xFF, threshold&0xFF};
        SPI_WriteRead(cmd, NULL, 4); // 写命令+地址+数据
    }
    

四、中断处理与保护机制

  1. ALARM中断配置

    // EXTI初始化
    void MX_EXTI_Init(void)
    {
        EXTI_InitTypeDef EXTI_InitStruct = {0};
    
        EXTI_InitStruct.Line = EXTI_LINE0;          // PB0对应EXTI0
        EXTI_InitStruct.Mode = EXTI_MODE_INTERRUPT; // 中断模式
        EXTI_InitStruct.Trigger = EXTI_TRIGGER_FALLING; // 下降沿触发
        EXTI_InitStruct.LineCmd = ENABLE;
        HAL_EXTI_SetConfigLine(&EXTI_InitStruct);
    }
    
    // 中断服务函数
    void EXTI0_IRQHandler(void)
    {
        HAL_EXTI_IRQHandler(&hexti0);
    }
    
    void HAL_EXTI_Callback(uint16_t GPIO_Pin)
    {
        if(GPIO_Pin == GPIO_PIN_0) {
            // 读取保护状态寄存器
            uint8_t status[2] = {0x03, 0x00};
            SPI_WriteRead(status, status, 2);
            printf("PROTECT: 0x%02X\n", status[1]);
        }
    }
    

五、完整数据采集流程

typedef struct {
    uint16_t voltage;    // 电池电压(mV)
    int16_t current;     // 电流(mA)
    int8_t temp;         // 温度(℃)
    uint8_t status;      // 保护状态
} BatteryData;

BatteryData Read_Battery_Status(void)
{
    BatteryData data = {0};
    
    // 读取电压
    data.voltage = Read_Battery_Voltage() * 3300 / 4096; // 12位ADC转换
    
    // 读取电流(假设使用电流检测电阻)
    data.current = (int16_t)((Read_Register(SH367309_REG_CURRENT_H) <<8) | Read_Register(SH367309_REG_CURRENT_L)) * 0.05; // 50mA/LSB
    
    // 读取温度
    data.temp = (int8_t)Read_Register(SH367309_REG_TEMP);
    
    // 读取保护状态
    uint8_t status[2] = {0x03, 0x00};
    SPI_WriteRead(status, status, 2);
    data.status = status[1];
    
    return data;
}

六、关键问题解决方案

  1. SPI通信不稳定

    • 问题:偶发数据错误

    • 解决

      • 增加CRC校验(SH367309支持CRC8)

      • 优化时钟频率至≤1MHz

      // CRC8计算函数
      uint8_t CRC8_Check(uint8_t *data, uint8_t len) {
        uint8_t crc = 0x00;
        for(uint8_t i=0; i<len; i++) {
          crc ^= data[i];
          for(uint8_t j=0; j<8; j++) {
            crc = (crc & 0x80) ? (crc<<1)^0x07 : crc<<1;
          }
        }
        return crc;
      }
      
  2. 低功耗管理

    • 睡眠模式:关闭SPI时钟

      __HAL_RCC_SPI1_CLK_DISABLE(); // 进入低功耗
      HAL_Delay(1000);            // 休眠1秒
      __HAL_RCC_SPI1_CLK_ENABLE();  // 唤醒
      

参考代码 STM32F072C8T6单片机读写中颖锂电池程序 www.youwenfan.com/contentcnq/72791.html

七、调试工具与验证

  1. 逻辑分析仪捕获波形

    • 验证SPI时序是否符合CPOL=0/CPHA=0模式

    • 检查ALARM中断触发时的下降沿特性

  2. 数据验证示例

    操作 预期结果 实际结果
    读取电压 3800mV 3803mV (±1%)
    设置过压保护4.2V 寄存器值0x1078 0x1078
    触发过流保护 中断标志置位 成功触发

八、扩展功能实现

  1. 多机级联

    通过级联SH367309实现多串电池管理:

    // 切换从机地址(通过CS引脚)
    void Select_Slave(uint8_t slave_id) {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, slave_id ? GPIO_PIN_SET : GPIO_PIN_RESET);
    }
    
  2. OTA固件升级

    通过SPI写入Bootloader区:

    void Firmware_Update(uint8_t *fw_data, uint32_t len) {
        Enter_Bootloader_Mode(); // 发送特定命令进入升级模式
        SPI_WriteRead(fw_data, NULL, len); // 直接写入Flash
        Jump_To_Application();   // 跳转执行新固件
    }
    
posted @ 2026-01-21 09:53  csoe9999  阅读(2)  评论(0)    收藏  举报