编程技术分享

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

0%

简介:大功率触控桌充,4个 24w USB-A可控制接口 + 2个65w Type-c

好的,作为一名高级嵌入式软件开发工程师,我将为您详细阐述一个针对大功率触控桌充的嵌入式系统软件架构设计,并提供相应的C代码实现。这个项目旨在构建一个可靠、高效、可扩展的平台,涵盖从需求分析到系统维护的完整生命周期。
关注微信公众号,提前获取相关推文

项目概述

项目名称: 大功率触控桌充嵌入式系统

功能描述:

  • 端口控制: 提供 4 个 24W USB-A 可控接口和 2 个 65W Type-C 接口,每个端口均可独立控制电源开关。
  • 触控交互: 用户通过触摸屏控制端口的开启和关闭,并可能扩展其他功能(如功率显示、充电协议切换等)。
  • 状态指示: 通过 LED 指示灯显示各端口的当前状态(开启/关闭/充电中/故障)。
  • 功率管理: 实现整体功率的智能分配和限制,确保系统稳定运行,并保护连接设备。
  • 安全保护: 过流保护、过压保护、过温保护、短路保护等,确保系统和连接设备的安全。
  • 可扩展性: 软件架构应具备良好的可扩展性,方便未来添加新功能或支持更多端口类型。
  • 可靠性: 系统需要稳定可靠运行,具备完善的错误处理和恢复机制。
  • 高效性: 系统响应速度快,资源占用低,功耗优化。

硬件平台(假设):

  • 微控制器 (MCU): 高性能 ARM Cortex-M 系列 MCU (如 STM32H7 系列),具备足够的处理能力、外设接口和内存资源。
  • 触控芯片: 电容式触摸屏控制器,通过 I2C 或 SPI 接口与 MCU 通信。
  • 电源管理 IC (PMIC): 负责整体电源分配、端口电源控制、充电协议支持、保护功能等。
  • USB 控制器: 支持 USB-A 和 Type-C 端口的控制器芯片,负责 USB 通信和功率输出。
  • LED 驱动芯片: 驱动 LED 指示灯。
  • 电流/电压检测芯片: 实时监测端口的电流和电压。
  • 温度传感器: 监测系统温度,用于过温保护。

软件架构设计

我们将采用分层架构来设计嵌入式系统软件,这种架构具有良好的模块化、可维护性和可扩展性。分层架构的核心思想是将系统划分为多个独立的层,每一层只关注特定的功能,并向上层提供服务接口。

软件架构图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
+-----------------------+
| **应用层 (Application Layer)** |
| - 用户界面逻辑 |
| - 系统管理 |
+-----------------------+
| **服务层 (Service Layer)** |
| - 电源管理服务 |
| - 触控服务 |
| - LED 控制服务 |
| - 状态监测服务 |
+-----------------------+
| **中间件层 (Middleware Layer)** |
| - 操作系统抽象层 (OSAL) |
| - 设备驱动框架 (Driver Framework)|
+-----------------------+
| **硬件抽象层 (HAL - Hardware Abstraction Layer)** |
| - MCU 驱动 (GPIO, Timer, ADC, I2C, SPI, UART) |
| - 外设驱动 (触控芯片, PMIC, USB 控制器, LED 驱动, 传感器) |
+-----------------------+
| **硬件层 (Hardware Layer)** |
| - MCU, 触控屏, PMIC, USB 控制器, LED, 传感器 等 |
+-----------------------+

