在STM32F334上开发降压转换器:工作原理,计算,原型设计

在我的前两篇文章中,我讨论了基于STM32F334R8T6微控制器的电源模块和控制板,它们是专门为实现功率转换器和电驱动器的控制系统而创建的。 还考虑了一个DC / AC转换器的示例,这只是一个演示,而不是完整的结构。 现在是时候做一些简单但有用的,最重要的事情了。

有关项目和电力电子设备的大多数问题都与特定的拓扑有关:有人对学习PFC控制算法感兴趣,有人想学习如何构建LLC半桥,但是最流行的拓扑无疑是降压。 毕竟,降压转换器(又名降压转换器)是最有趣的项目的主要驱动器:这是LED灯的驱动器,是太阳能电池板,充电器的MPPT控制器的基础。

该网络有很多关于降压的信息,包括数据表,但分散的信息,我个人还没有碰到能详细描述创建具有数字控制的降压转换器的过程的材料。 现在该修复它了。 几乎没有数学,解释是“在手指上”,因此对于以某种方式与电子学联系在一起的每个人都将很有趣。



引言


首先,您需要了解我们最终想要得到什么以及我们拥有什么介绍。 降压拓扑结构是降压型的,也就是说,它允许您构建降压型电压转换器。 如您将在后面看到的那样,降压转换器的输出电压几乎线性取决于输入电压,因此您需要添加反馈。 今天,我将讨论最简单的电压反馈,它是最直观的,可让您了解操作原理,而此反馈足以执行大多数任务。

在本文的最后,我们将获得一种根据“同步降压”拓扑结构工作的稳定电压源,该电压源通过数字控制在相当高的频率下运行,并使用高分辨率PWM(HRPWM)在STM32F334R8T6上实现。 输入电压范围是15 ... 60V,输出电压是12V,最大输出电流是2A。

第1章拓扑降压原理


我会从最基本的方面开始讲,并将逐步改进我们的转换器,因为 “同步降压”是改进版本的一个版本,具有更高的效率和控制复杂性。 您可能使用的拓扑的基本版本如下:



此拓扑结构用于低功率电压转换器,例如,为数字电路和其他低功率设备供电。 降低设备中使用的dc / dc的可能性可能是根据此拓扑在微电路上实现的。 这种芯片的示例是LMR16006

该电路的工作原理非常简单,将PWM信号提供给晶体管VT1,其工作本身分为两个阶段,一个接一个地交替:

  • LC电路中的能量存储阶段。 在此阶段,晶体管VT1断开,电流流过晶体管到达负载,同时将能量存储在电感器和输出电容中:

  • 放电阶段。 在这个阶段,晶体管VT1闭合,然后乐趣开始。 油门-如果向其施加电势(打开VT1),就会积蓄能量,如果电势消失(VT1处于关闭状态),则会释放能量。 同时,他不仅要提供能量,而且要保存电流值及其方向,因此,要使用此属性,您需要添加VD1二极管来闭合电路,因为电流仅在闭合电路中流动:


当我在第6-7课上熟悉这种拓扑时,我并没有立即理解为什么二极管在第一阶段不导通电流,现在看来很平常,但是我认为值得一提。 当VT1打开时,电势+ VIN(例如+ 20V)分别施加到二极管VD1的阴极,而地电势分别施加在二极管的阳极。 为了使电流流过二极管,必须正好相反:阳极上的电势必须大于阴极上的电势,因此,在降压时,在储能阶段,二极管“闭合”。 在放电阶段,二极管已经关闭电路,电位+ VIN不会作用于其阴极,也不会“锁定”它。 我希望我能清楚地解释。

然后,您应该问一个问题:“如果我们向输入施加20V的电压,那么输出电压将是多少?”。 和往常一样,一切都很简单:



从公式中可以看出,输出电压线性地取决于我们提供给晶体管VT1的PWM信号的占空比。 如果有人不知道或忘记了“占空比”,则这是晶体管处于打开状态的时间与周期长度之比。 该系数可以取0到1或0到100%的值。 此外,在控制转换器时,我们将使用该特定数字进行操作,但是为了理解其本质,让我们将这种关系替换为公式:



降压转换器的工作频率是恒定的,并且是在设计期间选择的,它在工作期间不会改变,因此周期(T)是恒定的。 事实证明,输出电压直接取决于两个物理量:

  • 从打开上晶体管(VT1)的时间开始,它断开的时间越长,则有更多的时间积聚在LC滤波器中,因此输出电压越高;
  • 从输入电压来看,例如,如果我们将填充量固定为50%,并将Vin从20V更改为40V,那么输出电压也会从10V更改为20V。

我认为总体情况和工作原理已经开始吸引您,让我们现在对其进行修复,并查看实际的波形图,并在实践中检查该比例。 我已经组装了一个装有10 W LED的降压布局。 我使用了示波器的3个通道,这些通道包括在以下几点中:



经验1-输入电压(Vin)恒定为20V,占空比会变化

  • Vin = 20V,D = 25%,Vout = D * Vin = 0.25 * 20V = 5V

  • Vin = 20V,D = 50%,Vout = D * Vin = 0.5 * 20V = 10V


从波形上可以看出,输出电压和占空比之间的关系是正确的。 当然,这是一个“理想化”的实验;实际上,输入电压不稳定并且在相当宽的范围内浮动。 现在让我们看看在固定填充下对输入电压的依赖性。

经验2-输入电压(Vin)变化,占空比恒定且等于50%

  • Vin = 15V,D = 50%,Vout = D * Vin = 0.5 * 15V = 7.5V

  • Vin = 20V,D = 50%,Vout = D * Vin = 0.5 * 20V = 10V

  • Vin = 30V,D = 50%,Vout = D * Vin = 0.5 * 30V = 15V


