编程技术分享

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

0%

我将为您详细解析并实现一个针对电子调试工程师痛点的多功能USB HUB项目,该项目专注于电流电压检测,并展示完整的嵌入式系统开发流程。

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

项目背景与需求分析

电子调试工程师在日常工作中经常需要同时连接多个USB设备进行测试、供电或数据传输。传统的USB HUB虽然解决了端口不足的问题,但缺乏对USB端口状态的监控能力,尤其是在电源和电流方面。当调试过程中出现异常,例如设备无法启动、供电不足、电流过大等问题时,工程师往往需要借助额外的仪表设备(如万用表、示波器)进行排查,这无疑增加了工作的复杂性和时间成本。

本项目的核心目标正是解决这一痛点,设计并实现一款多功能USB HUB,它不仅具备基础的USB端口扩展功能,更重要的是集成了高精度的电流电压检测模块,能够实时监控每个USB端口的电压、电流和功率,并将这些关键信息直观地显示出来。这将极大地提升电子调试的效率,帮助工程师快速定位问题,并进行电源性能分析。

系统架构设计

为了构建一个可靠、高效、可扩展的系统平台,我们采用分层架构的设计思想。分层架构将系统划分为多个独立的层级,每一层只关注特定的功能,层与层之间通过清晰定义的接口进行通信。这种架构具有良好的模块化特性,易于维护、扩展和复用。

本项目系统架构可以划分为以下几个主要层级:

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

    • 功能:HAL层是系统架构的最底层,直接与硬件交互。它封装了底层硬件的差异性,向上层提供统一的硬件访问接口。这使得上层软件可以独立于具体的硬件平台进行开发,提高了代码的可移植性。
    • 模块
      • GPIO 驱动:控制通用输入输出引脚,例如控制电源开关、LED指示灯等。
      • ADC 驱动:控制模数转换器,用于采集电压和电流模拟信号。
      • 显示屏驱动:控制显示屏,例如LCD、OLED,用于显示电压、电流等信息。
      • USB 控制器驱动:控制USB主机控制器,实现USB HUB的功能,并可能涉及到电流限制和保护。
      • 电源管理驱动:控制电源管理芯片,例如控制电压输出、过流保护等。
      • 定时器驱动:提供定时功能,用于数据采样、显示刷新等周期性任务。
      • 中断控制器驱动:管理中断,响应外部事件,例如ADC数据就绪中断。
  2. **驱动层 (Driver Layer)**:

    • 功能:驱动层构建在HAL层之上,负责管理和控制具体的硬件外设。它将HAL层提供的基本硬件操作接口封装成更高级、更易用的驱动接口,供服务层调用。
    • 模块
      • 电压电流检测驱动:基于ADC驱动,实现电压和电流的精确测量,包括校准、滤波等算法。
      • 显示管理驱动:基于显示屏驱动,实现显示内容的管理,例如文本显示、图形显示、界面切换等。
      • USB HUB 控制驱动:基于USB控制器驱动,实现USB HUB的功能,例如端口枚举、数据路由、电源管理等。
  3. **服务层 (Service Layer)**:

    • 功能:服务层构建在驱动层之上,提供更高级的功能服务,为应用层提供业务逻辑支持。服务层将底层的驱动操作组合成更具业务含义的服务接口。
    • 模块
      • 数据采集服务:调用电压电流检测驱动,周期性采集电压和电流数据,并进行数据处理和存储。
      • 显示服务:调用显示管理驱动,将采集到的电压、电流、功率等数据格式化并显示到屏幕上。
      • 电源管理服务:控制USB端口的电源开关,实现过流保护、短路保护等功能。
      • 配置管理服务:提供系统配置参数的读取和设置功能,例如采样频率、显示参数等。
  4. **应用层 (Application Layer)**:

    • 功能:应用层是系统架构的最顶层,负责实现用户的具体需求和业务逻辑。它调用服务层提供的接口,构建用户界面,处理用户交互,并完成系统的主要功能。
    • 模块
      • 用户界面模块:实现图形用户界面,显示电压、电流、功率等实时数据,并提供简单的配置选项。
      • 系统监控模块:监控系统状态,例如检测异常数据、报警提示等。
      • 主控制模块:协调各个服务模块,控制系统的整体运行流程。

代码设计与实现 (C 语言)

以下是基于分层架构的 C 代码实现框架和关键模块的示例代码。由于代码量要求较大,这里将提供详细的代码框架、关键模块的完整代码以及部分核心功能的代码实现,力求覆盖3000行代码的需求。实际项目中,代码量会根据具体功能和复杂度进一步增加。

1. 头文件定义 (包含各层接口声明)

  • hal.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
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
#ifndef HAL_H
#define HAL_H

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

// GPIO 控制
typedef enum {
GPIO_PIN_1,
GPIO_PIN_2,
GPIO_PIN_3,
GPIO_PIN_4,
// ... 更多 GPIO 引脚定义
GPIO_PIN_MAX
} GPIO_Pin_t;

typedef enum {
GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT
} GPIO_Mode_t;

typedef enum {
GPIO_LEVEL_LOW,
GPIO_LEVEL_HIGH
} GPIO_Level_t;

void HAL_GPIO_Init(GPIO_Pin_t pin, GPIO_Mode_t mode);
void HAL_GPIO_Write(GPIO_Pin_t pin, GPIO_Level_t level);
GPIO_Level_t HAL_GPIO_Read(GPIO_Pin_t pin);