各层功能详细描述:

  1. 硬件层 (Hardware Layer):

    • 这是系统的物理基础,包括 MCU、触控屏、电源管理 IC、USB 控制器、LED 指示灯、传感器等硬件组件。
  2. 硬件抽象层 (HAL - Hardware Abstraction Layer):

    • MCU 驱动: 提供对 MCU 内部外设 (GPIO、定时器、ADC、I2C、SPI、UART 等) 的底层访问接口。HAL 层将硬件细节屏蔽,为上层提供统一的、平台无关的接口。
    • 外设驱动: 驱动外部硬件设备,如触控芯片、PMIC、USB 控制器、LED 驱动芯片、传感器等。HAL 层负责与这些芯片进行通信和控制,将其功能抽象成易于使用的 API。
  3. 中间件层 (Middleware Layer):

    • 操作系统抽象层 (OSAL - Operating System Abstraction Layer): 如果系统使用 RTOS (实时操作系统),OSAL 层将 RTOS 的 API (任务管理、同步机制、内存管理等) 封装起来,为上层服务层提供统一的操作系统接口。这使得上层服务可以独立于具体的 RTOS 实现,增强了系统的可移植性。 如果不使用 RTOS,OSAL 层可以简化为提供一些基本的任务调度和同步机制的抽象。
    • 设备驱动框架 (Driver Framework): 提供一套通用的驱动管理和注册机制,方便驱动程序的开发、管理和维护。可以实现驱动的自动加载、卸载、初始化和资源管理。
  4. 服务层 (Service Layer):

    • 电源管理服务 (Power Management Service):
      • 负责管理各个 USB 端口的电源开关。
      • 实现功率分配策略,根据连接设备的需求和系统总功率限制,动态调整端口的功率输出。
      • 处理充电协议 (如 USB PD, QC 等) 的协商和控制 (可能需要 PMIC 或 USB 控制器硬件支持)。
      • 监测端口的电压、电流、功率,并提供状态反馈。
      • 实现过流、过压、过温、短路等保护机制 (与 PMIC 硬件协同工作)。
    • 触控服务 (Touch Service):
      • 负责接收来自触控芯片驱动的原始触控数据。
      • 进行触控事件解析和处理,识别触摸、滑动、长按等手势。
      • 将触控事件转换为应用层可以理解的操作指令 (如端口选择、开关控制等)。
      • 提供触控反馈 (例如,触摸音效,触摸震动 - 如果硬件支持)。
    • LED 控制服务 (LED Control Service):
      • 控制 LED 指示灯的显示状态 (颜色、亮度、闪烁模式)。
      • 根据系统状态和端口状态,更新 LED 显示,提供直观的用户反馈。
      • 可以实现多种 LED 显示模式,例如,端口开启/关闭指示、充电状态指示、故障报警指示等。
    • 状态监测服务 (Status Monitoring Service):
      • 定期或实时监测系统的关键状态参数,如端口电压、电流、温度、系统错误等。
      • 将状态数据汇总并提供给应用层,用于状态显示、故障诊断和系统维护。
      • 可以实现告警机制,当系统状态异常时,及时通知应用层或采取相应的保护措施。
  5. 应用层 (Application Layer):

    • 用户界面逻辑 (UI Logic):
      • 处理用户通过触控屏进行的操作,调用服务层的接口来实现具体功能。
      • 例如,当用户触摸 USB-A 端口 1 的开关图标时,UI 逻辑调用电源管理服务接口来开启或关闭端口 1 的电源。
      • 负责界面显示更新,将系统状态、端口状态等信息显示在触控屏上。
    • 系统管理 (System Management):
      • 系统初始化:在系统启动时,初始化 HAL 层、中间件层和服务层。
      • 错误处理:接收来自服务层和 HAL 层的错误报告,进行错误处理和恢复 (例如,重启端口,记录错误日志,告警等)。
      • 系统配置管理:读取和保存系统配置参数 (例如,功率分配策略、LED 显示模式等)。
      • 固件升级 (OTA - Over-The-Air): 预留固件升级接口,方便未来进行固件更新和维护 (如果需要)。
      • 调试接口:提供调试接口 (例如,串口调试、JTAG 调试) 用于开发和测试阶段的系统调试和诊断。

C 代码实现 (部分示例,3000 行代码完整实现超出篇幅限制,这里提供关键模块的框架和示例代码,实际项目中需要根据具体硬件和需求进行详细实现和扩展)

为了满足 3000 行代码的要求,我们将尽可能详细地展开各个模块的代码实现,并加入必要的注释和说明。以下代码示例将涵盖 HAL 层、服务层和应用层的关键部分。

1. HAL 层代码示例 (HAL - Hardware Abstraction Layer)

我们假设使用 STM32H7 系列 MCU,并使用 GPIO 控制 LED,使用 I2C 通信与触控芯片和 PMIC 芯片通信。

hal_gpio.h (GPIO HAL 接口头文件)

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
#ifndef HAL_GPIO_H
#define HAL_GPIO_H

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

// GPIO 端口定义 (根据实际硬件连接定义)
typedef enum {
GPIO_PORT_A,
GPIO_PORT_B,
GPIO_PORT_C,
// ... more ports
GPIO_PORT_MAX
} GPIO_Port_TypeDef;

// GPIO 引脚定义
typedef enum {
GPIO_PIN_0,
GPIO_PIN_1,
GPIO_PIN_2,
// ... more pins
GPIO_PIN_MAX
} GPIO_Pin_TypeDef;

// GPIO 方向定义
typedef enum {
GPIO_DIRECTION_INPUT,
GPIO_DIRECTION_OUTPUT
} GPIO_Direction_TypeDef;

// GPIO 输出类型定义
typedef enum {
GPIO_OUTPUT_TYPE_PUSH_PULL,
GPIO_OUTPUT_TYPE_OPEN_DRAIN
} GPIO_OutputType_TypeDef;

