编程技术分享

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

0%

简介:基于CH334H与AT32F403A的电流检测USB HUB

基于CH334H与AT32F403A的电流检测USB HUB嵌入式系统设计与实现

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

项目简介

本项目旨在设计并实现一个基于CH334H USB HUB芯片和AT32F403A微控制器的电流检测USB HUB。该系统不仅提供USB端口扩展功能,更重要的是能够实时监测并反馈每个USB端口的电流消耗情况。这对于需要精确控制和监控USB设备功耗的应用场景,例如电池供电设备管理、设备故障诊断、充电管理等,具有重要的实用价值。

系统架构设计

为了构建一个可靠、高效、可扩展的系统平台,我们采用分层架构进行代码设计。这种架构将系统功能划分为不同的层次,每个层次负责特定的任务,层与层之间通过定义明确的接口进行交互。分层架构的优点包括:

  • 模块化: 每个层次都是独立的模块,易于开发、测试和维护。
  • 可重用性: 底层模块可以被不同的上层模块复用,提高代码效率。
  • 可扩展性: 可以方便地添加新的功能模块,而不会影响到其他模块。
  • 可移植性: 通过抽象硬件细节,可以更容易地将系统移植到不同的硬件平台。

本项目采用的四层架构模型如下:

  1. 硬件抽象层 (HAL - Hardware Abstraction Layer): 直接与硬件交互,封装底层硬件操作细节,向上层提供统一的硬件访问接口。HAL层包括GPIO、ADC、SPI、I2C等外设驱动,以及时钟、中断等底层系统资源的配置和管理。

  2. 驱动层 (Driver Layer): 基于HAL层提供的接口,为特定的硬件设备提供驱动程序。驱动层负责设备的初始化、配置、数据收发等操作。本项目驱动层包括CH334H USB HUB驱动、电流传感器驱动(基于ADC)、以及可能的显示屏驱动(如果需要)。

  3. 服务层 (Service Layer): 在驱动层之上构建,提供高层次的系统服务功能。服务层负责业务逻辑的实现,例如USB HUB管理、电流检测与处理、数据记录与报警、用户接口(例如通过串口或显示屏)等。

  4. 应用层 (Application Layer): 系统的最高层,负责整个系统的流程控制和用户交互。应用层调用服务层提供的接口,实现具体的应用功能。本项目应用层主要负责系统初始化、任务调度、用户命令解析、以及系统状态显示等。

系统框图

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
+---------------------+     +---------------------+     +---------------------+     +---------------------+
| 应用层 (Application Layer) | --> | 服务层 (Service Layer) | --> | 驱动层 (Driver Layer) | --> | 硬件抽象层 (HAL - Hardware Abstraction Layer) |
+---------------------+ +---------------------+ +---------------------+ +---------------------+
^ ^ ^ ^
| | | |
+-------------------------------------------------------------------------------------------------+
系统控制与数据流

+---------------------+
| 用户接口 (UI) | <---- 应用层 (例如串口命令行,显示屏)
+---------------------+
^
|
+------------------------------------+
| 服务层 (Service Layer) |
| - USB HUB 管理服务 |
| - 电流检测服务 |
| - 数据处理与报警服务 |
+------------------------------------+
^
|
+----------------------------------------------------------+
| 驱动层 (Driver Layer) |
| - CH334H USB HUB 驱动 |
| - 电流传感器 (ADC) 驱动 |
| - 可选: 显示屏驱动 (例如 OLED/LCD) |
+----------------------------------------------------------+
^
|
+----------------------------------------------------------------------------------------------------+
| 硬件抽象层 (HAL - Hardware Abstraction Layer) |
| - GPIO 驱动 |
| - ADC 驱动 |
| - SPI/I2C 驱动 (如果 CH334H 或 显示屏 使用) |
| - 时钟管理 |
| - 中断管理 |
+----------------------------------------------------------------------------------------------------+
^
|
+----------------------------------------------------------------------------------------------------+
| 硬件平台 |
| - AT32F403A 微控制器 |
| - CH334H USB HUB 芯片 |
| - 电流传感器 (例如 分流电阻 + 放大器 + ADC) |
| - USB 连接器 (Type-A 母座) x 4 |
| - USB Type-C 输入接口 |
| - 可选: 显示屏 (OLED/LCD) |
+----------------------------------------------------------------------------------------------------+

关键技术与方法