// ADC 控制
typedef enum {
ADC_CHANNEL_1,
ADC_CHANNEL_2,
ADC_CHANNEL_3,
ADC_CHANNEL_4,
// ... 更多 ADC 通道定义
ADC_CHANNEL_MAX
} ADC_Channel_t;

void HAL_ADC_Init(ADC_Channel_t channel);
uint16_t HAL_ADC_Read(ADC_Channel_t channel);

// 显示屏控制 (示例:SPI 接口 LCD)
typedef enum {
DISPLAY_COLOR_BLACK,
DISPLAY_COLOR_WHITE,
DISPLAY_COLOR_RED,
DISPLAY_COLOR_GREEN,
DISPLAY_COLOR_BLUE
// ... 更多颜色定义
} DISPLAY_Color_t;

void HAL_Display_Init(void);
void HAL_Display_Clear(DISPLAY_Color_t color);
void HAL_Display_SetPixel(uint16_t x, uint16_t y, DISPLAY_Color_t color);
void HAL_Display_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, DISPLAY_Color_t color);
void HAL_Display_DrawRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, DISPLAY_Color_t color);
void HAL_Display_FillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, DISPLAY_Color_t color);
void HAL_Display_DrawCircle(uint16_t x, uint16_t y, uint16_t radius, DISPLAY_Color_t color);
void HAL_Display_FillCircle(uint16_t x, uint16_t y, uint16_t radius, DISPLAY_Color_t color);
void HAL_Display_WriteString(uint16_t x, uint16_t y, const char *str, DISPLAY_Color_t color, DISPLAY_Color_t bgcolor);
void HAL_Display_SetRotation(uint8_t rotation); // 屏幕旋转

// USB 控制器 (简化接口,实际 USB 控制器驱动会更复杂)
typedef enum {
USB_PORT_1,
USB_PORT_2,
USB_PORT_3,
USB_PORT_4,
// ... 更多 USB 端口定义
USB_PORT_MAX
} USB_Port_t;

typedef enum {
USB_POWER_STATE_ON,
USB_POWER_STATE_OFF
} USB_PowerState_t;

void HAL_USB_Init(void);
void HAL_USB_PortPowerControl(USB_Port_t port, USB_PowerState_t state);

// 定时器控制 (示例:基于 SysTick)
void HAL_Timer_Init(uint32_t tick_ms); // 初始化定时器,设置中断周期
void HAL_Timer_DelayMs(uint32_t ms); // 延时函数

// 中断控制
void HAL_Interrupt_Enable(uint32_t interrupt_source);
void HAL_Interrupt_Disable(uint32_t interrupt_source);
void HAL_Interrupt_RegisterCallback(uint32_t interrupt_source, void (*callback)(void));


#endif // HAL_H
  • driver.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
#ifndef DRIVER_H
#define DRIVER_H

#include "hal.h"

// 电压电流检测驱动
typedef struct {
float voltage;
float current;
} VoltageCurrentData_t;

void DRV_VoltageCurrent_Init(ADC_Channel_t voltage_channel, ADC_Channel_t current_channel);
VoltageCurrentData_t DRV_VoltageCurrent_Read(void);

// 显示管理驱动
void DRV_DisplayMgr_Init(void);
void DRV_DisplayMgr_ClearScreen(void);
void DRV_DisplayMgr_DisplayVoltageCurrent(VoltageCurrentData_t data, uint8_t port_num);
void DRV_DisplayMgr_UpdateDisplay(void); // 刷新显示

// USB HUB 控制驱动
void DRV_USBHub_Init(void);
void DRV_USBHub_PortEnable(USB_Port_t port);
void DRV_USBHub_PortDisable(USB_Port_t port);
void DRV_USBHub_PortOverCurrentProtect(USB_Port_t port); // 过流保护处理

#endif // DRIVER_H
  • 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
#ifndef SERVICE_H
#define SERVICE_H

#include "driver.h"

// 数据采集服务
typedef struct {
VoltageCurrentData_t port_data[USB_PORT_MAX];
} SystemData_t;

void SVC_DataAcquisition_Init(void);
SystemData_t SVC_DataAcquisition_GetData(void);
void SVC_DataAcquisition_StartSampling(void);
void SVC_DataAcquisition_StopSampling(void);

// 显示服务
void SVC_Display_Init(void);
void SVC_Display_UpdateData(SystemData_t system_data);
void SVC_Display_SetBrightness(uint8_t brightness); // 设置亮度

// 电源管理服务
void SVC_PowerMgr_Init(void);
void SVC_PowerMgr_EnablePortPower(USB_Port_t port);
void SVC_PowerMgr_DisablePortPower(USB_Port_t port);
void SVC_PowerMgr_MonitorOverCurrent(void); // 监控过流情况

// 配置管理服务
typedef struct {
uint32_t sample_rate_ms;
uint8_t display_brightness;
// ... 更多配置参数
} SystemConfig_t;

void SVC_ConfigMgr_Init(void);
SystemConfig_t SVC_ConfigMgr_GetConfig(void);
void SVC_ConfigMgr_SetConfig(SystemConfig_t config);
void SVC_ConfigMgr_LoadConfigFromFlash(void);
void SVC_ConfigMgr_SaveConfigToFlash(void);


#endif // SERVICE_H
  • app.h (应用层头文件)
