Boost电路实战详解!(高效率同步整流,PID闭环追踪)

avatar
作者
筋斗云
阅读量:4

文章目录


寄语

提示:若想实战演练,请先熟悉文章操作流程哦,不然会有危险!!
我建了一个群,分享我个人做项目的经历和资源,纯个人爱好,一切免费,看自己空闲时间答疑,有想法的可以加QQ群280730348

大家好!鸽了两个月的电路博主回归啦,这段时间一直在忙研究生开学的事儿,也算是适应了环境。加上最近到网上弄了一个boost电路的单子,正好趁这个机会,给想要做Boost升压电路的小伙伴们,一次实战演练交流!

下面是注意事项

  • Boost电路在开始测试时建议接一个大电阻的输出负载,原因在于输出带有电容,电容一直在储能,给电容电压一个输出。博主实测过,Buck电路空载测试没问题,但是Boost电路不要空载测试,实际电感充电时间会很小,容易击穿滤波电容。
  • 板载一个启动按键,控制PID追踪的启动和关闭,初始为关闭。按一下就能开启,再按一下就会关闭。
  • PWM1和PWM2的接线一定要对应好,由于是高级定时器一互补输出,所以软件内部只需要给一个PWM值就能控制两路输出。PWM1和2接反会导致占空比反过来控制,比如本来20%的占空比对应输出15V,但是PWM1和2接反就会导致80%的占空比,输出电压会飙上去。
  • 先开控制器电源,再开主电路供电电压,顺序不能反。

什么是BOOST电路

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。
如上图所示,这是最为基础的Boost升压拓扑,包含六个器件,从左至右分别是:
直流电源储能电感开关管肖特基二极管储能电容负载

  1. 直流电源提供输入电压
  2. 储能电感交换能量
  3. 开关管实现电路的开启和断开
  4. 肖特基二极管实现电路的被动开关断
  5. 储能电容实现对电压的储能
  6. 负载,顾名思义,消耗能量

电路的核心在于储能电感开关管,在小功率场合下,博主喜欢用Mos管作为开关器件。Mos管的特性就在于是电压控制器件,拿常见的IRF3205Mos管来说,总共有三个管脚,分别是G、D、S。想要控制开关管很简单,只需在GS端加上一定的电压,就可以控制DS导通或者断开,我们其实可以把Mos管看作一种高速的机械开关

那我们来说一下电路的原理,如何实现电能的变化呢?关键点就在高速开关状态下的电感储能。电路总共存在着两个工作状态,一个是开关管导通的工作状态,一个是开关管截至的工作状态。

首先我们看第一种工作状态,开关管处于导通状态。导通状态时,电流是怎么流通的呢?首先电流肯定会从输入电源流入进来,经过储能电感,此处我们注意,电流的流经方向是从左至右。当电流流经到Mos管和肖特基二极管的交点时,是不是就要考虑往哪个方向走了?那么很简单,记住这一点,电流总会往更容易流的地方跑。Mos管的特性就是导通电阻很小,相较于二极管而言,它对电流非常友好,所以在都可以走的前提下,电流会非常高兴的往Mos管那块跑。所以根据这个特性,电流流到了Mos管后,接下来就不会往负载那边流了,而是回到了电压输入负极,这样就完成了第一种工作状态。这个时候咱们的输出电压等于多少?其实就等于储能电容的电压大小,而储能电容电压大小其实就是输入电压减去二极管的压降电压,因此我们就可以得知这种状态下的输出电压。
在这里插入图片描述

那么我们再看第二种工作状态,开关管处于截至状态。开关管处于截至状态时,其实就相当于开关断开。这个时候电流没路可走了呀,所以就只能往肖特基二极管的那个方向走了,那么电流的方向就是流经电感再经过肖特基二极管再流向负载再回到输入电压的负极了。这个时候,由于负载能够消耗我们的电能了,所以咱们电路中的能量,就要全部往外提供了,怎么办,就不能给电感充电了。这个时候,电感就生气了,说不给我吃饭是吧,我给你对着干,于是在电感两端,就产生了与电流方向相反的电动势,也就是左负右正的反向电动势。为什么会产生反向电动势呢,其实跟电感本身的特性相关,这个请自行查阅相关知识啦。我们知道,这个反向电动势其实跟第一种工作状态下的充电时长有关系,充电的时间越长,反向电动势就越大。我们可以画一画电路图,此时输出的电压等于啥子,就等于输入电压加上反向电动势再减去肖特基二极管的压降。是不是就得到了比之前电压更高的直流电压了呢?
在这里插入图片描述

