编程技术分享

分享编程知识,探讨技术创新

0%

简介:**

关注微信公众号,提前获取相关推文

本项目旨在设计并实现一个高性能、多功能的升降压可调电源,其核心特点包括:

  • Type-C 输入: 兼容广泛的Type-C电源适配器,方便用户使用。
  • 100W 功率: 支持高达100W的功率输出,满足各种电子设备的供电需求。
  • 升降压功能: 能够实现输入电压高于或低于输出电压的转换,保证输出电压的稳定性。
  • 可调电压与电流: 用户可以通过旋钮或数字界面精确调节输出电压和电流,适应不同的应用场景。
  • 嵌入式系统: 采用微控制器作为核心控制单元,实现电源的智能控制和管理。
  • 显示界面: 通过OLED或LCD屏幕实时显示电压、电流、功率等关键参数,以及系统状态。
  • 保护功能: 具备过压保护(OVP)、过流保护(OCP)、过温保护(OTP)、短路保护(SCP)等全面的保护机制,确保系统和负载的安全。
  • 可扩展性: 系统设计应具备良好的可扩展性,方便后续功能升级和扩展。

第一部分:嵌入式系统开发流程

一个完整的嵌入式系统开发流程通常包括以下几个阶段:

  1. 需求分析阶段:

    • 明确功能需求: 详细定义电源的各项功能指标,如输入电压范围、输出电压范围、输出电流范围、功率范围、调节精度、保护功能、显示要求、控制方式等。
    • 确定性能指标: 定义电源的性能指标,如电压调整率、负载调整率、效率、纹波噪声、响应速度等。
    • 分析应用场景: 明确电源的应用场景,例如实验室电源、便携式设备供电、工业控制电源等,以便更好地进行设计。
    • 制定项目计划: 制定详细的项目开发计划,包括时间表、资源分配、风险评估等。
  2. 系统设计阶段:

    • 硬件系统设计:
      • 主控芯片选型: 根据系统功能和性能需求,选择合适的微控制器(MCU),例如STM32、ESP32、NXP Kinetis系列等。需要考虑MCU的处理能力、外设资源、功耗、成本等因素。
      • 电源拓扑结构设计: 选择合适的升降压电源拓扑结构,例如四开关Buck-Boost、SEPIC、Cuk等。根据效率、成本、体积等因素进行权衡。
      • 功率器件选型: 选择合适的MOSFET、二极管、电感、电容等功率器件,需要考虑器件的耐压、电流、功率、开关速度、导通电阻、ESR等参数。
      • 外围电路设计: 设计输入保护电路、输出滤波电路、采样电路、驱动电路、保护电路、显示电路、输入控制电路、通信接口电路等外围电路。
      • PCB 设计: 进行 PCB Layout 设计,需要考虑信号完整性、散热、EMC/EMI等问题。
    • 软件系统设计:
      • 系统架构设计: 确定软件系统的整体架构,例如分层架构、事件驱动架构、状态机架构等。
      • 模块划分: 将软件系统划分为不同的模块,例如HAL层、驱动层、服务层、应用层等,提高代码的可维护性和可重用性。
      • 算法设计: 设计电压电流控制算法、保护算法、显示算法、输入处理算法等核心算法。
      • 接口设计: 定义模块之间的接口、驱动程序接口、用户界面接口等。
  3. 详细设计阶段:

    • 硬件详细设计:
      • 电路原理图设计: 绘制详细的电路原理图,包括器件型号、参数、连接方式等。
      • PCB Layout 详细设计: 进行详细的 PCB Layout 设计,包括走线、过孔、焊盘、散热设计等。
      • BOM 清单生成: 生成物料清单(BOM),包括所有元器件的型号、数量、封装、供应商等信息。
    • 软件详细设计:
      • 模块详细设计: 详细描述每个模块的功能、输入输出、算法、数据结构、流程图等。
      • 接口详细设计: 详细定义每个接口的参数、返回值、调用方式、错误处理等。
      • 代码框架设计: 搭建代码框架,包括文件结构、函数声明、变量定义、注释规范等。
  4. 编码与单元测试阶段:

    • 代码编写: 根据详细设计文档,编写 C 代码实现各个模块的功能。
    • 代码审查: 进行代码审查,检查代码的规范性、可读性、正确性、效率等。
    • 单元测试: 对每个模块进行单元测试,验证模块的功能是否符合设计要求。可以使用单元测试框架,例如 Google Test、Unity 等。
  5. 集成测试阶段:

    • 硬件调试: 进行硬件调试,验证电路的正确性、功能是否正常。可以使用示波器、万用表、逻辑分析仪等工具进行调试。
    • 软件集成: 将各个模块的代码集成在一起,构建完整的软件系统。
    • 系统集成测试: 进行系统集成测试,验证整个系统的功能是否符合需求,性能是否满足指标。需要进行各种测试,例如功能测试、性能测试、稳定性测试、可靠性测试、兼容性测试、安全测试等。
  6. 系统验证阶段:

    • 用户测试: 邀请用户进行测试,收集用户反馈,改进系统。
    • Alpha 测试与 Beta 测试: 进行 Alpha 测试(内部测试)和 Beta 测试(外部测试),发现并修复 Bug。
    • 性能评估与优化: 对系统性能进行评估,找出瓶颈,进行优化。
  7. 维护与升级阶段:

    • Bug 修复: 及时修复用户反馈的 Bug。
    • 功能升级: 根据用户需求或市场变化,进行功能升级和扩展。
    • 性能优化: 持续对系统性能进行优化,提高效率和可靠性。
    • 版本管理: 使用版本管理工具(例如 Git)管理代码和文档,方便维护和升级。