1
2
3
4
5
6
7
8
9
10
11
#ifndef APP_H
#define APP_H

#include "service.h"

void APP_Init(void);
void APP_Run(void);
void APP_HandleUserInput(void); // 处理用户输入 (如果需要)
void APP_SystemTickHandler(void); // 系统定时器 Tick 处理函数

#endif // APP_H

2. 源文件实现 (部分关键模块完整代码及框架)

  • hal.c (硬件抽象层实现 - 示例:基于 STM32 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
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
#include "hal.h"
#include "stm32f4xx_hal.h" // 假设使用 STM32F4 系列 MCU 的 HAL 库

// GPIO 初始化和控制 (示例,需要根据实际硬件连接修改)
void HAL_GPIO_Init(GPIO_Pin_t pin, GPIO_Mode_t mode) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_TypeDef *GPIOx;
uint16_t GPIO_Pin;

// 根据 pin 枚举值确定 GPIO 端口和引脚
switch (pin) {
case GPIO_PIN_1: GPIOx = GPIOA; GPIO_Pin = GPIO_PIN_1; break;
case GPIO_PIN_2: GPIOx = GPIOA; GPIO_Pin = GPIO_PIN_2; break;
case GPIO_PIN_3: GPIOx = GPIOB; GPIO_Pin = GPIO_PIN_0; break;
case GPIO_PIN_4: GPIOx = GPIOB; GPIO_Pin = GPIO_PIN_1; break;
// ... 更多引脚配置
default: return; // 错误处理
}

// 使能 GPIO 时钟 (需要根据实际 MCU 时钟配置修改)
if (GPIOx == GPIOA) __HAL_RCC_GPIOA_CLK_ENABLE();
if (GPIOx == GPIOB) __HAL_RCC_GPIOB_CLK_ENABLE();
// ... 其他 GPIO 端口时钟使能

GPIO_InitStruct.Pin = GPIO_Pin;
if (mode == GPIO_MODE_OUTPUT) {
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
} else { // GPIO_MODE_INPUT
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
}
HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
}

void HAL_GPIO_Write(GPIO_Pin_t pin, GPIO_Level_t level) {
GPIO_TypeDef *GPIOx;
uint16_t GPIO_Pin;

switch (pin) {
case GPIO_PIN_1: GPIOx = GPIOA; GPIO_Pin = GPIO_PIN_1; break;
case GPIO_PIN_2: GPIOx = GPIOA; GPIO_Pin = GPIO_PIN_2; break;
case GPIO_PIN_3: GPIOx = GPIOB; GPIO_Pin = GPIO_PIN_0; break;
case GPIO_PIN_4: GPIOx = GPIOB; GPIO_Pin = GPIO_PIN_1; break;
default: return;
}

HAL_GPIO_WritePin(GPIOx, GPIO_Pin, (level == GPIO_LEVEL_HIGH) ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

GPIO_Level_t HAL_GPIO_Read(GPIO_Pin_t pin) {
GPIO_TypeDef *GPIOx;
uint16_t GPIO_Pin;

switch (pin) {
case GPIO_PIN_1: GPIOx = GPIOA; GPIO_Pin = GPIO_PIN_1; break;
case GPIO_PIN_2: GPIOx = GPIOA; GPIO_Pin = GPIO_PIN_2; break;
case GPIO_PIN_3: GPIOx = GPIOB; GPIO_Pin = GPIO_PIN_0; break;
case GPIO_PIN_4: GPIOx = GPIOB; GPIO_Pin = GPIO_PIN_1; break;
default: return GPIO_LEVEL_LOW; // 错误处理,默认返回低电平
}

return (HAL_GPIO_ReadPin(GPIOx, GPIO_Pin) == GPIO_PIN_SET) ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW;
}

// ADC 初始化和读取 (示例,需要根据实际 ADC 外设配置修改)
void HAL_ADC_Init(ADC_Channel_t channel) {
ADC_HandleTypeDef hadc;
ADC_ChannelConfTypeDef sConfig = {0};

// 使能 ADC 时钟 (需要根据实际 MCU 时钟配置修改)
__HAL_RCC_ADC1_CLK_ENABLE(); // 假设使用 ADC1

hadc.Instance = ADC1;
hadc.Init.Resolution = ADC_RESOLUTION_12B; // 12 位分辨率
hadc.Init.ScanConvMode = DISABLE; // 禁用扫描模式
hadc.Init.ContinuousConvMode = DISABLE; // 禁用连续转换模式
hadc.Init.DiscontinuousConvMode = DISABLE; // 禁用非连续转换模式
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; // 软件触发
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.NbrOfConversion = 1;
hadc.Init.DMAContinuousRequests = DISABLE;
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc) != HAL_OK) {
// 初始化错误处理
while(1); // 错误死循环
}

// 配置 ADC 通道
switch (channel) {
case ADC_CHANNEL_1: sConfig.Channel = ADC_CHANNEL_0; break; // 假设 ADC_CHANNEL_1 对应 ADC 通道 0
case ADC_CHANNEL_2: sConfig.Channel = ADC_CHANNEL_1; break; // 假设 ADC_CHANNEL_2 对应 ADC 通道 1
case ADC_CHANNEL_3: sConfig.Channel = ADC_CHANNEL_2; break;
case ADC_CHANNEL_4: sConfig.Channel = ADC_CHANNEL_3; break;
default: return; // 错误处理
}
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES; // 采样时间
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) {
// 通道配置错误处理
while(1); // 错误死循环
}
}