// GPIO 上下拉电阻定义
typedef enum {
GPIO_PULL_NONE,
GPIO_PULL_UP,
GPIO_PULL_DOWN
} GPIO_Pull_TypeDef;

// GPIO 初始化结构体
typedef struct {
GPIO_Port_TypeDef Port; // GPIO 端口
GPIO_Pin_TypeDef Pin; // GPIO 引脚
GPIO_Direction_TypeDef Direction; // GPIO 方向
GPIO_OutputType_TypeDef OutputType; // GPIO 输出类型
GPIO_Pull_TypeDef Pull; // GPIO 上下拉电阻
} GPIO_InitTypeDef;

// 初始化 GPIO
bool HAL_GPIO_Init(GPIO_InitTypeDef *GPIO_InitStruct);

// 设置 GPIO 输出电平
void HAL_GPIO_WritePin(GPIO_Port_TypeDef Port, GPIO_Pin_TypeDef Pin, bool PinState);

// 读取 GPIO 输入电平
bool HAL_GPIO_ReadPin(GPIO_Port_TypeDef Port, GPIO_Pin_TypeDef Pin);

#endif // HAL_GPIO_H

hal_gpio.c (GPIO HAL 接口实现文件)

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include "hal_gpio.h"
#include "stm32h7xx_hal.h" // 假设使用 STM32H7 HAL 库,需要包含相应的 HAL 库头文件

// 初始化 GPIO
bool HAL_GPIO_Init(GPIO_InitTypeDef *GPIO_InitStruct) {
GPIO_InitTypeDefTypeDef GPIO_HAL_InitStruct; // STM32 HAL 库的 GPIO 初始化结构体

// 将 HAL_GPIO_InitTypeDef 转换为 STM32 HAL 库的 GPIO_InitTypeDefTypeDef
switch (GPIO_InitStruct->Port) {
case GPIO_PORT_A: GPIO_HAL_InitStruct.Pin = (1 << GPIO_InitStruct->Pin); break;
case GPIO_PORT_B: GPIO_HAL_InitStruct.Pin = (1 << GPIO_InitStruct->Pin); break;
case GPIO_PORT_C: GPIO_HAL_InitStruct.Pin = (1 << GPIO_InitStruct->Pin); break;
// ... more ports
default: return false; // 端口无效
}

if (GPIO_InitStruct->Direction == GPIO_DIRECTION_INPUT) {
GPIO_HAL_InitStruct.Mode = GPIO_MODE_INPUT;
} else { // GPIO_DIRECTION_OUTPUT
GPIO_HAL_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 默认推挽输出
if (GPIO_InitStruct->OutputType == GPIO_OUTPUT_TYPE_OPEN_DRAIN) {
GPIO_HAL_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; // 开漏输出
}
}

if (GPIO_InitStruct->Pull == GPIO_PULL_NONE) {
GPIO_HAL_InitStruct.Pull = GPIO_NOPULL;
} else if (GPIO_InitStruct->Pull == GPIO_PULL_UP) {
GPIO_HAL_InitStruct.Pull = GPIO_PULLUP;
} else { // GPIO_PULL_DOWN
GPIO_HAL_InitStruct.Pull = GPIO_PULLDOWN;
}

GPIO_HAL_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 默认低速
// 可以根据需要配置 GPIO_HAL_InitStruct.Alternate // 复用功能配置

// 根据 GPIO_InitStruct->Port 选择对应的 GPIO 外设基地址,这里假设 GPIO_PORT_A 对应 GPIOA, GPIO_PORT_B 对应 GPIOB, ...
GPIO_TypeDef *GPIOx;
switch (GPIO_InitStruct->Port) {
case GPIO_PORT_A: GPIOx = GPIOA; break;
case GPIO_PORT_B: GPIOx = GPIOB; break;
case GPIO_PORT_C: GPIOx = GPIOC; break;
// ... more ports
default: return false; // 端口无效
}

HAL_GPIO_Init_Func(GPIOx, &GPIO_HAL_InitStruct); // 调用 STM32 HAL 库的 GPIO 初始化函数,需要根据实际 HAL 库函数名修改
return true;
}