第二部分:最适合的代码设计架构

对于这个嵌入式电源项目,最适合的代码设计架构是分层架构。分层架构将系统划分为不同的层次,每一层只负责特定的功能,层与层之间通过定义好的接口进行通信。这种架构具有良好的模块化、可维护性、可重用性和可扩展性。

分层架构通常包括以下几层:

  1. 硬件抽象层 (HAL, Hardware Abstraction Layer):

    • 功能: 直接操作硬件寄存器,提供统一的硬件访问接口,屏蔽底层硬件的差异。
    • 模块: GPIO 驱动、ADC 驱动、PWM 驱动、Timer 驱动、SPI 驱动、I2C 驱动、UART 驱动等。
    • 优点: 提高代码的可移植性,方便更换硬件平台。
  2. 驱动层 (Driver Layer):

    • 功能: 基于 HAL 层提供的接口,实现特定硬件设备的功能驱动。
    • 模块: 显示屏驱动 (OLED/LCD)、编码器驱动、电压电流传感器驱动、电源芯片驱动、风扇驱动、保护芯片驱动等。
    • 优点: 将硬件操作细节封装在驱动层,上层应用无需关心具体的硬件操作。
  3. 服务层 (Service Layer):

    • 功能: 提供系统核心业务逻辑服务,例如电源控制服务、显示管理服务、输入处理服务、保护管理服务、通信服务等。
    • 模块: 电压电流控制模块 (PID 控制器)、显示管理模块、编码器输入处理模块、保护逻辑模块、参数配置模块、状态机管理模块、通信协议处理模块等。
    • 优点: 实现业务逻辑的模块化,提高代码的可读性和可维护性。
  4. 应用层 (Application Layer):

    • 功能: 提供用户界面和系统控制接口,例如用户交互界面、系统状态监控、参数配置、故障处理等。
    • 模块: 用户界面模块、系统监控模块、参数配置模块、错误处理模块、命令解析模块等。
    • 优点: 实现用户交互和系统管理功能,提供友好的用户体验。

分层架构的优势:

  • 模块化: 系统被划分为独立的模块,每个模块只负责特定的功能,降低了系统的复杂性。
  • 可维护性: 模块之间的依赖性降低,修改一个模块不会影响其他模块,方便代码的维护和升级。
  • 可重用性: 底层模块(HAL 层、驱动层)可以被多个项目重用,提高了代码的复用率。
  • 可扩展性: 可以方便地添加新的模块或替换现有的模块,扩展系统功能。
  • 可测试性: 每个模块都可以独立进行单元测试,提高了代码的测试覆盖率。
  • 可移植性: HAL 层屏蔽了底层硬件的差异,使得上层代码可以更容易地移植到不同的硬件平台。

第三部分:具体的 C 代码实现

为了演示代码架构和关键功能实现,以下提供一个简化的 C 代码框架,包含关键模块的实现思路和代码示例。由于 3000 行代码的要求非常庞大,这里无法提供一个完整的、可直接编译运行的项目代码,但会尽可能详细地展示核心模块的实现逻辑和关键代码片段。

1. HAL 层 (Hardware Abstraction Layer)

hal_gpio.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#ifndef HAL_GPIO_H
#define HAL_GPIO_H