uint16_t HAL_ADC_Read(ADC_Channel_t channel) {
ADC_HandleTypeDef hadc;
hadc.Instance = ADC1; // 假设使用 ADC1

// 选择 ADC 通道 (虽然在 Init 中配置了,但为了代码完整性,这里可以再次设置,或者在 Init 中保存 channel 信息)
ADC_ChannelConfTypeDef sConfig = {0};
switch (channel) {
case ADC_CHANNEL_1: sConfig.Channel = ADC_CHANNEL_0; break;
case ADC_CHANNEL_2: sConfig.Channel = ADC_CHANNEL_1; break;
case ADC_CHANNEL_3: sConfig.Channel = ADC_CHANNEL_2; break;
case ADC_CHANNEL_4: sConfig.Channel = ADC_CHANNEL_3; break;
default: return 0; // 错误处理
}
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
HAL_ADC_ConfigChannel(&hadc, &sConfig);


HAL_ADC_Start(&hadc); // 启动 ADC 转换
HAL_ADC_PollForConversion(&hadc, 10); // 等待转换完成 (超时 10ms)
if (HAL_ADC_GetState(&hadc) == HAL_ADC_STATE_TIMEOUT) {
// ADC 超时错误处理
return 0; // 返回错误值
}
return HAL_ADC_GetValue(&hadc); // 读取 ADC 值
}


// 显示屏驱动 HAL 层函数实现 (需要根据实际显示屏驱动芯片和接口修改,这里仅为框架示例)
// 假设使用 SPI 接口的 LCD,驱动芯片例如 ST7735
#include "spi.h" // 假设 SPI 初始化函数在 spi.h 中

#define LCD_CS_PIN GPIO_PIN_4 // 片选信号引脚 (示例)
#define LCD_CS_GPIO_PORT GPIOA // 片选信号 GPIO 端口 (示例)
#define LCD_DC_PIN GPIO_PIN_5 // 数据/命令选择引脚 (示例)
#define LCD_DC_GPIO_PORT GPIOA // 数据/命令选择 GPIO 端口 (示例)
#define LCD_RST_PIN GPIO_PIN_6 // 复位引脚 (示例)
#define LCD_RST_GPIO_PORT GPIOA // 复位 GPIO 端口 (示例)

static SPI_HandleTypeDef hspi_lcd; // SPI 句柄 (假设 SPI 初始化在 spi.c 中完成)

void HAL_Display_Init(void) {
// 初始化 SPI (假设 SPI 初始化函数 SPI_LCD_Init() 在 spi.c 中实现,并初始化 hspi_lcd)
SPI_LCD_Init(&hspi_lcd);

// 初始化 LCD 控制引脚 (CS, DC, RST)
HAL_GPIO_Init(LCD_CS_PIN, GPIO_MODE_OUTPUT);
HAL_GPIO_Init(LCD_DC_PIN, GPIO_MODE_OUTPUT);
HAL_GPIO_Init(LCD_RST_PIN, GPIO_MODE_OUTPUT);

// LCD 复位
HAL_GPIO_Write(LCD_RST_PIN, GPIO_LEVEL_RESET);
HAL_Delay(100); // 延时 100ms
HAL_GPIO_Write(LCD_RST_PIN, GPIO_LEVEL_SET);
HAL_Delay(100);

// 初始化 LCD 驱动芯片 (发送初始化命令序列,具体命令参考 LCD 驱动芯片手册)
// ... 发送初始化命令 ...
}

static void LCD_CS_Select(void) {
HAL_GPIO_Write(LCD_CS_PIN, GPIO_LEVEL_RESET);
}

static void LCD_CS_Deselect(void) {
HAL_GPIO_Write(LCD_CS_PIN, GPIO_LEVEL_SET);
}

static void LCD_DC_DataMode(void) {
HAL_GPIO_Write(LCD_DC_PIN, GPIO_LEVEL_SET); // 数据模式
}

static void LCD_DC_CommandMode(void) {
HAL_GPIO_Write(LCD_DC_PIN, GPIO_LEVEL_RESET); // 命令模式
}

static void LCD_SendByte(uint8_t data) {
HAL_SPI_Transmit(&hspi_lcd, &data, 1, HAL_MAX_DELAY);
}

void HAL_Display_WriteCommand(uint8_t cmd) {
LCD_CS_Select();
LCD_DC_CommandMode();
LCD_SendByte(cmd);
LCD_CS_Deselect();
}

void HAL_Display_WriteData(uint8_t data) {
LCD_CS_Select();
LCD_DC_DataMode();
LCD_SendByte(data);
LCD_CS_Deselect();
}

void HAL_Display_SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
// 设置显示区域 (具体命令参考 LCD 驱动芯片手册)
HAL_Display_WriteCommand(0x2A); // Column Address Set
HAL_Display_WriteData(x0 >> 8);
HAL_Display_WriteData(x0 & 0xFF);
HAL_Display_WriteData(x1 >> 8);
HAL_Display_WriteData(x1 & 0xFF);

HAL_Display_WriteCommand(0x2B); // Row Address Set
HAL_Display_WriteData(y0 >> 8);
HAL_Display_WriteData(y0 & 0xFF);
HAL_Display_WriteData(y1 >> 8);
HAL_Display_WriteData(y1 & 0xFF);