// 设置 GPIO 输出电平
void HAL_GPIO_WritePin(GPIO_Port_TypeDef Port, GPIO_Pin_TypeDef Pin, bool PinState) {
GPIO_PinState state = PinState ? GPIO_PIN_SET : GPIO_PIN_RESET;
GPIO_TypeDef *GPIOx;
uint16_t GPIO_Pin;

switch (Port) {
case GPIO_PORT_A: GPIOx = GPIOA; break;
case GPIO_PORT_B: GPIOx = GPIOB; break;
case GPIO_PORT_C: GPIOx = GPIOC; break;
// ... more ports
default: return; // 端口无效
}
switch (Pin) {
case GPIO_PIN_0: GPIO_Pin = GPIO_PIN_0; break;
case GPIO_PIN_1: GPIO_Pin = GPIO_PIN_1; break;
case GPIO_PIN_2: GPIO_Pin = GPIO_PIN_2; break;
// ... more pins
default: return; // 引脚无效
}

HAL_GPIO_WritePin_Func(GPIOx, GPIO_Pin, state); // 调用 STM32 HAL 库的 GPIO 写引脚函数,需要根据实际 HAL 库函数名修改
}

// 读取 GPIO 输入电平
bool HAL_GPIO_ReadPin(GPIO_Port_TypeDef Port, GPIO_Pin_TypeDef Pin) {
GPIO_TypeDef *GPIOx;
uint16_t GPIO_Pin;

switch (Port) {
case GPIO_PORT_A: GPIOx = GPIOA; break;
case GPIO_PORT_B: GPIOx = GPIOB; break;
case GPIO_PORT_C: GPIOx = GPIOC; break;
// ... more ports
default: return false; // 端口无效
}
switch (Pin) {
case GPIO_PIN_0: GPIO_Pin = GPIO_PIN_0; break;
case GPIO_PIN_1: GPIO_Pin = GPIO_PIN_1; break;
case GPIO_PIN_2: GPIO_Pin = GPIO_PIN_2; break;
// ... more pins
default: return false; // 引脚无效
}

return (HAL_GPIO_ReadPin_Func(GPIOx, GPIO_Pin) == GPIO_PIN_SET); // 调用 STM32 HAL 库的 GPIO 读引脚函数,需要根据实际 HAL 库函数名修改
}

hal_i2c.h (I2C HAL 接口头文件)

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
#ifndef HAL_I2C_H
#define HAL_I2C_H

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

// I2C 设备定义
typedef enum {
I2C_DEVICE_1,
I2C_DEVICE_2,
// ... more I2C devices
I2C_DEVICE_MAX
} I2C_Device_TypeDef;

// I2C 初始化结构体
typedef struct {
I2C_Device_TypeDef Device; // I2C 设备
uint32_t ClockSpeed; // I2C 时钟速度
uint16_t OwnAddress1; // 设备自身地址 (7 位或 10 位)
uint32_t AddressingMode; // 地址模式 (7 位或 10 位)
uint32_t DualAddressMode; // 双地址模式
uint16_t OwnAddress2; // 第二个设备自身地址
uint32_t GeneralCallMode; // 广播呼叫模式
uint32_t NoStretchMode; // 时钟线拉伸模式
} I2C_InitTypeDef;

// 初始化 I2C
bool HAL_I2C_Init(I2C_InitTypeDef *I2C_InitStruct);

// I2C 发送数据
bool HAL_I2C_Master_Transmit(I2C_Device_TypeDef Device, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);

// I2C 接收数据
bool HAL_I2C_Master_Receive(I2C_Device_TypeDef Device, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);

#endif // HAL_I2C_H

hal_i2c.c (I2C HAL 接口实现文件)

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
#include "hal_i2c.h"
#include "stm32h7xx_hal.h" // 假设使用 STM32H7 HAL 库

// 初始化 I2C
bool HAL_I2C_Init(I2C_InitTypeDef *I2C_InitStruct) {
I2C_HandleTypeDef hi2c; // STM32 HAL 库的 I2C 句柄结构体

// 将 HAL_I2C_InitTypeDef 转换为 STM32 HAL 库的 I2C_InitTypeDefTypeDef
switch (I2C_InitStruct->Device) {
case I2C_DEVICE_1: hi2c.Instance = I2C1; break;
case I2C_DEVICE_2: hi2c.Instance = I2C2; break;
// ... more devices
default: return false; // 设备无效
}

hi2c.Init.ClockSpeed = I2C_InitStruct->ClockSpeed;
hi2c.Init.OwnAddress1 = I2C_InitStruct->OwnAddress1;
hi2c.Init.AddressingMode = I2C_InitStruct->AddressingMode;
hi2c.Init.DualAddressMode = I2C_InitStruct->DualAddressMode;
hi2c.Init.OwnAddress2 = I2C_InitStruct->OwnAddress2;
hi2c.Init.GeneralCallMode = I2C_InitStruct->GeneralCallMode;
hi2c.Init.NoStretchMode = I2C_InitStruct->NoStretchMode;

if (HAL_I2C_Init_Func(&hi2c) != HAL_OK) { // 调用 STM32 HAL 库的 I2C 初始化函数,需要根据实际 HAL 库函数名修改
return false;
}
return true;
}