#include <stdint.h>
#include <stdbool.h>

typedef enum {
GPIO_PIN_0,
GPIO_PIN_1,
GPIO_PIN_2,
// ... more pins
GPIO_PIN_MAX
} GPIO_PinTypeDef;

typedef enum {
GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT,
GPIO_MODE_ANALOG,
GPIO_MODE_AF_PP, // Alternate Function Push-Pull
GPIO_MODE_AF_OD // Alternate Function Open-Drain
} GPIO_ModeTypeDef;

typedef enum {
GPIO_PULL_NONE,
GPIO_PULLUP,
GPIO_PULLDOWN
} GPIO_PullTypeDef;

typedef enum {
GPIO_SPEED_LOW,
GPIO_SPEED_MEDIUM,
GPIO_SPEED_HIGH,
GPIO_SPEED_VERY_HIGH
} GPIO_SpeedTypeDef;

void HAL_GPIO_Init(GPIO_PinTypeDef GPIO_Pin, GPIO_ModeTypeDef GPIO_Mode, GPIO_PullTypeDef GPIO_Pull, GPIO_SpeedTypeDef GPIO_Speed);
void HAL_GPIO_WritePin(GPIO_PinTypeDef GPIO_Pin, bool PinState);
bool HAL_GPIO_ReadPin(GPIO_PinTypeDef GPIO_Pin);
void HAL_GPIO_TogglePin(GPIO_PinTypeDef GPIO_Pin);

#endif // HAL_GPIO_H

hal_gpio.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "hal_gpio.h"
// 假设使用 STM32 HAL 库,这里简化实现
void HAL_GPIO_Init(GPIO_PinTypeDef GPIO_Pin, GPIO_ModeTypeDef GPIO_Mode, GPIO_PullTypeDef GPIO_Pull, GPIO_SpeedTypeDef GPIO_Speed) {
// ... 具体硬件初始化代码,例如配置寄存器
(void)GPIO_Pin; (void)GPIO_Mode; (void)GPIO_Pull; (void)GPIO_Speed; // 防止编译器警告
// 例如: 根据 GPIO_Pin 选择 GPIO 端口和引脚
// 根据 GPIO_Mode 设置输入/输出模式
// 根据 GPIO_Pull 设置上下拉
// 根据 GPIO_Speed 设置速度
}

void HAL_GPIO_WritePin(GPIO_PinTypeDef GPIO_Pin, bool PinState) {
// ... 具体硬件写引脚代码,例如设置寄存器
(void)GPIO_Pin; (void)PinState;
// 例如: 根据 GPIO_Pin 选择 GPIO 端口和引脚
// 根据 PinState 设置引脚电平
}

bool HAL_GPIO_ReadPin(GPIO_PinTypeDef GPIO_Pin) {
// ... 具体硬件读引脚代码,例如读取寄存器
(void)GPIO_Pin;
// 例如: 根据 GPIO_Pin 选择 GPIO 端口和引脚
// 读取引脚电平并返回
return false; // 示例
}

void HAL_GPIO_TogglePin(GPIO_PinTypeDef GPIO_Pin) {
// ... 具体硬件翻转引脚代码
(void)GPIO_Pin;
// 例如: 读取引脚电平,然后翻转并写回
}

hal_adc.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef HAL_ADC_H
#define HAL_ADC_H

#include <stdint.h>

typedef enum {
ADC_CHANNEL_VOLTAGE_SENSE,
ADC_CHANNEL_CURRENT_SENSE,
// ... more ADC channels
ADC_CHANNEL_MAX
} ADC_ChannelTypeDef;

void HAL_ADC_Init(ADC_ChannelTypeDef ADC_Channel);
uint16_t HAL_ADC_GetValue(ADC_ChannelTypeDef ADC_Channel);

#endif // HAL_ADC_H

hal_adc.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "hal_adc.h"

void HAL_ADC_Init(ADC_ChannelTypeDef ADC_Channel) {
// ... 具体 ADC 初始化代码,例如配置 ADC 模块、通道、采样率等
(void)ADC_Channel;
// 例如: 使能 ADC 时钟
// 配置 ADC 转换模式、分辨率、采样时间
// 配置 ADC 通道
}

uint16_t HAL_ADC_GetValue(ADC_ChannelTypeDef ADC_Channel) {
// ... 具体 ADC 读取值代码,例如启动转换、等待转换完成、读取数据寄存器
(void)ADC_Channel;
// 例如: 选择 ADC 通道
// 启动 ADC 转换
// 等待转换完成
// 读取 ADC 数据寄存器
return 0; // 示例
}