HAL_Display_WriteCommand(0x2C); // Memory Write
}

void HAL_Display_Clear(DISPLAY_Color_t color) {
uint16_t width = 160; // 假设 LCD 宽度 160
uint16_t height = 128; // 假设 LCD 高度 128
uint16_t pixel_count = width * height;
uint16_t color_data = 0; // 黑色

switch (color) {
case DISPLAY_COLOR_BLACK: color_data = 0x0000; break;
case DISPLAY_COLOR_WHITE: color_data = 0xFFFF; break;
case DISPLAY_COLOR_RED: color_data = 0xF800; break;
case DISPLAY_COLOR_GREEN: color_data = 0x07E0; break;
case DISPLAY_COLOR_BLUE: color_data = 0x001F; break;
default: color_data = 0x0000; break;
}

HAL_Display_SetAddrWindow(0, 0, width - 1, height - 1);
LCD_CS_Select();
LCD_DC_DataMode();
for (uint32_t i = 0; i < pixel_count; i++) {
HAL_Display_WriteData((color_data >> 8) & 0xFF); // 高字节
HAL_Display_WriteData(color_data & 0xFF); // 低字节
}
LCD_CS_Deselect();
}

void HAL_Display_SetPixel(uint16_t x, uint16_t y, DISPLAY_Color_t color) {
if (x >= 160 || y >= 128) return; // 超出显示范围

HAL_Display_SetAddrWindow(x, y, x, y);
LCD_CS_Select();
LCD_DC_DataMode();
uint16_t color_data = 0;
switch (color) {
case DISPLAY_COLOR_BLACK: color_data = 0x0000; break;
case DISPLAY_COLOR_WHITE: color_data = 0xFFFF; break;
case DISPLAY_COLOR_RED: color_data = 0xF800; break;
case DISPLAY_COLOR_GREEN: color_data = 0x07E0; break;
case DISPLAY_COLOR_BLUE: color_data = 0x001F; break;
default: color_data = 0x0000; break;
}
HAL_Display_WriteData((color_data >> 8) & 0xFF);
HAL_Display_WriteData(color_data & 0xFF);
LCD_CS_Deselect();
}

// ... 其他 HAL_Display_DrawLine, HAL_Display_DrawRect, HAL_Display_WriteString 等图形函数的实现 (需要根据具体的图形库和字体库实现) ...

// USB 控制器 HAL 层函数实现 (简化示例,实际 USB 控制器驱动会更复杂,需要根据具体的 USB 控制器芯片和接口修改)
void HAL_USB_Init(void) {
// 初始化 USB 控制器硬件 (例如使能时钟,配置引脚等)
// ... USB 控制器硬件初始化代码 ...
}

void HAL_USB_PortPowerControl(USB_Port_t port, USB_PowerState_t state) {
// 控制 USB 端口的电源开关 (例如通过 GPIO 控制电源开关芯片)
GPIO_Pin_t power_pin;
switch (port) {
case USB_PORT_1: power_pin = GPIO_PIN_1; break; // 假设 USB_PORT_1 电源控制引脚为 GPIO_PIN_1
case USB_PORT_2: power_pin = GPIO_PIN_2; break;
case USB_PORT_3: power_pin = GPIO_PIN_3; break;
case USB_PORT_4: power_pin = GPIO_PIN_4; break;
default: return;
}

HAL_GPIO_Init(power_pin, GPIO_MODE_OUTPUT); // 初始化为输出
HAL_GPIO_Write(power_pin, (state == USB_POWER_STATE_ON) ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW); // 控制电源开关
}

// 定时器 HAL 层函数实现 (示例:基于 SysTick)
void HAL_Timer_Init(uint32_t tick_ms) {
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000 * tick_ms); // 配置 SysTick 中断周期
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); // 设置 SysTick 中断优先级
}

void HAL_Timer_DelayMs(uint32_t ms) {
HAL_Delay(ms); // 使用 HAL 库提供的延时函数
}

// 中断控制 HAL 层函数实现 (简化示例)
void HAL_Interrupt_Enable(uint32_t interrupt_source) {
// 使能指定的中断源 (需要根据具体的 MCU 中断控制器配置修改)
if (interrupt_source == ADC1_IRQn) { // 假设 ADC1 中断源为 ADC1_IRQn
HAL_NVIC_EnableIRQ(ADC1_IRQn);
}
// ... 其他中断源使能 ...
}

void HAL_Interrupt_Disable(uint32_t interrupt_source) {
// 禁用指定的中断源
if (interrupt_source == ADC1_IRQn) {
HAL_NVIC_DisableIRQ(ADC1_IRQn);
}
// ... 其他中断源禁用 ...
}

void HAL_Interrupt_RegisterCallback(uint32_t interrupt_source, void (*callback)(void)) {
// 注册中断回调函数 (需要根据具体的中断处理机制实现,例如使用函数指针数组)
// ... 中断回调注册 ...
}

// SysTick 中断处理函数 (示例)
void SysTick_Handler(void) {
HAL_IncTick(); // HAL 库维护的系统 Tick 计数器自增
APP_SystemTickHandler(); // 调用应用层系统 Tick 处理函数
}

// ADC 中断处理函数 (示例,需要根据实际 ADC 中断配置修改)
void ADC1_IRQHandler(void) {
// 处理 ADC 中断事件,例如读取 ADC 数据,清除中断标志等
// ... ADC 中断处理代码 ...
}
  • 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
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
#include "driver.h"
#include <stdio.h> // For sprintf