// I2C 发送数据
bool HAL_I2C_Master_Transmit(I2C_Device_TypeDef Device, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout) {
I2C_HandleTypeDef hi2c;
switch (Device) {
case I2C_DEVICE_1: hi2c.Instance = I2C1; break;
case I2C_DEVICE_2: hi2c.Instance = I2C2; break;
// ... more devices
default: return false;
}

if (HAL_I2C_Master_Transmit_Func(&hi2c, DevAddress << 1, pData, Size, Timeout) != HAL_OK) { // 调用 STM32 HAL 库的 I2C 发送函数,需要根据实际 HAL 库函数名修改
return false;
}
return true;
}

// I2C 接收数据
bool HAL_I2C_Master_Receive(I2C_Device_TypeDef Device, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout) {
I2C_HandleTypeDef hi2c;
switch (Device) {
case I2C_DEVICE_1: hi2c.Instance = I2C1; break;
case I2C_DEVICE_2: hi2c.Instance = I2C2; break;
// ... more devices
default: return false;
}

if (HAL_I2C_Master_Receive_Func(&hi2c, DevAddress << 1, pData, Size, Timeout) != HAL_OK) { // 调用 STM32 HAL 库的 I2C 接收函数,需要根据实际 HAL 库函数名修改
return false;
}
return true;
}

(为了满足 3000 行代码的要求,HAL 层可以继续扩展 UART, SPI, ADC, Timer 等模块的 HAL 接口和实现,并根据具体的 MCU 型号和外设进行详细的实现。例如,可以加入 DMA 支持的 I2C/SPI 传输函数,更详细的 GPIO 配置选项,Timer 的各种工作模式配置等等。)

2. 服务层代码示例 (Service Layer)

power_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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#ifndef POWER_SERVICE_H
#define POWER_SERVICE_H

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

// USB 端口定义
typedef enum {
USB_PORT_A1,
USB_PORT_A2,
USB_PORT_A3,
USB_PORT_A4,
USB_PORT_C1,
USB_PORT_C2,
USB_PORT_MAX
} USB_Port_TypeDef;

// 端口状态定义
typedef enum {
PORT_STATUS_OFF,
PORT_STATUS_ON,
PORT_STATUS_CHARGING,
PORT_STATUS_FAULT
} Port_Status_TypeDef;

// 初始化电源管理服务
bool PowerService_Init(void);

// 开启指定端口电源
bool PowerService_PortOn(USB_Port_TypeDef port);

// 关闭指定端口电源
bool PowerService_PortOff(USB_Port_TypeDef port);

// 获取指定端口状态
Port_Status_TypeDef PowerService_GetPortStatus(USB_Port_TypeDef port);

// 获取所有端口状态
Port_Status_TypeDef PowerService_GetAllPortStatus(Port_Status_TypeDef *port_status_array);

// 设置端口功率限制 (可选,如果 PMIC 支持)
bool PowerService_SetPortPowerLimit(USB_Port_TypeDef port, uint32_t power_mW);

// 获取端口实时电压电流 (可选,如果 PMIC 和电流电压检测芯片支持)
bool PowerService_GetPortVoltageCurrent(USB_Port_TypeDef port, float *voltage_V, float *current_A);

#endif // POWER_SERVICE_H

power_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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include "power_service.h"
#include "hal_gpio.h" // 使用 GPIO 控制端口电源开关 (假设)
#include "hal_i2c.h" // 使用 I2C 与 PMIC 芯片通信 (假设)
#include "led_service.h" // LED 服务用于指示端口状态

// 定义控制各个端口电源开关的 GPIO 引脚 (根据实际硬件连接定义)
#define USB_PORT_A1_PWR_EN_PORT GPIO_PORT_A
#define USB_PORT_A1_PWR_EN_PIN GPIO_PIN_0
#define USB_PORT_A2_PWR_EN_PORT GPIO_PORT_A
#define USB_PORT_A2_PWR_EN_PIN GPIO_PIN_1
#define USB_PORT_A3_PWR_EN_PORT GPIO_PORT_A
#define USB_PORT_A3_PWR_EN_PIN GPIO_PIN_2
#define USB_PORT_A4_PWR_EN_PORT GPIO_PORT_A
#define USB_PORT_A4_PWR_EN_PIN GPIO_PIN_3
#define USB_PORT_C1_PWR_EN_PORT GPIO_PORT_B
#define USB_PORT_C1_PWR_EN_PIN GPIO_PIN_0
#define USB_PORT_C2_PWR_EN_PORT GPIO_PORT_B
#define USB_PORT_C2_PWR_EN_PIN GPIO_PIN_1

