ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于STM32和IRF640的低边压控可调恒流源设计与实现

基于STM32和IRF640的低边压控可调恒流源设计与实现 做这个项目最初是因为实验室里有一批LED灯珠要做老化还有电池充放电实验需要稳定的电流源。市面上几十块钱的电流源模块要么只能固定某个档位要么电流一大就烫得不敢碰好一点的成品价格又开始离谱。所以干脆用STM32F103C8T6加IRF640自己搭一个300mA级可调恒流源。整套方案走的是低边压控恒流路线核心是运放闭环把采样电阻上的电压死死钳在设定值上MCU只负责给出设定电压和回读电流。做下来之后输出稳定性、可调性都能满足日常实验室需求整份BOM清单和调试经验我会在文章里全部放出来。这篇文章适合刚入门想做电源类项目的朋友也适合想把模拟闭环和单片机控制串起来理解的人。1. 方案选型为什么不是三极管恒流源1.1 双二极管恒流源只能解决“有”的问题网上搜双二极管恒流源其实就是两个同型号三极管或者场效应管接成电流镜让输出电流跟着参考支路走。优点是简单、成本几毛钱、不用任何基准源但它的缺点也是天生的电流由晶体管参数决定批次之间差异明显温度一变输出电流跟着飘。更麻烦的是想要从几十毫安调到300mA必须手动画换元件根本没法做成连续可调。我早年也试过用JFET和电阻搭固定电流源效果比双二极管方案好一点但依旧摆脱不了“换元件才能改电流”的问题。实验室场景里我经常需要在LED老化、电池充电、传感器供电之间来回切换这种固定电流源只能放在某个特定工位一直运行不具备通用性。所以一听到“可调恒流源”我首先会把纯分立器件的固定方案排除掉。1.2 运放加MOS管恒流源才是可调方案的正解运放加MOS管的恒流源其实是把“电流设定”和“功率调整”分开做了STM32负责给出一个设定电压Vset运放负责不断比较采样电阻上的电压和Vset差值被放大之后驱动MOS管的栅极形成一个负反馈闭环。只要环路增益足够采样电阻电压就会被钳制在设定电压附近于是负载电流I_out约等于Vset除以采样电阻R_sense。这个方案的好处非常明显输出电流只取决于Vset和采样电阻和MOS管的跨导、温度、批次关系都不大。换句话说MOS管在这里只是一个“功率放大执行器”只要它能在当前工作点通过电流精度就轮不到它决定。相比三极管恒流源受Vbe温漂影响运放方案显然更适合“实验室级”的要求。1.3 为什么选择了STM32和IRF640STM32F103C8T6在这种项目里属于非常顺手的控制核心16位定时器做PWM能提供比较细粒度的设定ADC回读电流UART做人机交互3.3V信号电平正好和运放输入范围匹配。哪怕你手上只有最常见的Blue Pill开发板也完全够用。IRF640作为调整管也有充足余量200V耐压、18A额定电流TO-220封装非常容易装散热片电子市场随便都能买到。在300mA这个工作点下IRF640的功耗一般也就1W到3W只要把散热片装好工作温度完全可控。如果你手头没有IRF640也可以换IRLZ34N或者IRF540N只是要重新确认栅极电容和Vgs阈值驱动电阻可能要做微调。不过我这次为了还原标题里的方案还是以IRF640作为主力器件往下写。1.4 系统结构MCU只干三件事这套系统的信号流可以用下面这张文字图来理解STM32 PA0 PWM - 两级RC低通 - U1A缓冲 - U1B同相输入 | 12V - LOAD - IRF640漏极 - 源极 - 10R采样电阻 - GND | ---- U1B反相输入 | STM32 ADC采样源极电压 - 换算电流 - UART回传MCU在这里只干三件事用PWM生成设定电压、用ADC回读采样电压、通过串口接收指令并调整输出。真正稳住电流的是模拟闭环运放会以微秒级的速度对负载变化做出响应。所以STM32完全不需要跑PID算法主循环只做采样和命令解析CPU占用率低得可怜。这也是这种架构最吸引人的地方模拟部分负责“快”数字部分负责“准”。2. 核心电路原理与关键参数计算2.1 低边压控恒流源的反馈闭环实际电路里U1B运放的同相输入端接来自PWM滤波后的Vset反相输入端直接连到IRF640的源极运放输出经过一个100Ω栅极电阻接到IRF640栅极。源极到地之间串着一个10Ω采样电阻RS负载接在电源正和MOS管漏极之间。这个反馈过程可以这样理解当负载电流偏低时流过RS的电流小源极电压低于Vset运放正负输入端之间存在正差值输出就会抬高栅极电压让MOS管导通更强电流增加电流增加之后源极电压上升运放两个输入端差值减小直到源极电压等于Vset电路才稳定。反过来电流一旦偏大源极电压高于Vset运放输出会往下拉MOS管电流自然回落。稳定之后运放的“虚短”特性会让两个输入端电压相等也就是源极电压等于Vset。由于源极到地之间只有一个采样电阻负载电流就等于Vset除以RS。这个关系非常干净没有MOS管的参数掺和进来所以RS的精度和温漂就直接决定了恒流源的静态精度。2.2 采样电阻RS为什么选10Ω选RS要同时看在STM32的3.3V设定电压下能不能覆盖300mA。理论最大值是3.3V除以0.3A等于11Ω超过11Ω就会出现“电压设到顶电流也到不了300mA”的情况。但直接选11Ω会把PWM拉到满量程没有余量所以我把RS定为10Ω。选10Ω还有一个好处300mA电流时源极电压刚好是3V给ADC留了大约0.3V的余量也避免了PWM输出100%占空比带来的非线性区。如果选1Ω输出能力会变成3.3A明显超出IRF640在线性区的安全工作范围如果选33Ω电流刚到100mA源极电压就已经3.3VADC量程不够用。所以10Ω是从多方面权衡下来的结果。RS的功耗也要算清楚300mA经过10Ω电阻功率是0.3乘0.3乘10等于0.9W。普通0805贴片电阻只有0.25W功率上去肯定发烫温度一高电阻值就飘电流也会跟着飘。我实际用的是5W金属氧化膜电阻功率余量超过5倍表面温度基本可以忽略这也是“实验室级”稳定性最重要的一个细节。2.3 PWM生成设定电压的完整链路STM32F103没有内部DAC所以使用PWM加低通滤波来产生Vset。我用TIM2的通道1配置频率20kHz预分频设为1自动重装值设为1799。在72MHz主频下定时器时钟被分频到36MHz36MHz除以1800正好等于20kHzPWM分辨率有1800级对一个固定输出的恒流源来说已经很细腻。两级RC滤波的参数是4.7kΩ配10μF再接一级2.2kΩ配10μF。这个滤波器的理论截止频率只有几赫兹20kHz的PWM基波和它的谐波会被衰减得非常干净经过一级运放缓冲之后送给U1B的电压基本是一条平直的直流线。代价是设置响应速度偏慢从改变PWM到Vset稳定大约需要几百毫秒。我做软启动时反而利用了这个特性不用额外做电流斜坡只要PWM步进加得稍微慢一点输出电压就不会有冲击。如果后续想让恒流源响应更快可以换成MCP4921这类12位SPI DAC用SPI直接输出0到4.096V的控制电压少掉RC滤波的等待时间。但普通实验室用途下PWM加RC已经够了成本也更低。2.4 电流回读和温度保护源极电压经过10Ω采样电阻之后正好落在0到3V范围可以直接进STM32的ADC引脚。ADC采样口我加了一级1kΩ加0.1μF的低通滤波再做64次均值读数就非常稳定。换算公式很简单电流毫安数等于源极电压除以10Ω再乘以1000。这套方案还可以顺便加一个NTC温度探头贴在IRF640散热片上用STM32的另一个ADC通道采集。当MOS管温度超过70℃时程序可以把电流逐步降回去或者直接触发串口报警。我这次主电路没有把NTC保护焊上去只预留了接口位后续要升级成独立小仪器时再补上。3. 软硬件实操从图纸到能用的恒流源3.1 电源和地线布局注意事项做模拟闭环最怕的不是原理图错误而是地线乱走。300mA电流虽然不算大但如果在PCB上走了一段很细的铜皮采样电阻下端的参考地就会飘导致运放反相输入端参考电位不稳最终电流回读值来回跳。我的做法是把功率地、模拟地、数字地做单点汇合。IRF640源极和RS下端属于功率路径RS下端单独引一条线到总接地点不要把运放的反相输入线直接接到功率电流路径的铜皮上。STM32的供电也尽量用独立的5V来源。调试时如果只用USB给STM32供电USB的地线和12V功率电源的地线必须可靠连接否则会出现奇怪的共模干扰。还有一个很多人忽略的地方TO-220封装的IRF640金属背板本身就是漏极带上电源正电压。给MOS管装散热片时散热片和MOS管之间必须夹一层绝缘垫片不然散热片直接碰到机壳或者旁边元件轻则短路保护重则直接炸管。3.2 原理图设计要点原理图并不复杂但有几个细节需要单独说清楚。输入电源侧我串联一个1A自恢复保险丝再在电源端子反并联一个SS34肖特基二极管用来防止电源反接。12V电源进来之后一部分直接给负载回路供电另一部分给LM358运放供电。如果单独做板还需要加一级AMS1117降到5V给STM32最小系统供电Blue Pill开发板则可以直接从5V引脚输入。运放部分U1A接成电压跟随器用来缓冲两级RC滤波后的Vset避免后面的反馈回路反灌影响滤波。U1B是核心误差放大器反相输入端直接接IRF640源极输出端串联100Ω电阻再接栅极。栅极到源极之间加一个10kΩ下拉电阻防止STM32还没初始化时MOS管栅极悬空误开启。运放输出到反相输入之间预留一个47pF小电容位如果示波器看到自激可以补上这个电容压住高频增益。负载连接电源正极先到负载正端负载负端接IRF640漏极。很多人容易接反把负载放到源极和地之间那样采样电压就不等于MOS管源极电压了整个反馈逻辑都会乱。3.3 STM32关键代码下面只给核心代码完整工程里还需要初始化串口、ADC和时钟这里不占篇幅。// 72MHz主频, PA0 - TIM2_CH1, 20kHz PWM void pwm_init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Prescaler 1; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_Period 1799; TIM_TimeBaseStructure.TIM_ClockDivision TIM_CKD_DIV1; TIM_TimeBaseInit(TIM2, TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse 0; TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; TIM_OC1Init(TIM2, TIM_OCInitStructure); TIM_Cmd(TIM2, ENABLE); } // 设电流时ccr mA * (1800 / 330)限幅300mA void set_current_mA(float mA) { uint32_t ccr; if (mA 0) mA 0; if (mA 300) mA 300; ccr (uint32_t)(mA * 5.4545f); // 软启动从当前值逐步加到目标值 uint32_t cur TIM_GetCapture1(TIM2); if (ccr cur) { for (uint32_t i cur; i ccr; i 10) { TIM_SetCompare1(TIM2, i); delay_ms(5); } } TIM_SetCompare1(TIM2, ccr); } uint16_t adc_read_ch0(void) { ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5); ADC_SoftwareStartConvCmd(ADC1, ENABLE); while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) RESET); return ADC_GetConversionValue(ADC1); } float read_current_mA(void) { uint32_t sum 0; for (int i 0; i 64; i) { sum adc_read_ch0(); } float v_source (sum / 64.0f) * 3.30f / 4095.0f; return v_source / 10.0f * 1000.0f; }这里的3.30V是按STM32供电电压估算的。如果希望精度更高建议用万用表实测3.3V引脚对地电压把代码里的3.30f换成实测值再配合后面的两步校准电流误差就能压到很小。3.4 校准流程两步拉平系统误差STM32的3.3V供电本身有误差PWM滤波之后的电压也不是严格线性所以必须做校准。校准工具只需要一块四位半万用表不需要六位半。我的做法是先设置100mA串入万用表实测电流记下实际值再设置250mA记录第二个点。根据这两组数据算出一次方程的斜率和截距把这两个系数存到STM32内部Flash的某个页里。程序每次执行set_current_mA时先把目标电流乘上斜率再加上截距再换算成PWM比较值。这样常温下的误差基本能控制在0.1%以内比单纯用理论公式靠谱得多。4. 实测数据与问题排查4.1 一组实测数据稳定性供参考测试条件是电源电压12V负载用的是20Ω/10W功率电阻散热片已经装好环境温度25℃左右。把串口设定电流和万用表读数列在一起得到下面这组数据。设定值/mA实测值/mA5分钟后/mA1小时后/mA漂移量/mA100100.02100.03100.080.06200199.98200.01200.120.11300300.05300.10300.210.16从数据看一个小时内的漂移不到0.2mA这种表现对大多数LED老化、电池充电实验来说已经够用了。要注意的是这个漂移主要是采样电阻发热和STM32供电基准缓慢变化带来的如果想要更长周期更稳定的输出可以把RS换成0.1%精度的低温漂电阻并给VREF引脚用上独立基准芯片成本会略高但效果更硬。4.2 最容易翻车的5个问题我在调试过程中踩过不少坑整理成表供大家对照现象可能原因解决办法电流完全不受控直接冲到最大U1B反相输入没接MOS管源极反馈断开检查反相输入线路必须直接接在源极和RS之间一上电负载就过流栅极没有下拉STM32初始化前MOS管误开启栅极和源极之间加10kΩ电阻设定电流后输出纹波大PWM滤波不干净或地线回路有干扰确认两级RC参数示波器查看Vset纹波是否在5mV以内IRF640温度特别高电源电压过高MOS管承担太多压降压低输入电压或加大散热片300mA下尽量让Vds小于5V电流换挡时容易过冲直接切换PWM比较值没有软启动程序里每次只加一小步延迟几毫秒4.3 几条独家避坑经验采样电阻一定要做开尔文接法。普通两个焊盘直接接电流路径和运放输入焊盘本身的电阻会被大电流吃掉一部分造成源极电压测量点不在电阻本体两端。正确做法是从采样电阻两端各引一条细线到运放反相输入附近不要和大电流走线共用铜皮。300mA下焊盘电阻造成的误差可能不明显但既然是做“实验室级”细节还是值得抠的。另一个体会是校准系数别写在源码常量里。我一开始图省事把校准后的斜率和截距写死在代码里后来换了一个STM32板子3.3V基准不同整套数据又要重新改代码编译。现在我把两个系数开机时从Flash读出来串口发送CAL命令在线修改再也不用反复烧录。还有一个看起来很小但很实用的点IRF640的散热片固定螺丝不要拧太猛。TO-220的塑料外壳很脆拧过头可能导致内部晶片和底板接触不良表现为电流回读正常但MOS管温度异常高。我拆过好几片因为螺丝过紧导致特性变坏的管子后来都用扭矩很小的螺丝刀带过问题再没出现过。5. BOM清单与成本估算5.1 完整BOM清单下面这张表里的元器件基本都是电子市场能买到的常用料总成本很亲民。类别型号/规格数量用途/备注参考价(元)控制核心STM32F103C8T6最小系统板1PWM、ADC、UART12调整管IRF640N TO-2201线性区电流控制2双运放LM358N DIP-81U1A缓冲U1B误差放大1采样电阻10Ω 5W 1%1电流-电压转换1.5RC一级电阻4.7kΩ 0.25W1PWM低通滤波0.1RC二级电阻2.2kΩ 0.25W1PWM低通滤波0.1RC一级电容10μF 25V1低通滤波0.3RC二级电容10μF 25V1低通滤波0.3ADC滤波电阻1kΩ 0.25W1ADC输入低通0.1ADC滤波电容0.1μF1ADC输入低通0.1栅极电阻100Ω 0.25W1防止栅极自激0.1栅极下拉电阻10kΩ 0.25W1上电默认关断0.1补偿电容47pF1抑制运放自激可选0.1保护元件1A自恢复保险丝1输入过流保护0.5保护元件SS34肖特基二极管1电源反接保护0.3保护元件SMBJ12A TVS1输入浪涌吸收0.3连接器XH2.54 2P2电源输入和负载输出0.6散热器TO-220黑色铝散热片1配绝缘垫片和螺丝1.5洞洞板/PCB7x9cm洞洞板1手工焊接用1如果不算12V电源适配器和万用表总物料成本大约25元左右。这里面STM32最小系统板占了大头如果手头有现成开发板实际新增成本也就十块钱上下。12V电源可以用实验室现有的可调电源也可以用普通的12V/3A适配器注意电流余量要够。5.2 替代方案与器件升级LM358是性价比最高的选择但它不是轨到轨运放失调电压也比较大。如果预算允许可以把U1B换成OP07或者OPA2277这类低失调低漂移运放静态精度会更好。换成OP07之后电源电压和引脚要重新核对OP07不是单电源轨到轨给双电源或偏置处理会更麻烦不建议新手一上来就换。IRF640也可以用IRF540N替代两者引脚基本一致耐压和导通电阻略有区别。如果使用更低驱动电压的场景比如运放供电只有3.3V那就必须换成逻辑电平MOS管IRLZ34N否则IRF640的Vgs阈值会让你很被动。但这个项目里运放供电是12VIRF640的驱动不是问题。6. 最后的经验总结最后说一点我自己的体会。做这个恒流源之前我也用过成品模块、双二极管搭过固定电流源时间长了发现真正决定一个电源好不好用的往往不是原理多高级而是采样电阻热不热、地线怎么走、上电瞬间是否可控这些细节。这次把STM32和模拟闭环配合起来之后300mA以下做LED老化、电解电容充电等实验基本一次搞定。如果你后续想扩展完全可以把NTC温度保护、OLED电流显示和独立按键加上再把它做成一块独立的小型仪器面板。对刚接触运放闭环的朋友来说先把Vset和Rsense之间的关系想清楚后面调试会顺畅很多。这篇文章里的电路和代码足够平时实验室用了遇到问题也可以回头查一查第4节的排查表。
返回列表