hal_pwm.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef HAL_PWM_H
#define HAL_PWM_H

#include <stdint.h>

typedef enum {
PWM_CHANNEL_BUCK_BOOST,
// ... more PWM channels
PWM_CHANNEL_MAX
} PWM_ChannelTypeDef;

void HAL_PWM_Init(PWM_ChannelTypeDef PWM_Channel, uint32_t frequency);
void HAL_PWM_SetDutyCycle(PWM_ChannelTypeDef PWM_Channel, float dutyCycle); // Duty cycle 0.0 - 1.0

#endif // HAL_PWM_H

hal_pwm.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "hal_pwm.h"

void HAL_PWM_Init(PWM_ChannelTypeDef PWM_Channel, uint32_t frequency) {
// ... 具体 PWM 初始化代码,例如配置 PWM 模块、通道、频率、占空比等
(void)PWM_Channel; (void)frequency;
// 例如: 使能 PWM 时钟
// 配置 PWM 模式、计数模式、预分频器、周期
// 配置 PWM 通道
}

void HAL_PWM_SetDutyCycle(PWM_ChannelTypeDef PWM_Channel, float dutyCycle) {
// ... 具体 PWM 设置占空比代码,例如设置比较寄存器
(void)PWM_Channel; (void)dutyCycle;
// 例如: 根据 dutyCycle 计算比较值
// 设置 PWM 比较寄存器
}

2. 驱动层 (Driver Layer)

oled_driver.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef OLED_DRIVER_H
#define OLED_DRIVER_H

#include <stdint.h>

typedef enum {
OLED_COLOR_BLACK,
OLED_COLOR_WHITE
} OLED_ColorTypeDef;

void OLED_Init(void);
void OLED_ClearDisplay(OLED_ColorTypeDef color);
void OLED_SetPixel(uint8_t x, uint8_t y, OLED_ColorTypeDef color);
void OLED_DrawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, OLED_ColorTypeDef color);
void OLED_DrawRectangle(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, OLED_ColorTypeDef color);
void OLED_DrawCircle(uint8_t x, uint8_t y, uint8_t radius, OLED_ColorTypeDef color);
void OLED_WriteString(uint8_t x, uint8_t y, const char *str, OLED_ColorTypeDef color);
void OLED_SetBrightness(uint8_t brightness); // 0-255

#endif // OLED_DRIVER_H

oled_driver.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include "oled_driver.h"
#include "hal_gpio.h"
#include "hal_spi.h" // 假设使用 SPI 接口

// ... OLED 驱动具体实现,例如初始化序列、命令发送函数、数据发送函数、绘图函数等
// ... 需要根据具体的 OLED 屏型号和驱动 IC 进行实现

void OLED_Init(void) {
// ... 初始化 OLED 屏,例如复位、配置命令
// ... 使用 HAL_GPIO 和 HAL_SPI 接口操作硬件
}

void OLED_ClearDisplay(OLED_ColorTypeDef color) {
// ... 清空显示缓冲区,并刷新到 OLED 屏
}

void OLED_SetPixel(uint8_t x, uint8_t y, OLED_ColorTypeDef color) {
// ... 设置像素点颜色,更新显示缓冲区
}

// ... 其他绘图函数实现

void OLED_WriteString(uint8_t x, uint8_t y, const char *str, OLED_ColorTypeDef color) {
// ... 字符串显示实现,例如逐个字符绘制
}

void OLED_SetBrightness(uint8_t brightness) {
// ... 设置 OLED 亮度控制,可能通过 PWM 或其他方式
}

encoder_driver.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef ENCODER_DRIVER_H
#define ENCODER_DRIVER_H

#include <stdint.h>

typedef struct {
int32_t count;
int32_t delta;
} EncoderDataTypeDef;

void Encoder_Init(void);
EncoderDataTypeDef Encoder_Read(void);
void Encoder_ResetCount(void);

#endif // ENCODER_DRIVER_H

encoder_driver.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "encoder_driver.h"
#include "hal_gpio.h"
#include "hal_timer.h" // 如果使用 timer 编码器模式

// ... 编码器驱动具体实现,例如读取编码器计数、处理方向和增量
// ... 可以使用 GPIO 中断方式或 Timer 编码器模式

void Encoder_Init(void) {
// ... 初始化编码器接口,例如配置 GPIO 或 Timer
}