现在我们已经在实践中看到,输出电压也线性地取决于固定占空比下的输入电压。 您是否已经了解它将如何稳定输出? 稳定原理很简单,因为公式本身-Vout为12V并且恒定,我们可以在微控制器的帮助下更改占空比,因此如果Vin增加,输出电压也会增加,这时我们减小占空比直到再次变为12V。 因此,当Vin降低时,我们开始增加占空比,直到电压Vout再次变为12V。

我还想在理论部分中引起什么注意...啊,是的! 当然,您想知道在晶体管最终变为具有微小波纹的恒定电压后,幅度为20V的PWM如何吗? 的确,如果将示波器的红色探针放在晶体管VT1的源极,将绿色探针放在LC滤波器之后,我们将看到以下图片:



您可以看到LC滤波器是如何将交流电压“润滑”到恒定的,但是事实是,存储在电感和电容中的能量不能立即消耗掉,因此电压也不能立即改变。 我们得到的结果是,当电感器前面的PWM变为0V时,输出电压由滤波器中存储的能量提供,该能量不会立即吸收,足以在VT1闭合时维持该电压。 当然,一切都在手指上,如果有必要更深入地研究,那么我一如既往地建议B. Yu。 Semenova“电力电子:从简单到复杂” ,关于降压器(斩波器)有一整章。

为效率而奋斗


正如我之前写的那样,这是拓扑的基本版本。 其主要缺点是在锁定二极管上的高损耗。 在MK和CPLD上运行的简单系统中当前有什么? 如果有某种TFT显示屏,通常在1A以内,有时在2A以内。 在这种情况下,即使使用肖特基二极管,损耗也将是0.4V * 2A = 0.8瓦。 原则上,即使在3.3V和2A的电压下,0.8V的损耗仍能达到12%的效率,但在SMA / SMB封装上允许如此多的耗散却没有问题。

现在想象一下当我们的电流为20A时的情况。 它可以是MPPT控制器,大型FPGA电源系统等等。 在这种情况下,损耗将为0.4V * 20A = 8 W! 这是什么意思? 例如,在MPPT的情况下,电池中存储的能量将减少,在FPGA功耗的情况下,这将额外增加8瓦的热量,必须将热量散发到任何地方,这两种情况无疑都是整体效率的损失。 该怎么办? 让我们用另一个N沟道Mosfet替换VD1二极管,得到以下电路:



现在,晶体管VT2充当二极管,也就是说,当VT1闭合时,它传导电流。 基本版本的二极管不需要控制,现在我们不得不支付额外的带有PWM信号的控制通道,以提高性能。

首先,让我们计算我们减少了多少损失。 现代mosfet的通道电阻为数兆欧。 例如,让我们从电源模块中取出一个晶体管,我在之前的文章中曾谈到过-通道电阻为8.3 mOhm的IPP083N10N5AKSA1 。 我们得到的静电损耗等于0.0083 * 20A * 20A = 3.32瓦。 当然,会有动态损耗,如果设计适当的驱动器,动态损耗将不超过20%,也就是说,对我们而言,总损耗为4瓦。 我们得到了从传统降压到同步降压的过渡可以使二极管的损耗减半。

现在让我们看一下更复杂的管理。 如我们已经了解的,当VT1关闭时,锁定二极管正在传导电流。 由此得出结论,当VT1打开时VT2必须关闭,因此,当VT1关闭时VT2打开。 如果更简单,则晶体管会交替工作:一个晶体管打开或另一个晶体管打开(如果两个晶体管都打开),则将有直通电流,因为 它们在VIN和GND之间互连。 让我们看看信号应该是什么,其中“黄色通道”是晶体管VT1,“绿色通道”是晶体管VT2:



如您所见,如果在黄色通道中(VT1上)设置了逻辑“ 1”,则此时必须在绿色通道中(VT2上)设置了逻辑“ 0”。 我们得到VT1将能量泵入LC滤波器,而VT2在放电阶段关闭电路。

您已经听到或阅读了有关上述最新知识的另一点。 事实是,一个实际的晶体管而不是理想的晶体管(MOSFET)在栅极上具有一定的电容,也就是说,实际上它不会立即从log.0变为log.1,并且晶体管中的能量不会立即溶解,从而导致晶体管在切换时的短时间内,两者可能都打开。 充其量,这可能导致最大的损失,这意味着增加热量,最坏的情况是导致损失,因为 直通电流是一种常见的短路(short)电路。 为了避免这种情况,在关断一个晶体管和导通另一个晶体管之间引入了延迟或所谓的停滞时间。 看起来像这样:



我想您已经注意到信号切换边界上有一个很小的间隙。 我安装时知道它很大(大约3%),以便您可以看到它,实际上它很小。 通常,死区时间(以下称为dt)设置得尽可能短,但同时又足以使晶体管闭合。 它可以计算,也可以凭经验选择,我个人认为这种选择是正常的,但是有胡子的绝地可能会告诉您:“有必要考虑一下,但最好对其建模!” 这当然是正确的,但要自己决定-如果您不太懒惰,请在LTspice中进行建模,并考虑导体和组件的杂散电感和电容。

对于本文的立场,我将dt设置为〜100 ns(实际上是104 ns)。 我的模块允许您减少安装,因为 驱动程序的应用非常苛刻,但是可以肯定的是,你们中的许多人都将在没有我的模块的情况下构建布局,这意味着很可能会出现鼻涕。 为了使我不会因打not而卡住,我会在dt上留一点余地,如果您板上的配线正常,那么您自己可以减少它-然后在代码章节中,您将看到,现在,我们将看看是否确实存在dt:



可以看出,dt持续2.5格,每格为40 ns,这意味着持续时间为预期的〜100 ns。 我希望您了解为什么需要dt,持续时间应该多长以及转换器如何根据降压拓扑工作。 如果您不理解,那么照例,将接受评论,PM和邮件中的问题,而我似乎回答了所有人。

第二章主要组成部分的计算


在本文的这一部分,我将展示如何快速轻松地计算同步降压转换器的主要功率成分,即:电感器,输入和输出电容器,晶体管。

让我提醒您输入数据:

  • 输入电压:15 ... 30V
  • 输出电压:12V
  • 额定输出电流:2A
  • 开关频率:100 kHz

选择12V的输出电压是因为 我计划使用一个12V 20W LED作为负载,事实证明它已经可以使用并且是非常明显的负载。 预计评论中“专家”的问题-是的,我知道LED需要电流稳定,但是我们需要一个稳压器,而LED只是负载。

输入电压是从推土机上选择的,您可以在15 ... 60V范围内进行操作,因此,如果您对不同的范围感兴趣,则可以自己计算其组件的值。 选择2A的额定电流可获得12V * 2A = 24 W的输出功率,即比LED所需的功率高一点。 LED本身在12V时消耗约1.82 ... 1.9A的电流。

剩下的最有趣的参数是转换器的工作频率。 应该是什么 您必须自己在这里回答,在我的情况下是100 kHz。 该选择基于两点:

  • 频率增加导致电感器,输入和输出电容器的必要电感减小。 简而言之-随着频率的增加,设备的尺寸会减小。 随着频率降低,尺寸增加。
  • 频率降低导致效率提高,因为 减少开关晶体管时的动态损耗。 频率增加会增加晶体管的动态分量,从而降低效率。

现在,我将不讨论频率的选择,仅假设100 kHz。 在显示计算方法之后,我们将回到这个问题,因为 根据公式,可以更清楚地看到主要部件的额定值对工作频率的依赖性。

步骤1.选择晶体管

我们将主要关注以下三个参数:最大电压“漏-源”,开路状态下的沟道电阻和栅极电容。 电压源(Vin)的全部电势被施加到晶体管,并且在切换时还会出现电涌。 您有2种选择:带电压裕度的VT1和VT2晶体管或VT2上的RC缓冲层。 在我的情况下,电源模块具有100V晶体管,而输入电压为30V,这是一个巨大的电压裕度,即使60V也足以承受缓冲,并保护晶体管免受击穿。

通道电阻-越小越好,但是有一个BUT。 随着沟道电阻的减小,我们减少了静态损耗(I 2 * R),但是该技术使得栅极电容增加,从而导致动态损耗增加。 您必须在“通道电阻”和“快门容量”之间找到中间地带。 对于高达100V的电压,我建议您注意Infineon OptiMOS系列晶体管,您自己可以通过参数搜索甚至查看IGBT晶体管来查看高压。 我的电源模块也支持后者,不需要对驱动程序进行任何更改。

步骤2.电感器电感的计算

有必要计算电感的最小值,这将使我们的dc / dc转换器在连续电流模式(L min )下工作:



就变量而言,我认为除了-k ind之外,其他所有内容都很清楚。 这些是电感器中允许的纹波电流,它们通常选择20 ... 50%的值,但我几乎总是将其设置为30%。 电流的纹波越小,我们离缠绕电感器的铁芯的饱和边界越远,但是从公式可以看出,电感器需要较大的电感。

现在我们计算出电感的最小值,这对于我的输入数据将是必需的,如上所述,我将产生30%的纹波:



应当理解,这是降压转换器以不可分割的电流模式工作所需的最小电感,但同样存在细微差别。 在增加作用在绕组中的电流的过程中,没有电流和有电流的情况下,铁芯的磁导率和电感的电感有所不同,对于不同的材料,其依赖性也不同。为了避免这种情况,当电感器中的电流增加时,电感会降至L min以下并且dc / dc不会进入分断电流模式,因此有必要稍微增加电感,即在绕组期间增加几圈额外的匝数。对于Kool Mu材料,将电感增加10-15%就足够了,我会cho住它。

步骤3.电感器的计算和制造

我想在“原型”一节中描述此过程,但是对您而言,电感的计算步骤仍然不太清楚,我可能会错过一些有趣的图片,因此在这里我将进行介绍。对于节气门的制造,我将使用透气性为60的Kool Mu材料制成的R26 / 14/11节气门(R为环,数字为尺寸),您可以下载其相关文档并在此处购买-妖怪



现在,您需要计算多少匝以及需要缠绕的导线。让我们从匝数开始。在文档中,对于内核A L来说有一个如此方便的参数,等于75 nH /匝2。在这里仔细-变成一个正方形!要找到磁芯电感,请将A L乘以平方匝数。从这里开始,求匝数的公式如下:



为了获得所需的最小电感,必须绕40匝,但是正如我们已经讨论过的,有必要稍微增加电感,让我们增加3匝。我们绕环旋转43圈,得到这样的节流阀:



现在,出于兴趣的考虑,我们计算出应该得出的电感值:



为了可靠性,我们用镊子检查电感器的电感:



137μH,太好了!结果收敛,±8%以内的误差对甲大号。在这里值得注意的是-如果您没有测量电感的能力,那么就不要在速达,计算机,电子产品和其他“食品”中购买速卖通的磁芯-有机会从另一种材料或具有错误的磁导率的磁芯中获得磁芯,但带有正确的标记-已验证。如果没有测量电感的能力,您将无法检查A L,并且将极大地折磨自己,以寻找转换器“ babakh”的原因。