本项目采用以下关键技术和方法,均经过实践验证:

  1. AT32F403A 微控制器: 选用雅特力AT32F403A系列高性能ARM Cortex-M4内核微控制器,具有丰富的片上外设资源,满足系统控制和数据处理的需求。其高主频和低功耗特性,保证系统的实时性和效率。

  2. CH334H USB HUB 芯片: 采用沁恒CH334H高速USB2.0 HUB芯片,提供稳定的USB端口扩展能力。CH334H芯片具有良好的兼容性和可靠性,能够满足多端口USB设备连接的需求。

  3. 高精度电流检测电路: 采用分流电阻配合运算放大器以及高精度ADC的方式进行电流检测。分流电阻选取低阻值精密电阻,减小电压损耗。运算放大器用于放大分流电阻上的压降信号,提高ADC采样精度。ADC选用AT32F403A片上集成的12位或更高精度的ADC,确保电流检测的准确性。为了降低噪声影响,电流检测电路设计中需要注意滤波和屏蔽。

  4. 模数转换 (ADC) 技术: 利用AT32F403A的ADC外设,将电流传感器输出的模拟电压信号转换为数字信号,供微控制器进行处理。ADC采样频率、分辨率和精度直接影响电流检测的性能,需要根据实际需求进行配置和优化。

  5. USB 通信协议: 理解USB协议的基本原理,包括设备枚举、数据传输、控制传输等,确保USB HUB芯片能够正常工作,并实现与上位机或其他USB设备的通信。

  6. 实时操作系统 (RTOS) (可选): 如果系统功能较为复杂,或者对实时性要求较高,可以考虑引入实时操作系统,例如FreeRTOS或RT-Thread。RTOS可以帮助管理任务调度、资源分配、线程同步等,提高系统的稳定性和效率。本项目为了代码清晰和便于理解,在示例代码中不强制使用RTOS,但会给出使用RTOS的建议和方向。

  7. 事件驱动编程: 采用事件驱动的编程模型,提高系统的响应速度和效率。例如,USB设备连接/断开事件、ADC采样完成事件、定时器事件等,都通过事件触发相应的处理函数。

  8. 数据滤波算法: 为了提高电流检测数据的稳定性和抗干扰能力,可以采用数字滤波算法,例如滑动平均滤波、中值滤波、卡尔曼滤波等。根据实际应用场景选择合适的滤波算法。

  9. 错误处理与异常管理: 在代码中加入完善的错误处理机制,例如参数校验、硬件故障检测、异常中断处理等,提高系统的鲁棒性和可靠性。

  10. 代码版本控制 (Git): 使用Git进行代码版本控制,方便代码管理、协作开发和版本回溯。

  11. 单元测试与集成测试: 在开发过程中进行单元测试和集成测试,验证各个模块的功能和接口,确保系统的整体质量。

详细C代码实现 (部分关键模块)

我们将尽可能详细地展示各个模块的代码实现,并加入大量的注释进行解释。以下代码仅为示例,实际项目中可能需要根据具体硬件和需求进行调整。

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

#include "at32f403a_conf.h" // 雅特力AT32F403A HAL库头文件,根据实际情况修改

// GPIO 端口定义
typedef enum {
GPIOA_PORT,
GPIOB_PORT,
GPIOC_PORT,
GPIOD_PORT,
GPIOE_PORT,
GPIOF_PORT,
GPIOG_PORT,
GPIOH_PORT,
GPIOI_PORT
} HAL_GPIO_Port;

// GPIO 引脚定义
typedef enum {
GPIO_PIN_0 = 0x0001, /*!< Pin 0 selected */
GPIO_PIN_1 = 0x0002, /*!< Pin 1 selected */
GPIO_PIN_2 = 0x0004, /*!< Pin 2 selected */
GPIO_PIN_3 = 0x0008, /*!< Pin 3 selected */
GPIO_PIN_4 = 0x0010, /*!< Pin 4 selected */
GPIO_PIN_5 = 0x0020, /*!< Pin 5 selected */
GPIO_PIN_6 = 0x0040, /*!< Pin 6 selected */
GPIO_PIN_7 = 0x0080, /*!< Pin 7 selected */
GPIO_PIN_8 = 0x0100, /*!< Pin 8 selected */
GPIO_PIN_9 = 0x0200, /*!< Pin 9 selected */
GPIO_PIN_10 = 0x0400, /*!< Pin 10 selected */
GPIO_PIN_11 = 0x0800, /*!< Pin 11 selected */
GPIO_PIN_12 = 0x1000, /*!< Pin 12 selected */
GPIO_PIN_13 = 0x2000, /*!< Pin 13 selected */
GPIO_PIN_14 = 0x4000, /*!< Pin 14 selected */
GPIO_PIN_15 = 0x8000, /*!< Pin 15 selected */
GPIO_PIN_ALL = 0xFFFF /*!< All pins selected */
} HAL_GPIO_Pin;

// GPIO 工作模式定义
typedef enum {
GPIO_MODE_INPUT, /*!< Input mode */
GPIO_MODE_OUTPUT, /*!< Output mode */
GPIO_MODE_ANALOG, /*!< Analog mode */
GPIO_MODE_AF_OUTPUT /*!< Alternate function output mode */
} HAL_GPIO_Mode;

// GPIO 输出类型定义
typedef enum {
GPIO_OUTPUT_PUSH_PULL, /*!< Push-pull output */
GPIO_OUTPUT_OPEN_DRAIN /*!< Open-drain output */
} HAL_GPIO_OutputType;

// GPIO 输出速度定义
typedef enum {
GPIO_SPEED_LOW, /*!< Low speed */
GPIO_SPEED_MEDIUM, /*!< Medium speed */
GPIO_SPEED_HIGH, /*!< High speed */
GPIO_SPEED_VERY_HIGH /*!< Very high speed */
} HAL_GPIO_Speed;

// GPIO 上下拉配置定义
typedef enum {
GPIO_PULL_NONE, /*!< No pull-up or pull-down */
GPIO_PULL_UP, /*!< Pull-up */
GPIO_PULL_DOWN /*!< Pull-down */
} HAL_GPIO_Pull;