EncoderDataTypeDef Encoder_Read(void) {
EncoderDataTypeDef data;
// ... 读取编码器计数,计算增量
data.count = 0; // 示例
data.delta = 0; // 示例
return data;
}

void Encoder_ResetCount(void) {
// ... 重置编码器计数器
}

voltage_current_sensor_driver.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef VOLTAGE_CURRENT_SENSOR_DRIVER_H
#define VOLTAGE_CURRENT_SENSOR_DRIVER_H

#include <stdint.h>

typedef struct {
float voltage; // V
float current; // A
} VoltageCurrentDataTypeDef;

void VoltageCurrentSensor_Init(void);
VoltageCurrentDataTypeDef VoltageCurrentSensor_Read(void);

#endif // VOLTAGE_CURRENT_SENSOR_DRIVER_H

voltage_current_sensor_driver.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "voltage_current_sensor_driver.h"
#include "hal_adc.h"

// ... 电压电流传感器驱动具体实现,例如读取 ADC 值、转换成电压电流值、校准
// ... 需要根据具体的电压电流传感器电路进行实现

#define VOLTAGE_ADC_CHANNEL ADC_CHANNEL_VOLTAGE_SENSE
#define CURRENT_ADC_CHANNEL ADC_CHANNEL_CURRENT_SENSE

#define VOLTAGE_DIVIDER_RATIO (10.0f) // 假设电压分压比为 10:1
#define CURRENT_SENSE_RESISTOR (0.01f) // 假设电流采样电阻为 0.01 Ohm
#define ADC_RESOLUTION (4096.0f) // 假设 ADC 分辨率为 12 位

void VoltageCurrentSensor_Init(void) {
HAL_ADC_Init(VOLTAGE_ADC_CHANNEL);
HAL_ADC_Init(CURRENT_ADC_CHANNEL);
}

VoltageCurrentDataTypeDef VoltageCurrentSensor_Read(void) {
VoltageCurrentDataTypeDef data;
uint16_t voltage_adc_value = HAL_ADC_GetValue(VOLTAGE_ADC_CHANNEL);
uint16_t current_adc_value = HAL_ADC_GetValue(CURRENT_ADC_CHANNEL);

// 将 ADC 值转换为电压值 (假设参考电压为 3.3V)
data.voltage = (float)voltage_adc_value / ADC_RESOLUTION * 3.3f * VOLTAGE_DIVIDER_RATIO;

// 将 ADC 值转换为电流值 (假设运放放大倍数为 1,电流 = 电压 / 电阻)
data.current = (float)current_adc_value / ADC_RESOLUTION * 3.3f / CURRENT_SENSE_RESISTOR;

return data;
}

3. 服务层 (Service Layer)

power_control_service.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#ifndef POWER_CONTROL_SERVICE_H
#define POWER_CONTROL_SERVICE_H

#include <stdint.h>
#include <stdbool.h>

typedef struct {
float targetVoltage; // V
float targetCurrent; // A
float outputVoltage; // V
float outputCurrent; // A
float outputPower; // W
bool isOverVoltage;
bool isOverCurrent;
bool isOverTemperature;
bool isShortCircuit;
} PowerStatusTypeDef;

void PowerControl_Init(void);
void PowerControl_SetTargetVoltage(float voltage);
void PowerControl_SetTargetCurrent(float current);
PowerStatusTypeDef PowerControl_GetStatus(void);
void PowerControl_Task(void); // 定期调用,执行控制算法和保护逻辑

#endif // POWER_CONTROL_SERVICE_H

power_control_service.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include "power_control_service.h"
#include "hal_pwm.h"
#include "voltage_current_sensor_driver.h"

#define PWM_CONTROL_CHANNEL PWM_CHANNEL_BUCK_BOOST

#define PID_KP 0.1f
#define PID_KI 0.01f
#define PID_KD 0.001f

static float target_voltage = 5.0f;
static float target_current = 2.0f;
static float current_duty_cycle = 0.5f; // 初始占空比
static float integral_error = 0.0f;
static float previous_error = 0.0f;
static PowerStatusTypeDef power_status;

void PowerControl_Init(void) {
HAL_PWM_Init(PWM_CONTROL_CHANNEL, 100000); // 100kHz PWM frequency
VoltageCurrentSensor_Init();
power_status.targetVoltage = target_voltage;
power_status.targetCurrent = target_current;
}

void PowerControl_SetTargetVoltage(float voltage) {
target_voltage = voltage;
power_status.targetVoltage = target_voltage;
}

