绝缘检测方案,绝缘检测资料。

通过使用STM32F103单片机【pp】,不平衡电桥测电阻,测高压绝缘阻值。通过隔离RS485通信芯片与主控板通信,协议使用通用协议。在充电桩上应用过,可以作为设计参考。
资料包括原理图,PCB,BOM,软件源代码,设计计算公式。
在这里插入图片描述
在这里插入图片描述
这是一个基于 STM32F103 的 不平衡电桥法高压绝缘检测方案 的核心代码实现。

该方案常用于充电桩(EVSE)、储能BMS等场景。核心原理是利用两个已知阻值的精密电阻(R_1, R_2)与电池正负极对地绝缘电阻(R_{p}, R_{n})构成电桥,通过STM32的ADC采集分压点电压,解方程组计算出绝缘阻值。

📂 项目文件结构建议
Insulation_Detection/
├── Core/
│ ├── Inc/
│ │ ├── insulation_algo.h // 核心算法头文件
│ │ └── main.h
│ └── Src/
│ ├── insulation_algo.c // 核心算法实现 (公式计算)
│ ├── main.c // 主逻辑 (ADC采集 + 状态机)
│ └── rs485_comm.c // RS485通信协议 (模拟通用协议)
├── Drivers/ // STM32 HAL库
└── User_App/
└── app_config.h // 参数配置 (电桥电阻值等)

核心算法层 (insulation_algo.h & .c)
这是方案的灵魂,包含设计计算公式的代码化实现。

insulation_algo.h
ifndef __INSULATION_ALGO_H
define __INSULATION_ALGO_H

include
include

// 定义绝缘检测结果结构体
typedef struct {
float r_positive; // 正极对地绝缘电阻 (MΩ)
float r_negative; // 负极对地绝缘电阻 (MΩ)
float total_voltage; // 总母线电压 (V)
bool alarm_flag; // 报警标志 (绝缘过低)
uint8_t status; // 状态: 0-正常,1-计算中,2-故障
} Insulation_Result_t;

// 初始化算法参数
void INS_Algo_Init(float r1_val, float r2_val, float adc_ref, uint16_t adc_max);

// 核心计算函数
// 输入:
// v_mid_pos: 正极电桥中点电压 (V)
// v_mid_neg: 负极电桥中点电压 (V) (如果是单路切换采集,则传入对应时刻电压)
// v_bus: 母线总电压 (V)
// 输出: 填充 Result 结构体
void INS_Calculate_Resistor(float v_mid_pos, float v_mid_neg, float v_bus, Insulation_Result_t *Result);

endif

insulation_algo.c
include “insulation_algo.h”
include

// 全局参数:电桥上下臂电阻值 (单位: kΩ 或 Ω,需统一)
// 假设原理图中:上臂 R1, 下臂 R2
static float R_BRIDGE_HIGH = 300.0f; // 例如 300kΩ
static float R_BRIDGE_LOW = 300.0f; // 例如 300kΩ
static float ADC_REF_VOLT = 3.3f;
static uint16_t ADC_MAX_VAL = 4095;

/**
@brief 初始化算法参数
@param r1_val 电桥高臂电阻值 (kΩ)
@param r2_val 电桥低臂电阻值 (kΩ)
*/
void INS_Algo_Init(float r1_val, float r2_val, float adc_ref, uint16_t adc_max) {
R_BRIDGE_HIGH = r1_val;
R_BRIDGE_LOW = r2_val;
ADC_REF_VOLT = adc_ref;
ADC_MAX_VAL = adc_max;
}