// GPIO 初始化结构体
typedef struct {
HAL_GPIO_Pin Pin; /*!< Specifies the GPIO pins to be configured.
This parameter can be a value of @ref HAL_GPIO_Pin */

HAL_GPIO_Mode Mode; /*!< Specifies the operating mode for the selected pins.
This parameter can be a value of @ref HAL_GPIO_Mode */

HAL_GPIO_OutputType OutputType; /*!< Specifies the output type for the selected pins.
This parameter can be a value of @ref HAL_GPIO_OutputType
This parameter is effective only when GPIO_MODE_OUTPUT or GPIO_MODE_AF_PP modes are selected. */

HAL_GPIO_Speed Speed; /*!< Specifies the speed for the selected pins.
This parameter can be a value of @ref HAL_GPIO_Speed
This parameter is effective only when GPIO_MODE_OUTPUT or GPIO_MODE_AF_PP modes are selected. */

HAL_GPIO_Pull Pull; /*!< Specifies the Pull-up or Pull-Down activation for the selected pins.
This parameter can be a value of @ref HAL_GPIO_Pull */
} HAL_GPIO_InitTypeDef;


// GPIO 初始化函数
void HAL_GPIO_Init(HAL_GPIO_Port Port, HAL_GPIO_InitTypeDef *GPIO_Init);

// GPIO 设置输出电平函数
void HAL_GPIO_WritePin(HAL_GPIO_Port Port, HAL_GPIO_Pin Pin, uint8_t PinState);

// GPIO 读取输入电平函数
uint8_t HAL_GPIO_ReadPin(HAL_GPIO_Port Port, HAL_GPIO_Pin Pin);

// ... 可以添加更多GPIO相关的HAL函数,例如GPIO时钟使能、GPIO复位等

#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
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 "hal_gpio.h"

// GPIO 初始化函数
void HAL_GPIO_Init(HAL_GPIO_Port Port, HAL_GPIO_InitTypeDef *GPIO_Init) {
gpio_init_type gpio_init_struct;

// 使能 GPIO 时钟 (根据 Port 参数选择对应的 GPIO 时钟)
switch (Port) {
case GPIOA_PORT: CRM_PERIPH_CLOCK_ENABLE(CRM_GPIOA_PERIPH_CLOCK, TRUE); break;
case GPIOB_PORT: CRM_PERIPH_CLOCK_ENABLE(CRM_GPIOB_PERIPH_CLOCK, TRUE); break;
case GPIOC_PORT: CRM_PERIPH_CLOCK_ENABLE(CRM_GPIOC_PERIPH_CLOCK, TRUE); break;
case GPIOD_PORT: CRM_PERIPH_CLOCK_ENABLE(CRM_GPIOD_PERIPH_CLOCK, TRUE); break;
case GPIOE_PORT: CRM_PERIPH_CLOCK_ENABLE(CRM_GPIOE_PERIPH_CLOCK, TRUE); break;
case GPIOF_PORT: CRM_PERIPH_CLOCK_ENABLE(CRM_GPIOF_PERIPH_CLOCK, TRUE); break;
case GPIOG_PORT: CRM_PERIPH_CLOCK_ENABLE(CRM_GPIOG_PERIPH_CLOCK, TRUE); break;
case GPIOH_PORT: CRM_PERIPH_CLOCK_ENABLE(CRM_GPIOH_PERIPH_CLOCK, TRUE); break;
case GPIOI_PORT: CRM_PERIPH_CLOCK_ENABLE(CRM_GPIOI_PERIPH_CLOCK, TRUE); break;
default: return; // 参数错误
}

// 初始化 GPIO 结构体
gpio_init_struct.gpio_pins = GPIO_Init->Pin;

switch (GPIO_Init->Mode) {
case GPIO_MODE_INPUT: gpio_init_struct.gpio_mode = GPIO_MODE_INPUT; break;
case GPIO_MODE_OUTPUT: gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT; break;
case GPIO_MODE_ANALOG: gpio_init_struct.gpio_mode = GPIO_MODE_ANALOG; break;
case GPIO_MODE_AF_OUTPUT: gpio_init_struct.gpio_mode = GPIO_MODE_MUX; break; // 复用功能
default: return; // 参数错误
}

switch (GPIO_Init->OutputType) {
case GPIO_OUTPUT_PUSH_PULL: gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; break;
case GPIO_OUTPUT_OPEN_DRAIN: gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN; break;
default: return; // 参数错误
}

switch (GPIO_Init->Speed) {
case GPIO_SPEED_LOW: gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE; break; // 低速,中等驱动能力
case GPIO_SPEED_MEDIUM: gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE; break; // 中速,中等驱动能力
case GPIO_SPEED_HIGH: gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_HIGH; break; // 高速,高驱动能力
case GPIO_SPEED_VERY_HIGH: gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_ULTRA_HIGH; break;// 超高速,超高驱动能力
default: return; // 参数错误
}

switch (GPIO_Init->Pull) {
case GPIO_PULL_NONE: gpio_init_struct.gpio_pull = GPIO_PULL_NONE; break;
case GPIO_PULL_UP: gpio_init_struct.gpio_pull = GPIO_PULL_UP; break;
case GPIO_PULL_DOWN: gpio_init_struct.gpio_pull = GPIO_PULL_DOWN; break;
default: return; // 参数错误
}

gpio_init(Get_GPIO_Periph(Port), &gpio_init_struct); // 调用雅特力HAL库 GPIO 初始化函数
}