好了明白了这两种工作状态,我们从宏观的角度来看,输出电压变高主要由什么来决定呢?答案是电感的反电动势的大小,而电感的反电动势大小与充电时长有关系,也就是说我们电感充电越久,第一种工作状态越久,那么充电时长就会越久,电感的反电动势自然会越高,自然从宏观角度来看输出电压就会越高。当然电感不可能一直充电,boost电路也不可能把小电压无限升高,这个过程跟很多因素有关。按照经验来说,一般boost电路充电时间不要长于一个周期的90%,当然也跟你的储能电容有关系,假设你储能电容只能扛100V,你占空比拉到90%的话,输出电压加到了200V,这个时候你可能就会体验到电容开花的效果哦。
在这里插入图片描述
好了,那么简单总结就是,我们单片机只需要输出一个PWM,通过控制PWM的占空比,可以改变输出电压的大小。占空比越高,输出电压越高,占空比越低,输出电压越低。占空比与输入电压输出电压的关系是:D=(VO-VI)/VO,其中输出电压为VO,输入电压为VI,输出电压一般都会比输入电压要高,当然肖特基二极管还是会有压降的(为了严谨!)

BOOST同步升压电路

我们来引入一个新的概念,叫做同步升压

万事万物都有其存在合理性,为什么要有这玩意儿的存在,原因无他,我们要把开关电源的优势体现出来。优势是啥,无非就是低损耗高效率呗。基本的boost拓扑结构显而易见的缺点是什么?很明显呀,那个肖特基二极管你看着他不碍眼么,反正我是瞅着他不咋顺眼,二极管那是啥,被动导通,抵抗能力杠杠强,损耗也大。那我们换个思路,找个主动的器件,不咋抵抗,不挺好么!

瞧,想主动,那我们可不可以把肖特基二极管,换成导通电阻超小的Mos管呢,答案是,当然没有问题。这样下来,电路中就有两个Mos管了,话不多说直接上图:
在这里插入图片描述
为了电路安全着想,在同一瞬间,我们要保证两个Mos管只有一个导通,他们两个Mos管可以同时截至,但是不能同时导通,为什么呢?因为两个导通电阻都很小,电流去哪一路都没问题,这个时候他们就会很纠结,纠结的话就会拉帮结派,然后干架,这样电流就会顺利的引爆你的电路,给你干穿。

那其实只要让他们工作状态完全相反即可,我们可以利用芯片去实现。比如半桥驱动芯片IR2104S,根据它的外围电路,你只需要输入一个PWM信号,输出就能得到LO和HO两路输出信号,其中HO信号与输入PWM信号相同,LO信号与输入信号相反。

还有一种方式是直接通过软件去实现,拿STM32F103C8T6来讲,其内部的高级定时器存在着一个功能是互补输出。比如TIM1的CH1为PA8,TIM1的CH1N为PB13,这两个口只要设置好了,你只需要控制TIM1的CH1通道PWM输出,就可以控制两路相反的PWM输出。我们今天的方案就拿第二种方式来弄!

设计要求

在这里插入图片描述
由于博主已经脱离了电力电子实验室,非常无奈,手头上连个滑动变阻器都没有,别问,问就是没钱。就只能做这种小的,能够承受的,当然根据博主之前设计的经验,我的这种拓扑结构,散热弄好了100w轻轻松松。现在就当给大伙儿打个样,入入门~

设计方案

设计方案如下:主电路选用boost同步升压拓扑,驱动电路选择光耦驱动。选用STM32F103C8T6作为此次电路的MCU控制单元,其中驱动电路的输入两路PWM为MCU的高级定时器一输出互补的PWM波,电压检测单元通过运放采集输出电压并缩放10倍左右,送入单片机内部进行检测,当单片机检测到了电压后经过运算显示到OLED屏幕上。内部采用PID算法对输出电压进行跟踪,若输出电压大于目标电压值则降低boost电路的占空比,若输出电压小于目标值则提高boost电路的占空比。