void PowerControl_SetTargetCurrent(float current) {
target_current = current;
power_status.targetCurrent = target_current;
}

PowerStatusTypeDef PowerControl_GetStatus(void) {
return power_status;
}

void PowerControl_Task(void) {
VoltageCurrentDataTypeDef sensor_data = VoltageCurrentSensor_Read();
power_status.outputVoltage = sensor_data.voltage;
power_status.outputCurrent = sensor_data.current;
power_status.outputPower = power_status.outputVoltage * power_status.outputCurrent;

// 简单的 PI 控制器 (仅电压环)
float error = target_voltage - power_status.outputVoltage;
integral_error += error;
float derivative_error = error - previous_error;
previous_error = error;

float pwm_adjustment = PID_KP * error + PID_KI * integral_error + PID_KD * derivative_error;
current_duty_cycle += pwm_adjustment;

// 占空比限制
if (current_duty_cycle < 0.0f) current_duty_cycle = 0.0f;
if (current_duty_cycle > 1.0f) current_duty_cycle = 1.0f;

HAL_PWM_SetDutyCycle(PWM_CONTROL_CHANNEL, current_duty_cycle);

// 保护逻辑 (示例,实际应用中需要更完善的保护机制)
power_status.isOverVoltage = (power_status.outputVoltage > 21.0f); // 假设过压阈值为 21V
power_status.isOverCurrent = (power_status.outputCurrent > target_current * 1.2f); // 假设过流阈值为目标电流的 120%
// ... 其他保护逻辑 (过温、短路等)
}

display_management_service.h

1
2
3
4
5
6
7
8
9
10
#ifndef DISPLAY_MANAGEMENT_SERVICE_H
#define DISPLAY_MANAGEMENT_SERVICE_H

#include <stdint.h>
#include "power_control_service.h"

void DisplayManagement_Init(void);
void DisplayManagement_UpdateDisplay(PowerStatusTypeDef powerStatus);

#endif // DISPLAY_MANAGEMENT_SERVICE_H

display_management_service.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "display_management_service.h"
#include "oled_driver.h"
#include <stdio.h> // for sprintf

void DisplayManagement_Init(void) {
OLED_Init();
OLED_ClearDisplay(OLED_COLOR_BLACK);
}

void DisplayManagement_UpdateDisplay(PowerStatusTypeDef powerStatus) {
char buffer[64];

OLED_ClearDisplay(OLED_COLOR_BLACK);

sprintf(buffer, "Target V: %.2fV", powerStatus.targetVoltage);
OLED_WriteString(0, 0, buffer, OLED_COLOR_WHITE);

sprintf(buffer, "Target A: %.2fA", powerStatus.targetCurrent);
OLED_WriteString(0, 10, buffer, OLED_COLOR_WHITE);

sprintf(buffer, "Output V: %.2fV", powerStatus.outputVoltage);
OLED_WriteString(0, 20, buffer, OLED_COLOR_WHITE);

sprintf(buffer, "Output A: %.2fA", powerStatus.outputCurrent);
OLED_WriteString(0, 30, buffer, OLED_COLOR_WHITE);

sprintf(buffer, "Power: %.2fW", powerStatus.outputPower);
OLED_WriteString(0, 40, buffer, OLED_COLOR_WHITE);

if (powerStatus.isOverVoltage) {
OLED_WriteString(0, 50, "OVP!", OLED_COLOR_WHITE);
}
if (powerStatus.isOverCurrent) {
OLED_WriteString(40, 50, "OCP!", OLED_COLOR_WHITE);
}
// ... 显示其他状态信息
}

input_handling_service.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef INPUT_HANDLING_SERVICE_H
#define INPUT_HANDLING_SERVICE_H

#include <stdint.h>
#include <stdbool.h>

typedef enum {
INPUT_EVENT_VOLTAGE_INC,
INPUT_EVENT_VOLTAGE_DEC,
INPUT_EVENT_CURRENT_INC,
INPUT_EVENT_CURRENT_DEC,
INPUT_EVENT_NONE
} InputEventTypeTypeDef;

void InputHandling_Init(void);
InputEventTypeTypeDef InputHandling_GetEvent(void);
void InputHandling_Task(void); // 定期调用,处理输入事件

#endif // INPUT_HANDLING_SERVICE_H

input_handling_service.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include "input_handling_service.h"
#include "encoder_driver.h"

#define VOLTAGE_ENCODER_INDEX 0
#define CURRENT_ENCODER_INDEX 1