// GPIO 设置输出电平函数
void HAL_GPIO_WritePin(HAL_GPIO_Port Port, HAL_GPIO_Pin Pin, uint8_t PinState) {
if (PinState == GPIO_PIN_RESET) {
gpio_reset_pin(Get_GPIO_Periph(Port), Pin); // 设置为低电平
} else {
gpio_set_pin(Get_GPIO_Periph(Port), Pin); // 设置为高电平
}
}

// GPIO 读取输入电平函数
uint8_t HAL_GPIO_ReadPin(HAL_GPIO_Port Port, HAL_GPIO_Pin Pin) {
if (gpio_input_data_bit_read(Get_GPIO_Periph(Port), Pin) != RESET) {
return GPIO_PIN_SET; // 高电平
} else {
return GPIO_PIN_RESET; // 低电平
}
}

// ... 可以添加更多GPIO相关的HAL函数实现

// 根据 HAL_GPIO_Port 获取对应的 GPIO 外设指针 (雅特力 HAL 库函数)
static GPIO_Type* Get_GPIO_Periph(HAL_GPIO_Port Port) {
switch (Port) {
case GPIOA_PORT: return GPIOA;
case GPIOB_PORT: return GPIOB;
case GPIOC_PORT: return GPIOC;
case GPIOD_PORT: return GPIOD;
case GPIOE_PORT: return GPIOE;
case GPIOF_PORT: return GPIOF;
case GPIOG_PORT: return GPIOG;
case GPIOH_PORT: return GPIOH;
case GPIOI_PORT: return GPIOI;
default: return NULL; // 参数错误
}
}

hal_adc.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
#ifndef HAL_ADC_H
#define HAL_ADC_H

#include "at32f403a_conf.h" // 雅特力AT32F403A HAL库头文件

// ADC 通道定义 (根据 AT32F403A 数据手册定义)
typedef enum {
ADC_CHANNEL_0 = 0x00,
ADC_CHANNEL_1 = 0x01,
ADC_CHANNEL_2 = 0x02,
ADC_CHANNEL_3 = 0x03,
ADC_CHANNEL_4 = 0x04,
ADC_CHANNEL_5 = 0x05,
ADC_CHANNEL_6 = 0x06,
ADC_CHANNEL_7 = 0x07,
ADC_CHANNEL_8 = 0x08,
ADC_CHANNEL_9 = 0x09,
ADC_CHANNEL_10 = 0x0A,
ADC_CHANNEL_11 = 0x0B,
ADC_CHANNEL_12 = 0x0C,
ADC_CHANNEL_13 = 0x0D,
ADC_CHANNEL_14 = 0x0E,
ADC_CHANNEL_15 = 0x0F,
ADC_CHANNEL_16 = 0x10, // 温度传感器
ADC_CHANNEL_17 = 0x11 // 内部参考电压
} HAL_ADC_Channel;

// ADC 初始化结构体
typedef struct {
uint32_t Resolution; /*!< Specifies the ADC resolution, This parameter can be a value of @ref ADC_resolution */
uint32_t ScanMode; /*!< Specifies whether the conversion is performed in scan (multichannel) or discontinuous mode.
This parameter can be a value of @ref ADC_scan_mode */
uint32_t ContinuousMode; /*!< Specifies whether the conversion is performed in continuous or single mode.
This parameter can be a value of @ref ADC_continuous_mode */
uint32_t ExternalTrigConvEdge;/*!< Specifies the external trigger edge and polarity for regular group conversion.
This parameter can be a value of @ref ADC_external_trigger_edge_regular */
uint32_t ExternalTrigConv; /*!< Specifies the external trigger for regular group conversion.
This parameter can be a value of @ref ADC_external_trigger_regular */
uint32_t DataAlign; /*!< Specifies whether the ADC data alignment is left or right.
This parameter can be a value of @ref ADC_data_alignment */
uint32_t OverrunMode; /*!< Specifies whether the overrun mode is enabled or disabled.
This parameter can be a value of @ref ADC_overrun_mode */
uint32_t DMAMode; /*!< Specifies whether the DMA mode is enabled or disabled.
This parameter can be a value of @ref ADC_dma_mode */
uint32_t DMAContinuousRequests;/*!< Specifies whether DMA continuous requests are enabled or disabled.
This parameter can be a value of @ref ADC_dma_continuous_requests */
uint32_t EOCSelection; /*!< Specifies the EOC event that triggers the DMA transfer.
This parameter can be a value of @ref ADC_eoc_selection */
} HAL_ADC_InitTypeDef;


// ADC 初始化函数
void HAL_ADC_Init(ADC_Type* ADCx, HAL_ADC_InitTypeDef *ADC_Init);

// ADC 通道配置函数
void HAL_ADC_ConfigChannel(ADC_Type* ADCx, HAL_ADC_Channel Channel, uint32_t Rank, uint32_t SampleTime);