这就提出了一个合理的问题-“我们是否有足够的核心及其尺寸?也许还需要更多吗?”。对于Kool Mu材料,磁感应极限为0.5 T;在实践中,最好不要在没有明显必要的情况下爬出超过0.45 T的阈值。事实证明,缠绕在铁芯上的绕组不必在铁芯的每个点上产生大于0.45 T的感应,因此我们进行了检查:



如您所见,0.06 T的磁感应值远低于极限0.5 T.由此可以得出两个结论:首先,油门不会进入饱和状态;其次,磁芯非常大,并且采用较小的环很强大。我之所以选择R26戒指,只是因为我有他们的整个盒子,没有其他秘密的含义。

剩下的事情就是确定将导线的哪一部分用于电感器。首先,我强烈建议您不要在如此高的频率下使用直径大于1 ... 1.2 mm的电线,因为皮肤效应已经具有显着的效果并减小了有效横截面。其次,必须根据冷却条件和功率来选择导线中的电流密度。在低功率(最高10-20 W)下,即使没有气流,您也可以安全地放置8..10 A / mm 2的电流密度。在功率高达几千瓦的情况下,最好将电流密度设置在5 ... 6 A / mm 2的范围内;在功率从10 kW开始时,将电流密度降低到3 ... 4 A / mm 2是合理的

触手可及的是直径为0.8毫米的漆包线。其横截面分别为〜0.5mm 2。在2A的电流下,我们在绕组中获得的电流密度约为4 A / mm 2。我可以使用横截面一半的导线,但是我的芯线足够大,因此可以使用较大横截面的导线而不会出现任何问题。优化设备时,您首先需要数数,然后购买所需横截面的线,然后可以获得最佳的电感尺寸。

步骤4.输出电容器的计算

在此阶段,与电感一样,我们将考虑必须在降压转换器输出处的LC滤波器中安装的电容的最小值。因此,如果您安装更多,它会更好,然后查看原因。让我们计算一下容量:



当然,容量也必须有一定的余量,特别是如果您仅在出口使用陶瓷的情况下,因为根据其施加的电压,其容量会大大降低。还需要注意对脉冲的依赖-可变V 脉冲。这是输出处纹波的最大值,即理想情况下,电容为147.8μF,纹波幅度将为0.2V,即输出电压将在11.9 ... 12.1V范围内浮动。要减少波纹吗?然后在公式中减少它们,结果容量的值将相应地增加,当然,您不会仅仅通过增加输出容量来获得实验室电源。还必须考虑对低ESR的需求,为此,它们通常平行放置1-2种电解质,并在陶瓷上以X7R电介质将其悬挂在几个微法拉上,最好。如果预算允许,则可以用聚合物钽(如GPU中)替换电解电容器,因此不需要陶瓷,它们的ESR很小。

频率注意事项

现在,正如我所说,我们将回到选择转换器工作频率的问题。让我将结论分为几个想法:

  • 从公式中可以看出,频率出现了,工作频率越高,电感器的电感就越低,绕线数也就越少-我们节省了铜,简化了绕组产品的制造
  • 电感和匝数存在于计算磁感应强度的公式中,尽管您还记得,电感对匝数具有二次依赖性,这意味着当匝数减少2倍时,电感减小4倍。由此可见,随着频率的增加,电感和磁感应强度值减小,这意味着可以使用更小的铁芯,即,我们减小了尺寸
  • , — , , . !
  • … , . buck- mosfet- 200 . ( ) ? GaN

我认为,从这些论文中您可以清楚地了解开关频率会受到什么影响,现在您需要学习如何在晶体管的损耗与器件本身的尺寸之间找到“黄金平均值”。在以下文章之一中,我将教您优化工作频率以实现最大效率,主要的事情是不要忘记我会这样做。

第3章组装降压转换器布局


因此,最繁琐但最重要的部分已经结束,现在硬件和代码将消失。让我们整理一个布局,在该布局上我们将执行理论计算。为此,您将需要在上一篇文章中谈到的两个模块:STM32F334上的电源模块控制模块。您还可以自己在面包板上用IR2110类型的任何即兴垃圾组装半桥,并使用任何MK作为控件:STM32-Discovery,LaunchPad,Arduino,并根据自己喜欢的MK调整工作和代码的逻辑,如果没有的话,不会太复杂您从前两章了解了降压转换器的工作原理。

现在,通过在其中添加所有组件的值并正确反映电容器的数量,并使我们的降压图更“现实”,并注意电源模块可以实现的部分:



从图中可以看出,该模块已经包含一个用于实现同步降压的半桥(两个晶体管)和一个输入电容器,顺便说一下,它在模块中具有巨大的余量-每种电解质都有3个1000 uF和100V的电解质,这足以轻松地组装500个降压器-800瓦我们仍然需要增加一个扼流圈,该扼流圈我们已经制造并输出电容器,后者也要留有余地,因为我发现只有4700 uF 25V的低电压,但它们是某种中文,所以我还决定并联几个。实际上,那里有足够的470 uF,但我在输出版本中没有那么琐碎的东西。原来是这样的设计:



, 20 . , , 12 21...22 buck-. -8 , , 5-7 ( +40...50 o C), . 2 HRPWM, GND buck- , :



4.


现在,我们拥有开始编写代码和恢复buck转换器所需的一切。 首先,让我们看一下位于控制模块中的STM32F334R8T6微控制器的引脚排列:



现在我们了解了将使用哪些微控制器引脚。 在模块本身上,我只需要5个通道中的1个来控制功率单元,我们将使用通道“ A”。 与其他所有通道一样,该通道具有2个高精度PWM(HRPWM)输出,1个错误输入(我们不使用它),GND(用于组合电路板的接地)和2个ADC通道(我们将仅使用一个作为电压)。