这里插一句专业的,开关电源内部的损耗大致可以分为:开关损耗导通损耗附加损耗电阻损耗,其中开关损耗和导通损耗是典型的开关电源内部最主要的两个损耗源,控制这两个损耗的典型方法是使功率开关导通期间的电压降最小。采用同步整流技术,将效率提高1%~6%;选取导通电阻更低、满足要求的开关管;确保开关管工作在饱和状态,具有足够驱动能力;电感选用铁硅铝磁芯,降低铁损。

Mos管选型:其实主要就是看DS可承受电压,导通电阻和电流,我这里选的是IRF3205,导通电阻6.5mΩ左右,很不错。DS电压55V左右,具体的话去看手册吧,记得根据你输出最大电压选型,不要超过了DS电压,最好是留一点阈值。
在这里插入图片描述

储能电感选型:打公式比较麻烦,我直接截图
在这里插入图片描述

储能电容选型:无它,手熟而,我的经验选型330uf,50V左右即可。

驱动电路

它还是值得单独拿出来讲讲的,我还是对光耦驱动情有独钟,为什么呢?光耦可隔离呀,烧光耦还是烧我的单片机,这个我还是分得清楚的。之前的IR2104存在的一个弊病就是,他不隔离,如果你芯片烧了很有可能就波及到IR2104了,所以用光耦隔离一下,可以有效降低危险。

驱动电路的话通过光耦驱动芯片TLP250H进行驱动。别用TLP250,因为光耦也分高频和低频,我受过罪,整体驱动电路采用自举驱动的原理。驱动的PWM波通过单片机产生,单片机通过高级定时器一产生互补的PWM波,分别称之为PWM1和PWM2。因为单片机开关频率有时候会受到外界的干扰,TLP250H这个光耦芯片也有一定的开关频率限制,因此通过反相器74HC04产生反向的波形,以此来限制住开关的速度大小。输出采取自举驱动原理,本质上就是通过自举二极管RS1M也可以用ss34和ss56,主要看可以承受的反向电压,我是一劳永逸,RS1M可以承受反向电压1KV,这个反向电压跟你电路最大输出有关系的和自举电容2.2UF来实现对HO1开关的充电放电,从而使得电路图中的Q2开关断。此处请自行搜索自举电路的驱动原理

整体存在着两种工作状态

第一种状态是PWM1为高电平,PWM2为低电平。这种情况下通过反相器在U27的光电二极管的阴极得到了PWM1的反向信号低电平,在U26的光电二极管的阴极得到了PWM2的反向信号高电平。因此在这一瞬间,由于U26光电二极管没有产生电压差,U27产生了电压差,故U26光电二极管未导通,不能产生光电信号,U27可以产生光电信号,LO1吸收能量产生高电平,HO1未吸收能量产生低电平。因此在输出端口处HO1驱动的mos管闭合,LO1驱动的mos管开启。

第二种状态与第一种完全相反,即HO1驱动的mos管开启,LO1驱动的mos管关闭。
在这里插入图片描述

电压采样电路

直流电压采样电路如下,通过运放实现采集电压的缩放。VOUT是我们检测到的直流电压,这个地方可以直接连接到主电路的输出电压口,假设输出电压是15V,通过R31和R32电阻分压,在运放的3号口能得到15V1/(10+1)的电压也就是15/11v。根据运放的虚短虚断,2号口电压也为15/11v。再通过R33和R34电阻分压,在运放的1号口得到15/1111/10=1.5v的电压。再通过一个电压跟随器降低电压阻抗,最终到输出电压口得到1,5V电压。因此输入15V电压,可以输出1.5V电压。这个1.5V的电压送入单片机内部进行检测,当单片机检测到1.5V以后,通过内部乘以电压系数就能够得到正确的输出电压。此处电压缩放比为10倍,通过改变R25和R24的大小,即可得到不同的缩放倍数。
在这里插入图片描述

总体电路

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码