/**
@brief 不平衡电桥法计算绝缘电阻

  • 数学模型推导 (简化版):
    设母线电压为 U, 正对地绝缘 Rp, 负对地绝缘 Rn
    接入检测电阻 R1(接正), R2(接地) -> 测得电压 V1
    接入检测电阻 R3(接负), R4(接地) -> 测得电压 V2

  • 本方案采用经典双路或切换式电桥,此处以典型的“正负分别对地分压”模型为例:
    实际上通常是通过继电器切换,或者双路ADC同时采样。

  • 假设电路结构:
    正极 --[Rp]-- GND
    负极 --[Rn]-- GND

  • 测量正极时:R1接正,R2接地,中点电压 Va
    测量负极时:R3接负,R4接地,中点电压 Vb

  • 根据基尔霍夫定律联立方程求解 Rp 和 Rn。
    以下公式为通用解算逻辑,具体系数需根据您的原理图电阻网络调整。
    */
    void INS_Calculate_Resistor(float v_mid_pos, float v_mid_neg, float v_bus, Insulation_Result_t *Result) {
    if (v_bus status = 2;
    Result->r_positive = 0;
    Result->r_negative = 0;
    return;
    }

    Result->total_voltage = v_bus;
    Result->status = 0;

    // — 核心计算公式开始 —
    // 注意:实际公式取决于您的具体硬件连接方式。
    // 这里提供一个常见的“双电阻切换法”或“双路并行法”的近似解算逻辑。
    // 假设:
    // Vpos_meas 是正极分压点电压 (相对于系统地)
    // Vneg_meas 是负极分压点电压 (相对于系统地,通常为负值或经过运放抬升)

    // 为了演示,假设硬件已经做了电平移位,ADC读到的都是正电压。
    // 设 K1 = (R1+R2)/R2, K2 = (R3+R4)/R4

    float K_pos = (R_BRIDGE_HIGH + R_BRIDGE_LOW) / R_BRIDGE_LOW;
    float K_neg = (R_BRIDGE_HIGH + R_BRIDGE_LOW) / R_BRIDGE_LOW; // 假设对称

    // 还原未接检测电阻时的理论对地电压 (估算)
    // 实际工程中常用联立方程组求解:
    // (U_pos - 0)/Rp + (U_pos - U_bus)/Rn + (U_pos - U_bus)/R1 + U_pos/R2 = 0 … (复杂节点电压法)

    // 【简化工程公式】(适用于常见的不平衡电桥模块)
    // Rp = (U_bus * R_ref * (V2 - V1)) / (V1 * (U_bus - V2) - V2 * (U_bus - V1)) … 此类形式
    // 由于缺乏具体原理图,以下使用标准的节点电压法解算逻辑伪代码,请代入您的具体电阻值。

    // 假设场景:
    // 1. 闭合S1 (正极检测): 测得 V1
    // 2. 闭合S2 (负极检测): 测得 V2
    // 此时系统方程为:
    // V1 = U_bus * (Rn // R2) / (Rp + (Rn // R2)) 转换为 MΩ)
    // 这里的公式是示意性的,真实公式需依据:
    // Rp = R_ref * (U_bus - V_measure) / (2V_measure) … 类似变体
    Result->r_positive = (R_BRIDGE_HIGH * (v_bus - v_mid_pos * 2.0f)) / (v_mid_pos * 2.0f);
    Result->r_negative = (R_BRIDGE_HIGH * (v_bus - v_mid_neg * 2.0f)) / (v_mid_neg * 2.0f);

    // 修正负值 (绝缘电阻不能为负)
    if (Result->r_positive r_positive = 999.9f; // 视为无穷大
    if (Result->r_negative r_negative = 999.9f;

    // 转换为 MΩ
    Result->r_positive /= 1000.0f;
    Result->r_negative /= 1000.0f;

    // 报警阈值判断 (例如:低于 50kΩ/V 或 固定 1MΩ)
    float threshold = 1.0f; // 1 MΩ
    if (Result->r_positive r_negative alarm_flag = true;
    } else {
    Result->alarm_flag = false;
    }
    }

主控逻辑层 (main.c)
负责ADC采集、RS485调度。

include “main.h”
include “insulation_algo.h”
include “rs485_comm.h”
include

// 外部变量声明 (需在 ADC 部分实现)
extern uint16_t adc_val_pos;
extern uint16_t adc_val_neg;
extern float measured_bus_voltage;

Insulation_Result_t g_ins_result;

// 配置参数
define BRIDGE_R_VAL 300.0f // 300kΩ
define ADC_REF 3.3f
define ADC_MAX 4095

void System_Init(void) {
HAL_Init();
// 初始化时钟、GPIO、ADC、UART(RS485)
// … 省略具体HAL初始化代码 …

// 初始化绝缘算法
INS_Algo_Init(BRIDGE_R_VAL, BRIDGE_R_VAL, ADC_REF, ADC_MAX);

// 初始化RS485
RS485_Init(9600); 

}

void Main_Loop(void) {
float v_pos, v_neg;

while (1) {
    // 1. 采集 ADC (假设已做滤波处理)
    // 将 ADC 值转换为电压值
    v_pos = (float)adc_val_pos * ADC_REF / ADC_MAX;
    v_neg = (float)adc_val_neg * ADC_REF / ADC_MAX;
    
    // 注意:如果硬件上有运放放大或分压,需在此处乘以倍率
    // 例如:v_pos = v_pos * 10.0f; 

    // 2. 执行绝缘电阻计算
    INS_Calculate_Resistor(v_pos, v_neg, measured_bus_voltage, &g_ins_result);

    // 3. 处理报警
    if (g_ins_result.alarm_flag) {
        // 点亮报警LED 或 切断继电器
        HAL_GPIO_WritePin(ALARM_LED_Port, ALARM_LED_Pin, GPIO_PIN_SET);
    } else {
        HAL_GPIO_WritePin(ALARM_LED_Port, ALARM_LED_Pin, GPIO_PIN_RESET);
    }

    // 4. 通过 RS485 上报数据 (通用协议示例)
    // 协议帧格式示例: [Head][Len][Cmd][Data...][CRC]
    uint8_t tx_buffer[64];
    int len = sprintf((char*)tx_buffer, 
        "INS,Rp=%.2f,Rn=%.2f,Ubus=%.1f,Alarm=%drn", 
        g_ins_result.r_positive, 
        g_ins_result.r_negative, 
        g_ins_result.total_voltage,
        g_ins_result.alarm_flag ? 1 : 0);
    
    RS485_Send(tx_buffer, len);

    // 延时,控制采样频率 (例如 1Hz)
    HAL_Delay(1000);
}

}

RS485 通信协议层 (rs485_comm.c)
实现隔离通信,采用简单的通用文本协议或Modbus RTU。这里展示一个通用文本协议实现,方便调试。

include “rs485_comm.h”
include

// UART Handle 需根据实际工程定义
extern UART_HandleTypeDef huart1;

void RS485_Init(uint32_t baudrate) {
// 配置 UART1 波特率,启用 RS485 方向控制引脚 (DE/RE)
// … HAL_UART_Init …
}

void RS485_Send(uint8_t *data, uint16_t size) {
// 1. 置发送使能 (DE High)
HAL_GPIO_WritePin(RS485_DE_Port, RS485_DE_Pin, GPIO_PIN_SET);

// 2. 发送数据
HAL_UART_Transmit(&huart1, data, size, 100);

// 3. 短暂延时确保发送完成
HAL_Delay(2);

// 4. 置接收使能 (DE Low)
HAL_GPIO_WritePin(RS485_DE_Port, RS485_DE_Pin, GPIO_PIN_RESET);

}

📐 设计计算公式说明 (文档补充)
设计计算公式部分应包含以下推导(代码中已体现逻辑):

假设电路模型如下:
U: 母线总电压
R_p: 正极对地绝缘电阻
R_n: 负极对地绝缘电阻
R_1, R_2: 检测电桥电阻 (已知)

步骤 1:闭合正极检测开关 (K_1)
此时 R_1 并联在 R_p 上(或串联分压,视具体电路),测得中点电压 V_1。
根据节点电压法:
frac{V_1}{R_2} + frac{V_1 - U}{R_p // R_1} + frac{V_1}{R_n} = 0 (注:具体方程需依据原理图是“分压式”还是“注入式”)

步骤 2:闭合负极检测开关 (K_2)
测得中点电压 V_2。
同理列出方程。

步骤 3:联立求解
通过 V_1, V_2, U 和已知电阻 R_1, R_2,解二元一次方程组得到 R_p 和 R_n。

代码中的简化处理:
上述 insulation_algo.c 中的公式是基于典型对称电桥的简化版。如果您的原理图是非对称的(例如 R_1 neq R_2),请务必在 INS_Calculate_Resistor 函数中代入真实的代数解。

在这里插入图片描述
PCB(印刷电路板)的顶层布线图,从颜色和布局来看:

红色区域:通常是 顶层铜箔(Top Layer)
蓝色/紫色走线:可能是 底层或内层走线(Bottom/Internal Layers)
黄色圆圈/焊盘:元件焊盘、过孔或测试点
黑色背景:非导电区域(阻焊层覆盖)
四个角绿色圆孔:安装孔或定位孔

这张图是 硬件设计成果,不是“代码”,而是由 EDA 工具(如 Altium Designer、KiCad、EasyEDA 等)生成的 PCB 布局文件。

PCB 设计自动化脚本(Python + KiCad API)
用于批量生成类似结构的 PCB 布局框架(适合重复性设计)

🎯 2. Gerber 文件解析与可视化代码(Python)
用于读取和分析您这张 PCB 图对应的制造数据

🎯 3. BOM 表自动生成脚本(从原理图到 Excel)
配合您的“资料包括 BOM”需求

🎯 4. 绝缘检测模块的 FPGA/Verilog 控制逻辑(如果需要数字隔离控制)

pcb_generator.py
import sys
sys.path.append(“/usr/lib/kicad/scripting”) # KiCad Python API 路径

from pcbnew import *

def create_insulation_pcb():
board = BOARD.New()

# 设置板框尺寸 (例如 100mm x 80mm)
board.SetBoardEdgesRectangle(wxPoint(0, 0), wxPoint(100000000, 80000000))

# 创建两个对称的绝缘检测单元
for i in range(2):
    offset_x = i * 50000000  # 50mm 间距
    
    # 放置 STM32F103 封装 (QFP48)
    footprint = FootprintLoad("/path/to/STM32F103C8T6.kicad_mod")
    footprint.SetPosition(wxPoint(offset_x + 25000000, 40000000))
    board.Add(footprint)
    
    # 放置高压分压电阻网络 (R1, R2)
    for j, res_val in enumerate(["300k", "300k"]):
        res_fp = FootprintLoad("/path/to/Resistor_SMD_R0805.kicad_mod")
        res_fp.SetPosition(wxPoint(offset_x + 25000000 + (j-0.5)*10000000, 20000000))
        board.Add(res_fp)
        
    # 放置 RS485 隔离芯片 (如 ADM2587)
    iso_fp = FootprintLoad("/path/to/SOIC16_ADM2587.kicad_mod")
    iso_fp.SetPosition(wxPoint(offset_x + 25000000, 60000000))
    board.Add(iso_fp)
    
    # 添加电源和地平面铺铜
    zone = ZONE(board)
    zone.SetLayer(F_Cu)
    zone.Outline().AddPolygon([wxPoint(0,0), wxPoint(100000000,0), wxPoint(100000000,80000000), wxPoint(0,80000000)])
    board.Add(zone)

# 保存为 .kicad_pcb 文件
board.Save("insulation_detection_board.kicad_pcb")
print("✅ PCB 已生成: insulation_detection_board.kicad_pcb")

if name == “main”:
create_insulation_pcb()

💡 注意:此代码需安装 KiCad 并配置 Python API 环境。实际使用时需替换封装路径和坐标。

📊 如果您已有 Gerber 文件 —— 可用以下代码解析并可视化

gerber_viewer.py
import matplotlib.pyplot as plt
from gerber import load_layer

加载顶层铜箔 Gerber 文件
copper_top = load_layer(‘insulation_detection.GTL’) # GTL = Gerber Top Layer

绘制
fig, ax = plt.subplots(figsize=(10, 8))
copper_top.render(ax, alpha=0.7, color=‘red’)

plt.title(“PCB Top Copper Layer Visualization”)
plt.axis(‘equal’)
plt.show()

安装依赖:
pip install gerber matplotlib

🧾 BOM 表自动生成脚本(从 CSV 到 Excel)

假设您有 bom.csv 文件:

Designator,Value,Footprint,Quantity
R1,R300k,R0805,2
R2,R300k,R0805,2
U1,STM32F103C8T6,QFP48,1
U2,ADM2587,SOIC16,1

bom_generator.py
import pandas as pd

df = pd.read_csv(‘bom.csv’)

按 Value 分组统计数量
grouped = df.groupby([‘Value’, ‘Footprint’]).size().reset_index(name=‘Total_Qty’)

导出为 Excel
with pd.ExcelWriter(‘BOM_Insulation_Detection.xlsx’) as writer:
grouped.to_excel(writer, sheet_name=‘Summary’, index=False)
df.to_excel(writer, sheet_name=‘Detailed’, index=False)

print(“✅ BOM 表已生成:BOM_Insulation_Detection.xlsx”)

⚙️ 进阶:Verilog 控制逻辑(如需 FPGA 实现绝缘采样时序)

如果您打算用 FPGA 替代 STM32 做高速采样控制:

// insulation_controller.v
module insulation_controller (
input clk,
input rst_n,
output reg adc_start,
output reg [1:0] mux_sel, // 选择正/负极采样
input [11:0] adc_data,
output reg [31:0] result_rp,
output reg [31:0] result_rn
);

parameter STATE_IDLE = 2’b00;
parameter STATE_SAMPLE_POS = 2’b01;
parameter STATE_SAMPLE_NEG = 2’b10;
parameter STATE_CALC = 2’b11;

reg [1:0] state;
reg [11:0] v_pos, v_neg;

always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= STATE_IDLE;
adc_start <= 0;
mux_sel <= 0;
end else begin
case (state)
STATE_IDLE: begin
mux_sel <= 2’b01; // 选正极
adc_start <= 1;
state <= STATE_SAMPLE_POS;
end
STATE_SAMPLE_POS: begin
adc_start <= 0;
v_pos <= adc_data;
mux_sel <= 2’b10; // 选负极
adc_start <= 1;
state <= STATE_SAMPLE_NEG;
end
STATE_SAMPLE_NEG: begin
adc_start <= 0;
v_neg <= adc_data;
state <= STATE_CALC;
end
STATE_CALC: begin
// 在此处插入绝缘电阻计算公式
// result_rp = …; result_rn = …;
state <= STATE_IDLE;
end
endcase
end
end

endmodule

     功能说明

PCB 设计 pcb_generator.py 参数化生成对称布局 PCB

Gerber 分析 gerber_viewer.py 可视化制造文件

BOM 管理 bom_generator.py 自动生成 Excel 格式物料清单

数字控制逻辑 insulation_controller.v FPGA 实现采样时序控制

核心算法 insulation_algo.c/h (前文) 不平衡电桥法计算绝缘电阻

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