关于HRPWM的一些知识

在Internet俄语部分的广阔范围内,我几乎没有见过任何有关HRPWM的培训材料,也没有见过关于使用基于STM32微控制器的HRPWM的所有材料,这是非常有用的外围设备。

我不会在本文的框架内深入研究这种外围的理论,因此我将描述其本质。 HRPWM或高分辨率PWM是我们常用的PWM模块,它具有用于设置占空比的高分辨率,并且通常具有更灵活的设置。



  • STM32F334R8T6微控制器具有10个HRPWM通道,这些通道被组合成5组,每组2个通道。 组中的这两个渠道可以独立工作,也可以形成互补对。
  • 在2个PWM信号之间的互补对内部,可以安装硬件死区时间以防止通过电流。
  • 所有10个通道均由一个定时器(主定时器)提供时钟,因此它们都彼此同步,因此您不必手动配置一系列定时器。 打开主机和定时器A ... E定时器以从其计时就足够了;
  • HRPWM处的频率加倍,即在72 MHz的核心频率处,HRPWM处的频率在带PLL的附加乘数(x2)之后为144 MHz。 这样就可以以数百kHz的频率控制转换器。
  • 例如,PWM控制的许多设置,以及将PWM生成绑定到周期的开始和结束的功能,还有4个以上可配置的事件(comp),使您可以在周期的任何时间点(周期的开始/结束)将PWM转换为0或1。
  • 有一些特定拓扑的模式,例如推挽模式,它允许您实现许多推挽拓扑。

这只是功能的一小部分,在HRPWM器件图上,您可以看到带有大量事件,DAC,MK中内置的比较器的同步功能,并且与该框图一起,还有更多的文献记载的可能性。

仍然需要解决最后一个问题-“为什么此PWM为高电平?”。 为此,请考虑一个简单的示例。 想象一下,我们决定使用不带HRPWM的MK,例如STM32F103C8T6,它也可以在72 MHz的频率下工作。 我们需要将半桥控制在70 kHz的频率上,我们考虑可以得到的调节阶跃:72 000 000/1025阶跃= 70 243 Hz。 是的,我们有1025步长,调整时我们可以以1/1025 =〜0.1%的理论步长更改输出电压。 现在我们以STM32F334为例,其时钟频率为144 MHz,定时器的移位宽度为32位,则得到的等效频率为144 MHz * 32 = 4.608 GHz。 对于那些害怕和怀疑这个数字的人:



不,这不是工作频率,这是等效频率。 这给了我们什么? 我们采用4 608 000 000 Hz / 70 300 Hz = 65 535步的等效频率。 现在,我们可以以1/65 535 =〜0.001%的增量来调整输出上的电压(或电流),也就是说,精度提高了100倍!

现在开始吧-我们有700 kHz的频率,例如,对于多相降压,这是正常的。 F103将获得72,000,000 Hz / 700,000 Hz = 102步长,这最多可使您获得1%的调节率,但占空比为1%,也就是说,实际上,步长如此多,您的输出端将浮有电压,就好像稳定时一样并非如此。 对于F334,步数约为6500,这仍然使您可以构建非常精确的电压或电流调节器。 我们发现,占空比设置的分辨率(步长)比内置标准PWM模块的传统MK更高/更多。

时钟系统设置

在本文中,我将TrueSTUDIO用作开发环境,因为它是免费的,不像Keil或IAR那样痛苦, 是的,请告诉我它的出色调试器 ,跨平台以及也许不仅是初学者的最佳解决方案。 在文章的结尾,将有一个包含此IDE项目的存档。 我不会告诉您如何创建和配置项目,只留下指向视频的链接,其中详细显示了所有内容- 观看

创建项目并使LED闪烁之后,需要配置时钟系统,即从8 MHz开始,将频率提高到72 MHz并应用于内核,然后调节分频器以降低提供给ADC的频率:

void StartInitClock (void) { RCC->CR |= RCC_CR_HSEON; // Enable HSE while (!(RCC->CR & RCC_CR_HSERDY)); FLASH->ACR |= FLASH_ACR_LATENCY_1; RCC->CFGR |= RCC_CFGR_PLLMUL9; // PLL mult x9 RCC->CFGR |= RCC_CFGR_PLLSRC; // Source HSE RCC->CFGR2 |= RCC_CFGR2_ADCPRE12_DIV10; // ADC source AHB/10 RCC->CR |= RCC_CR_PLLON; while((RCC->CR & RCC_CR_PLLRDY) == 0){} RCC->CFGR &= ~RCC_CFGR_SW; RCC->CFGR |= RCC_CFGR_SW_PLL; // Select source SYSCLK = PLL while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_1) {} // Wait PLL } 

在这里,我只是认为,调整算法如下: 它切换到外部石英(HSE)->等待转换完成并设置就绪标志时,我们等待->我们将石英的信号发送到PLL输入->将8 MHz乘以9->将频率除以72 MHz乘以10为ADC计时->打开PLL->等待直到打开并设置就绪标志->从PLL向系统总线和内核发送信号->等待直到开关完成->完成。

HRPWM设置

这里的一切都比较复杂,因为 该模块具有很多功能,可以进行很多设置,文档量非常大,但这也是一个缺点,同时又要加上-您必须付出灵活性。

 RCC->CFGR3 |= RCC_CFGR3_HRTIM1SW_PLL; RCC->APB2ENR |= RCC_APB2ENR_HRTIM1EN; 

您需要指定HRTIM是由PLL时钟驱动的,默认情况下已启用x2乘法器。 然后,我们只需打开HRTIM的时钟,这是第一个功能-因为我们了解到定时器是由PLL时钟驱动的,但我们为APB2打开了时钟。 这并不完全合乎逻辑,但是可以使用CMSIS或文档轻松地在文件中进行搜索。

  RCC->AHBENR |= RCC_AHBENR_GPIOAEN; GPIOA->MODER &= ~GPIO_MODER_MODER8; GPIOA->MODER |= GPIO_MODER_MODER8_1; // Alternative PP GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR8; // Very high speed GPIOA->MODER &= ~GPIO_MODER_MODER9; GPIOA->MODER |= GPIO_MODER_MODER9_1; GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9; GPIOA->AFR[1] |= 0xDD; // PA8 and PA9 - AF13 

PA8和PA9是定时器A的输出,在我的模块上它到达通道1,您可以在图中和引脚上看到。 支腿配置为推挽式,具有其他功能,双支腿的功能本身数目为13。 调至最大GPIO频率也很重要,否则,将无法理解信号的前,后降落,这对于电力电子设备极为重要。

 HRTIM1->sCommonRegs.DLLCR |= HRTIM_DLLCR_CAL | HRTIM_DLLCR_CALEN; while ((HRTIM1->sCommonRegs.ISR & HRTIM_ISR_DLLRDY) == RESET); 

在开始之前,您需要校准计时器,因为 它以最小的延迟工作,然后只需等待就绪标志。

 HRTIM1->sTimerxRegs[0].PERxR = PeriodTimerA; // Period for timer A HRTIM1->sTimerxRegs[0].CMP1xR = 0; // Duty for timer A 

那就是灵活性。 首先,我们可以为每个定时器A ... E设置自己的频率,这里我们只记录PWM的周期。 其次,默认情况下,我们在周期的开始处进行PWM对齐,也就是说,在新周期的开始处信号进入log.1,现在我们需要选择何时返回比较器1的log.0,即比较器1我本质上是在问责任系数。

例如,您可以在周期开始时而不是在比较器1之前转换PWM,并通过比较器2返回到log.0,从而使硬件移相。

 // Deadtime enable HRTIM1->sTimerxRegs[0].OUTxR |= HRTIM_OUTR_DTEN; // Tdtg = 6.94 ns HRTIM1->sTimerxRegs[0].DTxR |= HRTIM_DTR_DTPRSC_0 | HRTIM_DTR_DTPRSC_1; // Deadtime rising = 15*Ttg = 104 ns HRTIM1->sTimerxRegs[0].DTxR |= HRTIM_DTR_DTR_0 | HRTIM_DTR_DTR_1 | HRTIM_DTR_DTR_2 | HRTIM_DTR_DTR_3; // Deadtime falling = 15*Ttg = 104 ns HRTIM1->sTimerxRegs[0].DTxR |= HRTIM_DTR_DTF_0 | HRTIM_DTR_DTF_1 | HRTIM_DTR_DTF_2 | HRTIM_DTR_DTF_3; HRTIM1->sTimerxRegs[0].DTxR |= HRTIM_DTR_DTFSLK | HRTIM_DTR_DTRSLK; 

在此阶段,我们启用死区时间并对其进行配置,原则上,注释包含所有公式,也可以在参考手册中找到它们。 在本文的理论章节中,您已经在波形上看到了持续时间约为100 ns的DT。 死区时间可以在信号的边缘和下降沿分别设置。 顺便说一下,[0]是定时器A,[1]是定时器B,依此类推。

 // Samples in middle of ON time HRTIM1->sTimerxRegs[0].CMP2xR = PeriodTimerA / 10; // ADC trigger 1 update: Timer A HRTIM1->sCommonRegs.CR1 |= HRTIM_CR1_ADC1USRC_0; // ADC trigger 1 event: Timer A compare 2 HRTIM1->sCommonRegs.ADC1R |= HRTIM_ADC1R_AD1TAC2; 

对我来说,这不是最明显的时刻。 底线是-我想确保在定时器A周期的10%内产生一个事件,该事件将触发ADC转换并测量反馈信号。 为什么是10%? 简而言之,理想情况下,测量不应在PWM从0过渡到1或反之时进行,因为 目前,功率单元中存在瞬变和干扰,但我们无需对其进行测量。 因此,就我而言,最佳值为10%,因为 在12V输出和30V时,占空比的输入电压将不会降至10%,并且晶体管的开关时刻将与ADC测量值不完全匹配。

现在,您需要查看HRTIM与ADC之间的事件通信系统:



在第一行中,我们选择比较器何时被触发,在我的情况下,它是定时器A周期的10%。接下来,我们在ADC中选择一个将与MK联系的特定触发器,我们可以访问第一或第三。 现在,它只是表明哪个事件会将信号发送到ADC,在我的例子中是比较器2。

 // Enable output PWM for TA1 and TA2 HRTIM1->sCommonRegs.OENR |= HRTIM_OENR_TA1OEN | HRTIM_OENR_TA2OEN; // Continuous mode HRTIM1->sTimerxRegs[0].TIMxCR |= HRTIM_TIMCR_CONT; // Period for master timer HRTIM1->sMasterRegs.MPER = 65000; // Enable counter for Master and timer A HRTIM1->sMasterRegs.MCR |= HRTIM_MCR_MCEN | HRTIM_MCR_TACEN; 

最后的和弦! 我们允许HRTIM从定时器A向GPIO输出信号。 现在我们选择模式,它会无休止地发生(我有它),但是碰巧定时器打开了1个周期,然后需要再次启动它。 接下来,设置主定时器的周期,并在最后一步将其打开,它开始为通道定时器计时,PWM信号出现在输出端。

这是一个调优功能,剩下的工作就是设置占空比系数,在创建控制器时我们将使用它:

 void SetDutyTimerA (uint16_t duty) { HRTIM1->sTimerxRegs[0].CMP1xR = duty; } 

列出功能设置并设置占空比
 // f = 102,4 kHz #define PeriodTimerA ((uint16_t)45000) void InitHRPWM (void) { RCC->CFGR3 |= RCC_CFGR3_HRTIM1SW_PLL; RCC->APB2ENR |= RCC_APB2ENR_HRTIM1EN; /************************************************ * Setting GPIO ***********************************************/ RCC->AHBENR |= RCC_AHBENR_GPIOAEN; // Alternative PP GPIOA->MODER &= ~GPIO_MODER_MODER8; GPIOA->MODER |= GPIO_MODER_MODER8_1; // Very high speed GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR8; GPIOA->MODER &= ~GPIO_MODER_MODER9; GPIOA->MODER |= GPIO_MODER_MODER9_1; GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9; // PA8 and PA9 - AF13 GPIOA->AFR[1] |= 0xDD; /************************************************ * Setting timer A ***********************************************/ HRTIM1->sCommonRegs.DLLCR |= HRTIM_DLLCR_CAL | HRTIM_DLLCR_CALEN; while ((HRTIM1->sCommonRegs.ISR & HRTIM_ISR_DLLRDY) == RESET); // Period for timer A HRTIM1->sTimerxRegs[0].PERxR = PeriodTimerA; // Duty for timer A HRTIM1->sTimerxRegs[0].CMP1xR = 0; // Deadtime enable HRTIM1->sTimerxRegs[0].OUTxR |= HRTIM_OUTR_DTEN; // Tdtg = 6.94 ns HRTIM1->sTimerxRegs[0].DTxR |= HRTIM_DTR_DTPRSC_0 | HRTIM_DTR_DTPRSC_1; // Deadtime rising = 15*Ttg = 104 ns HRTIM1->sTimerxRegs[0].DTxR |= HRTIM_DTR_DTR_0 | HRTIM_DTR_DTR_1 | HRTIM_DTR_DTR_2 | HRTIM_DTR_DTR_3; // Deadtime falling = 15*Ttg = 104 ns HRTIM1->sTimerxRegs[0].DTxR |= HRTIM_DTR_DTF_0 | HRTIM_DTR_DTF_1 | HRTIM_DTR_DTF_2 | HRTIM_DTR_DTF_3; HRTIM1->sTimerxRegs[0].DTxR |= HRTIM_DTR_DTFSLK | HRTIM_DTR_DTRSLK; // Event forces the output to active state for TA1 HRTIM1->sTimerxRegs[0].SETx1R |= HRTIM_SET1R_PER; // Event forces the output to inactive state for TA1 HRTIM1->sTimerxRegs[0].RSTx1R |= HRTIM_RST1R_CMP1; /************************************************ * ADC trigger intialization (with CMP2 event) ************************************************/ // Samples in middle of ON time HRTIM1->sTimerxRegs[0].CMP2xR = PeriodTimerA / 10; // ADC trigger 1 update: Timer A HRTIM1->sCommonRegs.CR1 |= HRTIM_CR1_ADC1USRC_0; // ADC trigger 1 event: Timer A compare 2 HRTIM1->sCommonRegs.ADC1R |= HRTIM_ADC1R_AD1TAC2; /************************************************ * HRTIM start ***********************************************/ // Enable output PWM for TA1 and TA2 HRTIM1->sCommonRegs.OENR |= HRTIM_OENR_TA1OEN | HRTIM_OENR_TA2OEN; // Continuous mode HRTIM1->sTimerxRegs[0].TIMxCR |= HRTIM_TIMCR_CONT; // Period for master timer HRTIM1->sMasterRegs.MPER = 65000; // Enable counter for Master and timer A HRTIM1->sMasterRegs.MCR |= HRTIM_MCR_MCEN | HRTIM_MCR_TACEN; } void SetDutyTimerA (uint16_t duty) { HRTIM1->sTimerxRegs[0].CMP1xR = duty; } 


现在,让我们找出我们是否朝着正确的方向前进。 在主要功能中,初始化HRTIM设置并设置占空比,例如22500。使用20V的输入电压和45000的周期,我们的占空比将为50%,输出约为10V。 这不足以将LED扩展到满,但它应该点亮,并且我们将了解电源部分是否工作正常,dt没问题等等。 我是第一次开始一切:



您可以看到所有先前的理论计算均已确认。 固定占空比为50%时,输出电压只需除以2:20V-> 10V,22V-> 11V,18V-> 9V。 现在,让输出电压稳定且独立于输入,即添加反馈。

ADC和控制器调整

在我之前,已经有很多关于STM32中ADC的文章,我只讨论设置与HRTIM比较器相关的触发器。 我将简要介绍其余的ADC设置。 我们来看一下初始化函数:

 void InitBasicADC (void) { RCC->AHBENR |= RCC_AHBENR_ADC12EN; RCC->AHBENR |= RCC_AHBENR_GPIOCEN; /************************************************ * Calibration ***********************************************/ ADC2->CR &= ~ADC_CR_ADVREGEN; ADC2->CR |= ADC_CR_ADVREGEN_0; // Vref enable Delay(10); ADC2->CR &= ~ADC_CR_ADCALDIF; ADC2->CR |= ADC_CR_ADCAL; // Start calibration while (ADC2->CR & ADC_CR_ADCAL); // Wait end calibration /************************************************ * Select event trigger and channel ***********************************************/ // Enable start conversion external trigger ADC2->CFGR |= ADC_CFGR_EXTEN_0; // Event 7 - HRTIM ADC2->CFGR |= ADC_CFGR_EXTSEL_0 | ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_2; // Select ADC2 channel IN5 ADC2->SQR1 |= ADC_SQR1_SQ1_0 | ADC_SQR1_SQ1_2; // Length regular ADC channel = 1 ADC2->SQR1 &= ~ADC_SQR1_L; ADC2->IER |= ADC_IER_EOCIE; // Interrupt enable NVIC_EnableIRQ(ADC1_2_IRQn); // enable interrupt ADC1 and ADC2 /************************************************ * Start ADC ***********************************************/ ADC2->CR |= ADC_CR_ADEN; // Enable ADC2 Delay(10); ADC2->CR |= ADC_CR_ADSTART; } 

我使用常规通道模式,我只有一个通道,并且在SQR1寄存器中选择了 。 涉及ADC 2,即其输入IN5,它速度很快,并且可以在最大采样频率下工作,但这次不行。 采样频率等于PWM频率,因为 1个周期= 1个样本,原则上,这绰绰有余。

另外,在CFGR寄存器中, 我们需要选择转换开始的事件 ,即事件7 ,为什么要转换呢? 我们看RM:



来自HRPWM模块的触发器1进入事件2,用于我们的ADC 2号,它在这种情况下作为从设备工作,然后由HRPWM模块控制。 我认为现在很清楚如何连接2个模块,原则上,该算法对于任何外设和任何计时器都是相似的,只是寄存器名称会有所不同。

当到达主定时器周期计数器时,将开始转换,该转换大约在15个周期后(对于RM中有多少精确计数)将引起中断,您可以在其中获取结果。 正是在这种中断下,我们组织了控制算法。 是的,在中断内部,最好不要做一些大的事情,最好设置标志并继续执行,但是我可以简化一下,因为在这种情况下,我的控制器没有特别加载,它将设法计算并退出中断,概率为146%。一个新的出现。

有关管理的一点

想象一下,您进入洗手间并决定在洗手池中洗手。 您稍微打开水,用手摸一下,冷吗? 加更多的热水,温暖吗? 好啊 加更多的热水? 几乎需要什么? 好啊 加更多的热水,用手试试,烧自己吗? 让我们现在降低热点。 好吗 因此,将水龙头转到无穷远,直到水温达到理想水平为止。 这是最简单的旋钮!

只有我们不调节热水量,而是调节PWM占空比。 我们有一个可以测量结果的ADC,而不是手工制作的。 剩下的只是实现逻辑。 我们将计算ADC在12V输出下应产生的功率,然后使用if条件,通过改变占空比来迫使我们的控制器保持该值。

首先,让我们挂起一个分压器以将12V降低至2-2.5V,例如,因为 ADC的测量范围为0至+ 3.3V,如果提供12V,则微控制器将简单地烧毁。 因此,我将放置一个标称值为10 kOhm和2 kOhm的分压器,分压比为6,因此,我们的+ 12V将变为+ 2V。 我们的ADC将产生结果:adcResult =(V out / k)/ V ref * 2 12 =(12V / 6)/ 3.3 * 4095 =2481。现在,我们为中断处理程序编写代码:

 void ADC1_2_IRQHandler (void) { ADC2->ISR |= ADC_ISR_EOC; adcResult = ADC2->DR; if (adcResult > 2480) { dutyControl = dutyControl - 10; } else { dutyControl = dutyControl + 10; } SetDutyTimerA(dutyControl); } 

首先,进入中断处理程序后,您需要清除此中断的标志,否则第二次您将不会进入中断处理程序。 然后,我们读取结果并将其另存为adcResult变量。 现在,了解了输出电压,您需要调整PWM的占空比,我只是通过if条件实现了这一点。 在每个PWM周期中,我们都会进行测量,增加或减少占空比并为下一个周期设置结果。 一切都很简单,快速,本质是可见的。 我们看一下工作的结果:



如您所见,一切正常,当输入电压变化时,输出本身保持稳定在12V。 非常细心的人会注意到细小的针头滑过,然后您只需要将X7R陶瓷悬挂在1-10微法拉的输出上,它们就会离开,我懒得去寻找和焊接它。 现在示波图本身,以免损害眼睛:



在这里,您可以看到输出电压如何上升。 事实是,由于控制算法的原因,为了使填充达到例如0到10000的值,需要一千个周期或大约10 ms。 它适合我,因为软启动要减少上升时间,请使算法复杂一点,并增加+1000,而不是+10,并且您越接近指定的12V,则调节越少,直到达到+10 。 通常,在管理方面可以完成很多事情,因此您需要进行实验。

另一个有趣的问题是关机时的振荡,例如“谐波”。 事实是,关闭电源后,我的数字部分继续通过另一个PSU工作,并试图将所需的值保持在输出上。 能量从何而来? 是的,从输入电容器来看,这些已经是1000微法拉的3个了,这是一个有趣的现象。

结论


这篇文章并不小,但是您想要一切,他们立即说让我们准备好铁了-拿走。 希望您喜欢这篇文章,我试图使它不是科学的,而是通俗的,以使具有不同知识和经验水平的人们都可以使用该材料。 也许将来我会类似地分析其他拓扑,例如升压,全桥等。

顺便说一下,本文和代码将用于我正在设计的20A新型MPPT控制器。 现在,我在等待PCBway板 ,它实际上是自愿赞助印刷电路板的开源项目,MPPT的资源也将与我所有的模块一样开放。

我忘了最重要的事情! 将项目保留为TrueSTDIO- RAR的代码。

Source: https://habr.com/ru/post/zh-CN432778/


All Articles