代码部分的话,我就讲几个比较关键的点儿吧

主电路代码
注释的比较详细了,while循环里面其实就是对启动按键进行一个扫描已经OLED显示屏显示输出电压和目标电压,这个加VOUT+0.11的意思是其实是一种矫正,因为通过软件仿真我看到追踪的电压一直在14.89附近,实际测得电压又是15.02V,所以就懒得改了。其实只要改个电压系数就好了,我图省事儿大家不要学我哈。

//主电路代码 #include "delay.h" #include "sys.h" #include "usart.h" #include "timer.h" #include "show.h" #include "oled.h" #include "adc.h" #include "key.h" #include "main.h" #include "pid.h" //接线定义 /* OLED屏幕:SDA->PA5   SCL->PA6 电压检测:电压->PB0   启动关闭按键:PA11 boost输出:PWM1->PA8,PWM2->PB13 */   //定义参数 float V_OUT=0;   //检测到的显示输出电压 float now_v=0.0f;//检测到的当前输出电压 float target_v=15.00f;//追踪的目标值 u16 pwm=0;       //输出的占空比 u8 work_mode=0;  //为0的时候PID不工作,为1的时候PID工作  int main(void) {	 	u8 key; 	delay_init();	    	 //延时函数初始化	   	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 	uart_init(115200);	     //串口初始化为115200 	Init_adc();              //初始化ADC 	KEY_Init(); 	init_boost_PID(15.0); 	TIM2_Int_Init(9999,71);  //初始化定时器,每次执行定时时间为10ms,执行一次PID 	TIM3_Int_Init(999,71); 	 //初始化定时器,每次执行定时时间为1ms,500ms执行一次电压平均 	BOOST_PWM_Init();	       //初始化boost电路输出,开关频率20KHz     OLED_Init();			 //初始化OLED   	OLED_Clear();            //清屏OLED 	start_view();   while(1) 	{ 		key=KEY_Scan(1); 		if(key==KEY0_PRES)work_mode=!work_mode;         OLED_ShowNum(72,3,(u16)(V_OUT+0.11),2,16);            //显示输出直流电压整数位 		OLED_ShowNum(96,3,(u16)((V_OUT+0.11)*100)%100,2,16);  //显示输出直流电压小数位 		OLED_ShowNum(72,5,(u16)target_v,2,16);            //显示输出直流电压整数位 		OLED_ShowNum(96,5,(u16)(target_v*100)%100,2,16);  //显示输出直流电压小数位 	} }   

定时器代码
定时器二的作用是执行PID,每隔10ms执行一次PID。work_mode这个参数是通过按键扫描来改变的,等于1就启动PID,=0就把占空比拉到一个定值,避免过压。boost_pid是PID里面的一个函数,就是进行一个PID的运算,这里为了看效果,PID的参数没有调很大。

定时器三的作用是每隔1ms采集一次电压数据,累计500次以后取一个平均,这样显示的数据就会更加稳定一点。V_xishu是电压放大的倍数,根据我们电路实际的缩放倍数来决定,我们在这里由于缩放倍数是10,所以再main.h文件里面设定为10.0。

高级定时器一就是配置互补输出PWM