// 定义 PMIC 芯片的 I2C 地址 (根据 PMIC 芯片手册定义)
#define PMIC_I2C_ADDRESS 0x68 // 示例地址,需要根据实际 PMIC 芯片修改

// 定义端口状态数组
static Port_Status_TypeDef port_status[USB_PORT_MAX];

// 初始化电源管理服务
bool PowerService_Init(void) {
// 初始化 GPIO 引脚用于控制端口电源开关
GPIO_InitTypeDef gpio_init_struct = {0};
gpio_init_struct.Direction = GPIO_DIRECTION_OUTPUT;
gpio_init_struct.OutputType = GPIO_OUTPUT_TYPE_PUSH_PULL;
gpio_init_struct.Pull = GPIO_PULL_NONE;

gpio_init_struct.Port = USB_PORT_A1_PWR_EN_PORT; gpio_init_struct.Pin = USB_PORT_A1_PWR_EN_PIN; HAL_GPIO_Init(&gpio_init_struct);
gpio_init_struct.Port = USB_PORT_A2_PWR_EN_PORT; gpio_init_struct.Pin = USB_PORT_A2_PWR_EN_PIN; HAL_GPIO_Init(&gpio_init_struct);
gpio_init_struct.Port = USB_PORT_A3_PWR_EN_PORT; gpio_init_struct.Pin = USB_PORT_A3_PWR_EN_PIN; HAL_GPIO_Init(&gpio_init_struct);
gpio_init_struct.Port = USB_PORT_A4_PWR_EN_PORT; gpio_init_struct.Pin = USB_PORT_A4_PWR_EN_PIN; HAL_GPIO_Init(&gpio_init_struct);
gpio_init_struct.Port = USB_PORT_C1_PWR_EN_PORT; gpio_init_struct.Pin = USB_PORT_C1_PWR_EN_PIN; HAL_GPIO_Init(&gpio_init_struct);
gpio_init_struct.Port = USB_PORT_C2_PWR_EN_PORT; gpio_init_struct.Pin = USB_PORT_C2_PWR_EN_PIN; HAL_GPIO_Init(&gpio_init_struct);

// 初始化 I2C 用于与 PMIC 芯片通信 (如果使用 PMIC 控制电源)
// I2C_InitTypeDef i2c_init_struct = {0};
// i2c_init_struct.Device = I2C_DEVICE_1; // 选择 I2C 设备
// i2c_init_struct.ClockSpeed = 100000; // 100kHz
// i2c_init_struct.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
// i2c_init_struct.OwnAddress1 = 0; // Master 设备不需要配置自身地址
// HAL_I2C_Init(&i2c_init_struct);

// 初始化端口状态为 OFF
for (int i = 0; i < USB_PORT_MAX; i++) {
port_status[i] = PORT_STATUS_OFF;
}

return true;
}

// 开启指定端口电源
bool PowerService_PortOn(USB_Port_TypeDef port) {
switch (port) {
case USB_PORT_A1: HAL_GPIO_WritePin(USB_PORT_A1_PWR_EN_PORT, USB_PORT_A1_PWR_EN_PIN, true); break;
case USB_PORT_A2: HAL_GPIO_WritePin(USB_PORT_A2_PWR_EN_PORT, USB_PORT_A2_PWR_EN_PIN, true); break;
case USB_PORT_A3: HAL_GPIO_WritePin(USB_PORT_A3_PWR_EN_PORT, USB_PORT_A3_PWR_EN_PIN, true); break;
case USB_PORT_A4: HAL_GPIO_WritePin(USB_PORT_A4_PWR_EN_PORT, USB_PORT_A4_PWR_EN_PIN, true); break;
case USB_PORT_C1: HAL_GPIO_WritePin(USB_PORT_C1_PWR_EN_PORT, USB_PORT_C1_PWR_EN_PIN, true); break;
case USB_PORT_C2: HAL_GPIO_WritePin(USB_PORT_C2_PWR_EN_PORT, USB_PORT_C2_PWR_EN_PIN, true); break;
default: return false; // 端口无效
}

port_status[port] = PORT_STATUS_ON; // 更新端口状态
LEDService_SetPortLED(port, LED_STATE_ON); // 更新 LED 指示灯状态
return true;
}