// ADC 开始转换函数
void HAL_ADC_Start(ADC_Type* ADCx);

// ADC 停止转换函数
void HAL_ADC_Stop(ADC_Type* ADCx);

// ADC 获取转换结果函数
uint16_t HAL_ADC_GetValue(ADC_Type* ADCx);

// ... 可以添加更多ADC相关的HAL函数,例如ADC时钟使能、ADC中断配置等

#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
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
#include "hal_adc.h"

// ADC 初始化函数
void HAL_ADC_Init(ADC_Type* ADCx, HAL_ADC_InitTypeDef *ADC_Init) {
adc_init_type adc_init_struct;

// 使能 ADC 时钟 (根据 ADCx 参数选择对应的 ADC 时钟)
if (ADCx == ADC1) {
CRM_PERIPH_CLOCK_ENABLE(CRM_ADC1_PERIPH_CLOCK, TRUE);
} else if (ADCx == ADC2) {
CRM_PERIPH_CLOCK_ENABLE(CRM_ADC2_PERIPH_CLOCK, TRUE);
} else {
return; // 参数错误
}

// 初始化 ADC 结构体
adc_init_struct.data_align_mode = ADC_Init->DataAlign;
adc_init_struct.exter_trig_mode = ADC_Init->ExternalTrigConv;
adc_init_struct.exter_trig_select = ADC_Init->ExternalTrigConvEdge;
adc_init_struct.mode = ADC_Init->ContinuousMode;
adc_init_struct.ordinary_channel_length = 1; // 默认只配置一个通道
adc_init_struct.oversampling_mode = ADC_OVERSAMPLING_DISABLE; // 默认关闭过采样
adc_init_struct.resolution_mode = ADC_Init->Resolution;
adc_init_struct.sequence_mode = ADC_Init->ScanMode;
adc_init_struct.sequent_channels = 0; // 默认通道序列为空

adc_init(ADCx, &adc_init_struct);

// 使能 ADC 电源
adc_power_on(ADCx);

// 等待 ADC 就绪
while (adc_flag_get(ADCx, ADC_RD_FLAG) == RESET);
}

// ADC 通道配置函数
void HAL_ADC_ConfigChannel(ADC_Type* ADCx, HAL_ADC_Channel Channel, uint32_t Rank, uint32_t SampleTime) {
adc_ordinary_channel_set(ADCx, Channel, Rank, SampleTime);
}

// ADC 开始转换函数
void HAL_ADC_Start(ADC_Type* ADCx) {
adc_ordinary_conversion_continue_mode(ADCx, TRUE); // 连续转换模式
adc_ordinary_conversion_trigger_enable(ADCx, TRUE); // 启动转换
}

// ADC 停止转换函数
void HAL_ADC_Stop(ADC_Type* ADCx) {
adc_ordinary_conversion_trigger_enable(ADCx, FALSE); // 停止转换
adc_ordinary_conversion_continue_mode(ADCx, FALSE); // 关闭连续转换模式
}

// ADC 获取转换结果函数
uint16_t HAL_ADC_GetValue(ADC_Type* ADCx) {
return adc_ordinary_get_conversion_value(ADCx);
}

// ... 可以添加更多ADC相关的HAL函数实现

2. 驱动层 (Driver Layer)

ch334h_driver.h

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef CH334H_DRIVER_H
#define CH334H_DRIVER_H

#include "hal_gpio.h" // 假设 CH334H 控制使用 GPIO

// CH334H 驱动初始化函数
void CH334H_Init(void);

// ... 可以添加 CH334H 控制相关的驱动函数,例如 USB HUB 复位、电源控制等
// ... CH334H 通常是硬件自动工作的,软件驱动可能只需要初始化和复位

#endif // CH334H_DRIVER_H

ch334h_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
#include "ch334h_driver.h"
#include "hal_gpio.h"

// CH334H 控制引脚定义 (根据实际硬件连接修改)
#define CH334H_RESET_PORT GPIOA_PORT
#define CH334H_RESET_PIN GPIO_PIN_0

// CH334H 驱动初始化函数
void CH334H_Init(void) {
HAL_GPIO_InitTypeDef GPIO_InitStruct;

// 初始化 CH334H 复位引脚为输出模式
GPIO_InitStruct.Pin = CH334H_RESET_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;
GPIO_InitStruct.OutputType = GPIO_OUTPUT_PUSH_PULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Pull = GPIO_PULL_NONE;
HAL_GPIO_Init(CH334H_RESET_PORT, &GPIO_InitStruct);

// 复位 CH334H 芯片 (拉低复位引脚一段时间)
HAL_GPIO_WritePin(CH334H_RESET_PORT, CH334H_RESET_PIN, GPIO_PIN_RESET);
delay_ms(10); // 延时 10ms
HAL_GPIO_WritePin(CH334H_RESET_PORT, CH334H_RESET_PIN, GPIO_PIN_SET);
delay_ms(100); // 延时 100ms,等待 CH334H 初始化完成
}

// ... 可以添加 CH334H 控制相关的驱动函数实现,如果需要

current_sensor_driver.h

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

#include "hal_adc.h"