#include "timer.h" #include "usart.h" #include "adc.h" #include "main.h" #include "pid.h"  /*boost同步整流电路配置*/ #define BOOST_TIMx TIM1 #define BOOST_Plus 5//初始化占空比为0.5%,高电平有效时的低电平占空比  #define BOOST_ARR 3599//重装载值3600 #define BOOST_PSC 0//分频系数1 extern __IO uint16_t ADC_ConvertedValue[2]; float ADC_ConvertedValueLocal;   void TIM2_Int_Init(u16 arr,u16 psc) {     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure; 	NVIC_InitTypeDef NVIC_InitStructure;  	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能  	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 计数到5000为500ms 	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率   	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim 	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式 	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位  	TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_Trigger,ENABLE); 	 	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  //TIM2中断 	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级 	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  //从优先级3级 	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能 	NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器  	TIM_Cmd(TIM2, ENABLE);  //使能TIMx外设 							  } void TIM2_IRQHandler(void)   //TIM2中断 { 	if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源  	{ 		if(work_mode==1) 		{ 		    now_v=(float)ADC_ConvertedValue[0]/4096*3.3; 		    pwm = boost_pid((now_v/3.3*4096),5,2600);             set_pwm(TIM1,1,pwm,2600);		 		} 		else 		{ 			pwm=500; 		    set_pwm(TIM1,1,pwm,1000);		 		} 		 		TIM_ClearITPendingBit(TIM2, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源  	} }  void TIM3_Int_Init(u16 arr,u16 psc) {     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure; 	NVIC_InitTypeDef NVIC_InitStructure;  	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能  	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 计数到5000为500ms 	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率   	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim 	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式 	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位  	TIM_ITConfig(TIM3,TIM_IT_Update|TIM_IT_Trigger,ENABLE); 	 	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断 	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级 	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级 	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能 	NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器  	TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设 							  } void TIM3_IRQHandler(void)   //TIM3中断 { 	static float V_zong=0.0f; 	static u16 count=0; 	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源  	{ 		count++; 		ADC_ConvertedValueLocal=(float)ADC_ConvertedValue[0]/4096*3.3f; 		V_zong+=ADC_ConvertedValueLocal; 		if(count>=500)       //500ms进行一次计算 		{ 			count=0; 			V_OUT=V_zong/500*V_xishu; 			V_zong=0; 		} 		TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源  	} }  /*boost电路同步整流PWM函数PA8、PB13*/ void BOOST_PWM_Init(void)//boost电路输出互补PWM波形(PA8、PB13) {    	GPIO_InitTypeDef GPIO_InitStructure; 	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; 	TIM_BDTRInitTypeDef TIM_BDTRInitStruct; 	TIM_OCInitTypeDef TIM_OCInitStruct; 	 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE); //使能PORTA,B时钟 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); 	//初始化GPIO,PA8 	 	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//端口复用 	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8; 	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; 	GPIO_Init(GPIOA,&GPIO_InitStructure); //PA8 	 	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13; 	GPIO_Init(GPIOB,&GPIO_InitStructure);//PB13 		 	//初始化时具单元 	TIM_DeInit(BOOST_TIMx); 	 	TIM_TimeBaseInitStruct.TIM_ClockDivision=0; 	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up; 	TIM_TimeBaseInitStruct.TIM_Period=BOOST_ARR; 	TIM_TimeBaseInitStruct.TIM_Prescaler=BOOST_PSC; 	TIM_TimeBaseInit(BOOST_TIMx,&TIM_TimeBaseInitStruct); 	 	//将输出通道2初始化为PWM模式1 	 	TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1; 	TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable; 	TIM_OCInitStruct.TIM_OutputNState=TIM_OutputNState_Enable; 	TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High; 	TIM_OCInitStruct.TIM_OCNPolarity=TIM_OCNPolarity_High; 	TIM_OCInitStruct.TIM_OCIdleState=TIM_OCIdleState_Set; 	TIM_OCInitStruct.TIM_OCNIdleState=TIM_OCNIdleState_Reset; 	TIM_OCInitStruct.TIM_Pulse=BOOST_Plus; 	TIM_OC1Init(BOOST_TIMx,&TIM_OCInitStruct); 	//使能预装载寄存器 	TIM_OC1PreloadConfig(BOOST_TIMx,TIM_OCPreload_Enable); 	 	//死区和刹车功能配置 	 	TIM_BDTRInitStruct.TIM_OSSIState=TIM_OSSIState_Disable; 	TIM_BDTRInitStruct.TIM_OSSRState=TIM_OSSRState_Disable; 	TIM_BDTRInitStruct.TIM_LOCKLevel=TIM_LOCKLevel_1; 	TIM_BDTRInitStruct.TIM_DeadTime=3; //40.92ns 	TIM_BDTRInitStruct.TIM_BreakPolarity=TIM_BreakPolarity_Low; 	TIM_BDTRInitStruct.TIM_Break=TIM_Break_Disable; 	TIM_BDTRInitStruct.TIM_AutomaticOutput=TIM_AutomaticOutput_Enable; 	TIM_BDTRConfig(BOOST_TIMx,&TIM_BDTRInitStruct); 	 	//使能自动重装载 	TIM_ARRPreloadConfig(BOOST_TIMx,ENABLE); 	 	//开启定时器 	TIM_Cmd(BOOST_TIMx,ENABLE); 	 	//主输出使能 	TIM_CtrlPWMOutputs(BOOST_TIMx,ENABLE); }  /*选择通道函数*/ void set_pwm(TIM_TypeDef* TIMx,u8 chx,u16 prec,u16 up) { 	//判断输入参数是否正确 	if(chx<1||chx>4) 		return; 	if(prec>up) 		prec=up; 	//根据输入的通道设置PWM占空比 	switch(chx) 	{ 		case 1:TIM_SetCompare1(TIMx,prec);break; 		case 2:TIM_SetCompare2(TIMx,prec);break;      		case 3:TIM_SetCompare3(TIMx,prec);break; 		case 4:TIM_SetCompare4(TIMx,prec);break;            	} } 