static EncoderDataTypeDef encoders[2]; // 假设有两个编码器

void InputHandling_Init(void) {
Encoder_Init(); // 初始化编码器驱动
}

InputEventTypeTypeDef InputHandling_GetEvent(void) {
static int32_t voltage_encoder_count_prev = 0;
static int32_t current_encoder_count_prev = 0;

encoders[VOLTAGE_ENCODER_INDEX] = Encoder_Read(); // 读取电压编码器
encoders[CURRENT_ENCODER_INDEX] = Encoder_Read(); // 读取电流编码器

InputEventTypeTypeDef event = INPUT_EVENT_NONE;

if (encoders[VOLTAGE_ENCODER_INDEX].count > voltage_encoder_count_prev) {
event = INPUT_EVENT_VOLTAGE_INC;
} else if (encoders[VOLTAGE_ENCODER_INDEX].count < voltage_encoder_count_prev) {
event = INPUT_EVENT_VOLTAGE_DEC;
}

if (encoders[CURRENT_ENCODER_INDEX].count > current_encoder_count_prev) {
if (event == INPUT_EVENT_NONE) event = INPUT_EVENT_CURRENT_INC;
} else if (encoders[CURRENT_ENCODER_INDEX].count < current_encoder_count_prev) {
if (event == INPUT_EVENT_NONE) event = INPUT_EVENT_CURRENT_DEC;
}

voltage_encoder_count_prev = encoders[VOLTAGE_ENCODER_INDEX].count;
current_encoder_count_prev = encoders[CURRENT_ENCODER_INDEX].count;

return event;
}

void InputHandling_Task(void) {
// ... 可以添加按键检测、长按短按判断等更复杂的输入处理逻辑
}

4. 应用层 (Application Layer)

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include "hal_init.h" // 假设包含 HAL 初始化函数
#include "power_control_service.h"
#include "display_management_service.h"
#include "input_handling_service.h"
#include "delay.h" // 假设有延时函数

int main(void) {
HAL_Init(); // 初始化 HAL 层
PowerControl_Init();
DisplayManagement_Init();
InputHandling_Init();

float current_target_voltage = 5.0f;
float current_target_current = 2.0f;

PowerControl_SetTargetVoltage(current_target_voltage);
PowerControl_SetTargetCurrent(current_target_current);

while (1) {
PowerControl_Task(); // 电源控制任务
PowerStatusTypeDef power_status = PowerControl_GetStatus();
DisplayManagement_UpdateDisplay(power_status); // 更新显示

InputEventTypeTypeDef input_event = InputHandling_GetEvent();
if (input_event != INPUT_EVENT_NONE) {
switch (input_event) {
case INPUT_EVENT_VOLTAGE_INC:
current_target_voltage += 0.1f;
if (current_target_voltage > 20.0f) current_target_voltage = 20.0f;
PowerControl_SetTargetVoltage(current_target_voltage);
break;
case INPUT_EVENT_VOLTAGE_DEC:
current_target_voltage -= 0.1f;
if (current_target_voltage < 0.0f) current_target_voltage = 0.0f;
PowerControl_SetTargetVoltage(current_target_voltage);
break;
case INPUT_EVENT_CURRENT_INC:
current_target_current += 0.1f;
if (current_target_current > 5.0f) current_target_current = 5.0f;
PowerControl_SetTargetCurrent(current_target_current);
break;
case INPUT_EVENT_CURRENT_DEC:
current_target_current -= 0.1f;
if (current_target_current < 0.0f) current_target_current = 0.0f;
PowerControl_SetTargetCurrent(current_target_current);
break;
default:
break;
}
}
InputHandling_Task(); // 输入处理任务
Delay_ms(10); // 延时,控制循环频率
}
return 0;
}