// 电流传感器通道定义 (根据实际硬件连接修改)
#define CURRENT_SENSOR_CHANNEL_PORT1 ADC_CHANNEL_0
#define CURRENT_SENSOR_CHANNEL_PORT2 ADC_CHANNEL_1
#define CURRENT_SENSOR_CHANNEL_PORT3 ADC_CHANNEL_2
#define CURRENT_SENSOR_CHANNEL_PORT4 ADC_CHANNEL_3

// 电流传感器初始化函数
void CurrentSensor_Init(void);

// 读取指定端口的电流值 (单位: mA)
float CurrentSensor_ReadCurrent(uint8_t port_index);

#endif // CURRENT_SENSOR_DRIVER_H

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
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 "current_sensor_driver.h"
#include "hal_adc.h"
#include "delay.h" // 延时函数,需要自行实现

// ADC 外设定义 (假设使用 ADC1)
#define CURRENT_SENSOR_ADC ADC1

// ADC 通道配置数组
const HAL_ADC_Channel current_sensor_channels[] = {
CURRENT_SENSOR_CHANNEL_PORT1,
CURRENT_SENSOR_CHANNEL_PORT2,
CURRENT_SENSOR_CHANNEL_PORT3,
CURRENT_SENSOR_CHANNEL_PORT4
};

// 分流电阻阻值 (单位: 欧姆) - 根据实际电路参数修改
#define SHUNT_RESISTANCE 0.1f

// 运放放大倍数 - 根据实际电路参数修改
#define AMPLIFIER_GAIN 10.0f

// ADC 参考电压 (单位: V) - 根据 AT32F403A 参考电压或外部参考电压修改
#define ADC_REFERENCE_VOLTAGE 3.3f

// ADC 最大计数值 (12位 ADC 为 4095)
#define ADC_MAX_VALUE 4095.0f

// 电流传感器初始化函数
void CurrentSensor_Init(void) {
HAL_ADC_InitTypeDef ADC_InitStruct;

// ADC 初始化配置
ADC_InitStruct.Resolution = ADC_RMW_12BIT; // 12位分辨率
ADC_InitStruct.ScanMode = ADC_SCAN_DISABLE; // 单通道模式
ADC_InitStruct.ContinuousMode = ADC_CONTINUOUS_MODE_DISABLE; // 单次转换模式
ADC_InitStruct.ExternalTrigConvEdge = ADC_EXT_TRIG_CONV_NONE; // 软件触发
ADC_InitStruct.ExternalTrigConv = ADC_EXT_TRIG_REGULAR_NONE;
ADC_InitStruct.DataAlign = ADC_DATA_ALIGN_RIGHT; // 右对齐
ADC_InitStruct.OverrunMode = ADC_OVR_DATA_OVERWRITTEN;
ADC_InitStruct.DMAMode = ADC_DMA_DISABLE;
ADC_InitStruct.DMAContinuousRequests = ADC_DMA_CONTINUOUS_REQUESTS_DISABLE;
ADC_InitStruct.EOCSelection = ADC_EOC_SINGLE_CONV;
HAL_ADC_Init(CURRENT_SENSOR_ADC, &ADC_InitStruct);

// 配置电流传感器通道 (假设使用通道 0-3)
for (uint8_t i = 0; i < sizeof(current_sensor_channels) / sizeof(current_sensor_channels[0]); i++) {
HAL_ADC_ConfigChannel(CURRENT_SENSOR_ADC, current_sensor_channels[i], i + 1, ADC_SAMP_CYCLE_28_5); // 采样时间 28.5 cycles
}
}

// 读取指定端口的电流值 (单位: mA)
float CurrentSensor_ReadCurrent(uint8_t port_index) {
if (port_index >= sizeof(current_sensor_channels) / sizeof(current_sensor_channels[0])) {
return -1.0f; // 参数错误
}

HAL_ADC_Channel channel = current_sensor_channels[port_index];

HAL_ADC_ConfigChannel(CURRENT_SENSOR_ADC, channel, 1, ADC_SAMP_CYCLE_28_5); // 重新配置通道 (虽然初始化已经配置,但为了代码完整性)

HAL_ADC_Start(CURRENT_SENSOR_ADC); // 启动 ADC 转换
delay_us(10); // 延时等待转换完成 (根据 ADC 采样时间调整)
while (adc_flag_get(CURRENT_SENSOR_ADC, ADC_OCCO_FLAG) == RESET); // 等待转换完成标志

uint16_t adc_value = HAL_ADC_GetValue(CURRENT_SENSOR_ADC); // 读取 ADC 值
HAL_ADC_Stop(CURRENT_SENSOR_ADC); // 停止 ADC

// 计算电流值 (单位: mA)
float voltage = (float)adc_value / ADC_MAX_VALUE * ADC_REFERENCE_VOLTAGE; // 计算电压值 (V)
float current = voltage / AMPLIFIER_GAIN / SHUNT_RESISTANCE * 1000.0f; // 计算电流值 (mA)

return current;
}

3. 服务层 (Service Layer)

usb_hub_service.h

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

// USB HUB 服务初始化函数
void USBHubService_Init(void);

// ... 可以添加 USB HUB 管理相关的服务函数,例如 获取 USB 连接状态,控制 USB 电源等
// ... CH334H 通常是硬件自动工作的,服务层可能只需要初始化和监控