#define VOLTAGE_ADC_CHANNEL ADC_CHANNEL_1 // 假设电压检测使用 ADC 通道 1
#define CURRENT_ADC_CHANNEL ADC_CHANNEL_2 // 假设电流检测使用 ADC 通道 2

#define VOLTAGE_REF 3.3f // ADC 参考电压 (V)
#define ADC_RESOLUTION 4096.0f // 12 位 ADC 分辨率
#define VOLTAGE_DIVIDER_RATIO 1.0f // 电压分压比例 (如果直接测量,比例为 1.0)
#define CURRENT_SENSE_RESISTOR 0.1f // 电流采样电阻 (欧姆)
#define CURRENT_AMP_GAIN 10.0f // 电流放大器增益 (如果使用放大器)

void DRV_VoltageCurrent_Init(ADC_Channel_t voltage_channel, ADC_Channel_t current_channel) {
HAL_ADC_Init(voltage_channel);
HAL_ADC_Init(current_channel);
}

VoltageCurrentData_t DRV_VoltageCurrent_Read(void) {
VoltageCurrentData_t data;

// 读取电压 ADC 值并转换为电压值
uint16_t voltage_adc_value = HAL_ADC_Read(VOLTAGE_ADC_CHANNEL);
float voltage_raw = (float)voltage_adc_value / ADC_RESOLUTION * VOLTAGE_REF;
data.voltage = voltage_raw * VOLTAGE_DIVIDER_RATIO; // 应用分压比例

// 读取电流 ADC 值并转换为电流值
uint16_t current_adc_value = HAL_ADC_Read(CURRENT_ADC_CHANNEL);
float current_raw_voltage = (float)current_adc_value / ADC_RESOLUTION * VOLTAGE_REF;
data.current = current_raw_voltage / CURRENT_AMP_GAIN / CURRENT_SENSE_RESISTOR; // 计算电流值

return data;
}

// 显示管理驱动实现 (示例)
#include "font.h" // 假设字体库头文件为 font.h

void DRV_DisplayMgr_Init(void) {
HAL_Display_Init();
DRV_DisplayMgr_ClearScreen();
}

void DRV_DisplayMgr_ClearScreen(void) {
HAL_Display_Clear(DISPLAY_COLOR_BLACK);
}

void DRV_DisplayMgr_DisplayVoltageCurrent(VoltageCurrentData_t data, uint8_t port_num) {
char voltage_str[20];
char current_str[20];
char power_str[20];
float power = data.voltage * data.current;

sprintf(voltage_str, "V: %.3fV", data.voltage);
sprintf(current_str, "I: %.3fA", data.current);
sprintf(power_str, "P: %.3fW", power);

uint16_t start_y = 10 + (port_num - 1) * 30; // 每个端口显示区域的起始 Y 坐标
uint16_t start_x = 10;

HAL_Display_WriteString(start_x, start_y, voltage_str, DISPLAY_COLOR_GREEN, DISPLAY_COLOR_BLACK);
HAL_Display_WriteString(start_x, start_y + 10, current_str, DISPLAY_COLOR_GREEN, DISPLAY_COLOR_BLACK);
HAL_Display_WriteString(start_x, start_y + 20, power_str, DISPLAY_COLOR_GREEN, DISPLAY_COLOR_BLACK);
}

void DRV_DisplayMgr_UpdateDisplay(void) {
// 刷新显示 (如果显示屏需要显存刷新操作,则在这里实现)
// 例如:如果使用 DMA 传输显存数据到 LCD,则在这里启动 DMA 传输
}

// USB HUB 控制驱动实现 (简化示例)
void DRV_USBHub_Init(void) {
HAL_USB_Init();
// 初始化 USB 端口电源状态 (例如默认关闭所有端口)
for (int i = 0; i < USB_PORT_MAX; i++) {
DRV_USBHub_PortDisable((USB_Port_t)i);
}
}

void DRV_USBHub_PortEnable(USB_Port_t port) {
HAL_USB_PortPowerControl(port, USB_POWER_STATE_ON);
}

void DRV_USBHub_PortDisable(USB_Port_t port) {
HAL_USB_PortPowerControl(port, USB_POWER_STATE_OFF);
}

void DRV_USBHub_PortOverCurrentProtect(USB_Port_t port) {
// 过流保护处理,例如禁用端口电源,报警提示等
DRV_USBHub_PortDisable(port);
// ... 报警提示 ...
}
  • 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
#include "service.h"
#include "FreeRTOS.h" // 假设使用 FreeRTOS
#include "task.h"

#define SAMPLE_RATE_MS 100 // 默认采样率 100ms

static SystemData_t system_data;
static bool sampling_enabled = false;

void SVC_DataAcquisition_Init(void) {
DRV_VoltageCurrent_Init(VOLTAGE_ADC_CHANNEL, CURRENT_ADC_CHANNEL); // 初始化电压电流检测驱动
}

SystemData_t SVC_DataAcquisition_GetData(void) {
return system_data;
}

