你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32F769I-DISC的可调数字电源

[复制链接]
lugl 发布时间:2025-3-9 17:11

【硬件准备】 1、【EV1WO505B-LVH-00A】评估板。 2、四路继电器 3、STM32F769I-DISC评估板。 4、TFTLCD触摸屏。 【软件开发环境】 1、STM32CubeMX 主要对STM32F769的基础环境进行创建。 2、Vscocde代码编译器。 3、LVGL开源GUI图形界面。 4、Gui-Guider设计工具。 【原理图设计】

image.png

隔离电源模块的原理图:

image.png

根据原理图,需要把EN通过100K的电阻对GND1,低电平时,才可以通过CN1来切换对GND2或者Vout来实现3.3V或者5V的电压输出。

【界面设计】

我使用Gui-Guider工具设计了图形界面如下:

image.png

主要是思路是sw1开控制一组继电器,实现VIN的电源输入通断,通过sw2来实现电压的在线切换。

设计好后,使用Gui-Guider生成代码,复制custom、generated两个文件夹到原来lvgl工程目录下面,并把文件添加进CMakeLists.txt使他们参与编译。

【代码实现】

1、sw1sw2的点击事件,通过判断他的值来对应GPIO进行切换。代码如下:


static void screen_sw_1_event_handler(lv_event_t *e)
{
    lv_event_code_t code = lv_event_get_code(e);
    switch (code)
    {
    case LV_EVENT_VALUE_CHANGED:
    {
        lv_obj_t *status_obj = lv_event_get_target(e);
        int status = lv_obj_has_state(status_obj, LV_STATE_CHECKED) ? true : false;
        if (status == true)
        {
            power_switch_control(POWER_ON);
            printf("SW 1 is ON\r\n");
        }
        else
        {
            power_switch_control(POWER_OFF);
            printf("SW 1 is OFF\r\n");
        }
        break;
    }
    default:
        break;
    }
}

static void screen_sw_2_event_handler(lv_event_t *e)
{
    lv_event_code_t code = lv_event_get_code(e);
    switch (code)
    {
    case LV_EVENT_VALUE_CHANGED:
    {
        lv_obj_t *status_obj = lv_event_get_target(e);
        int status = lv_obj_has_state(status_obj, LV_STATE_CHECKED) ? true : false;
        if(status == true)
        {
            voltage_switch(VOLTAGE_5V);
            printf("SW 2 is ON\r\n");
        }
        else
        {
            voltage_switch(VOLTAGE_3V3);
            printf("SW 2 is OFF\r\n");
        }
        break;
    }
    default:
        break;
    }
}
/**
 * Create a demo application
 */

void custom_init(lv_ui *ui)
{
    lv_obj_add_event_cb(ui->screen_sw_1, screen_sw_1_event_handler, LV_EVENT_ALL, ui);
    lv_obj_add_event_cb(ui->screen_sw_2, screen_sw_2_event_handler, LV_EVENT_ALL, ui);
    /* Add your codes here */
}

2、编写一个mps.c/h的文件,把相关逻辑写出来,具体代码如下,详细功能在代码中注释:

#include "lvgl.h"
#include "gui_guider.h"
#include <stdio.h>

// 假设ADC句柄已经在别处正确初始化
extern ADC_HandleTypeDef hadc1;
extern lv_ui gui_guider_ui;

// 定义ADC的分辨率(对于12位ADC,分辨率为4096)
#define ADC_RESOLUTION 4096

// 定义参考电压(单位:伏特)
#define REFERENCE_VOLTAGE 3.3f

// 进行ADC采集并转换为保留一位小数的电压值
uint32_t adc_voltage_conversion(void)
{
    uint32_t adc_value;

    // 启动ADC转换
    if (HAL_ADC_Start(&hadc1) != HAL_OK)
    {
        printf("ADC conversion failed.\n");
        // 处理启动失败的情况
        return 0;
    }

    // 等待ADC转换完成
    if (HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY) != HAL_OK)
    {
        printf("ADC conversion timeout.\n");
        // 处理转换失败的情况
        HAL_ADC_Stop(&hadc1);
        return 0;
    }
    // 等待ADC转换完成
    adc_value = HAL_ADC_GetValue(&hadc1);
    printf("ADC value: %d\n", adc_value);
    return adc_value;
}



// 电源开关控制函数
void power_switch_control(PowerStatus status)
{
    if (status == POWER_ON)
    {
        // 高电平开启电源
        HAL_GPIO_WritePin(ON_OFF_GPIO_Port, ON_OFF_Pin, GPIO_PIN_RESET);
    }
    else if (status == POWER_OFF)
    {
        // 低电平关闭电源
        HAL_GPIO_WritePin(ON_OFF_GPIO_Port, ON_OFF_Pin, GPIO_PIN_SET);
    }
}



