基于STM32G0的USB PD协议学习(2)

本文介绍了使用STM32控制的DRP设备中,包括ChargeIC的API函数开发、PD协议应用、45W放电功率的OTG功能、以及1.3寸OLED显示屏的实时监控设计,展示了如何管理电池充放电和OLED显示充电状态的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0、前言

 本设计的内容是一个DRP设备,需要完成SINK(受电放)和SRC(供电方)的代码。在完成SRC部分代码的时候,还需要搭配Charge IC和电池,完成对外放电,因此本章节先完成Charge IC的API函数,同时完成OLED显示部分,方便充电状态的实时监控。

1、充放电管理模块

这里充电管理模块指的是,对电池的充放电管理,STM32控制Charge IC结合PD协议,完成电池的充电和放电。Charge IC需要选择具有buck-boost工作模式,且具有对外放电和充电功能的,因为2节电池电压为7-8V,而PD协议SPR支持的电压为5V~21V。

1.1、充放电模块的OTG功能

本设计是45W的放电功率,在设备处于SRC模式下,充放电模块的OTG功能能够实现以下的PDO电压:

Fix PDO: 5V-3A、9V-3A、15V-3A

PPS: 5V(5V~5.9V)、9V(5V~11V)、15V(5V~16V)

我这里还没时间去做PPS,如果要做PPS的话,那么对Charge IC就有更高的需求,输出精度至少需要20mV/bit

1.2、充电功能 

2节18650电池的充电电压一般为8.4V,因此在设备处于SNK模式下,设备请求的PDO最好为9V,这样才能保证最大的充电效率。

2、Charge IC的API函数

不同的Charge IC其寄存器定义基本上不一样,但尽量封装以下的API功能函数

/**  SNK 部分API函数  **/
HAL_StatusTypeDef     dcdc_set_charge_current(uint16_t value);
HAL_StatusTypeDef     dcdc_set_max_charge_voltage(uint16_t value);
HAL_StatusTypeDef     dcdc_set_input_current_limit(uint16_t value);
HAL_StatusTypeDef     dcdc_set_input_voltage_limit(uint16_t value);
HAL_StatusTypeDef     dcdc_snk_switch(uint8_t value);
HAL_StatusTypeDef     dcdc_snk_mode_init(void);

/**  SRC 部分API函数  **/
HAL_StatusTypeDef     dcdc_set_discharge_voltage(uint16_t value);
HAL_StatusTypeDef     dcdc_otg_voltage(uint16_t value);
HAL_StatusTypeDef     dcdc_otg_current(uint16_t value);
HAL_StatusTypeDef     dcdc_otg_en(uint8_t value);
HAL_StatusTypeDef     dcdc_src_switch(uint8_t value);
HAL_StatusTypeDef     dcdc_src_mode_init(void);

3、OLED模块

采用IIC驱动的1.3寸OLED显示屏12864液晶屏(SH1106驱动) 

4、OLED驱动代码

 代码是集合了DCDC驱动部分和PD部分的内容,移植了UGUI,仅作参考!!!

/* USER CODE BEGIN Header_Start_OLED_Task */
/**
* @brief Function implementing the OLED_Task thread.
* @param argument: Not used
* @retval None
*/

//I2C写入字节参数
void OLED_WriteByte(uint8_t dat,uint8_t cmd)
{
    HAL_I2C_Mem_Write(&hi2c1, 0x78, cmd, I2C_MEMADD_SIZE_8BIT, &dat, 1, 0xFFFF);
}

//SH1106 driver
void OLED_Init()
{
    osDelay(100);

    OLED_WriteByte(0xAE, OLED_CMD);         //--display off
    OLED_WriteByte(0xAE, OLED_CMD);         //set display display ON/OFF,AFH/AEH
    OLED_WriteByte(0x02, OLED_CMD);
    OLED_WriteByte(0x10, OLED_CMD);
    OLED_WriteByte(0x40, OLED_CMD);         //set display start line:COM0
    OLED_WriteByte(0xB0, OLED_CMD);
    OLED_WriteByte(0x81, OLED_CMD);         //set contrast control
    OLED_WriteByte(0xCF, OLED_CMD);


    OLED_WriteByte(0xA1, OLED_CMD);         //entire display on: A4H:OFF/A5H:ON
    OLED_WriteByte(0xC0, OLED_CMD);         //set show direction
    //OLED_WriteByte(0xC8, OLED_CMD);

    OLED_WriteByte(0xAF, OLED_CMD);
    OLED_WriteByte(0xA7, OLED_CMD);         //set normal/inverse display: A6H:normal/A7H:inverse

    OLED_WriteByte(0xA8, OLED_CMD);         //set multiplex ratio
    OLED_WriteByte(0x3F, OLED_CMD);         //1/64duty
    OLED_WriteByte(0xD3, OLED_CMD);         //set display offset
    OLED_WriteByte(0x00, OLED_CMD);         //
    OLED_WriteByte(0xD5, OLED_CMD);         //set display clock divide ratio/oscillator frequency
    OLED_WriteByte(0x80, OLED_CMD);         //105Hz
    OLED_WriteByte(0xD9, OLED_CMD);         //Dis-charge /Pre-charge Period Mode Set
    OLED_WriteByte(0xF1, OLED_CMD);         //
    OLED_WriteByte(0xDA, OLED_CMD);         //Common Pads Hardware Configuration Mode Set
    OLED_WriteByte(0x12, OLED_CMD);         //
    OLED_WriteByte(0xDB, OLED_CMD);         //set vcomh deselect level
    OLED_WriteByte(0x40, OLED_CMD);         //VCOM = β X VREF = (0.430 + A[7:0] X 0.006415) X VREF
    OLED_WriteByte(0xA4, OLED_CMD);         
    OLED_WriteByte(0xA6, OLED_CMD);         
    OLED_WriteByte(0xAF, OLED_CMD);         //set display display ON/OFF,AEH/AFH
}