static void DataAcquisitionTask(void *pvParameters) {
while (1) {
if (sampling_enabled) {
for (int i = 0; i < USB_PORT_MAX; i++) {
system_data.port_data[i] = DRV_VoltageCurrent_Read(); // 读取电压电流数据
// 可以根据端口号选择不同的 ADC 通道,如果每个端口有独立的检测电路
// 例如: DRV_VoltageCurrent_Read(voltage_channels[i], current_channels[i]);
}
SVC_Display_UpdateData(system_data); // 更新显示数据
}
vTaskDelay(pdMS_TO_TICKS(SAMPLE_RATE_MS)); // 延时采样周期
}
}

void SVC_DataAcquisition_StartSampling(void) {
sampling_enabled = true;
}

void SVC_DataAcquisition_StopSampling(void) {
sampling_enabled = false;
}

// 显示服务实现 (示例)
void SVC_Display_Init(void) {
DRV_DisplayMgr_Init();
}

void SVC_Display_UpdateData(SystemData_t system_data) {
DRV_DisplayMgr_ClearScreen(); // 清屏
for (int i = 0; i < USB_PORT_MAX; i++) {
DRV_DisplayMgr_DisplayVoltageCurrent(system_data.port_data[i], i + 1); // 显示每个端口的数据
}
DRV_DisplayMgr_UpdateDisplay(); // 刷新显示
}

void SVC_Display_SetBrightness(uint8_t brightness) {
// 设置显示亮度 (如果显示屏支持亮度调节功能)
// ... 亮度调节代码 ...
}

// 电源管理服务实现 (示例)
void SVC_PowerMgr_Init(void) {
DRV_USBHub_Init();
}

void SVC_PowerMgr_EnablePortPower(USB_Port_t port) {
DRV_USBHub_PortEnable(port);
}

void SVC_PowerMgr_DisablePortPower(USB_Port_t port) {
DRV_USBHub_PortDisable(port);
}

void SVC_PowerMgr_MonitorOverCurrent(void) {
// 监控过流情况 (例如周期性检测电流值,超过阈值则触发过流保护)
// ... 过流监控代码 ...
}

// 配置管理服务实现 (示例 - 简化的配置参数,实际项目可能需要更复杂的配置管理)
static SystemConfig_t current_config = {
.sample_rate_ms = SAMPLE_RATE_MS,
.display_brightness = 100, // 默认亮度 100%
};

void SVC_ConfigMgr_Init(void) {
SVC_ConfigMgr_LoadConfigFromFlash(); // 尝试从 Flash 加载配置
}

SystemConfig_t SVC_ConfigMgr_GetConfig(void) {
return current_config;
}

void SVC_ConfigMgr_SetConfig(SystemConfig_t config) {
current_config = config;
SVC_ConfigMgr_SaveConfigToFlash(); // 保存配置到 Flash
}

void SVC_ConfigMgr_LoadConfigFromFlash(void) {
// 从 Flash 加载配置参数 (需要根据具体的 Flash 驱动和存储方式实现)
// ... 从 Flash 读取配置 ...
// 示例:假设配置参数存储在 Flash 的特定地址,并使用简单的结构体存储
// memcpy(&current_config, (void *)FLASH_CONFIG_ADDRESS, sizeof(SystemConfig_t));
}

void SVC_ConfigMgr_SaveConfigToFlash(void) {
// 保存配置参数到 Flash (需要根据具体的 Flash 驱动和存储方式实现)
// ... 保存配置到 Flash ...
// 示例:擦除 Flash 扇区,然后写入配置结构体
// FLASH_EraseSector(FLASH_SECTOR_X, VOLTAGE_RANGE_3);
// FLASH_Program(FLASH_TYPEPROGRAM_WORD, FLASH_CONFIG_ADDRESS, (uint32_t *)&current_config, sizeof(SystemConfig_t));
}
  • app.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
#include "app.h"
#include "FreeRTOS.h"
#include "task.h"

#define TASK_PRIORITY_APP 3
#define TASK_PRIORITY_DATA_ACQ 2
#define TASK_PRIORITY_DISPLAY 1

static TaskHandle_t data_acq_task_handle = NULL;
static TaskHandle_t display_task_handle = NULL;

void APP_Init(void) {
SVC_ConfigMgr_Init(); // 初始化配置管理服务
SVC_DataAcquisition_Init(); // 初始化数据采集服务
SVC_Display_Init(); // 初始化显示服务
SVC_PowerMgr_Init(); // 初始化电源管理服务

// 创建数据采集任务
BaseType_t xReturned = xTaskCreate(
DataAcquisitionTask, /* 任务函数. */
"DataAcqTask", /* 任务名. */
128, /* 堆栈大小 (字). */
NULL, /* 任务参数. */
TASK_PRIORITY_DATA_ACQ, /* 优先级. */
&data_acq_task_handle ); /* 任务句柄. */

if( xReturned != pdPASS )
{
// 任务创建失败处理
while(1);
}

SVC_DataAcquisition_StartSampling(); // 启动数据采样

// 启动 USB HUB 端口电源 (默认启动所有端口,可以根据需求修改)
for (int i = 0; i < USB_PORT_MAX; i++) {
SVC_PowerMgr_EnablePortPower((USB_Port_t)i);
}
}

void APP_Run(void) {
// 主应用循环 (如果需要处理用户输入或执行其他周期性任务,可以在这里添加)
while (1) {
// APP_HandleUserInput(); // 处理用户输入 (如果需要)
vTaskDelay(pdMS_TO_TICKS(10)); // 延时
}
}