// 电压转换功能函数
void voltage_switch(Voltage target_voltage)
{
    // 第一步:切换CH引脚
    if (target_voltage == VOLTAGE_5V)
    {
        // 高电平为5V
        HAL_GPIO_WritePin(CH_GPIO_Port, CH_Pin, GPIO_PIN_SET);
    }
    else if (target_voltage == VOLTAGE_3V3)
    {
        // 低电平为3.3V
        HAL_GPIO_WritePin(CH_GPIO_Port, CH_Pin, GPIO_PIN_RESET);
    }

    // 第二步:SWICTH_V拉高10ms再拉低
    HAL_GPIO_WritePin(SWICTH_V_GPIO_Port, SWICTH_V_Pin, GPIO_PIN_RESET);
    HAL_Delay(100); // 延时10ms
    HAL_GPIO_WritePin(SWICTH_V_GPIO_Port, SWICTH_V_Pin, GPIO_PIN_SET);
}

// 更新标签显示ADC采集电压值的函数
void update_label_with_voltage(void)
{
    uint32_t value = adc_voltage_conversion();
    float voltage = (float)value * 2 * REFERENCE_VOLTAGE / ADC_RESOLUTION ;

    char voltage_str[6];

    // 将电压值格式化为保留一位小数的字符串
    snprintf(voltage_str, sizeof(voltage_str), "%d.%02d", (int)voltage, (int)(voltage*100)%100);
    printf("ADC voltage: %s\n", voltage_str);
    // 更新标签文本
    lv_label_set_text(gui_guider_ui.screen_label_5, voltage_str);
    lv_obj_invalidate(gui_guider_ui.screen_label_5); // 标记控件需要重绘
}

最后,把update_labe_with_voltage放到主循环里周期调用。

【作品视频介绍】

https://www.bilibili.com/video/BV1eeRhYpEkR/

收藏 评论1 发布时间:2025-3-9 17:11

举报

1个回答
lugl 回答时间:昨天 17:15

然后添加mps.c/h,实现对电源的开关、切换与电压显示,代码如下:

#include "lvgl.h"
#include "gui_guider.h"
#include <stdio.h>

// 假设ADC句柄已经在别处正确初始化
extern ADC_HandleTypeDef hadc1;
extern lv_ui gui_guider_ui;

// 定义ADC的分辨率(对于12位ADC,分辨率为4096)
#define ADC_RESOLUTION 4096

// 定义参考电压(单位:伏特)
#define REFERENCE_VOLTAGE 3.3f

// 进行ADC采集并转换为保留一位小数的电压值
uint32_t adc_voltage_conversion(void)
{
    uint32_t adc_value;

    // 启动ADC转换
    if (HAL_ADC_Start(&hadc1) != HAL_OK)
    {
        printf("ADC conversion failed.\n");
        // 处理启动失败的情况
        return 0;
    }

    // 等待ADC转换完成
    if (HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY) != HAL_OK)
    {
        printf("ADC conversion timeout.\n");
        // 处理转换失败的情况
        HAL_ADC_Stop(&hadc1);
        return 0;
    }
    // 等待ADC转换完成
    adc_value = HAL_ADC_GetValue(&hadc1);
    printf("ADC value: %d\n", adc_value);
    return adc_value;
}



// 电源开关控制函数
void power_switch_control(PowerStatus status)
{
    if (status == POWER_ON)
    {
        // 高电平开启电源
        HAL_GPIO_WritePin(ON_OFF_GPIO_Port, ON_OFF_Pin, GPIO_PIN_RESET);
    }
    else if (status == POWER_OFF)
    {
        // 低电平关闭电源
        HAL_GPIO_WritePin(ON_OFF_GPIO_Port, ON_OFF_Pin, GPIO_PIN_SET);
    }
}



// 电压转换功能函数
void voltage_switch(Voltage target_voltage)
{
    // 第一步:切换CH引脚
    if (target_voltage == VOLTAGE_5V)
    {
        // 高电平为5V
        HAL_GPIO_WritePin(CH_GPIO_Port, CH_Pin, GPIO_PIN_SET);
    }
    else if (target_voltage == VOLTAGE_3V3)
    {
        // 低电平为3.3V
        HAL_GPIO_WritePin(CH_GPIO_Port, CH_Pin, GPIO_PIN_RESET);
    }

    // 第二步:SWICTH_V拉高10ms再拉低
    HAL_GPIO_WritePin(SWICTH_V_GPIO_Port, SWICTH_V_Pin, GPIO_PIN_RESET);
    HAL_Delay(100); // 延时10ms
    HAL_GPIO_WritePin(SWICTH_V_GPIO_Port, SWICTH_V_Pin, GPIO_PIN_SET);
}

// 更新标签显示ADC采集电压值的函数
void update_label_with_voltage(void)
{
    uint32_t value = adc_voltage_conversion();
    float voltage = (float)value * 2 * REFERENCE_VOLTAGE / ADC_RESOLUTION ;

    char voltage_str[6];

    // 将电压值格式化为保留一位小数的字符串
    snprintf(voltage_str, sizeof(voltage_str), "%d.%02d", (int)voltage, (int)(voltage*100)%100);
    printf("ADC voltage: %s\n", voltage_str);
    // 更新标签文本
    lv_label_set_text(gui_guider_ui.screen_label_5, voltage_str);
    lv_obj_invalidate(gui_guider_ui.screen_label_5); // 标记控件需要重绘
}

最后把更新函数放到主循环里周期调用就可以实现既有的功能了。

视频介绍:

https://www.bilibili.com/video/BV1eeRhYpEkR/

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版