uint8_t OLED_GRAM[128][8];

static void OLED_Screen_Clear()
{
    uint8_t i,n;
    
    for(i = 0; i < 8; i++)  
    {  
        OLED_WriteByte (0xb0+i, OLED_CMD);    //设置页地址(0~7)
        OLED_WriteByte (0x01, OLED_CMD);      //设置显示位置—列低地址
        OLED_WriteByte (0x10, OLED_CMD);      //设置显示位置—列高地址   
        for(n = 0; n < 130; n++)
        {
            OLED_WriteByte(0x00, OLED_DATA); //write 0x00;
        }
    } 
}

static void OLED_Ram_Clear(void)  
{  
    uint8_t i,n;
    
    for(i = 0; i < 8; i++)  
    {  
        for(n = 0; n < 128; n++)
        {
            OLED_GRAM[n][i] = 0X00;
        }
    }
}

void OLED_Refresh_Gram(void)
{
    uint8_t i,n;
    
    for(i = 0; i < 8; i++)  
    {  
        OLED_WriteByte (0xb0+i, OLED_CMD);    //设置页地址(0~7)
        OLED_WriteByte (0x01, OLED_CMD);      //设置显示位置—列低地址
        OLED_WriteByte (0x10, OLED_CMD);      //设置显示位置—列高地址   
        for(n = 0; n < 128; n++)
        {
            OLED_WriteByte(OLED_GRAM[n][i], OLED_DATA); //write 0x00;
        }
    }   
}

void OLED_DrawPoint(int16_t x,int16_t y,uint32_t t)
{
    uint8_t pos, bx,temp=0;

    if(x > 128 || y > 64)
    {
        return;//超出范围了.
    }
    
    pos = 7 - y/8;
    bx = y%8;
    temp = 1<<(7-bx);
    
    if(t)
    {
        OLED_GRAM[x][pos]|=temp;
    }
    else 
    {
        OLED_GRAM[x][pos]&=~temp;
    }
}

/* USER CODE END Header_Start_OLED_Task */
void Start_OLED_Task(void const * argument)
{
  /* USER CODE BEGIN Start_OLED_Task */
    
    uint32_t time = 0;
    char show_str[32];
    UG_GUI gui ; // Global GUI structure
    
    OLED_Init();
    OLED_Screen_Clear();
    
    UG_Init(&gui, OLED_DrawPoint, 128 , 64);
    UG_SelectGUI(&gui);
    
    //      printf("\
//*************************     \r\n\
//      adc_system_power:       %d mv \r\n\
//      adc_input_voltage:      %d mv \r\n\
//      adc_bat_discharge_cur:  %d ma \r\n\
//      adc_bat_charge_cur:     %d ma \r\n\
//      adc_cmpin_voltage:      %d mv \r\n\
//      adc_input_cur:          %d ma \r\n\
//      adc_bat_voltage:        %d mv \r\n\
//      adc_system_voltage:     %d mv \r\n\
//*************************",\
//      dcdc_adc_conv_data.adc_system_power,
//      dcdc_adc_conv_data.adc_input_voltage,
//      dcdc_adc_conv_data.adc_bat_discharge_cur,
//      dcdc_adc_conv_data.adc_bat_charge_cur,
//      dcdc_adc_conv_data.adc_cmpin_voltage,
//      dcdc_adc_conv_data.adc_input_cur,
//      dcdc_adc_conv_data.adc_bat_voltage,
//      dcdc_adc_conv_data.adc_system_voltage);
    
  /* Infinite loop */
    for(;;)
    {
        OLED_Ram_Clear();
        
        //Title
        UG_FontSelect(&FONT_8X12);
        UG_PutString(40, 1, "PD LED");
        UG_DrawRoundFrame(5, 0, 123, 13, 3, C_WHITE);
        
        //DCDC
        UG_FontSelect(&FONT_6X10);
        UG_PutString(2, 17, "|Name | mV  | mA |");
        UG_DrawLine(5, 28, 122, 28, C_WHITE);
        sprintf(show_str,   "|Bus  |%05d|%04d|", dcdc_adc_conv_data.adc_input_voltage, dcdc_adc_conv_data.adc_input_cur);
        UG_PutString(2, 30, show_str);
        if (DPM_Params[0].PE_PowerRole == USBPD_PORTPOWERROLE_SRC)
        {
            sprintf(show_str,   "|Batt |%05d|%04d|", dcdc_adc_conv_data.adc_bat_voltage, dcdc_adc_conv_data.adc_bat_discharge_cur);
        }else
        {
            sprintf(show_str,   "|Batt |%05d|%04d|", dcdc_adc_conv_data.adc_bat_voltage, dcdc_adc_conv_data.adc_bat_charge_cur);
        }
        UG_PutString(2, 40, show_str);
        
        //Time
        UG_FontSelect(&FONT_6X8);
        sprintf(show_str, "Time:%04d", time++);
        UG_PutString(60, 54, show_str);
        
        OLED_Refresh_Gram();
        osDelay(1000);
    }
  /* USER CODE END Start_OLED_Task */
}

5、 实物展示

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值