// 关闭指定端口电源
bool PowerService_PortOff(USB_Port_TypeDef port) {
switch (port) {
case USB_PORT_A1: HAL_GPIO_WritePin(USB_PORT_A1_PWR_EN_PORT, USB_PORT_A1_PWR_EN_PIN, false); break;
case USB_PORT_A2: HAL_GPIO_WritePin(USB_PORT_A2_PWR_EN_PORT, USB_PORT_A2_PWR_EN_PIN, false); break;
case USB_PORT_A3: HAL_GPIO_WritePin(USB_PORT_A3_PWR_EN_PORT, USB_PORT_A3_PWR_EN_PIN, false); break;
case USB_PORT_A4: HAL_GPIO_WritePin(USB_PORT_A4_PWR_EN_PORT, USB_PORT_A4_PWR_EN_PIN, false); break;
case USB_PORT_C1: HAL_GPIO_WritePin(USB_PORT_C1_PWR_EN_PORT, USB_PORT_C1_PWR_EN_PIN, false); break;
case USB_PORT_C2: HAL_GPIO_WritePin(USB_PORT_C2_PWR_EN_PORT, USB_PORT_C2_PWR_EN_PIN, false); break;
default: return false; // 端口无效
}

port_status[port] = PORT_STATUS_OFF; // 更新端口状态
LEDService_SetPortLED(port, LED_STATE_OFF); // 更新 LED 指示灯状态
return true;
}

// 获取指定端口状态
Port_Status_TypeDef PowerService_GetPortStatus(USB_Port_TypeDef port) {
if (port >= USB_PORT_MAX) {
return PORT_STATUS_FAULT; // 端口无效
}
return port_status[port];
}

// 获取所有端口状态
Port_Status_TypeDef PowerService_GetAllPortStatus(Port_Status_TypeDef *port_status_array) {
if (port_status_array == NULL) {
return PORT_STATUS_FAULT; // 参数无效
}
for (int i = 0; i < USB_PORT_MAX; i++) {
port_status_array[i] = port_status[i];
}
return PORT_STATUS_ON; // 成功返回,可以根据实际情况定义返回值
}

// 设置端口功率限制 (可选,如果 PMIC 支持,需要通过 I2C 与 PMIC 通信)
bool PowerService_SetPortPowerLimit(USB_Port_TypeDef port, uint32_t power_mW) {
// ... 通过 I2C 与 PMIC 通信,写入功率限制寄存器 ...
// ... 具体实现需要参考 PMIC 芯片手册 ...
return false; // 示例,未实现
}

// 获取端口实时电压电流 (可选,如果 PMIC 和电流电压检测芯片支持,需要通过 I2C 通信)
bool PowerService_GetPortVoltageCurrent(USB_Port_TypeDef port, float *voltage_V, float *current_A) {
// ... 通过 I2C 与 PMIC 或电流电压检测芯片通信,读取电压电流数据 ...
// ... 具体实现需要参考 PMIC 或电流电压检测芯片手册 ...
return false; // 示例,未实现
}

(类似地,可以实现 touch_service.htouch_service.cled_service.hled_service.cstatus_monitor_service.hstatus_monitor_service.c 等服务层模块。 例如,touch_service 需要驱动触控芯片,解析触控事件,并向上层提供触控事件回调接口。 led_service 需要驱动 LED 驱动芯片或直接使用 GPIO 控制 LED,实现 LED 的各种显示模式。 status_monitor_service 需要定期读取电压、电流、温度等传感器数据,进行异常检测和告警。)

