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

文章目录

  • 寄语
  • 什么是BOOST电路
  • BOOST同步升压电路
  • 设计要求
  • 设计方案
    • 驱动电路
    • 电压采样电路
  • 总体电路
  • 代码
  • 实物图
  • 总结


寄语

提示:若想实战演练,请先熟悉文章操作流程哦,不然会有危险!!
我建了一个群,分享我个人做项目的经历和资源,纯个人爱好,一切免费,看自己空闲时间答疑,有想法的可以加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。再通过R25和R23电阻分压,在运放的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);	     //串口初始化为115200Init_adc();              //初始化ADCKEY_Init();init_boost_PID(15.0);TIM2_Int_Init(9999,71);  //初始化定时器,每次执行定时时间为10ms,执行一次PIDTIM3_Int_Init(999,71); 	 //初始化定时器,每次执行定时时间为1ms,500ms执行一次电压平均BOOST_PWM_Init();	       //初始化boost电路输出,开关频率20KHzOLED_Init();			 //初始化OLED  OLED_Clear();            //清屏OLEDstart_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为500msTIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_timTIM_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为500msTIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_timTIM_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,PA8GPIO_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); //PA8GPIO_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模式1TIM_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.92nsTIM_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;//Mspid1.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的分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/126722.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hadoop生态圈中的Hive数据仓库技术

Hadoop生态圈中的Hive数据仓库技术 一、Hive数据仓库的基本概念二、Hive的架构组成三、Hive和数据库的区别四、Hive的安装部署五、Hive的基本使用六、Hive的元数据库的配置问题七、Hive的相关配置项八、Hive的基本使用方式1、Hive的命令行客户端的使用2、使用hiveserver2方法操…

Inno Setup 打包的文件以管理员权限运行

在 Inno Setup 安装目录中找到文件 SetupLdr.e32&#xff0c;用软件 ResourceHacker 打开。如下图&#xff0c;点开清单&#xff0c;找到 <requestedExecutionLevel level"asInvoker" uiAccess"false"/></requestedPrivileges>改为 <requ…

hadoop-MapReduce

分布式计算模型MapReduce 1.理解MapReduce设计思想 2.理解MapReduce分布式计算的基本原理 3.掌握使用Java进行MapReduce编程 4.掌握在Hadoop集群中提交MapReduce任务 1. MapReduce设计思想 1.1 什么是MapReduce 1&#xff09;MapReduce是一个分布式计算框架 它将大型数据操作…

【MySQL】数据库基础知识

本文基于Linux的MySQL 文章目录 一. 什么是数据库二. 主流数据库三. 服务器&#xff0c;数据库和表的关系四. MySQL架构五. SQL语句分类结束语 一. 什么是数据库 数据库本质是对数据内容存储的一套解决方案 如何理解呢&#xff1f; 首先&#xff0c;说到数据内容存储&#xff…

解决防火墙导致虚拟机不能ping通宿主机的问题

今天&#xff0c;无缘无故的&#xff0c;虚拟机突然用不了&#xff0c;网络连上不了&#xff0c;一番折腾翻找&#xff0c;最后才发现&#xff0c;是因为虚拟机ping不同宿主主机了&#xff0c;连网关都ping不通了&#xff0c;但是&#xff0c;宿主主机却可以ping通虚拟机 。 最…

element-ui dialog弹窗 设置点击空白处不关闭

根据官网提供方法 场景&#xff1a;vue实现的网站有两个弹窗同时出现时&#xff0c;关闭报警&#xff0c;批量进度条弹窗也关闭了&#xff0c; 1、每一个页面都有可能出现的报警弹窗&#xff0c; 2、页面a批量操控硬件添加操作的进度条弹窗 开始以为是因为点击报警弹窗&#…

高效数据湖构建与数据仓库融合:大规模数据架构最佳实践

文章目录 数据湖和数据仓库&#xff1a;两大不同理念数据湖数据仓库 数据湖与数据仓库的融合统一数据目录数据清洗和转换数据安全和权限控制数据分析和可视化 数据湖与数据仓库融合的优势未来趋势云原生数据湖自动化数据处理边缘计算与数据湖融合 结论 &#x1f389;欢迎来到云…

利用python进行视频下载并界面播放快速下载素材

工具&#xff1a;python designer&#xff08;python自带&#xff09;:UI界面设计工具 VLC&#xff1a;视频播放工具 需要的库如下&#xff1a; import os,platform os.environ[PYTHON_VLC_MODULE_PATH] "./vlc-3.0.14" import vlc from 脚本 import Player from …