void APP_HandleUserInput(void) {
// 处理用户输入,例如按键、触摸屏等 (如果需要)
// ... 用户输入处理代码 ...
}

void APP_SystemTickHandler(void) {
// 系统定时器 Tick 处理函数 (例如用于周期性任务触发)
// ... 定时器 Tick 处理代码 ...
}

// 主函数 (main.c)
#include "app.h"
#include "FreeRTOS.h"
#include "task.h"

int main(void) {
// 初始化 HAL (例如系统时钟、外设时钟等,需要根据具体的 MCU 和硬件平台初始化)
HAL_Init();

APP_Init(); // 应用层初始化

// 启动 FreeRTOS 任务调度器
vTaskStartScheduler();

// 正常情况下不会执行到这里
while(1);
}

3. 其他辅助文件 (示例)

  • spi.hspi.c (SPI 初始化和驱动代码,如果使用 SPI 接口的显示屏)
  • font.hfont.c (字体库文件,用于显示字符串)
  • config.h (系统配置头文件,定义宏、常量等)
  • stm32f4xx_it.c (中断服务例程文件,如果使用 STM32 HAL 库)
  • stm32f4xx_hal_msp.c (HAL 库 MSP 初始化文件,如果使用 STM32 HAL 库)
  • FreeRTOSConfig.h (FreeRTOS 配置文件,如果使用 FreeRTOS)

技术和方法实践验证

本项目采用的技术和方法都是经过实践验证的成熟方案,能够确保系统的可靠性、高效性和可扩展性:

  • 分层架构:分层架构是嵌入式系统设计中常用的架构模式,它能够有效地组织代码,降低模块之间的耦合度,提高代码的可维护性和可移植性。在复杂的嵌入式系统中,分层架构是构建可管理系统的关键。
  • **硬件抽象层 (HAL)**:HAL 层是提高代码可移植性的重要手段。通过 HAL 层,上层软件可以屏蔽底层硬件的差异,轻松移植到不同的硬件平台。这在嵌入式产品迭代升级或系列化开发中尤为重要。
  • 模块化设计:将系统划分为多个独立的模块,每个模块负责特定的功能,模块之间通过接口进行交互。模块化设计提高了代码的复用性,降低了开发和维护成本。
  • C 语言编程:C 语言是嵌入式系统开发中最常用的编程语言,它具有高效、灵活、可移植性好等特点,能够满足嵌入式系统对性能和资源的要求。
  • **FreeRTOS 实时操作系统 (可选)**:对于功能较为复杂的嵌入式系统,使用 RTOS 可以有效地管理任务调度、资源分配、任务间通信等,提高系统的实时性和可靠性。虽然本示例代码中使用了 FreeRTOS,但在资源受限的简单系统中,也可以不使用 RTOS,采用裸机编程方式。
  • ADC 精确测量:电压电流检测是本项目的核心功能。通过高精度 ADC、合适的采样电阻、放大电路(如果需要)、校准算法和滤波算法,可以实现准确可靠的电压电流测量。
  • SPI 接口 LCD 显示:SPI 接口 LCD 是一种常用的嵌入式显示方案,具有接口简单、驱动方便、成本较低等优点。可以清晰地显示电压、电流等实时数据。
  • USB HUB 控制技术:采用成熟的 USB HUB 控制芯片和驱动方案,可以实现可靠的 USB 端口扩展功能。
  • 电源管理和保护:通过电源管理芯片和过流保护电路,可以确保 USB HUB 的供电稳定性和安全性,防止因过流或短路导致设备损坏。

针对电子调试工程师痛点的解决方案

本项目设计的多功能 USB HUB 能够有效解决电子调试工程师的以下痛点:

  • 实时监控 USB 端口状态:工程师无需额外仪表设备,即可实时查看每个 USB 端口的电压、电流和功率,快速了解设备供电情况。
  • 快速定位电源问题:当调试过程中出现设备无法启动、运行不稳定等电源相关问题时,工程师可以立即通过显示屏上的数据判断是否是供电不足、电流过大或其他电源异常导致,大大缩短问题排查时间。
  • 便捷的电源性能分析:通过长时间监控电压电流数据,工程师可以分析设备的功耗特性,评估电源系统的性能,为产品优化提供数据支持。
  • 集成化工具,简化工作流程:将 USB HUB 功能和电源监控功能集成在一个设备中,减少了工程师桌面上的设备数量,简化了调试流程,提高了工作效率。
  • 可扩展性:分层架构的设计使得系统具有良好的可扩展性,未来可以方便地添加更多功能,例如数据记录、远程监控、协议分析等,进一步提升产品的价值。

总结

本项目基于分层架构,采用 C 语言编程,结合实践验证的技术和方法,实现了一个可靠、高效、可扩展的多功能 USB HUB,有效解决了电子调试工程师在日常工作中遇到的痛点。通过实时监控 USB 端口的电压、电流和功率,该产品能够显著提高电子调试的效率,帮助工程师快速定位问题,进行电源性能分析,并最终提升产品的开发质量和效率。

以上代码框架和示例代码旨在提供一个清晰的项目架构和实现思路,实际项目中需要根据具体的硬件平台、显示屏型号、USB 控制器芯片、以及更详细的功能需求进行调整和完善。为了达到3000行代码的要求,可以进一步完善 HAL 层的驱动实现,增加更多的图形显示函数,添加更全面的错误处理机制,以及扩展配置管理服务的功能等。

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