3. 应用层代码示例 (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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include "power_service.h"
#include "touch_service.h"
#include "led_service.h"
#include "status_monitor_service.h"
#include "osal.h" // 操作系统抽象层 (如果使用 RTOS)

// 定义端口开关状态,用于 UI 显示
typedef enum {
PORT_UI_STATE_OFF,
PORT_UI_STATE_ON
} Port_UI_State_TypeDef;

static Port_UI_State_TypeDef port_ui_state[USB_PORT_MAX];

// 触控事件回调函数 (在 touch_service 中注册)
void TouchEventHandler(Touch_Event_TypeDef event) {
USB_Port_TypeDef touched_port;

switch (event) {
case TOUCH_EVENT_PORT_A1_TAP: touched_port = USB_PORT_A1; break;
case TOUCH_EVENT_PORT_A2_TAP: touched_port = USB_PORT_A2; break;
case TOUCH_EVENT_PORT_A3_TAP: touched_port = USB_PORT_A3; break;
case TOUCH_EVENT_PORT_A4_TAP: touched_port = USB_PORT_A4; break;
case TOUCH_EVENT_PORT_C1_TAP: touched_port = USB_PORT_C1; break;
case TOUCH_EVENT_PORT_C2_TAP: touched_port = USB_PORT_C2; break;
default: return; // 其他触控事件忽略
}

// 切换端口状态
if (port_ui_state[touched_port] == PORT_UI_STATE_OFF) {
PowerService_PortOn(touched_port);
port_ui_state[touched_port] = PORT_UI_STATE_ON;
} else {
PowerService_PortOff(touched_port);
port_ui_state[touched_port] = PORT_UI_STATE_OFF;
}

// 更新 UI 显示 (例如,刷新触控屏上的端口状态图标)
// UpdateUIDisplay(); // 假设有 UI 显示更新函数,这里省略具体实现
}

int main(void) {
// 系统初始化
HAL_Init(); // STM32 HAL 库初始化 (或其他 MCU 平台初始化)
OSAL_Init(); // 操作系统抽象层初始化 (如果使用 RTOS)

PowerService_Init();
LEDService_Init();
TouchService_Init();
StatusMonitorService_Init();

// 注册触控事件回调函数
TouchService_RegisterEventHandler(TouchEventHandler);

// 初始化 UI 状态
for (int i = 0; i < USB_PORT_MAX; i++) {
port_ui_state[i] = PORT_UI_STATE_OFF;
}

// 主循环 (如果使用 RTOS,则创建任务并启动调度器)
while (1) {
// 处理系统任务 (例如,状态监测、UI 更新等)
StatusMonitorService_Task();
LEDService_Task();
TouchService_Task(); // 触控服务任务,处理触控事件

// 可以添加其他应用层任务

OSAL_TaskDelay(10); // 适当的延时,降低 CPU 占用 (如果未使用 RTOS,需要自行实现延时)
}

return 0;
}

(为了满足 3000 行代码的要求,应用层可以扩展更多功能,例如:)

  • UI 显示更新函数 UpdateUIDisplay() 的详细实现: 包括触控屏驱动代码,UI 元素的绘制 (端口状态图标、功率显示、设置菜单等),以及 UI 交互逻辑。
  • 系统配置管理功能: 实现配置参数的读取、保存和修改,例如,通过触控屏菜单设置功率分配策略、LED 显示模式等,并将配置参数保存到 Flash 或 EEPROM 中。
  • 固件升级 (OTA) 功能: 实现通过 USB 或其他通信接口进行固件升级的功能,包括固件接收、校验、写入 Flash 和系统重启等流程。
  • 更完善的错误处理和告警机制: 当系统发生错误时,记录错误日志,并通过 LED 或触控屏显示错误信息,方便用户和开发者进行故障诊断。
  • 高级功率管理功能: 例如,根据连接设备的类型和需求,智能选择充电协议 (USB PD, QC 等),实现最佳充电效率。 实现动态功率分配,根据总功率限制和各端口的负载情况,动态调整端口的功率输出。

项目中采用的技术和方法

  1. 分层架构: 采用分层架构设计软件系统,提高了系统的模块化、可维护性和可扩展性。
  2. 硬件抽象层 (HAL): 通过 HAL 层屏蔽硬件差异,提高了代码的可移植性,方便在不同硬件平台之间进行移植。
  3. 服务层设计: 将系统功能划分为多个独立的服务模块,每个服务模块负责特定的功能,降低了系统的复杂性,提高了代码的复用性。
  4. 事件驱动编程: 触控事件处理采用事件驱动编程模型,提高了系统的响应速度和效率。
  5. 模块化编程: 代码按照模块进行组织,每个模块包含独立的头文件和源文件,方便代码的管理和维护。
  6. 代码注释和文档: 代码中包含详细的注释,方便代码的理解和维护。 同时,需要编写相应的软件设计文档和用户手册,方便项目的开发、测试和使用。
  7. 版本控制: 使用 Git 等版本控制工具管理代码,方便代码的版本管理和团队协作。
  8. 单元测试和集成测试: 在开发过程中,需要进行单元测试和集成测试,验证各个模块和整个系统的功能和性能。
  9. 代码审查: 进行代码审查,提高代码质量,减少 Bug。
  10. 静态代码分析和动态代码分析: 使用静态代码分析工具和动态代码分析工具,检测代码中的潜在 Bug 和性能问题。

总结

以上代码示例和架构设计提供了一个大功率触控桌充嵌入式系统软件开发的框架。 实际项目中,需要根据具体的硬件平台、功能需求和性能指标进行详细的设计和实现。 为了满足 3000 行代码的要求,可以进一步扩展各个模块的功能,例如,更详细的 HAL 层实现,更完善的服务层功能,更丰富的应用层特性,以及完善的测试代码和文档。 这个项目的设计目标是构建一个可靠、高效、可扩展的嵌入式系统平台,为用户提供稳定、便捷的大功率充电体验。

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