STM32 硬件IIC 控制OLED I2C卡死问题

#更新通知&#xff1a;2023-09-06 STM32L151 固件库 使用I2C 太难了&#xff0c;又宕机了&#xff0c;建议不要在固件库版本上尝试硬件IIC 了&#xff0c;一般人真用不了&#xff0c;直接使用软件模拟的&#xff0c;或者不要使用固件库了&#xff0c;用HAL 库吧&#xff0c;据说…

APP启动优化Android篇

背景 为什么重提启动优化&#xff1f;首先&#xff0c;用户进入APP唯一的路径就是启动&#xff0c;这是体验核心链路的第一环。启动分为冷启动、热启动和温启动&#xff0c;本文中「启动」一词如果没有特别说明&#xff0c;均为冷启动。启动时间过长&#xff0c;会造成用户流失…

C++内存泄露

目录 1.什么是内存泄露 2.内存泄露的危害 3.如何解决内存泄露等相关的问题 1.什么是内存泄露 在C/C中 &#xff0c;我们申请了资源&#xff0c;因为一些原因忘记对申请的资源进行释放&#xff0c;或者因为异常安全等问题没有进行释放就会造成内存泄露的。 2.内存泄露的危害…

【好书推荐】《速学Linux:系统应用从入门到精通》

目录 前言一、为什么学习Linux系统二、Linux系统的应用领域&#xff11;.Linux在服务器的应用&#xff12;.嵌入式Linux的应用&#xff13;.桌面Linux的应用 三、Linux的版本选择1、经验人士使用的Debian2、以桌面应用为主的Ubuntu3、以经典桌面配置为主的Mint4、社区企业操作系…

【Docker】用Dockerfile制作个人的镜像文件

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 七七的闲谈 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f…

《DevOps实践指南》- 读书笔记(一)

DevOps实践指南 Part 1 DevOps 介绍精益运动敏捷宣言 1. 敏捷、持续交付和三步法1.1 制造业价值流1.2 技术价值流1.2.1 聚焦于部署前置时间1.2.2 关注返工指标——%C/A 1.3 三步工作法&#xff1a;DevOps 的基础原则 2. 第一步&#xff1a;流动原则2.1 使工作可见2.2 限制制品数…

力扣|找出和所对应的两数的下标

从零开始刷力扣&#xff08;bushi 题目放在这&#xff1a; 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出和为目标值target的两个整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一…

提升你的Android开发技能:从AR/VR沉浸到UI设计和故障排除

文章目录 探索最新AR/VR应用在教育、游戏、医疗等领域的应用教育领域游戏领域医疗领域 深入了解Android内存管理与性能优化的方法与技巧垃圾回收机制内存泄漏使用弱引用避免过度渲染内存优化图像优化延迟加载Android中的调试技术应用程序分析 分享如何提高Android应用的易用性和…

【算法专题突破】滑动窗口 - 长度最小的子数组(9)

目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后&#xff1a; 1. 题目解析 题目链接&#xff1a;209. 长度最小的子数组 - 力扣&#xff08;Leetcode&#xff09; 要注意的是&#xff0c;题目给的是正整数&#xff0c; 而题目要求并不难理解&#xff0c;就是找最短的…

领域驱动设计:领域事件

文章目录 领域事件识别领域事件领域事件相关案例领域事件总体架构 领域事件 领域事件是领域模型中非常重要的一部分&#xff0c;用来表示领域中发生的事件。一个领域事件将导致进一步的业务操作&#xff0c;在实现业务解耦的同时&#xff0c;还有助于形成完整的业务闭环。 举例…

【面试专题】Spring篇②

&#x1f4c3;个人主页&#xff1a;个人主页 &#x1f525;系列专栏&#xff1a;Java面试专题 目录 1.spring-bean的循环依赖 2.springMVC执行流程 3.Springboot自动配置原理 4.Spring框架常见的注解&#xff08;Spring&#xff0c;SpringMVC&#xff0c;SpringBoot&#x…

qsort 函数的使用

一、qsort 函数的形式 1.1使用 qsort 函数包含的库 1.2qsort 函数的参数 qsort&#xff1a;对数组的元素进行排序 1.3参数中的 compar 函数 struct stu {char name[20];//姓名int age;//年龄double grade;//成绩 }; int cmp_name(void* p1, void* p2) {//如果按照姓名排序ret…