#endif // USB_HUB_SERVICE_H

usb_hub_service.c

1
2
3
4
5
6
7
8
9
#include "usb_hub_service.h"
#include "ch334h_driver.h"

// USB HUB 服务初始化函数
void USBHubService_Init(void) {
CH334H_Init(); // 初始化 CH334H 驱动
}

// ... 可以添加 USB HUB 管理相关的服务函数实现,如果需要

current_monitor_service.h

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

#include <stdint.h>

// 电流监控服务初始化函数
void CurrentMonitorService_Init(void);

// 获取指定 USB 端口的电流值 (单位: mA)
float CurrentMonitorService_GetCurrent(uint8_t port_index);

// 设置电流过流阈值 (单位: mA)
void CurrentMonitorService_SetOverCurrentThreshold(uint8_t port_index, float threshold_mA);

// 获取电流过流阈值 (单位: mA)
float CurrentMonitorService_GetOverCurrentThreshold(uint8_t port_index);

// 检查指定 USB 端口是否过流
uint8_t CurrentMonitorService_IsOverCurrent(uint8_t port_index);

#endif // CURRENT_MONITOR_SERVICE_H

current_monitor_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
#include "current_monitor_service.h"
#include "current_sensor_driver.h"
#include "stdio.h" // 用于 printf 调试输出

#define NUM_USB_PORTS 4 // USB 端口数量

// 每个 USB 端口的过流阈值 (单位: mA),默认值
float over_current_thresholds[NUM_USB_PORTS] = {500.0f, 500.0f, 500.0f, 500.0f};

// 电流监控服务初始化函数
void CurrentMonitorService_Init(void) {
CurrentSensor_Init(); // 初始化电流传感器驱动
}

// 获取指定 USB 端口的电流值 (单位: mA)
float CurrentMonitorService_GetCurrent(uint8_t port_index) {
if (port_index >= NUM_USB_PORTS) {
return -1.0f; // 参数错误
}
return CurrentSensor_ReadCurrent(port_index);
}

// 设置电流过流阈值 (单位: mA)
void CurrentMonitorService_SetOverCurrentThreshold(uint8_t port_index, float threshold_mA) {
if (port_index < NUM_USB_PORTS) {
over_current_thresholds[port_index] = threshold_mA;
}
}

// 获取电流过流阈值 (单位: mA)
float CurrentMonitorService_GetOverCurrentThreshold(uint8_t port_index) {
if (port_index < NUM_USB_PORTS) {
return over_current_thresholds[port_index];
}
return -1.0f; // 参数错误
}

// 检查指定 USB 端口是否过流
uint8_t CurrentMonitorService_IsOverCurrent(uint8_t port_index) {
if (port_index >= NUM_USB_PORTS) {
return 0; // 参数错误,默认不过流
}

float current = CurrentMonitorService_GetCurrent(port_index);
float threshold = CurrentMonitorService_GetOverCurrentThreshold(port_index);

if (current > threshold) {
printf("Port %d Overcurrent! Current: %.2f mA, Threshold: %.2f mA\r\n", port_index + 1, current, threshold); // 打印过流信息
return 1; // 过流
} else {
return 0; // 未过流
}
}

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
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
#include "at32f403a.h"
#include "delay.h"
#include "usb_hub_service.h"
#include "current_monitor_service.h"
#include "stdio.h" // 标准输入输出库,用于串口打印

// 初始化系统时钟 (根据实际晶振频率配置)
void SystemClock_Config(void) {
crm_clocks_freq_type clocks_freq;

/* 使能 HSE */
crm_clock_source_enable(CRM_CLOCK_SOURCE_HSE, TRUE);

/* 等待 HSE 稳定 */
while(crm_flag_get(CRM_HSE_STABLE_FLAG) != SET);

/* 配置 PLL */
crm_pll_config_set(CRM_PLL_SOURCE_HSE, CRM_PLL_MUL_9); // HSE * 9 = 72MHz
crm_pll_clock_enable(TRUE);

/* 等待 PLL 稳定 */
while(crm_flag_get(CRM_PLL_STABLE_FLAG) != SET);

/* 选择 PLL 作为系统时钟源 */
crm_sysclk_switch_set(CRM_SYSCLK_SOURCE_PLL);

/* 等待 PLL 切换为系统时钟 */
while(crm_sysclk_switch_get() != CRM_SYSCLK_SOURCE_PLL);

/* 获取时钟频率 */
crm_clocks_freq_get(&clocks_freq);

/* 配置外设时钟分频器 (如果需要) */
// ... 例如 APB2 时钟分频器 ...

/* 更新 SystemCoreClock 变量 */
SystemCoreClockUpdate();
}

// 初始化串口 (用于调试输出)
void UART_Config(void) {
gpio_init_type gpio_init_struct;
uart_init_type uart_init_struct;

/* 使能 GPIOA 时钟 */
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

/* 使能 UART1 时钟 */
crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);

/* 配置 UART1 TX 引脚 (PA9) 为复用推挽输出 */
gpio_init_struct.gpio_pins = GPIO_PIN_9;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_pull = GPIO_PULL_UP;
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
gpio_init(GPIOA, &gpio_init_struct);