PID代码
带有部分注释,需要修改的其实就是init_boost_PID那个函数,里面有一个pid1.sv,那个是我们要追踪的目标值,而boost_pid里面的Now,是我们采集到的输出电压值。

#include "pid.h" #include "main.h" PID_Struct pid1;   float boost_pid(float NOW,float SIGNLE_ADD_NUM_LIMIT,float SUM_OUTPUT_NUM_LIMIT)//SIGNLE_ADD_NUM_LIMIT是单次增加最大值 如100即为单次转换输出不能超过+-100 { 	//SUM_OUTPUT_NUM_LIMIT 是总输出限位 如100 即总输出不能超出+-100的范围 防止长时间低于或高于 对于突变反应不及时 	static float OUT=150; 	if(work_mode==0)OUT=500; 	pid1.Pv=NOW; 	pid1.Ek=pid1.Sv-pid1.Pv; 	pid1.Pout=pid1.Kp_P*(pid1.Ek-pid1.Ek_1); 	pid1.Iout=pid1.Kp_I*pid1.Ek*pid1.T/pid1.Ti; 	pid1.Dout=pid1.Kp_D*pid1.Td*(pid1.Ek-pid1.Ek_1-pid1.Ek_1+pid1.Ek_2)/pid1.T; 	pid1.OUT_Single=pid1.Pout+pid1.Iout+pid1.Dout; 	if(pid1.OUT_Single>SIGNLE_ADD_NUM_LIMIT)pid1.OUT_Single=SIGNLE_ADD_NUM_LIMIT; 	else if(pid1.OUT_Single<-SIGNLE_ADD_NUM_LIMIT)pid1.OUT_Single=-SIGNLE_ADD_NUM_LIMIT; 	OUT+=pid1.OUT_Single; 	if(OUT>SUM_OUTPUT_NUM_LIMIT)OUT=SUM_OUTPUT_NUM_LIMIT; 	//else if(OUT<-SUM_OUTPUT_NUM_LIMIT)OUT=-SUM_OUTPUT_NUM_LIMIT; 	else if(OUT<0)OUT=0; 	pid1.Ek_2=pid1.Ek_1; 	pid1.Ek_1=pid1.Ek; 	return OUT; }      void init_boost_PID(float voltage_set) { 	pid1.Kp_P=0; 	pid1.Kp_I=1; 	pid1.Kp_D=0; 	pid1.Sv=voltage_set*0.1/3.3*4096-14; 	pid1.T=1;//Ms 	pid1.Td=2.5; 	pid1.Ti=150; 	pid1.Pv=1000; 	pid1.Ek_2=0; 	pid1.Ek_1=0; 	pid1.Ek=0; } 

实物图

在这里插入图片描述
在这里插入图片描述


总结

测试结果
第一问完全满足,第二问负载调整率接近为0,第三问变换器效率95%。稍后会把测试视频上传。

有任何疑问到评论区下方留言,我是很乐于回答问题的,记得点个关注点赞收藏,我这要求不过分吧哈哈哈哈。

所有资料如下:

链接:https://pan.baidu.com/s/1MNfkIqY_M__j8LUZjMNjTA
提取码:yd15
–来自百度网盘超级会员V4的分享

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!