电流采样与保护完全指南¶
概述¶
电流采样是嵌入式系统中最重要的模拟信号采集技术之一。准确的电流测量对于电源管理、电机控制、电池监测、故障诊断等应用至关重要。本教程将全面深入地讲解电流检测的各种方法、ADC采样技术、校准算法以及过流保护的实现。
什么是电流采样¶
电流采样是指将电路中的电流信号转换为可以被微控制器处理的电压信号的过程。由于微控制器的ADC只能直接测量电压,因此需要通过各种传感器将电流转换为电压。
电流采样的重要性¶
电流采样的应用场景:
1. 电源管理
- 电池充放电监测
- 功耗分析
- 电源效率计算
- 负载识别
2. 电机控制
- 转矩控制
- 过流保护
- 堵转检测
- FOC算法
3. 安全保护
- 过流保护
- 短路检测
- 漏电保护
- 故障诊断
4. 计量应用
- 电能计量
- 功率因数测量
- 谐波分析
- 负载监测
电流检测方法对比¶
常见电流检测方法:
┌──────────────┬─────────┬─────────┬─────────┬─────────┐
│ 方法 │ 分流电阻│ 霍尔传感│ 电流互感│ 磁阻传感│
├──────────────┼─────────┼─────────┼─────────┼─────────┤
│ 测量范围 │ mA-kA │ mA-kA │ A-kA │ mA-A │
│ 精度 │ 0.1-1% │ 1-3% │ 1-5% │ 1-2% │
│ 带宽 │ DC-MHz │ DC-100k│ AC only│ DC-MHz │
│ 隔离性 │ 否 │ 是 │ 是 │ 否 │
│ 功耗 │ 高 │ 低 │ 低 │ 中 │
│ 成本 │ 低 │ 中 │ 高 │ 中 │
│ 温度漂移 │ 小 │ 中 │ 小 │ 中 │
│ 线性度 │ 优秀 │ 良好 │ 良好 │ 良好 │
└──────────────┴─────────┴─────────┴─────────┴─────────┘
选择建议:
- 低成本、高精度:分流电阻
- 需要隔离:霍尔传感器或电流互感器
- 仅交流:电流互感器
- 高频应用:分流电阻或磁阻传感器
本文内容概览¶
本教程将涵盖以下内容:
- 分流电阻采样:原理、选型、电路设计、放大器配置
- 霍尔传感器:工作原理、类型、应用电路、性能优化
- ADC采样配置:采样率、分辨率、参考电压、滤波
- 电流计算:转换公式、校准算法、温度补偿
- 过流保护:硬件保护、软件保护、多级保护策略
- 校准方法:零点校准、增益校准、非线性校准
- 实战项目:电池监测系统、电机电流控制、智能插座
第一部分:分流电阻采样技术¶
1.1 分流电阻工作原理¶
分流电阻(Shunt Resistor)是最简单、最常用的电流检测方法,基于欧姆定律:V = I × R
基本原理:
分流电阻采样原理:
I →
┌────────┐
│ │
──┤ R ├──
│ shunt │
└────────┘
│ │
V+ V-
电压测量:
V = I × Rshunt
电流计算:
I = V / Rshunt
功耗:
P = I² × Rshunt
温度系数影响:
R(T) = R₀ × (1 + α × ΔT)
放置位置选择:
1. 高侧采样(High-Side Sensing)
VCC ──┬── Rshunt ──┬── 负载 ── GND
│ │
V+ V-
优点:
- 可检测负载短路到地
- 不影响负载地电位
缺点:
- 共模电压高
- 需要差分放大器
- 成本较高
2. 低侧采样(Low-Side Sensing)
VCC ── 负载 ──┬── Rshunt ──┬── GND
│ │
V+ V-
优点:
- 共模电压低(接近GND)
- 电路简单
- 成本低
缺点:
- 无法检测负载短路到地
- 影响负载地电位
- 不适合PWM负载
1.2 分流电阻选型¶
关键参数:
/**
* @brief 分流电阻选型参数
*/
typedef struct {
float resistance; // 阻值(Ω)
float tolerance; // 精度(%)
float temp_coeff; // 温度系数(ppm/°C)
float power_rating; // 额定功率(W)
float max_current; // 最大电流(A)
float voltage_drop; // 压降(V)
} shunt_resistor_spec_t;
/**
* @brief 分流电阻选型计算
*/
void calculate_shunt_resistor(float max_current, float max_voltage_drop)
{
// 计算最大阻值
float max_resistance = max_voltage_drop / max_current;
// 计算功耗
float power = max_current * max_current * max_resistance;
// 选择功率等级(留20%余量)
float power_rating = power * 1.2;
printf("最大阻值: %.4f Ω\n", max_resistance);
printf("功耗: %.3f W\n", power);
printf("建议功率等级: %.1f W\n", power_rating);
}
/**
* @brief 常用分流电阻阻值
*/
#define SHUNT_1M_OHM 0.001 // 1mΩ - 大电流应用(>10A)
#define SHUNT_5M_OHM 0.005 // 5mΩ - 中大电流(5-10A)
#define SHUNT_10M_OHM 0.010 // 10mΩ - 中等电流(1-5A)
#define SHUNT_50M_OHM 0.050 // 50mΩ - 小电流(0.1-1A)
#define SHUNT_100M_OHM 0.100 // 100mΩ - 微小电流(<0.1A)
选型示例:
示例1:电机电流采样
- 最大电流:10A
- 允许压降:100mV
- 计算:R = 0.1V / 10A = 10mΩ
- 功耗:P = 10² × 0.01 = 1W
- 选择:10mΩ, 2W, ±1%, 50ppm/°C
示例2:电池充电监测
- 最大电流:2A
- 允许压降:50mV
- 计算:R = 0.05V / 2A = 25mΩ
- 功耗:P = 2² × 0.025 = 0.1W
- 选择:25mΩ, 0.5W, ±1%, 50ppm/°C
示例3:微功耗设备
- 最大电流:100mA
- 允许压降:100mV
- 计算:R = 0.1V / 0.1A = 1Ω
- 功耗:P = 0.1² × 1 = 0.01W
- 选择:1Ω, 0.125W, ±1%, 100ppm/°C
1.3 差分放大器电路¶
运算放大器配置:
高侧电流采样电路:
VCC ──┬── Rshunt ──┬── 负载
│ │
│ R1 │ R2
├───┴───┐ ├───┴───┐
│ │ │ │
│ ┌───┴────┴───┐ │
│ │ + - │ │
│ │ OP-AMP │ │
│ │ │ │
│ └─────┬──────┘ │
│ │ │
R3 │Vout R4
│ │ │
GND ADC GND
增益计算:
Gain = (R2 / R1) × (1 + R3/R4)
输出电压:
Vout = (V+ - V-) × Gain
专用电流检测放大器:
/**
* @file ina219_driver.c
* @brief INA219电流检测芯片驱动
* @note INA219是TI的高侧电流检测芯片,集成12位ADC
*/
#include <stdint.h>
#include "i2c.h"
/* INA219寄存器地址 */
#define INA219_REG_CONFIG 0x00
#define INA219_REG_SHUNT_V 0x01
#define INA219_REG_BUS_V 0x02
#define INA219_REG_POWER 0x03
#define INA219_REG_CURRENT 0x04
#define INA219_REG_CALIBRATION 0x05
/* INA219 I2C地址 */
#define INA219_ADDR 0x40
/* 配置寄存器位定义 */
#define INA219_CONFIG_RESET 0x8000
#define INA219_CONFIG_BUS_RANGE_32V 0x2000
#define INA219_CONFIG_BUS_RANGE_16V 0x0000
#define INA219_CONFIG_GAIN_1_40MV 0x0000
#define INA219_CONFIG_GAIN_2_80MV 0x0800
#define INA219_CONFIG_GAIN_4_160MV 0x1000
#define INA219_CONFIG_GAIN_8_320MV 0x1800
#define INA219_CONFIG_BADC_12BIT 0x0400
#define INA219_CONFIG_SADC_12BIT 0x0008
#define INA219_CONFIG_MODE_CONTINUOUS 0x0007
/**
* @brief INA219配置结构
*/
typedef struct {
float shunt_resistor; // 分流电阻值(Ω)
float max_current; // 最大电流(A)
uint8_t i2c_addr; // I2C地址
} ina219_config_t;
static ina219_config_t ina219_cfg;
/**
* @brief 写INA219寄存器
*/
static int ina219_write_reg(uint8_t reg, uint16_t value)
{
uint8_t data[3];
data[0] = reg;
data[1] = (value >> 8) & 0xFF;
data[2] = value & 0xFF;
return i2c_master_write(ina219_cfg.i2c_addr, data, 3);
}
/**
* @brief 读INA219寄存器
*/
static int ina219_read_reg(uint8_t reg, uint16_t *value)
{
uint8_t data[2];
if (i2c_master_write(ina219_cfg.i2c_addr, ®, 1) != 0) {
return -1;
}
if (i2c_master_read(ina219_cfg.i2c_addr, data, 2) != 0) {
return -1;
}
*value = ((uint16_t)data[0] << 8) | data[1];
return 0;
}
/**
* @brief 初始化INA219
*/
int ina219_init(float shunt_resistor, float max_current)
{
ina219_cfg.shunt_resistor = shunt_resistor;
ina219_cfg.max_current = max_current;
ina219_cfg.i2c_addr = INA219_ADDR;
// 复位芯片
ina219_write_reg(INA219_REG_CONFIG, INA219_CONFIG_RESET);
HAL_Delay(10);
// 配置寄存器
uint16_t config = INA219_CONFIG_BUS_RANGE_32V |
INA219_CONFIG_GAIN_8_320MV |
INA219_CONFIG_BADC_12BIT |
INA219_CONFIG_SADC_12BIT |
INA219_CONFIG_MODE_CONTINUOUS;
ina219_write_reg(INA219_REG_CONFIG, config);
// 计算校准值
// Current_LSB = Max_Current / 32768
// Cal = 0.04096 / (Current_LSB × Rshunt)
float current_lsb = max_current / 32768.0f;
uint16_t cal = (uint16_t)(0.04096f / (current_lsb * shunt_resistor));
ina219_write_reg(INA219_REG_CALIBRATION, cal);
return 0;
}
/**
* @brief 读取分流电压(mV)
*/
float ina219_read_shunt_voltage(void)
{
uint16_t value;
if (ina219_read_reg(INA219_REG_SHUNT_V, &value) != 0) {
return 0.0f;
}
// 转换为有符号数
int16_t shunt_v = (int16_t)value;
// LSB = 10μV
return shunt_v * 0.01f; // mV
}
/**
* @brief 读取总线电压(V)
*/
float ina219_read_bus_voltage(void)
{
uint16_t value;
if (ina219_read_reg(INA219_REG_BUS_V, &value) != 0) {
return 0.0f;
}
// 右移3位,LSB = 4mV
return ((value >> 3) * 4) / 1000.0f; // V
}
/**
* @brief 读取电流(mA)
*/
float ina219_read_current(void)
{
uint16_t value;
if (ina219_read_reg(INA219_REG_CURRENT, &value) != 0) {
return 0.0f;
}
// 转换为有符号数
int16_t current = (int16_t)value;
// Current_LSB = Max_Current / 32768
float current_lsb = ina219_cfg.max_current / 32768.0f;
return current * current_lsb * 1000.0f; // mA
}
/**
* @brief 读取功率(mW)
*/
float ina219_read_power(void)
{
uint16_t value;
if (ina219_read_reg(INA219_REG_POWER, &value) != 0) {
return 0.0f;
}
// Power_LSB = 20 × Current_LSB
float current_lsb = ina219_cfg.max_current / 32768.0f;
float power_lsb = 20.0f * current_lsb;
return value * power_lsb * 1000.0f; // mW
}
第二部分:霍尔传感器技术¶
2.1 霍尔效应原理¶
霍尔效应是指当电流通过置于磁场中的导体时,在垂直于电流和磁场的方向上会产生电压。
基本原理:
霍尔效应示意图:
磁场 B ⊙(垂直纸面向外)
┌─────────────┐
I → │ │ → I
│ 霍尔片 │
│ │
└──┬───────┬──┘
│ │
V+ V-
霍尔电压:
VH = (RH × I × B) / t
其中:
- VH:霍尔电压
- RH:霍尔系数
- I:电流
- B:磁感应强度
- t:霍尔片厚度
2.2 霍尔电流传感器类型¶
开环霍尔传感器:
开环霍尔传感器结构:
电流导体
│
↓
┌──────┐
│ 磁芯 │
│ ╱╲ │
│ ╱ ╲ │
│╱ 霍尔╲│
│ 元件 │
└──────┘
│
Vout
特点:
- 结构简单
- 成本低
- 响应快
- 精度中等(1-3%)
- 有温度漂移
- 线性度良好
应用:
- 电机电流监测
- 电源电流监测
- 一般工业应用
闭环霍尔传感器(零磁通):
闭环霍尔传感器结构:
原边电流 Ip
│
↓
┌──────────┐
│ 磁芯 │
│ ╱╲ │
│ ╱ ╲ │
│╱ 霍尔╲ │
│ 元件 │ │
│ │ │
│ 补偿线圈│
│ Is ←──┤
└──────────┘
│
Vout
工作原理:
1. 原边电流产生磁场
2. 霍尔元件检测磁场
3. 反馈电路产生补偿电流
4. 补偿电流产生反向磁场
5. 使磁芯磁通为零
特点:
- 精度高(0.1-1%)
- 线性度好
- 温漂小
- 响应快
- 成本高
应用:
- 精密测量
- 变频器
- 伺服驱动
- 电能计量
2.3 霍尔传感器应用电路¶
/**
* @file hall_sensor.c
* @brief 霍尔电流传感器驱动
* @note 以ACS712为例(Allegro开环霍尔传感器)
*/
#include <stdint.h>
#include <math.h>
#include "adc.h"
/* ACS712型号参数 */
#define ACS712_5A_SENSITIVITY 185.0f // mV/A
#define ACS712_20A_SENSITIVITY 100.0f // mV/A
#define ACS712_30A_SENSITIVITY 66.0f // mV/A
#define ACS712_VCC 5.0f // V
#define ACS712_VREF 2.5f // V (VCC/2)
/**
* @brief 霍尔传感器配置
*/
typedef struct {
float sensitivity; // 灵敏度(mV/A)
float vref; // 参考电压(V)
float vcc; // 供电电压(V)
uint8_t adc_channel; // ADC通道
uint16_t adc_resolution; // ADC分辨率
} hall_sensor_config_t;
static hall_sensor_config_t hall_cfg;
/**
* @brief 初始化霍尔传感器
*/
void hall_sensor_init(float sensitivity, uint8_t adc_channel)
{
hall_cfg.sensitivity = sensitivity;
hall_cfg.vref = ACS712_VREF;
hall_cfg.vcc = ACS712_VCC;
hall_cfg.adc_channel = adc_channel;
hall_cfg.adc_resolution = 4096; // 12位ADC
}
/**
* @brief 读取ADC电压
*/
static float hall_read_voltage(void)
{
uint16_t adc_value = adc_read(hall_cfg.adc_channel);
// 转换为电压
float voltage = (adc_value * hall_cfg.vcc) / hall_cfg.adc_resolution;
return voltage;
}
/**
* @brief 读取电流(A)
*/
float hall_read_current(void)
{
float voltage = hall_read_voltage();
// 计算电流
// I = (Vout - Vref) / Sensitivity
float current = (voltage - hall_cfg.vref) / (hall_cfg.sensitivity / 1000.0f);
return current;
}
/**
* @brief 读取电流(带滤波)
*/
float hall_read_current_filtered(uint16_t samples)
{
float sum = 0.0f;
for (uint16_t i = 0; i < samples; i++) {
sum += hall_read_current();
HAL_Delay(1);
}
return sum / samples;
}
/**
* @brief 读取RMS电流(交流)
*/
float hall_read_current_rms(uint16_t samples)
{
float sum_squares = 0.0f;
for (uint16_t i = 0; i < samples; i++) {
float current = hall_read_current();
sum_squares += current * current;
HAL_Delay(1);
}
return sqrtf(sum_squares / samples);
}
/**
* @brief 零点校准
* @note 在无电流时调用
*/
void hall_calibrate_zero(uint16_t samples)
{
float sum = 0.0f;
for (uint16_t i = 0; i < samples; i++) {
sum += hall_read_voltage();
HAL_Delay(1);
}
hall_cfg.vref = sum / samples;
printf("零点校准完成: Vref = %.3f V\n", hall_cfg.vref);
}
2.4 霍尔传感器性能优化¶
温度补偿:
/**
* @brief 温度补偿系数
*/
#define TEMP_COEFF_SENSITIVITY -0.0005f // 灵敏度温度系数(%/°C)
#define TEMP_COEFF_OFFSET 0.002f // 偏移温度系数(mV/°C)
#define TEMP_REFERENCE 25.0f // 参考温度(°C)
/**
* @brief 带温度补偿的电流读取
*/
float hall_read_current_temp_compensated(float temperature)
{
float voltage = hall_read_voltage();
// 温度补偿
float temp_diff = temperature - TEMP_REFERENCE;
// 补偿灵敏度
float sensitivity_comp = hall_cfg.sensitivity *
(1.0f + TEMP_COEFF_SENSITIVITY * temp_diff);
// 补偿偏移
float vref_comp = hall_cfg.vref + TEMP_COEFF_OFFSET * temp_diff / 1000.0f;
// 计算电流
float current = (voltage - vref_comp) / (sensitivity_comp / 1000.0f);
return current;
}
第三部分:ADC采样配置¶
3.1 ADC基础配置¶
ADC参数选择:
/**
* @file current_adc.c
* @brief 电流采样ADC配置
*/
#include "stm32f4xx_hal.h"
/* ADC句柄 */
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
/**
* @brief ADC初始化(12位分辨率)
*/
void current_adc_init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
/* ADC1配置 */
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc1) != HAL_OK) {
Error_Handler();
}
/* 配置ADC通道 */
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
Error_Handler();
}
}
/**
* @brief ADC DMA配置
*/
void current_adc_dma_init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA配置 */
hdma_adc1.Instance = DMA2_Stream0;
hdma_adc1.Init.Channel = DMA_CHANNEL_0;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK) {
Error_Handler();
}
__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
/* DMA中断配置 */
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
}
3.2 采样率和分辨率¶
采样率计算:
ADC采样率计算:
采样时间 = 采样周期 + 转换时间
对于STM32F4(12位ADC):
- 转换时间 = 12个ADC时钟周期
- 采样周期可配置:3, 15, 28, 56, 84, 112, 144, 480个ADC时钟
示例(84MHz系统时钟,4分频):
ADC时钟 = 84MHz / 4 = 21MHz
采样周期 = 84个时钟
转换时间 = 12个时钟
总时间 = 84 + 12 = 96个时钟
采样率 = 21MHz / 96 = 218.75 kSPS
应用建议:
- 直流电流:1-10 kSPS
- 工频交流(50/60Hz):>1 kSPS(每周期>20个采样点)
- 高频PWM电流:>100 kSPS
- 电机FOC控制:10-50 kSPS
分辨率选择:
/**
* @brief ADC分辨率配置
*/
typedef enum {
ADC_RES_12BIT = ADC_RESOLUTION_12B, // 12位,4096级
ADC_RES_10BIT = ADC_RESOLUTION_10B, // 10位,1024级
ADC_RES_8BIT = ADC_RESOLUTION_8B, // 8位,256级
ADC_RES_6BIT = ADC_RESOLUTION_6B // 6位,64级
} adc_resolution_t;
/**
* @brief 计算ADC分辨率
*/
void calculate_adc_resolution(float vref, uint16_t bits, float max_current, float sensitivity)
{
uint32_t levels = 1 << bits;
float voltage_lsb = vref / levels;
float current_lsb = voltage_lsb / (sensitivity / 1000.0f);
printf("ADC分辨率: %d位\n", bits);
printf("量化级数: %u\n", levels);
printf("电压LSB: %.3f mV\n", voltage_lsb * 1000.0f);
printf("电流LSB: %.3f mA\n", current_lsb * 1000.0f);
printf("最大可测电流: %.2f A\n", max_current);
printf("理论精度: %.3f%%\n", (current_lsb / max_current) * 100.0f);
}
/**
* @brief 示例:12位ADC,5A量程
*/
void example_12bit_5a(void)
{
// ACS712-5A: 185mV/A, Vref=2.5V, 量程±5A
calculate_adc_resolution(5.0f, 12, 5.0f, 185.0f);
/*
* 输出:
* ADC分辨率: 12位
* 量化级数: 4096
* 电压LSB: 1.221 mV
* 电流LSB: 6.6 mA
* 最大可测电流: 5.00 A
* 理论精度: 0.132%
*/
}
3.3 数字滤波技术¶
移动平均滤波:
/**
* @brief 移动平均滤波器
*/
#define MA_FILTER_SIZE 16
typedef struct {
uint16_t buffer[MA_FILTER_SIZE];
uint8_t index;
uint32_t sum;
bool filled;
} ma_filter_t;
static ma_filter_t current_filter = {0};
/**
* @brief 移动平均滤波初始化
*/
void ma_filter_init(ma_filter_t *filter)
{
filter->index = 0;
filter->sum = 0;
filter->filled = false;
for (int i = 0; i < MA_FILTER_SIZE; i++) {
filter->buffer[i] = 0;
}
}
/**
* @brief 移动平均滤波更新
*/
uint16_t ma_filter_update(ma_filter_t *filter, uint16_t new_value)
{
// 减去最旧的值
filter->sum -= filter->buffer[filter->index];
// 添加新值
filter->buffer[filter->index] = new_value;
filter->sum += new_value;
// 更新索引
filter->index++;
if (filter->index >= MA_FILTER_SIZE) {
filter->index = 0;
filter->filled = true;
}
// 计算平均值
if (filter->filled) {
return filter->sum / MA_FILTER_SIZE;
} else {
return filter->sum / (filter->index + 1);
}
}
一阶低通滤波:
/**
* @brief 一阶低通滤波器
*/
typedef struct {
float alpha; // 滤波系数(0-1)
float output; // 输出值
bool initialized; // 初始化标志
} lpf_filter_t;
static lpf_filter_t current_lpf = {0};
/**
* @brief 低通滤波器初始化
* @param cutoff_freq: 截止频率(Hz)
* @param sample_freq: 采样频率(Hz)
*/
void lpf_filter_init(lpf_filter_t *filter, float cutoff_freq, float sample_freq)
{
float rc = 1.0f / (2.0f * 3.14159f * cutoff_freq);
float dt = 1.0f / sample_freq;
filter->alpha = dt / (rc + dt);
filter->output = 0.0f;
filter->initialized = false;
}
/**
* @brief 低通滤波器更新
*/
float lpf_filter_update(lpf_filter_t *filter, float input)
{
if (!filter->initialized) {
filter->output = input;
filter->initialized = true;
} else {
filter->output = filter->alpha * input + (1.0f - filter->alpha) * filter->output;
}
return filter->output;
}
/**
* @brief 示例:10Hz截止频率,1kHz采样率
*/
void example_lpf_filter(void)
{
lpf_filter_t filter;
lpf_filter_init(&filter, 10.0f, 1000.0f);
// 模拟采样
for (int i = 0; i < 100; i++) {
float raw_current = hall_read_current();
float filtered_current = lpf_filter_update(&filter, raw_current);
printf("原始: %.3f A, 滤波: %.3f A\n", raw_current, filtered_current);
HAL_Delay(1);
}
}
中值滤波:
/**
* @brief 中值滤波器
*/
#define MEDIAN_FILTER_SIZE 5
typedef struct {
uint16_t buffer[MEDIAN_FILTER_SIZE];
uint8_t index;
} median_filter_t;
static median_filter_t current_median = {0};
/**
* @brief 比较函数(用于排序)
*/
static int compare_uint16(const void *a, const void *b)
{
return (*(uint16_t*)a - *(uint16_t*)b);
}
/**
* @brief 中值滤波更新
*/
uint16_t median_filter_update(median_filter_t *filter, uint16_t new_value)
{
// 添加新值
filter->buffer[filter->index] = new_value;
filter->index = (filter->index + 1) % MEDIAN_FILTER_SIZE;
// 复制缓冲区用于排序
uint16_t sorted[MEDIAN_FILTER_SIZE];
memcpy(sorted, filter->buffer, sizeof(sorted));
// 排序
qsort(sorted, MEDIAN_FILTER_SIZE, sizeof(uint16_t), compare_uint16);
// 返回中值
return sorted[MEDIAN_FILTER_SIZE / 2];
}
3.4 过采样和平均¶
/**
* @brief 过采样配置
*/
#define OVERSAMPLE_RATIO 16 // 过采样倍数
#define OVERSAMPLE_SHIFT 4 // 右移位数(log2(16) = 4)
/**
* @brief 过采样读取
* @note 提高有效分辨率
*/
uint16_t adc_read_oversampled(uint8_t channel)
{
uint32_t sum = 0;
// 采集多个样本
for (int i = 0; i < OVERSAMPLE_RATIO; i++) {
sum += adc_read(channel);
}
// 平均并右移
return (uint16_t)(sum >> OVERSAMPLE_SHIFT);
}
/**
* @brief 计算过采样提升的位数
*/
void calculate_oversample_bits(uint16_t ratio)
{
// 每4倍过采样提升1位分辨率
float extra_bits = log2f(ratio) / 2.0f;
printf("过采样倍数: %d\n", ratio);
printf("提升位数: %.1f位\n", extra_bits);
printf("12位ADC → %.1f位有效分辨率\n", 12.0f + extra_bits);
}
第四部分:过流保护实现¶
4.1 硬件过流保护¶
比较器保护电路:
硬件比较器过流保护:
Vshunt ──┬────────┐
│ │
R1 ┌───┴───┐
│ │ + │
GND │ CMP │──→ 中断/关断
│ │ - │
R2 └───┬───┘
│ │
Vref ────┴────────┘
工作原理:
1. 分流电阻电压 > 阈值电压
2. 比较器输出高电平
3. 触发中断或直接关断负载
4. 响应时间:<1μs
优点:
- 响应极快
- 不依赖软件
- 可靠性高
缺点:
- 阈值固定
- 无法记录数据
- 需要额外硬件
专用保护芯片:
/**
* @file overcurrent_protection.c
* @brief 过流保护实现
*/
#include <stdint.h>
#include <stdbool.h>
#include "gpio.h"
#include "tim.h"
/* 保护参数 */
#define OCP_THRESHOLD_MA 5000 // 过流阈值(mA)
#define OCP_DELAY_MS 10 // 过流延时(ms)
#define OCP_RETRY_COUNT 3 // 重试次数
#define OCP_RETRY_INTERVAL_MS 1000 // 重试间隔(ms)
/**
* @brief 过流保护状态
*/
typedef enum {
OCP_STATE_NORMAL = 0, // 正常
OCP_STATE_WARNING, // 警告
OCP_STATE_FAULT, // 故障
OCP_STATE_SHUTDOWN // 关断
} ocp_state_t;
/**
* @brief 过流保护结构
*/
typedef struct {
ocp_state_t state; // 当前状态
float threshold; // 阈值(A)
uint32_t fault_count; // 故障计数
uint32_t retry_count; // 重试计数
uint32_t last_fault_time; // 上次故障时间
bool enabled; // 使能标志
} ocp_context_t;
static ocp_context_t ocp_ctx = {0};
/**
* @brief 初始化过流保护
*/
void ocp_init(float threshold_a)
{
ocp_ctx.state = OCP_STATE_NORMAL;
ocp_ctx.threshold = threshold_a;
ocp_ctx.fault_count = 0;
ocp_ctx.retry_count = 0;
ocp_ctx.last_fault_time = 0;
ocp_ctx.enabled = true;
// 配置关断输出引脚
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = SHUTDOWN_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(SHUTDOWN_PORT, &GPIO_InitStruct);
// 初始状态:使能输出
HAL_GPIO_WritePin(SHUTDOWN_PORT, SHUTDOWN_PIN, GPIO_PIN_SET);
}
/**
* @brief 过流检测
* @param current: 当前电流(A)
* @return true: 过流, false: 正常
*/
bool ocp_check(float current)
{
if (!ocp_ctx.enabled) {
return false;
}
// 检查是否超过阈值
if (fabsf(current) > ocp_ctx.threshold) {
return true;
}
return false;
}
/**
* @brief 过流保护处理
*/
void ocp_process(float current)
{
static uint32_t fault_start_time = 0;
uint32_t current_time = HAL_GetTick();
switch (ocp_ctx.state) {
case OCP_STATE_NORMAL:
if (ocp_check(current)) {
// 检测到过流,进入警告状态
ocp_ctx.state = OCP_STATE_WARNING;
fault_start_time = current_time;
printf("警告:检测到过流 %.2f A\n", current);
}
break;
case OCP_STATE_WARNING:
if (!ocp_check(current)) {
// 电流恢复正常
ocp_ctx.state = OCP_STATE_NORMAL;
printf("过流警告解除\n");
} else if ((current_time - fault_start_time) >= OCP_DELAY_MS) {
// 过流持续超过延时,进入故障状态
ocp_ctx.state = OCP_STATE_FAULT;
ocp_ctx.fault_count++;
ocp_ctx.last_fault_time = current_time;
printf("故障:过流保护触发 %.2f A\n", current);
// 关断输出
HAL_GPIO_WritePin(SHUTDOWN_PORT, SHUTDOWN_PIN, GPIO_PIN_RESET);
}
break;
case OCP_STATE_FAULT:
// 检查是否可以重试
if ((current_time - ocp_ctx.last_fault_time) >= OCP_RETRY_INTERVAL_MS) {
if (ocp_ctx.retry_count < OCP_RETRY_COUNT) {
// 尝试恢复
ocp_ctx.retry_count++;
ocp_ctx.state = OCP_STATE_NORMAL;
HAL_GPIO_WritePin(SHUTDOWN_PORT, SHUTDOWN_PIN, GPIO_PIN_SET);
printf("尝试恢复(%d/%d)\n", ocp_ctx.retry_count, OCP_RETRY_COUNT);
} else {
// 重试次数用尽,进入关断状态
ocp_ctx.state = OCP_STATE_SHUTDOWN;
printf("错误:过流保护永久关断\n");
}
}
break;
case OCP_STATE_SHUTDOWN:
// 需要手动复位
break;
}
}
/**
* @brief 复位过流保护
*/
void ocp_reset(void)
{
ocp_ctx.state = OCP_STATE_NORMAL;
ocp_ctx.fault_count = 0;
ocp_ctx.retry_count = 0;
// 使能输出
HAL_GPIO_WritePin(SHUTDOWN_PORT, SHUTDOWN_PIN, GPIO_PIN_SET);
printf("过流保护已复位\n");
}
/**
* @brief 获取保护状态
*/
ocp_state_t ocp_get_state(void)
{
return ocp_ctx.state;
}
/**
* @brief 获取故障计数
*/
uint32_t ocp_get_fault_count(void)
{
return ocp_ctx.fault_count;
}
4.2 多级保护策略¶
/**
* @brief 多级保护阈值
*/
typedef struct {
float warning_level; // 警告级别(80%)
float limit_level; // 限流级别(90%)
float fault_level; // 故障级别(100%)
float critical_level; // 严重级别(120%)
} ocp_levels_t;
static ocp_levels_t ocp_levels = {
.warning_level = 4.0f, // 4A
.limit_level = 4.5f, // 4.5A
.fault_level = 5.0f, // 5A
.critical_level = 6.0f // 6A
};
/**
* @brief 多级保护处理
*/
void ocp_multi_level_process(float current)
{
float abs_current = fabsf(current);
if (abs_current >= ocp_levels.critical_level) {
// 严重过流:立即关断,无延时
HAL_GPIO_WritePin(SHUTDOWN_PORT, SHUTDOWN_PIN, GPIO_PIN_RESET);
printf("严重过流:立即关断 %.2f A\n", current);
ocp_ctx.state = OCP_STATE_SHUTDOWN;
} else if (abs_current >= ocp_levels.fault_level) {
// 故障级过流:延时关断
static uint32_t fault_time = 0;
if (fault_time == 0) {
fault_time = HAL_GetTick();
} else if ((HAL_GetTick() - fault_time) >= OCP_DELAY_MS) {
HAL_GPIO_WritePin(SHUTDOWN_PORT, SHUTDOWN_PIN, GPIO_PIN_RESET);
printf("过流故障:延时关断 %.2f A\n", current);
ocp_ctx.state = OCP_STATE_FAULT;
fault_time = 0;
}
} else if (abs_current >= ocp_levels.limit_level) {
// 限流级别:降低输出功率
pwm_reduce_duty(10); // 降低10%占空比
printf("限流:降低输出 %.2f A\n", current);
} else if (abs_current >= ocp_levels.warning_level) {
// 警告级别:记录日志
printf("警告:电流接近上限 %.2f A\n", current);
} else {
// 正常范围:恢复输出
if (ocp_ctx.state == OCP_STATE_WARNING) {
pwm_restore_duty();
ocp_ctx.state = OCP_STATE_NORMAL;
}
}
}
4.3 软件限流算法¶
/**
* @brief PI控制器限流
*/
typedef struct {
float kp; // 比例系数
float ki; // 积分系数
float integral; // 积分累积
float output_max; // 输出上限
float output_min; // 输出下限
} pi_controller_t;
static pi_controller_t current_limiter = {
.kp = 0.5f,
.ki = 0.1f,
.integral = 0.0f,
.output_max = 100.0f,
.output_min = 0.0f
};
/**
* @brief PI限流控制
* @param current: 当前电流
* @param limit: 电流限制
* @return 控制输出(PWM占空比)
*/
float pi_current_limit(float current, float limit)
{
// 计算误差
float error = limit - current;
// 比例项
float p_term = current_limiter.kp * error;
// 积分项
current_limiter.integral += error;
float i_term = current_limiter.ki * current_limiter.integral;
// 计算输出
float output = p_term + i_term;
// 限幅
if (output > current_limiter.output_max) {
output = current_limiter.output_max;
current_limiter.integral -= error; // 抗积分饱和
} else if (output < current_limiter.output_min) {
output = current_limiter.output_min;
current_limiter.integral -= error;
}
return output;
}
/**
* @brief 限流控制示例
*/
void current_limit_example(void)
{
float current_limit = 5.0f; // 5A限制
while (1) {
// 读取当前电流
float current = hall_read_current();
// PI限流控制
float duty = pi_current_limit(current, current_limit);
// 更新PWM占空比
pwm_set_duty(duty);
printf("电流: %.2f A, 占空比: %.1f%%\n", current, duty);
HAL_Delay(10);
}
}
第五部分:校准方法¶
5.1 零点校准¶
/**
* @brief 校准数据结构
*/
typedef struct {
float zero_offset; // 零点偏移(V)
float gain; // 增益系数
float temp_coeff; // 温度系数
bool calibrated; // 校准标志
} calibration_data_t;
static calibration_data_t cal_data = {
.zero_offset = 0.0f,
.gain = 1.0f,
.temp_coeff = 0.0f,
.calibrated = false
};
/**
* @brief 零点校准
* @note 在无电流时调用
*/
int calibrate_zero_point(uint16_t samples)
{
float sum = 0.0f;
float sum_sq = 0.0f;
printf("开始零点校准,请确保无电流...\n");
HAL_Delay(1000);
// 采集多个样本
for (uint16_t i = 0; i < samples; i++) {
float voltage = hall_read_voltage();
sum += voltage;
sum_sq += voltage * voltage;
HAL_Delay(10);
}
// 计算平均值
float mean = sum / samples;
// 计算标准差
float variance = (sum_sq / samples) - (mean * mean);
float std_dev = sqrtf(variance);
// 检查稳定性
if (std_dev > 0.01f) {
printf("错误:信号不稳定,标准差 = %.4f V\n", std_dev);
return -1;
}
// 保存零点偏移
cal_data.zero_offset = mean;
cal_data.calibrated = true;
printf("零点校准完成:偏移 = %.4f V, 标准差 = %.4f V\n", mean, std_dev);
return 0;
}
5.2 增益校准¶
/**
* @brief 两点校准法
* @param ref_current1: 参考电流1(A)
* @param measured_voltage1: 测量电压1(V)
* @param ref_current2: 参考电流2(A)
* @param measured_voltage2: 测量电压2(V)
*/
int calibrate_gain_two_point(float ref_current1, float measured_voltage1,
float ref_current2, float measured_voltage2)
{
// 去除零点偏移
float v1 = measured_voltage1 - cal_data.zero_offset;
float v2 = measured_voltage2 - cal_data.zero_offset;
// 计算理论灵敏度
float sensitivity_measured = (v2 - v1) / (ref_current2 - ref_current1);
// 计算增益系数
float sensitivity_nominal = hall_cfg.sensitivity / 1000.0f; // V/A
cal_data.gain = sensitivity_nominal / sensitivity_measured;
printf("增益校准完成:\n");
printf(" 测量灵敏度: %.4f V/A\n", sensitivity_measured);
printf(" 标称灵敏度: %.4f V/A\n", sensitivity_nominal);
printf(" 增益系数: %.4f\n", cal_data.gain);
return 0;
}
/**
* @brief 多点校准法
*/
typedef struct {
float ref_current; // 参考电流
float measured_voltage; // 测量电压
} calibration_point_t;
int calibrate_gain_multi_point(calibration_point_t *points, uint8_t count)
{
if (count < 2) {
return -1;
}
// 最小二乘法拟合
float sum_x = 0.0f, sum_y = 0.0f;
float sum_xx = 0.0f, sum_xy = 0.0f;
for (uint8_t i = 0; i < count; i++) {
float x = points[i].ref_current;
float y = points[i].measured_voltage - cal_data.zero_offset;
sum_x += x;
sum_y += y;
sum_xx += x * x;
sum_xy += x * y;
}
// 计算斜率(灵敏度)
float n = (float)count;
float sensitivity = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x);
// 计算增益系数
float sensitivity_nominal = hall_cfg.sensitivity / 1000.0f;
cal_data.gain = sensitivity_nominal / sensitivity;
// 计算拟合误差
float sum_error = 0.0f;
for (uint8_t i = 0; i < count; i++) {
float x = points[i].ref_current;
float y = points[i].measured_voltage - cal_data.zero_offset;
float y_fit = sensitivity * x;
float error = y - y_fit;
sum_error += error * error;
}
float rms_error = sqrtf(sum_error / n);
printf("多点校准完成:\n");
printf(" 校准点数: %d\n", count);
printf(" 拟合灵敏度: %.4f V/A\n", sensitivity);
printf(" 增益系数: %.4f\n", cal_data.gain);
printf(" RMS误差: %.4f V\n", rms_error);
return 0;
}
/**
* @brief 校准示例
*/
void calibration_example(void)
{
// 1. 零点校准
printf("=== 零点校准 ===\n");
calibrate_zero_point(100);
HAL_Delay(2000);
// 2. 两点校准
printf("\n=== 两点校准 ===\n");
printf("请施加1A电流,按任意键继续...\n");
wait_for_key();
float v1 = hall_read_voltage();
printf("请施加5A电流,按任意键继续...\n");
wait_for_key();
float v2 = hall_read_voltage();
calibrate_gain_two_point(1.0f, v1, 5.0f, v2);
// 3. 保存校准数据到Flash
save_calibration_to_flash(&cal_data);
printf("\n校准完成!\n");
}
5.3 温度补偿校准¶
/**
* @brief 温度校准数据
*/
typedef struct {
float temp; // 温度(°C)
float zero_offset; // 零点偏移
float gain; // 增益
} temp_cal_point_t;
#define TEMP_CAL_POINTS 5
static temp_cal_point_t temp_cal_table[TEMP_CAL_POINTS];
/**
* @brief 温度校准
*/
int calibrate_temperature(void)
{
float temperatures[] = {-20.0f, 0.0f, 25.0f, 50.0f, 85.0f};
for (int i = 0; i < TEMP_CAL_POINTS; i++) {
printf("请将温度设置为 %.1f°C,按任意键继续...\n", temperatures[i]);
wait_for_key();
// 等待温度稳定
HAL_Delay(5000);
// 读取温度
float temp = read_temperature();
// 零点校准
calibrate_zero_point(100);
// 保存校准点
temp_cal_table[i].temp = temp;
temp_cal_table[i].zero_offset = cal_data.zero_offset;
temp_cal_table[i].gain = cal_data.gain;
printf("温度 %.1f°C: 零点=%.4f V, 增益=%.4f\n",
temp, cal_data.zero_offset, cal_data.gain);
}
return 0;
}
/**
* @brief 温度补偿插值
*/
void temperature_compensation(float current_temp, float *zero_offset, float *gain)
{
// 查找温度区间
int i;
for (i = 0; i < TEMP_CAL_POINTS - 1; i++) {
if (current_temp <= temp_cal_table[i + 1].temp) {
break;
}
}
// 线性插值
float t1 = temp_cal_table[i].temp;
float t2 = temp_cal_table[i + 1].temp;
float ratio = (current_temp - t1) / (t2 - t1);
*zero_offset = temp_cal_table[i].zero_offset +
ratio * (temp_cal_table[i + 1].zero_offset - temp_cal_table[i].zero_offset);
*gain = temp_cal_table[i].gain +
ratio * (temp_cal_table[i + 1].gain - temp_cal_table[i].gain);
}
/**
* @brief 带温度补偿的电流读取
*/
float read_current_with_temp_comp(void)
{
// 读取温度
float temp = read_temperature();
// 获取补偿参数
float zero_offset, gain;
temperature_compensation(temp, &zero_offset, &gain);
// 读取电压
float voltage = hall_read_voltage();
// 计算电流
float current = ((voltage - zero_offset) * gain) / (hall_cfg.sensitivity / 1000.0f);
return current;
}
第六部分:实战项目¶
6.1 电池监测系统¶
/**
* @file battery_monitor.c
* @brief 电池充放电监测系统
*/
#include <stdint.h>
#include <stdbool.h>
/**
* @brief 电池监测数据
*/
typedef struct {
float voltage; // 电压(V)
float current; // 电流(A)
float power; // 功率(W)
float capacity_mah; // 容量(mAh)
float energy_mwh; // 能量(mWh)
float soc; // 电量百分比(%)
uint32_t time_sec; // 运行时间(秒)
} battery_data_t;
static battery_data_t battery = {0};
/**
* @brief 初始化电池监测
*/
void battery_monitor_init(float initial_capacity_mah)
{
battery.capacity_mah = initial_capacity_mah;
battery.soc = 100.0f;
battery.time_sec = 0;
}
/**
* @brief 电池监测更新(每秒调用)
*/
void battery_monitor_update(void)
{
// 读取电压和电流
battery.voltage = read_battery_voltage();
battery.current = hall_read_current();
// 计算功率
battery.power = battery.voltage * battery.current;
// 累积容量(库仑计数法)
// ΔQ = I × Δt
float delta_capacity = battery.current * (1.0f / 3600.0f); // mAh
battery.capacity_mah += delta_capacity;
// 累积能量
float delta_energy = battery.power * (1.0f / 3600.0f); // mWh
battery.energy_mwh += delta_energy;
// 更新SOC
float nominal_capacity = 2000.0f; // 2000mAh
battery.soc = (battery.capacity_mah / nominal_capacity) * 100.0f;
// 限制SOC范围
if (battery.soc > 100.0f) battery.soc = 100.0f;
if (battery.soc < 0.0f) battery.soc = 0.0f;
// 更新时间
battery.time_sec++;
// 打印数据
printf("电压: %.2f V, 电流: %.3f A, 功率: %.2f W, SOC: %.1f%%\n",
battery.voltage, battery.current, battery.power, battery.soc);
}
/**
* @brief 获取电池数据
*/
const battery_data_t* battery_get_data(void)
{
return &battery;
}
/**
* @brief 电池充电监测
*/
void battery_charge_monitor(void)
{
printf("=== 电池充电监测 ===\n");
battery_monitor_init(0.0f); // 从0开始
while (battery.soc < 100.0f) {
battery_monitor_update();
// 检查充电电流
if (battery.current < 0.05f) {
printf("警告:充电电流过小\n");
}
// 检查充电电压
if (battery.voltage > 4.2f) {
printf("警告:充电电压过高\n");
break;
}
HAL_Delay(1000);
}
printf("充电完成!\n");
printf("总容量: %.1f mAh\n", battery.capacity_mah);
printf("总能量: %.1f mWh\n", battery.energy_mwh);
printf("充电时间: %u 秒\n", battery.time_sec);
}
6.2 电机电流控制¶
/**
* @file motor_current_control.c
* @brief 电机电流闭环控制
*/
/**
* @brief 电机控制参数
*/
typedef struct {
float target_current; // 目标电流(A)
float actual_current; // 实际电流(A)
float duty_cycle; // PWM占空比(%)
float kp; // 比例系数
float ki; // 积分系数
float kd; // 微分系数
float integral; // 积分累积
float last_error; // 上次误差
} motor_control_t;
static motor_control_t motor_ctrl = {
.target_current = 0.0f,
.kp = 1.0f,
.ki = 0.5f,
.kd = 0.1f,
.integral = 0.0f,
.last_error = 0.0f
};
/**
* @brief PID电流控制
*/
float motor_current_pid_control(float target, float actual, float dt)
{
// 计算误差
float error = target - actual;
// 比例项
float p_term = motor_ctrl.kp * error;
// 积分项
motor_ctrl.integral += error * dt;
float i_term = motor_ctrl.ki * motor_ctrl.integral;
// 微分项
float d_term = motor_ctrl.kd * (error - motor_ctrl.last_error) / dt;
motor_ctrl.last_error = error;
// PID输出
float output = p_term + i_term + d_term;
// 限幅
if (output > 100.0f) {
output = 100.0f;
motor_ctrl.integral -= error * dt; // 抗积分饱和
} else if (output < 0.0f) {
output = 0.0f;
motor_ctrl.integral -= error * dt;
}
return output;
}
/**
* @brief 电机电流控制任务
*/
void motor_current_control_task(void)
{
const float dt = 0.001f; // 1ms控制周期
while (1) {
// 读取实际电流
motor_ctrl.actual_current = hall_read_current();
// PID控制
motor_ctrl.duty_cycle = motor_current_pid_control(
motor_ctrl.target_current,
motor_ctrl.actual_current,
dt
);
// 更新PWM
pwm_set_duty(motor_ctrl.duty_cycle);
// 过流保护
ocp_process(motor_ctrl.actual_current);
// 打印数据
if ((HAL_GetTick() % 100) == 0) {
printf("目标: %.2f A, 实际: %.2f A, 占空比: %.1f%%\n",
motor_ctrl.target_current,
motor_ctrl.actual_current,
motor_ctrl.duty_cycle);
}
HAL_Delay(1);
}
}
/**
* @brief 设置目标电流
*/
void motor_set_target_current(float current_a)
{
motor_ctrl.target_current = current_a;
printf("设置目标电流: %.2f A\n", current_a);
}
/**
* @brief 电机启动序列
*/
void motor_start_sequence(void)
{
printf("=== 电机启动序列 ===\n");
// 1. 初始化
motor_ctrl.target_current = 0.0f;
motor_ctrl.integral = 0.0f;
motor_ctrl.last_error = 0.0f;
// 2. 缓启动(斜坡)
float ramp_rate = 0.1f; // 0.1A/s
float target = 2.0f; // 目标2A
while (motor_ctrl.target_current < target) {
motor_ctrl.target_current += ramp_rate * 0.01f; // 10ms步进
HAL_Delay(10);
}
printf("电机启动完成\n");
}
/**
* @brief 电机堵转检测
*/
bool motor_detect_stall(void)
{
static uint32_t high_current_time = 0;
const float stall_current = 5.0f; // 堵转电流阈值
const uint32_t stall_time = 500; // 堵转时间阈值(ms)
if (motor_ctrl.actual_current > stall_current) {
if (high_current_time == 0) {
high_current_time = HAL_GetTick();
} else if ((HAL_GetTick() - high_current_time) >= stall_time) {
printf("检测到电机堵转!\n");
return true;
}
} else {
high_current_time = 0;
}
return false;
}
6.3 智能插座功率监测¶
/**
* @file smart_socket.c
* @brief 智能插座功率监测
*/
/**
* @brief 功率监测数据
*/
typedef struct {
float voltage_rms; // 电压有效值(V)
float current_rms; // 电流有效值(A)
float power_active; // 有功功率(W)
float power_apparent; // 视在功率(VA)
float power_factor; // 功率因数
float energy_kwh; // 累计电能(kWh)
uint32_t on_time_sec; // 通电时间(秒)
} power_monitor_t;
static power_monitor_t power_mon = {0};
/**
* @brief 采样缓冲区
*/
#define SAMPLE_COUNT 200 // 10个周期(50Hz)
static float voltage_samples[SAMPLE_COUNT];
static float current_samples[SAMPLE_COUNT];
/**
* @brief 采集电压和电流波形
*/
void acquire_waveform(void)
{
for (int i = 0; i < SAMPLE_COUNT; i++) {
voltage_samples[i] = read_ac_voltage();
current_samples[i] = hall_read_current();
HAL_Delay(1); // 1ms采样间隔
}
}
/**
* @brief 计算RMS值
*/
float calculate_rms(float *samples, uint16_t count)
{
float sum_squares = 0.0f;
for (uint16_t i = 0; i < count; i++) {
sum_squares += samples[i] * samples[i];
}
return sqrtf(sum_squares / count);
}
/**
* @brief 计算有功功率
*/
float calculate_active_power(float *v_samples, float *i_samples, uint16_t count)
{
float sum = 0.0f;
for (uint16_t i = 0; i < count; i++) {
sum += v_samples[i] * i_samples[i];
}
return sum / count;
}
/**
* @brief 功率监测更新
*/
void power_monitor_update(void)
{
// 采集波形
acquire_waveform();
// 计算RMS值
power_mon.voltage_rms = calculate_rms(voltage_samples, SAMPLE_COUNT);
power_mon.current_rms = calculate_rms(current_samples, SAMPLE_COUNT);
// 计算功率
power_mon.power_active = calculate_active_power(voltage_samples, current_samples, SAMPLE_COUNT);
power_mon.power_apparent = power_mon.voltage_rms * power_mon.current_rms;
// 计算功率因数
if (power_mon.power_apparent > 0.1f) {
power_mon.power_factor = power_mon.power_active / power_mon.power_apparent;
} else {
power_mon.power_factor = 0.0f;
}
// 累计电能(每秒更新)
power_mon.energy_kwh += (power_mon.power_active / 3600000.0f); // Wh -> kWh
// 更新时间
power_mon.on_time_sec++;
// 打印数据
printf("电压: %.1f V, 电流: %.3f A, 功率: %.1f W, PF: %.2f\n",
power_mon.voltage_rms,
power_mon.current_rms,
power_mon.power_active,
power_mon.power_factor);
}
/**
* @brief 负载识别
*/
typedef enum {
LOAD_NONE = 0,
LOAD_RESISTIVE, // 电阻性负载(加热器、白炽灯)
LOAD_INDUCTIVE, // 电感性负载(电机、变压器)
LOAD_CAPACITIVE, // 电容性负载(开关电源)
LOAD_NONLINEAR // 非线性负载(LED灯、电子设备)
} load_type_t;
load_type_t identify_load_type(void)
{
if (power_mon.current_rms < 0.01f) {
return LOAD_NONE;
}
float pf = power_mon.power_factor;
if (pf > 0.95f) {
return LOAD_RESISTIVE;
} else if (pf > 0.7f && pf <= 0.95f) {
return LOAD_INDUCTIVE;
} else if (pf < 0.5f) {
return LOAD_CAPACITIVE;
} else {
return LOAD_NONLINEAR;
}
}
/**
* @brief 智能插座主程序
*/
void smart_socket_main(void)
{
printf("=== 智能插座启动 ===\n");
// 初始化
power_mon.energy_kwh = 0.0f;
power_mon.on_time_sec = 0;
while (1) {
// 更新功率监测
power_monitor_update();
// 负载识别
load_type_t load = identify_load_type();
// 过载保护
if (power_mon.current_rms > 10.0f) {
printf("警告:过载!关闭输出\n");
relay_off();
}
// 显示统计信息(每分钟)
if ((power_mon.on_time_sec % 60) == 0) {
printf("\n=== 统计信息 ===\n");
printf("累计电能: %.3f kWh\n", power_mon.energy_kwh);
printf("通电时间: %u 秒\n", power_mon.on_time_sec);
printf("平均功率: %.1f W\n",
(power_mon.energy_kwh * 1000.0f) / (power_mon.on_time_sec / 3600.0f));
}
HAL_Delay(1000);
}
}
第七部分:故障排除¶
7.1 常见问题诊断¶
问题1:读数不稳定
症状:
- 电流读数跳动
- 噪声大
- 无法稳定
可能原因:
1. ADC参考电压不稳定
2. 电源噪声
3. 地线回路
4. EMI干扰
5. 采样率不足
解决方案:
1. 使用稳定的参考电压源
2. 添加电源滤波电容
3. 优化PCB布局,单点接地
4. 添加RC滤波器
5. 提高采样率并平均
6. 使用屏蔽线缆
问题2:零点漂移
/**
* @brief 零点漂移检测
*/
typedef struct {
float initial_zero; // 初始零点
float current_zero; // 当前零点
float drift_rate; // 漂移速率(V/h)
uint32_t last_cal_time; // 上次校准时间
} zero_drift_monitor_t;
static zero_drift_monitor_t drift_mon = {0};
/**
* @brief 监测零点漂移
*/
void monitor_zero_drift(void)
{
uint32_t current_time = HAL_GetTick();
// 每小时检查一次
if ((current_time - drift_mon.last_cal_time) >= 3600000) {
// 测量当前零点
float zero = measure_zero_point(100);
// 计算漂移
float drift = zero - drift_mon.current_zero;
drift_mon.drift_rate = drift; // V/h
printf("零点漂移: %.4f V/h\n", drift_mon.drift_rate);
// 如果漂移过大,重新校准
if (fabsf(drift) > 0.01f) {
printf("警告:零点漂移过大,重新校准\n");
calibrate_zero_point(100);
}
drift_mon.current_zero = zero;
drift_mon.last_cal_time = current_time;
}
}
问题3:非线性误差
/**
* @brief 非线性校正表
*/
typedef struct {
float input; // 输入电流
float correction; // 校正值
} nonlinear_correction_t;
#define CORRECTION_POINTS 10
static nonlinear_correction_t correction_table[CORRECTION_POINTS] = {
{0.0f, 0.0f},
{0.5f, 0.01f},
{1.0f, 0.02f},
{2.0f, 0.03f},
{3.0f, 0.04f},
{4.0f, 0.05f},
{5.0f, 0.05f},
{6.0f, 0.04f},
{8.0f, 0.02f},
{10.0f, 0.0f}
};
/**
* @brief 非线性校正
*/
float apply_nonlinear_correction(float current)
{
// 查找区间
int i;
for (i = 0; i < CORRECTION_POINTS - 1; i++) {
if (current <= correction_table[i + 1].input) {
break;
}
}
// 线性插值
float x1 = correction_table[i].input;
float x2 = correction_table[i + 1].input;
float y1 = correction_table[i].correction;
float y2 = correction_table[i + 1].correction;
float ratio = (current - x1) / (x2 - x1);
float correction = y1 + ratio * (y2 - y1);
return current + correction;
}
7.2 调试技巧¶
示波器调试:
示波器测量要点:
1. 分流电阻压降
- 探头:10:1
- 耦合:DC
- 带宽:20MHz
- 测量:峰峰值、RMS
2. ADC输入信号
- 探头:10:1
- 耦合:DC
- 触发:边沿
- 检查:噪声、偏移
3. PWM电流波形
- 探头:电流探头
- 耦合:AC+DC
- 带宽:100MHz
- 测量:纹波、平均值
4. 地线噪声
- 探头:1:1
- 耦合:AC
- 带宽:全带宽
- 测量:噪声幅度
串口调试输出:
/**
* @brief 调试信息输出
*/
void debug_print_current_info(void)
{
printf("\n=== 电流采样调试信息 ===\n");
// ADC原始值
uint16_t adc_raw = adc_read(ADC_CHANNEL_CURRENT);
printf("ADC原始值: %u (0x%04X)\n", adc_raw, adc_raw);
// ADC电压
float adc_voltage = (adc_raw * 3.3f) / 4096.0f;
printf("ADC电压: %.4f V\n", adc_voltage);
// 零点偏移
printf("零点偏移: %.4f V\n", cal_data.zero_offset);
// 差分电压
float diff_voltage = adc_voltage - cal_data.zero_offset;
printf("差分电压: %.4f V\n", diff_voltage);
// 电流值
float current = (diff_voltage * cal_data.gain) / (hall_cfg.sensitivity / 1000.0f);
printf("电流值: %.3f A\n", current);
// 校准状态
printf("校准状态: %s\n", cal_data.calibrated ? "已校准" : "未校准");
printf("增益系数: %.4f\n", cal_data.gain);
// 保护状态
printf("保护状态: ");
switch (ocp_get_state()) {
case OCP_STATE_NORMAL: printf("正常\n"); break;
case OCP_STATE_WARNING: printf("警告\n"); break;
case OCP_STATE_FAULT: printf("故障\n"); break;
case OCP_STATE_SHUTDOWN: printf("关断\n"); break;
}
printf("故障计数: %u\n", ocp_get_fault_count());
printf("========================\n\n");
}
7.3 性能测试¶
/**
* @brief 精度测试
*/
void test_accuracy(void)
{
printf("=== 精度测试 ===\n");
float test_currents[] = {0.1f, 0.5f, 1.0f, 2.0f, 5.0f, 10.0f};
int test_count = sizeof(test_currents) / sizeof(test_currents[0]);
for (int i = 0; i < test_count; i++) {
printf("\n测试点: %.1f A\n", test_currents[i]);
printf("请设置标准电流源,按任意键继续...\n");
wait_for_key();
// 采集多个样本
float sum = 0.0f;
float sum_sq = 0.0f;
int samples = 100;
for (int j = 0; j < samples; j++) {
float current = hall_read_current();
sum += current;
sum_sq += current * current;
HAL_Delay(10);
}
// 计算统计值
float mean = sum / samples;
float variance = (sum_sq / samples) - (mean * mean);
float std_dev = sqrtf(variance);
float error = mean - test_currents[i];
float error_percent = (error / test_currents[i]) * 100.0f;
printf("测量平均值: %.3f A\n", mean);
printf("标准差: %.4f A\n", std_dev);
printf("误差: %.3f A (%.2f%%)\n", error, error_percent);
}
}
/**
* @brief 响应时间测试
*/
void test_response_time(void)
{
printf("=== 响应时间测试 ===\n");
// 阶跃响应测试
printf("准备阶跃响应测试...\n");
printf("将在3秒后施加阶跃电流\n");
HAL_Delay(3000);
uint32_t start_time = HAL_GetTick();
float target = 5.0f; // 目标5A
float threshold = target * 0.9f; // 90%阈值
// 记录波形
#define WAVEFORM_SIZE 1000
float waveform[WAVEFORM_SIZE];
for (int i = 0; i < WAVEFORM_SIZE; i++) {
waveform[i] = hall_read_current();
// 检测是否达到90%
if (waveform[i] >= threshold && start_time == HAL_GetTick()) {
uint32_t response_time = HAL_GetTick() - start_time;
printf("响应时间(90%%): %u ms\n", response_time);
}
HAL_Delay(1);
}
// 输出波形数据
printf("\n波形数据:\n");
for (int i = 0; i < WAVEFORM_SIZE; i += 10) {
printf("%d ms: %.3f A\n", i, waveform[i]);
}
}
/**
* @brief 长期稳定性测试
*/
void test_long_term_stability(void)
{
printf("=== 长期稳定性测试 ===\n");
printf("测试时间: 24小时\n");
float test_current = 2.0f; // 2A恒流
uint32_t test_duration = 24 * 3600; // 24小时
uint32_t sample_interval = 60; // 每分钟采样
float max_current = 0.0f;
float min_current = 999.0f;
float sum = 0.0f;
uint32_t sample_count = 0;
for (uint32_t t = 0; t < test_duration; t += sample_interval) {
float current = hall_read_current_filtered(10);
sum += current;
sample_count++;
if (current > max_current) max_current = current;
if (current < min_current) min_current = current;
// 每小时打印一次
if ((t % 3600) == 0) {
float avg = sum / sample_count;
printf("%u小时: 平均=%.3f A, 最大=%.3f A, 最小=%.3f A\n",
t / 3600, avg, max_current, min_current);
}
HAL_Delay(sample_interval * 1000);
}
// 最终统计
float avg = sum / sample_count;
float drift = max_current - min_current;
float drift_percent = (drift / test_current) * 100.0f;
printf("\n=== 测试结果 ===\n");
printf("平均值: %.3f A\n", avg);
printf("最大值: %.3f A\n", max_current);
printf("最小值: %.3f A\n", min_current);
printf("漂移: %.3f A (%.2f%%)\n", drift, drift_percent);
}
第八部分:最佳实践¶
8.1 硬件设计最佳实践¶
PCB布局要点:
PCB布局建议:
1. 分流电阻布局
┌─────────────────┐
│ 电源层 │
│ ┌───┐ │
│ │ R │ 短而宽 │
│ └───┘ │
│ │ │ │
│ V+ V- 差分走线 │
│ │ │ │
│ ┌─────┐ │
│ │ AMP │ │
│ └─────┘ │
└─────────────────┘
要点:
- 分流电阻靠近电源
- 差分走线等长、等宽
- 远离数字信号
- 地平面完整
2. 霍尔传感器布局
- 远离强磁场源
- 屏蔽电磁干扰
- 电源去耦电容靠近
- 信号线使用屏蔽线
3. ADC输入保护
- 串联电阻限流
- 并联TVS管
- RC滤波器
- ESD保护
电源设计:
/**
* @brief 电源质量监测
*/
typedef struct {
float vcc; // 供电电压
float vref; // 参考电压
float ripple; // 纹波电压
bool power_good; // 电源正常标志
} power_quality_t;
static power_quality_t power_quality = {0};
/**
* @brief 监测电源质量
*/
void monitor_power_quality(void)
{
// 测量VCC
power_quality.vcc = read_vcc_voltage();
// 测量Vref
power_quality.vref = read_vref_voltage();
// 测量纹波(AC耦合)
power_quality.ripple = measure_ripple_voltage();
// 检查电源质量
power_quality.power_good = true;
if (power_quality.vcc < 3.0f || power_quality.vcc > 3.6f) {
printf("警告:VCC电压异常 %.2f V\n", power_quality.vcc);
power_quality.power_good = false;
}
if (power_quality.ripple > 0.1f) {
printf("警告:电源纹波过大 %.3f V\n", power_quality.ripple);
power_quality.power_good = false;
}
if (fabsf(power_quality.vref - 2.5f) > 0.05f) {
printf("警告:参考电压偏移 %.3f V\n", power_quality.vref);
power_quality.power_good = false;
}
}
8.2 软件设计最佳实践¶
状态机设计:
/**
* @brief 电流采样状态机
*/
typedef enum {
CURRENT_STATE_INIT = 0,
CURRENT_STATE_CALIBRATING,
CURRENT_STATE_READY,
CURRENT_STATE_SAMPLING,
CURRENT_STATE_ERROR
} current_state_t;
typedef struct {
current_state_t state;
uint32_t error_code;
bool calibration_required;
} current_sm_t;
static current_sm_t current_sm = {0};
/**
* @brief 状态机更新
*/
void current_state_machine_update(void)
{
switch (current_sm.state) {
case CURRENT_STATE_INIT:
// 初始化硬件
if (init_hardware() == 0) {
current_sm.state = CURRENT_STATE_CALIBRATING;
} else {
current_sm.state = CURRENT_STATE_ERROR;
current_sm.error_code = ERROR_HARDWARE_INIT;
}
break;
case CURRENT_STATE_CALIBRATING:
// 执行校准
if (calibrate_zero_point(100) == 0) {
current_sm.state = CURRENT_STATE_READY;
current_sm.calibration_required = false;
} else {
current_sm.state = CURRENT_STATE_ERROR;
current_sm.error_code = ERROR_CALIBRATION;
}
break;
case CURRENT_STATE_READY:
// 等待采样请求
if (current_sm.calibration_required) {
current_sm.state = CURRENT_STATE_CALIBRATING;
} else {
current_sm.state = CURRENT_STATE_SAMPLING;
}
break;
case CURRENT_STATE_SAMPLING:
// 正常采样
float current = hall_read_current();
// 检查异常
if (isnan(current) || isinf(current)) {
current_sm.state = CURRENT_STATE_ERROR;
current_sm.error_code = ERROR_INVALID_DATA;
} else {
// 处理数据
process_current_data(current);
}
break;
case CURRENT_STATE_ERROR:
// 错误处理
handle_error(current_sm.error_code);
// 尝试恢复
if (try_recover()) {
current_sm.state = CURRENT_STATE_INIT;
}
break;
}
}
数据记录:
/**
* @brief 数据记录器
*/
#define LOG_BUFFER_SIZE 1000
typedef struct {
uint32_t timestamp;
float current;
float voltage;
float power;
} current_log_entry_t;
static current_log_entry_t log_buffer[LOG_BUFFER_SIZE];
static uint16_t log_index = 0;
static bool log_full = false;
/**
* @brief 记录数据
*/
void log_current_data(float current, float voltage)
{
log_buffer[log_index].timestamp = HAL_GetTick();
log_buffer[log_index].current = current;
log_buffer[log_index].voltage = voltage;
log_buffer[log_index].power = current * voltage;
log_index++;
if (log_index >= LOG_BUFFER_SIZE) {
log_index = 0;
log_full = true;
}
}
/**
* @brief 导出日志到SD卡
*/
int export_log_to_sd(const char *filename)
{
FIL file;
FRESULT res;
res = f_open(&file, filename, FA_CREATE_ALWAYS | FA_WRITE);
if (res != FR_OK) {
return -1;
}
// 写入CSV头
f_printf(&file, "Timestamp,Current,Voltage,Power\n");
// 写入数据
uint16_t count = log_full ? LOG_BUFFER_SIZE : log_index;
for (uint16_t i = 0; i < count; i++) {
f_printf(&file, "%u,%.3f,%.2f,%.2f\n",
log_buffer[i].timestamp,
log_buffer[i].current,
log_buffer[i].voltage,
log_buffer[i].power);
}
f_close(&file);
printf("日志已导出: %s (%u条记录)\n", filename, count);
return 0;
}
8.3 安全性考虑¶
看门狗保护:
/**
* @brief 看门狗配置
*/
void watchdog_init(void)
{
IWDG_HandleTypeDef hiwdg;
hiwdg.Instance = IWDG;
hiwdg.Init.Prescaler = IWDG_PRESCALER_64;
hiwdg.Init.Reload = 4095; // 约2秒超时
HAL_IWDG_Init(&hiwdg);
}
/**
* @brief 喂狗
*/
void watchdog_feed(void)
{
HAL_IWDG_Refresh(&hiwdg);
}
/**
* @brief 主循环(带看门狗)
*/
void main_loop_with_watchdog(void)
{
while (1) {
// 读取电流
float current = hall_read_current();
// 过流保护
ocp_process(current);
// 喂狗
watchdog_feed();
HAL_Delay(10);
}
}
故障安全设计:
/**
* @brief 故障安全检查
*/
bool fail_safe_check(void)
{
bool safe = true;
// 检查传感器连接
if (!sensor_is_connected()) {
printf("错误:传感器未连接\n");
safe = false;
}
// 检查ADC工作
if (!adc_is_working()) {
printf("错误:ADC故障\n");
safe = false;
}
// 检查校准数据
if (!cal_data.calibrated) {
printf("警告:未校准\n");
safe = false;
}
// 检查电源质量
monitor_power_quality();
if (!power_quality.power_good) {
printf("错误:电源质量不良\n");
safe = false;
}
// 如果不安全,关断输出
if (!safe) {
HAL_GPIO_WritePin(SHUTDOWN_PORT, SHUTDOWN_PIN, GPIO_PIN_RESET);
}
return safe;
}
第九部分:高级主题¶
9.1 多通道电流采样¶
/**
* @brief 多通道电流采样
*/
#define CURRENT_CHANNELS 4
typedef struct {
uint8_t adc_channel;
float current;
float calibration_offset;
float calibration_gain;
bool enabled;
} current_channel_t;
static current_channel_t channels[CURRENT_CHANNELS] = {
{ADC_CHANNEL_0, 0.0f, 0.0f, 1.0f, true},
{ADC_CHANNEL_1, 0.0f, 0.0f, 1.0f, true},
{ADC_CHANNEL_2, 0.0f, 0.0f, 1.0f, true},
{ADC_CHANNEL_3, 0.0f, 0.0f, 1.0f, true}
};
/**
* @brief 多通道采样(DMA)
*/
uint16_t adc_dma_buffer[CURRENT_CHANNELS];
void multi_channel_sampling_init(void)
{
// 配置ADC多通道扫描模式
ADC_ChannelConfTypeDef sConfig = {0};
for (int i = 0; i < CURRENT_CHANNELS; i++) {
sConfig.Channel = channels[i].adc_channel;
sConfig.Rank = i + 1;
sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}
// 启动DMA采样
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_dma_buffer, CURRENT_CHANNELS);
}
/**
* @brief 读取所有通道
*/
void read_all_channels(void)
{
for (int i = 0; i < CURRENT_CHANNELS; i++) {
if (!channels[i].enabled) {
continue;
}
// 转换ADC值为电压
float voltage = (adc_dma_buffer[i] * 3.3f) / 4096.0f;
// 应用校准
voltage = (voltage - channels[i].calibration_offset) * channels[i].calibration_gain;
// 转换为电流
channels[i].current = voltage / (hall_cfg.sensitivity / 1000.0f);
printf("通道%d: %.3f A\n", i, channels[i].current);
}
}
9.2 高精度电流测量¶
Sigma-Delta ADC应用:
/**
* @brief Sigma-Delta ADC配置(如ADS1220)
*/
#define ADS1220_CMD_RESET 0x06
#define ADS1220_CMD_START 0x08
#define ADS1220_CMD_RDATA 0x10
/**
* @brief ADS1220初始化(24位ADC)
*/
void ads1220_init(void)
{
// 复位
spi_write_byte(ADS1220_CMD_RESET);
HAL_Delay(10);
// 配置寄存器0:增益=128, PGA使能
uint8_t config0 = 0x70; // Gain=128
ads1220_write_reg(0, config0);
// 配置寄存器1:数据速率=20SPS
uint8_t config1 = 0x20;
ads1220_write_reg(1, config1);
// 配置寄存器2:参考电压=内部2.048V
uint8_t config2 = 0x10;
ads1220_write_reg(2, config2);
}
/**
* @brief 读取24位ADC值
*/
int32_t ads1220_read_current(void)
{
uint8_t data[3];
// 启动转换
spi_write_byte(ADS1220_CMD_START);
// 等待转换完成
HAL_Delay(50); // 20SPS = 50ms
// 读取数据
spi_write_byte(ADS1220_CMD_RDATA);
spi_read_bytes(data, 3);
// 组合24位数据
int32_t adc_value = ((int32_t)data[0] << 16) |
((int32_t)data[1] << 8) |
data[2];
// 符号扩展
if (adc_value & 0x800000) {
adc_value |= 0xFF000000;
}
return adc_value;
}
/**
* @brief 高精度电流计算
*/
float calculate_high_precision_current(void)
{
int32_t adc_value = ads1220_read_current();
// 24位ADC,参考电压2.048V,增益128
float voltage = (adc_value * 2.048f) / (8388608.0f * 128.0f);
// 分流电阻0.001Ω
float current = voltage / 0.001f;
return current;
}
9.3 无线电流监测¶
/**
* @brief 无线数据包结构
*/
typedef struct {
uint32_t timestamp;
float current;
float voltage;
float power;
float temperature;
uint8_t status;
uint16_t crc;
} wireless_packet_t;
/**
* @brief 发送无线数据
*/
void send_wireless_data(void)
{
wireless_packet_t packet;
// 填充数据
packet.timestamp = HAL_GetTick();
packet.current = hall_read_current();
packet.voltage = read_voltage();
packet.power = packet.current * packet.voltage;
packet.temperature = read_temperature();
packet.status = get_system_status();
// 计算CRC
packet.crc = calculate_crc16((uint8_t*)&packet, sizeof(packet) - 2);
// 发送数据(通过LoRa/WiFi/BLE等)
wireless_transmit((uint8_t*)&packet, sizeof(packet));
}
/**
* @brief 接收无线数据
*/
bool receive_wireless_data(wireless_packet_t *packet)
{
if (wireless_receive((uint8_t*)packet, sizeof(wireless_packet_t))) {
// 验证CRC
uint16_t crc = calculate_crc16((uint8_t*)packet, sizeof(wireless_packet_t) - 2);
if (crc == packet->crc) {
return true;
} else {
printf("错误:CRC校验失败\n");
return false;
}
}
return false;
}
9.4 机器学习应用¶
/**
* @brief 负载特征提取
*/
typedef struct {
float mean_current;
float std_dev;
float peak_current;
float power_factor;
float thd; // 总谐波失真
} load_features_t;
/**
* @brief 提取负载特征
*/
void extract_load_features(float *current_samples, uint16_t count, load_features_t *features)
{
// 计算平均值
float sum = 0.0f;
for (uint16_t i = 0; i < count; i++) {
sum += current_samples[i];
}
features->mean_current = sum / count;
// 计算标准差
float sum_sq = 0.0f;
for (uint16_t i = 0; i < count; i++) {
float diff = current_samples[i] - features->mean_current;
sum_sq += diff * diff;
}
features->std_dev = sqrtf(sum_sq / count);
// 查找峰值
features->peak_current = 0.0f;
for (uint16_t i = 0; i < count; i++) {
if (fabsf(current_samples[i]) > features->peak_current) {
features->peak_current = fabsf(current_samples[i]);
}
}
// 计算功率因数(简化)
features->power_factor = features->mean_current / features->peak_current;
// 计算THD(需要FFT)
features->thd = calculate_thd(current_samples, count);
}
/**
* @brief 负载分类(简单决策树)
*/
const char* classify_load(load_features_t *features)
{
if (features->std_dev < 0.1f) {
return "恒流负载";
} else if (features->power_factor > 0.95f) {
return "电阻性负载";
} else if (features->power_factor < 0.7f) {
if (features->thd > 0.3f) {
return "开关电源";
} else {
return "电感性负载";
}
} else {
return "混合负载";
}
}
第十部分:总结与展望¶
10.1 关键要点回顾¶
电流采样技术要点:
1. 传感器选择
✓ 分流电阻:低成本、高精度、无隔离
✓ 霍尔传感器:有隔离、中等精度、适合大电流
✓ 电流互感器:仅交流、高隔离、适合高压
2. ADC配置
✓ 分辨率:12位以上
✓ 采样率:根据应用选择
✓ 参考电压:稳定、低噪声
✓ 滤波:硬件+软件
3. 校准方法
✓ 零点校准:消除偏移
✓ 增益校准:提高精度
✓ 温度补偿:减少漂移
✓ 非线性校正:改善线性度
4. 保护策略
✓ 硬件保护:快速响应
✓ 软件保护:灵活可配
✓ 多级保护:可靠安全
✓ 故障记录:便于诊断
5. 最佳实践
✓ PCB布局:减少干扰
✓ 电源设计:稳定可靠
✓ 软件架构:模块化、可维护
✓ 测试验证:全面充分
10.2 常见应用总结¶
应用场景对比:
┌──────────────┬─────────┬─────────┬─────────┬─────────┐
│ 应用 │ 电流范围│ 精度要求│ 响应时间│ 推荐方案│
├──────────────┼─────────┼─────────┼─────────┼─────────┤
│ 电池监测 │ 0-5A │ 1% │ 1s │ INA219 │
│ 电机控制 │ 0-50A │ 2% │ 1ms │ 霍尔 │
│ 电源监测 │ 0-10A │ 0.5% │ 100ms │ 分流+ADC│
│ 智能插座 │ 0-16A │ 1% │ 1s │ ACS712 │
│ 焊接机 │ 0-200A │ 5% │ 10ms │ 霍尔 │
│ 充电桩 │ 0-100A │ 1% │ 100ms │ 霍尔 │
│ 变频器 │ 0-500A │ 0.5% │ 1ms │ 闭环霍尔│
│ 电能表 │ 0-60A │ 0.2% │ 1s │ 专用芯片│
└──────────────┴─────────┴─────────┴─────────┴─────────┘
10.3 学习路径建议¶
进阶学习路径:
1. 基础阶段(1-2周)
□ 理解欧姆定律和基本电路
□ 学习ADC原理和使用
□ 掌握分流电阻采样
□ 实现简单的电流读取
2. 进阶阶段(2-4周)
□ 学习霍尔效应原理
□ 掌握差分放大器设计
□ 实现校准算法
□ 添加过流保护
3. 高级阶段(1-2月)
□ 多通道采样
□ 高精度测量
□ 无线传输
□ 数据分析
4. 专家阶段(持续)
□ 机器学习应用
□ 故障诊断
□ 系统优化
□ 创新应用
10.4 参考资源¶
推荐芯片: - INA219/INA226:高侧电流检测 - ACS712:霍尔电流传感器 - ADS1220:24位Sigma-Delta ADC - LMP8640:精密电流检测放大器
参考文献: 1. "Current Sensing for Energy Metering" - Texas Instruments 2. "Hall Effect Sensing and Application" - Honeywell 3. "Precision Current Measurement" - Analog Devices 4. "Overcurrent Protection Design Guide" - ON Semiconductor
在线资源: - TI E2E论坛:电流检测专区 - Allegro技术文档:霍尔传感器应用 - ST社区:STM32 ADC应用 - GitHub:开源电流监测项目
相关标准: - IEC 61000-4-30:电能质量测量 - IEC 62053:电能表标准 - UL 2231:电动汽车充电标准
总结¶
电流采样是嵌入式系统中的关键技术,涉及模拟电路、数字信号处理、控制算法等多个领域。通过本教程的学习,您应该掌握了:
- 理论基础:电流检测原理、传感器工作机制
- 硬件设计:电路设计、PCB布局、元件选型
- 软件实现:ADC配置、数据处理、算法实现
- 系统集成:校准、保护、通信、应用
- 工程实践:调试技巧、测试方法、最佳实践
电流采样技术仍在不断发展,新的传感器、算法和应用不断涌现。建议持续关注行业动态,不断学习和实践,才能在这个领域保持竞争力。
下一步学习¶
完成本教程后,建议继续学习以下相关主题:
祝您学习愉快,在嵌入式电流采样领域取得成功!