/* 配置 UART1 RX 引脚 (PA10) 为复用输入 */
gpio_init_struct.gpio_pins = GPIO_PIN_10;
gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
gpio_init_struct.gpio_pull = GPIO_PULL_UP;
gpio_init(GPIOA, &gpio_init_struct);

/* UART1 参数配置 */
uart_init_struct.uart_baudrate = 115200;
uart_init_struct.uart_hardware_flow_control_enable= UART_HARDWARE_FLOW_CONTROL_NONE;
uart_init_struct.uart_mode = UART_MODE_TX_RX;
uart_init_struct.uart_parity_select = UART_PARITY_NONE;
uart_init_struct.uart_stop_bits = UART_STOP_BITS_1;
uart_init_struct.uart_word_length = UART_WORD_LENGTH_8B;
uart_init(USART1, &uart_init_struct);

/* 使能 UART1 */
uart_transmitter_enable(USART1, TRUE);
uart_receiver_enable(USART1, TRUE);
}

// 重定向 printf 到串口
int fputc(int ch, FILE *f) {
uart_data_transmit(USART1, (uint8_t)ch);
while(uart_flag_get(USART1, UART_TDC_FLAG) == RESET);
return ch;
}

int main(void) {
SystemClock_Config(); // 配置系统时钟
delay_init(); // 初始化延时函数
UART_Config(); // 配置串口

printf("System Start!\r\n");

USBHubService_Init(); // 初始化 USB HUB 服务
CurrentMonitorService_Init(); // 初始化电流监控服务

printf("USB HUB and Current Monitor Initialized!\r\n");

// 设置 USB 端口 1 的过流阈值为 600mA
CurrentMonitorService_SetOverCurrentThreshold(0, 600.0f);

while (1) {
printf("---------------------\r\n");
for (uint8_t i = 0; i < NUM_USB_PORTS; i++) {
float current = CurrentMonitorService_GetCurrent(i);
printf("Port %d Current: %.2f mA, Overcurrent: %s\r\n",
i + 1, current, CurrentMonitorService_IsOverCurrent(i) ? "YES" : "NO");
delay_ms(10); // 延时,避免频繁采样
}
delay_ms(1000); // 1秒采样一次
}
}

5. 其他辅助代码

delay.hdelay.c 需要根据AT32F403A的定时器或SysTick实现精确的毫秒和微秒延时函数。这里省略具体代码,可以参考雅特力提供的例程或HAL库中的延时函数。

at32f403a_conf.h 需要包含雅特力AT32F403A HAL库的头文件,并根据实际使用的外设进行配置。

代码编译和测试

  1. 环境搭建: 安装AT32F403A的开发环境,例如Keil MDK、IAR Embedded Workbench 或者 GCC 编译工具链。配置好编译选项和链接脚本。
  2. 代码编译: 将以上C代码添加到工程中,编译生成可执行文件。
  3. 程序下载: 使用J-Link、ST-Link或其他调试器将编译好的程序下载到AT32F403A开发板上。
  4. 硬件连接: 确保CH334H USB HUB芯片、电流传感器电路、USB连接器等硬件电路连接正确,并连接到AT32F403A微控制器。
  5. 功能测试:
    • 连接USB设备到USB HUB的各个端口,观察电流检测数据是否正常。
    • 测试过流保护功能,当USB设备电流超过阈值时,系统是否能正确检测并报警。
    • 通过串口打印输出,监控电流数据和系统状态。
  6. 性能优化: 根据测试结果,优化ADC采样参数、滤波算法、代码效率等,提高系统的性能和稳定性。

系统维护与升级

为了保证系统的长期稳定运行和可维护性,需要考虑以下方面:

  • 模块化设计: 分层架构和模块化代码,方便后续的功能扩展和bug修复。
  • 详细注释: 代码中加入详细的注释,提高代码可读性和可维护性。
  • 版本控制: 使用Git进行代码版本控制,方便版本管理和团队协作。
  • 固件升级: 预留固件升级接口,方便后续的功能升级和bug修复。可以使用串口、USB 或 OTA (Over-The-Air) 等方式进行固件升级。
  • 日志记录: 加入系统日志记录功能,方便故障排查和系统监控。
  • 参数配置: 将一些关键参数 (例如电流阈值、采样频率等) 外部化配置,方便用户根据实际需求进行调整。

总结

本项目详细介绍了基于CH334H和AT32F403A的电流检测USB HUB的嵌入式系统设计与实现过程。从系统架构设计、关键技术方法,到详细的C代码实现,都进行了全面的阐述。代码示例涵盖了硬件抽象层、驱动层、服务层和应用层,展示了分层架构的优势和实践应用。通过本项目的学习和实践,可以掌握嵌入式系统开发的基本流程和方法,并构建一个可靠、高效、可扩展的电流检测USB HUB系统平台。

代码行数统计

以上代码示例 (包括头文件和源文件) 加上详细的注释和解释。 实际项目中,为了更完善的功能和更高的代码质量,代码量还会进一步增加。

免责声明: 以上代码仅为示例和演示用途,可能需要根据具体的硬件平台和应用场景进行调整和完善。在实际应用中,请务必进行充分的测试和验证,确保系统的安全性和可靠性。

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