第四部分:项目中采用的各种技术和方法

  1. 分层架构: 如上所述,采用分层架构来组织代码,提高模块化、可维护性、可重用性和可扩展性。
  2. HAL 硬件抽象层: 使用 HAL 层屏蔽底层硬件差异,提高代码的可移植性。
  3. 模块化设计: 将系统划分为独立的模块,每个模块负责特定的功能,降低系统复杂性,提高代码可读性和可维护性。
  4. PID 控制算法: 采用 PID 控制算法实现精确的电压和电流闭环控制,保证输出电压和电流的稳定性。
  5. PWM 脉冲宽度调制: 使用 PWM 技术控制 Buck-Boost 电路的开关管,调节输出电压和电流。
  6. ADC 模数转换: 使用 ADC 采集电压电流传感器的信号,实现电压和电流的实时监测。
  7. OLED/LCD 显示驱动: 编写 OLED/LCD 驱动程序,实现电压、电流、功率等参数的实时显示。
  8. 编码器输入处理: 编写编码器驱动程序,处理编码器输入,实现用户对电压电流的调节。
  9. 保护机制: 实现过压保护(OVP)、过流保护(OCP)、过温保护(OTP)、短路保护(SCP)等全面的保护机制,确保系统和负载的安全。
  10. 状态机: 可以使用状态机管理电源的不同工作状态,例如正常工作状态、保护状态、设置状态等。
  11. 异常处理: 在代码中加入适当的错误处理和异常处理机制,提高系统的鲁棒性。
  12. 代码审查和单元测试: 进行代码审查和单元测试,确保代码质量和功能正确性。
  13. 版本管理工具: 使用 Git 等版本管理工具管理代码和文档,方便团队协作和版本控制。

第五部分:测试验证和维护升级

  1. 测试验证:

    • 单元测试: 对每个模块进行单元测试,例如 HAL 层驱动、传感器驱动、PID 控制器、显示驱动、输入处理等。
    • 集成测试: 将各个模块集成在一起进行测试,验证模块之间的协同工作是否正常。
    • 系统测试: 对整个系统进行全面的功能和性能测试,包括:
      • 功能测试: 验证电压电流调节功能、保护功能、显示功能、输入控制功能等是否符合需求。
      • 性能测试: 测试电压调整率、负载调整率、效率、纹波噪声、响应速度等性能指标是否满足设计要求。
      • 稳定性测试: 长时间运行测试,验证系统在各种工况下的稳定性。
      • 可靠性测试: 进行环境测试(高温、低温、振动等)、寿命测试等,评估系统的可靠性。
      • 保护功能测试: 专门测试过压保护、过流保护、过温保护、短路保护等保护功能是否有效。
      • 用户体验测试: 邀请用户进行测试,收集用户反馈,改进用户体验。
    • 自动化测试: 可以考虑使用自动化测试工具和脚本,提高测试效率和覆盖率。
  2. 维护升级:

    • 模块化维护: 由于采用分层架构和模块化设计,系统的维护和升级可以针对特定模块进行,降低维护成本和风险。
    • 固件升级: 预留固件升级接口,方便后续功能升级和 Bug 修复。可以使用 UART、USB、OTA (Over-The-Air) 等方式进行固件升级。
    • 日志记录: 加入日志记录功能,记录系统运行状态和错误信息,方便故障诊断和维护。
    • 远程监控和管理: 如果需要,可以考虑加入网络通信接口,实现远程监控和管理功能。
    • 用户反馈收集: 建立用户反馈渠道,及时收集用户意见和建议,持续改进产品。

总结

这个项目展示了一个完整的嵌入式系统开发流程,从需求分析到系统实现,再到测试验证和维护升级。通过采用分层架构、模块化设计、PID 控制算法、完善的保护机制等技术和方法,构建了一个可靠、高效、可扩展的升降压可调电源系统平台。 代码示例虽然是简化版本,但展示了关键模块的实现思路和代码框架,可以作为实际项目开发的参考。 在实际项目中,还需要根据具体的需求和硬件平台进行详细的设计和实现,并进行充分的测试验证,才能确保产品的质量和性能。

为了满足 3000 行代码的要求,以上代码示例可以进一步扩展和完善,例如:

  • HAL 层: 完善 HAL 层驱动,实现更多硬件外设的驱动,例如 SPI、I2C、UART、Timer 等。
  • 驱动层: 添加更多驱动程序,例如风扇驱动、保护芯片驱动、Type-C PD 协议驱动等。
  • 服务层: 完善 PID 控制算法,加入电流环控制、Buck-Boost 模式切换、效率优化算法、参数配置功能、状态机管理、通信协议处理等。
  • 应用层: 完善用户界面,实现更丰富的显示内容和用户交互功能,例如菜单界面、参数设置界面、故障诊断界面、通信控制界面等。
  • 测试代码: 编写单元测试代码,对各个模块进行单元测试。
  • 文档注释: 添加详细的文档注释,提高代码的可读性和可维护性。

通过以上扩展和完善,可以轻松达到 3000 行代码的要求,并构建一个更加完善和强大的嵌入式升降压可调电源系统。

欢迎关注我的其它发布渠道