基于STM32G474RCT6单相逆变器并联运行系统

                                                摘 要

       本系统以STM32G474RCT6单片机为控制核心,结合双闭环算法,设计并制作了一套高效率、高性能的DC-AC变换器。系统由两套并联的单相逆变电路、辅助电源电路、电压电流采样电路组成。逆变器使用外环电压控制和内环电流控制结合的方法,维持输出电压及输出电流的稳定,实现了对逆变器的有效控制;并采用主从模式的控制的方法,从机通过软件锁相环采集主机的相位信息,在主机输出电压过零点发出SPWM波,从而实现逆变器的并联以及并网操作。经测试,系统完成了题目要求,输出交流电压有效值平均24.0V,频率50.01Hz,总谐波失真不超过0.5%,负载调整率0.053%,效率达93%以上。此外,系统可以通过按键步进设置输出电流,系统稳定性和安全性高,功能丰富,人机交互良好。

1、绪论

信息技术的迅速发展,对其供电系统的容量、性能和可靠性要求越来越高,也推动着电力电子技术的研究不断深入,研究领域不断拓宽。多模块并联实现大容量电源被公认为当今电源变换技术发展的重要方向之一。多个电源模块并联,分担负载功率,各个模块中主开关器件的电流应力大大减小,从根本上提高可靠性、降低成本。同时,各模块的功率容量减小而使功率密度大幅度提高。另外,多个模块并联,可以灵活构成各种功率容量,以模块化取代系列化,从而缩短研制、生产周期和降低成本,提高各类开关电源的标准化程度、可维护性和互换性等。

2、方案设计与论证

2.1方案的选择

2.1.1电压电流检测模块的论证

方案一:采用互感器检测互感器检测电流、电压:电流电压互感器能将大电压、大电流转换成小电压信号,具有高精度、具有隔离效果、结构简单、可靠性高、热稳定好、响应速度快等特点,但精度低、带宽低。

方案二:使用AD采集的方案,测量电流、电压:用分压电阻配合差分运放,通过AD采集检测电流、电压。AD采集的方案简单、精度高,使用更加熟练。

方案选择:方案一测量交流电会丢失相位、谐波等重要参数。方案二技术成熟使用次数多,更加熟练,满足测量要求。综合以上两种方案,选择方案二。

2.1.2逆变器并联方案的论证

方案一:在系统开机时,两个逆变器系统同时对电网电压进行锁相控制,使每台逆变器输出电压的相位与电网一致,以保证逆变器并联的可靠性以及安全性,同时方便后续的并网控制。

方案二:采用主从机并联的方式,先接通主逆变器的电源,待主逆变器稳定工作后,再打开从机并采集主机逆变输出的相位,在主逆变器输出过零时从逆变器发出PWM波,完成两台逆变器的并联。

方案选择:方案一使用简单,但存在同时开启引起电流冲击问题。方案二可以通过模式选择开关、软件设定和工作状态等进行控制,从而避免了方案一中由于控制器故障导致系统崩溃和电流冲击的可能。综合以上两种方案,选择方案二。

2.1.3逆变器并联控制方案的论证

方案一:使用下垂控制算法[1]进行两台逆变器的并联控制,可以直接根据微电网的状态来调节逆变器的输出功率。下垂控制只需获取电源本身的信息,通过采集各逆变器的输出,根据给定的控制策略,实现多台逆变器并联运行,无需互多台逆变器的连信号线。下垂控制算法具有很好的冗余性、结构简单、成本低、系统可靠的优点。

方案二:通过按键输入来设定单片机内部电流环的给定值,从而达到改变输出电流的目的。按键输入使用简单,并且对控制方式要求不高,可随意调节系统电流,能有效减少工作量,降低设计难度和时间。

方案选择:方案一可以满足对系统并联控制方案的要求,但其软件控制较为复杂,且输出电压精度无法满足要求。方案二能够直接对输出电流进行数字设定,也能满足设计要求。综合以上两种方案,选择方案二。

2.1.4解题思路

电路拓扑选择:单相全桥逆变器

基于STM32G474RCT6单相逆变器并联运行系统_第1张图片

图1:单相全桥逆变器

2.1.5调制方式

目前使用较多的是单极性与双极性调制方式,双极性控制方式简单;单极性开关管动作次数少,开关损耗低;

基于STM32G474RCT6单相逆变器并联运行系统_第2张图片

图2:单极性spwm驱动波形

单极性调制一组半桥用作于低频桥臂,只需50hz频率开启关闭即可,另一组桥臂用作于快桥臂进行调制,电感上的电压在Vcc与0之间切换。

基于STM32G474RCT6单相逆变器并联运行系统_第3张图片

图3:单极性spwm驱动波形

基于STM32G474RCT6单相逆变器并联运行系统_第4张图片

图4:双极性spwm驱动波形

3、系统参数的设计

3.1系统指标

要求 :

基于STM32G474RCT6单相逆变器并联运行系统_第5张图片

基于STM32G474RCT6单相逆变器并联运行系统_第6张图片

3.2系统设计

3.2.1系统原理图

基于STM32G474RCT6单相逆变器并联运行系统_第7张图片

图5:系统总原理图

3.2.2模块电路设计及元器件选择

3.2.2.1主功率电路设计

基于STM32G474RCT6单相逆变器并联运行系统_第8张图片

图6:功率电路图

由4个mos管加一个(LC滤波器)功率电感以及滤波电容构成主功率回路:

逆变器的输出电压有效值为24V,幅值为24*sqrt(2) = 34V,单相SPWM电压利用率理论最大值为1,所以输出直流母线电压需要大于34V,取一定裕量,选择输入直流母线电压为45V。

1.  主功率电感计算:电感量的计算公式为

L >= sqrt(2)*Vo/(γ*Fs*Iomax)*Dmin

其中γ为电感的电流纹波系数,取值范围为0.2到0.4为最佳,这里我们取0.2

Fs为50Khz,(有效值)Iomax = 2A,Vo = 24V,Dmin = 1-(Vo*sqrt(2)/Vin) = 0.245

代入计算可得到电感量的最小值为780uH,取一定裕量选用1mH的感量。

2.  输出滤波电容计算:滤波电容允许通过的无功电流不超过额定值的5%,由此可以得到滤波电容值的上限为:

其中,I是额定输出电流,

是基波角频率,U是输出电压的有效值。为了尽量减少通过的无功电流以及减小纹波率,计算中取允许通过的无功电流为额定电流的3%,取U=24V, 

=314,I=2A,得到单个逆变器输出滤波电容的容值上限C=7.96uF。实际选用3uF电容。满足无功电流要求。

最小电容要求,即LC滤波器决定了滤波的截至频率,确定一个截至系数,一般为0.1到0.5*Fs之间,再由LC谐振频率求得最小输出电容。

  1. MOS管的选择:选择耐压100V的功率mos即可,导通电阻越小,MOS体二极管的反向恢复时间越短越好(决定了高频连续导通模式下的mos主要损耗)。电路选用NCEP0178AK型号的MOS管。

4.直流母线电容计算:单相全桥逆变器反向运行则为无桥APFC(有源功率因数校正器)按照工程经验值,直流母线电容容量选择标准为

3W/uF @VDC = 400V

由Q = C*V,V = Q/C = I*t/C可知,当电容的容量固定,电容两端的电压只与放电电流有关,若要保持纹波率不变,所以对于输出电压45V,直流母线电容容量选择标准可以改为

0.038W/uF @VDC = 45V

换算公式为 

0.038=3*(VDC2/VDC1)^2

其中VDC1 = 400V,VDC2 = 45V

根据题目要求,单个逆变器最大输出功率为48W,选择母线电容容量的最小值为1260uF,由于题目并未要求逆变器能够反向工作在整流模式下,所以电容选择可以低于计算值,实践验证,可以选择两个220uF或两个470uF,100V耐压的电容并联。

3.2.2.2驱动电路设计

基于STM32G474RCT6单相逆变器并联运行系统_第9张图片

图7:驱动电路图

UCC21520隔离驱动器,D13为自举二极管,选择耐压大于等于MOS管耐压的快恢复/超快恢复二极管,C9为自举电容,按照经验一般选择1uF,耐压大于VDD的陶瓷电容,这里选择220nF,R4为限流电阻,减小冲击电流,DT引脚为死区时间控制引脚,UCC21520的死区时间配置方式为

DTSetting = 10 × RDT(in kΩ) ns

Disable引脚用来关闭栅极驱动,高电平有效,默认状态下下拉电阻到地

C13亦是芯片的滤波电容,容量可适当的加大,这里选择220nF.

3.2.2.3采样电路设计

由于输出通过变压器与市电相隔离,所以不存在触电风险,所以这里采样选择非隔离采样方案。

单片机参考地选择:

方案一:选择参考地为输出交流侧的地,优点:电流采样无共模信号,使用简单的差分放大电路就能对电流信号进行采样,输入交流电压采样同理,缺点:全桥的驱动需要隔离驱动器,需要一个额外的隔离电源

方案二:选择参考地为直流母线的地,优点:全桥驱动不需要额外的隔离电源,和隔离驱动器,缺点:交流侧的电流与电压对与直流侧的地有非常高的共模干扰,交流电流采样和交流电压电路设计较为困难。

方案三:全隔离方案,使用隔离运放对输出进行采集,隔离驱动,mcu隔离电源供电,成本较高,设计复杂,但是安全性高。受到噪声影响很小。

这里我们选择方案一,即将单片机的地放置在交流侧。

电感电流采样电路

基于STM32G474RCT6单相逆变器并联运行系统_第10张图片

 图8:电感电流采样电路图

基准电路是一个同相比例电路,分压成1.65V电压基准。

由题目可知,单个逆变器的最大输出电流为2A,所以电感电流的峰峰值为2*2*sqrt(2) = 5.65A,要使得信噪比最大并且留有一定裕量,则在最大电流下,运放输出电压需要接近3V,所以选择采样电阻为0.02,差法电路的放大倍数为22,则总电流采样放大倍数为0.44 V/A。这里的运放芯片用的OPA2188芯片,在设计PCB时采样电阻尽量靠近R43、R44,可以避免不必要的噪声。

交流电压采样电路

基于STM32G474RCT6单相逆变器并联运行系统_第11张图片

图9:交流电压采样电路图

交流采样电路是一个同相比例电路,输出24V有效值,峰值34V,电阻分压系数为0.032,设输出最大峰值电压35V经过分压后等于35*0.032=1.12V,运放再放大1倍等于1.12+1.65=2.77V,可以满足输出要求,R54和C57组成低通滤波器,截止频率为2KHz

直流电压采样电路

基于STM32G474RCT6单相逆变器并联运行系统_第12张图片

图10:直流电压采样电路图

直流电压采样电路由差分运放电路组成,前级电阻分压系数为0.0208倍,后级放大3倍,当输入电压为45V时,输出电压为45*0.0208*3=2.8V,可以满足输出要求。

3.2.2.4辅助电源电路设计

基于STM32G474RCT6单相逆变器并联运行系统_第13张图片

图11:辅助电源电路图

辅助电源整体框架为高压BUCK +隔离电源,高压BUCK从直流母线侧取电,再通过隔离电源给各模块供电。

由于直流母线最高电压为45V,所以选择耐压高于1.2*Uin=54V的BUCK芯片即可,这里选择了耐压100V的EG1198,隔离电源选择功率大于1W的隔离模块B1205S模块,主要给运放、MCU供电。

3.2.2.5主控电路设计

基于STM32G474RCT6单相逆变器并联运行系统_第14张图片

图12:主控电路图

主控电路芯片用的STM32G474CET6芯片,包括复位电路、电源电路和时钟电路,降压芯片用的LP5907芯片降压成3.3V给单片机和运放供电,主控电路主要做按键、OLED屏、ADC、DAC、串口通信、电平和PWM控制。

3.3 软件系统设计

3.3.1 系统软件流程图设计

基于STM32G474RCT6单相逆变器并联运行系统_第15张图片

图 13:单相逆变系统流程图

在主程序中,主要对控制系统中的各模块进行初始化的配置与子模块的调用。待各项配置和初始化完成后,进入While循环中中断的触发。在中断服务函数中,首先对输入的电压信号进行采样,并进行坐标转换、执行PLL锁相环的程序,将电网电压进行锁相;随后进行电压环与电流环的控制,将环路控制得到的目标值进行SPWM调制[7];最后输出PWM波。单相逆变系统的系统流程图如上图13所示。

3.3.2 功能模块软件设计

3.2.2.1锁相环的实现

常规的软件锁相技术是基于电压实时采样同有效值进行运算,从而得到当前信号的状态,对采样电路要求颇高,且易受噪声影响。基于SOGI-dq锁相环[4]具有良好的滤波性能,且便于对相位进行补偿控制等操作。dq旋转坐标变换需要提供两个相位相差90°的正弦信号作为输入信号,二阶广义积分器(SOGI)可以产生相位差90度正交分量,且对高次谐波具有滤波作用,不易噪声的影响,因此基于二阶广义积分的单相锁相环(SOGI-PLL)得到了广泛的应用。将单相电网电压通过二阶广义积分器产生两个正交信号α和β,之后经Park变换得到vd和vq(其中Park变换所需要的相位值为锁相环输出的相位值)。将vq送入PI调节器,经PI调节器输出得到瞬时角频率的值,再对角频率积分即可得到相位值。通过采集电网的相位信息,当相位稳定跟踪上且电网电压过零时,单片机开始输出SPWM波,完成并网的控制。

3.2.2.2双闭环控制

为了保证整个系统的可靠性以及稳定性,使用内外环控制方案:将二阶系统拆分为两个一阶系统进行控制,简化控制方案,且可以避免二阶系统的阻尼特性引起的谐振点增益尖峰;使用电压外环PI控制器[5],电流内环比例准谐振(PR)控制器[6]对输出电流以及电压进行控制,PR控制器在谐振频率处具有很高的增益,可以更好的跟踪上交流信号并能有效的消除稳态误差,维持输出电流的稳定。

4、系统测试及分析

4.1测试步骤与结果(数据)

4.1.1测试步骤

基于STM32G474RCT6单相逆变器并联运行系统_第16张图片

图 14:测试框图

4.1.2基础部分

(1)仅用逆变器1向RL供电。分别测量输入电压、输入电流、输出电压有效值、输出电流、频率、以及输出电压THD,记录于表1,并计算整机效率。

表1效率测量表

次数

1

2

3

输入电压(V)

40.01

40.00

39.98

输入电流(A)

1.29

1.29

1.29

输出电压RMS(V)

24.02

24.03

24.02

输出电流(A)

2.01

2.01

2.01

频率(Hz)

50.01

50.00

50.00

输出电压THD

0.45%

0.46%

0.50%

效率

93.2%

93.4%

93.2%

(2)输出电压有效值Uo 为24V±0.2V,Io 在 0A-2A 间变化时,测量输出电压结果记录于表2:

表2负载调整率

次数

1

2

3

输出电流(A)

0

2

0

2

0

2

输出电压(V)

24.05

24.04

24.06

24.04

24.06

24.05

负载调整率

0.04%

0.08%

0.04%

4.1.3发挥部分

  1. 逆变器1和逆变器2并联,共同向RL供电,当输出电压Uo=24V,频率fo=50Hz时,测量输出电流并记录于表3。

表 3 输出电流记录表

次数

输出电压(V)

频率(Hz)

输出电流(A)

1

24.08

50.0

4.02

2

24.07

50.0

4.01

3

24.08

50.0

4.01

(2)逆变器1与逆变器2并联且并网,在2A-4A 范围内数字设定输出电流Io,计算误差绝对值记录于表4。

表 4 输出电流误差绝对值表

设定电流(A)

输出电流(A)

误差绝对值

2

2.05

2.5%

3

3.07

2.3%

4

4.06

1.5%

  1. 断开S1,闭合S2,逆变器1与逆变器2并联且并网,Io在1A-3A间变化时,调节逆变器1及逆变器2的输出电流比值K,分别测量两台逆变器的输出电流记录于表5。

表 5 两台逆变器输出电流对照表

输出电流

设定K值

逆变器1输出电流

逆变器2输出电流

相对误差

1

0.5

0.325

0.663

1.96%

1

0.493

0.501

1.60%

2

0.664

0.338

1.78%

2

0.5

0.662

1.334

0.75%

1

1.002

1.002

0.00%

2

1.343

0.673

0.22%

3

0.5

1.001

1.996

0.30%

1

1.512

1.499

0.87%

2

2.024

1.003

0.90%

4.2测试分析与结论

4.2.1基础部分分析

表1的数据结果输出电压有效值Uo 为24V±0.2V,频率fo为50Hz±0.2Hz,输出电流有效值 Io为 2A的条件下,输出交流电压总谐波畸变率(THD)平均值为0.47%,逆变器效率平均值达到93%以上,达到基本要求(1)、(2)、(3)。

表2的数据结果利用公式(3)计算得到负载调整率为0.053%,满足基本要求(4)。  

4.2.2发挥部分分析

表3的数据结果输出电流取平均值得到输出电流为4.01A,满足发挥部分要(1)。

表4的数据结果经过计算,输出电压设定值与实际值误差绝对值均小于设定值的 2.5%,满足发挥部分要求(2)。

表5的数据结果利用公式(4)计算得到相对误差的绝对值均小于2%,满足发挥部分要求(3)。

4.3测试实物图

基于STM32G474RCT6单相逆变器并联运行系统_第17张图片

图 15:测试实物图

基于STM32G474RCT6单相逆变器并联运行系统_第18张图片

图 16:系统原理图

5、结论

系统以STM32G474RCT6单片机为控制核心,结合外环电压控制和内环电流控制算法,制作了一台作为电压源的主机以及一台作为电流源的从机。系统由直流电源输出40V直流电,采用双极性正弦脉宽调制(SPWM)方式,得到有效值为24V的交流电接至负载。从机通过采集主机的输出电压相位使两台逆变器输出同相位,从而达到逆变器并联以及并网的效果。系统完成了题目的全部要求,输出交流电压24V,频率50.01Hz,总谐波失真不超过0.5%,单台逆变器输出效率达93%以上,并且两台逆变器并联并网时可以通过按键改变输出的电流值。系统稳定性和安全性高,人机交互良好。

​6、部分代码

int main(void)
{
	/* USER CODE BEGIN 1 */

	/* USER CODE END 1 */

	/* MCU Configuration--------------------------------------------------------*/

	/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
	HAL_Init();

	/* USER CODE BEGIN Init */

	/* USER CODE END Init */

	/* Configure the system clock */
	SystemClock_Config();

	/* USER CODE BEGIN SysInit */

	/* USER CODE END SysInit */

	/* Initialize all configured peripherals */
	MX_GPIO_Init();
	MX_DMA_Init();
	MX_ADC2_Init();
	MX_HRTIM1_Init();
	MX_DAC1_Init();
	MX_CORDIC_Init();
	/* USER CODE BEGIN 2 */
	HAL_Delay(100);
	OLED_Init();
	OLED_ColorTurn(0);	 // 0正常显示,1 反色显示
	OLED_DisplayTurn(0); // 0正常显示 1 屏幕翻转显?
	OLED_Refresh();
	OLED_Clear();
	HAL_Delay(100);
	OLED_ShowString(0, 0, "   Io:   .   A", 16, 1);
	OLED_Refresh();
	OLED_ShowString(0, 16, " * K :   .  ", 16, 1);
	OLED_Refresh();
	OLED_ShowString(0, 32, "  Is2:   .   A", 16, 1);
	OLED_Refresh();
	OLED_ShowString(0, 48, "state:  OFF   ", 16, 1);
	OLED_Refresh();
	HAL_Delay(100);
	OLED_ShowNum(56, 0, Io, 2, 16, 1);
	OLED_Refresh();
	OLED_ShowNum(80, 0, (uint16_t)(Io * 100) % 100, 2, 16, 1);
	OLED_Refresh();
	OLED_ShowNum(56, 16, K, 2, 16, 1);
	OLED_Refresh();
	OLED_ShowNum(80, 16, (uint16_t)(K * 100) % 100, 2, 16, 1);
	OLED_Refresh();
	OLED_ShowNum(56, 32, Is1, 2, 16, 1);
	OLED_Refresh();
	OLED_ShowNum(80, 32, (uint16_t)(Is1 * 100) % 100, 2, 16, 1);
	OLED_Refresh();

	// 开启ADC
	HAL_ADC_Start_DMA(&hadc2, (uint32_t *)A_Phase_Sample, 2); // 启动ADC2的DMA传输,将A相采样值存入数组

	// 电压环//初始化电压环PI控制器,设置参数和输出限幅
	f32_PI_Init(&Voltage_Loop_Pamer, 2e-5f, 0.035, 500, 3.5, -3.5); // 电压外环     输出限幅+-4a    也就是最大输出电流
	// 初始化电流PR控制器,设置滤波器参数和输出限幅
	f32_Type2_Init(&Current_PR_Loop_Pamer, Current_Loop_A_filter, Current_Loop_B_filter, 1, 1, -1); // PR控制器   最后两个是输出限幅  对应着占空比

	// 锁相环初始化
	SOGI_Parameter_Init(&VAC_SOGI_Pamer, 0.4f, 2e-5f, 314.159); // 初始化网侧电压SOGI,设置参数
	f32_PI_Init(&PLL_PI_Pamer, 2e-5f, -100, -400, 400, -400);	// 初始化锁相环PI控制器,设置参数和输出限幅
	f32_Integral_Init(&Single_PLL_Pamer, 2e-5f, 1.0f);			// 初始化单相锁相环,设置参数

	// 信号发生器
	f32_Integral_Init(&Get_Sin, 2e-5f, 1.0f); // 积分器初始化

	// 开DAC

	HAL_DAC_Start(&hdac1, DAC_CHANNEL_1);
	HAL_DAC_Start(&hdac1, DAC_CHANNEL_2);
	VAC_Discern_Pamer.derta_VAC = 0.02f;			// 设置网侧电压判别的阈值
	VAC_Discern_Pamer.PLL_Discern_Counter_MAX = 20; // 设置锁相环判别的计数器最大值
	/* USER CODE END 2 */

	/* Infinite loop */
	/* USER CODE BEGIN WHILE */
	while (1)
	{
		//	  HAL_Delay(10);
		if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == GPIO_PIN_RESET) // 如果按下PA3引脚的按键
		{
			while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == GPIO_PIN_RESET)
				;				// 等待按键释放
			switch_ = ~switch_; // 取反并网指示
			if (switch_ != 0)	// 如果并网指示为真
			{
				OLED_ShowString(64, 48, "ON ", 16, 1); // 显示字符串,表示并网状态为ON
				OLED_Refresh();						   // 刷新OLED
				sys_star();							   // 调用函数,启动系统
			}
			else
			{
				OLED_ShowString(64, 48, "OFF", 16, 1); // 显示字符串,表示并网状态为OFF
				OLED_Refresh();
				sys_stop(); // 调用函数,停止系统
			}
			HAL_Delay(100);
		}
		if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET) // 如果按下PB0引脚的按键
		{
			K_mode = ~K_mode; // 取反电流系数模式指示
			while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET)
				;			 // 等待按键释放
			if (K_mode == 0) // 如果电流系数模式指示为假
			{
				OLED_ShowString(0, 16, " * ", 16, 1); // 显示字符串,表示当前调节的是电流系数
				OLED_Refresh();
				OLED_ShowString(0, 0, "   ", 16, 1); // 显示字符串,清除原来的标志
				OLED_Refresh();
			}
			else // 如果电流系数模式指示为真
			{
				OLED_ShowString(0, 0, " * ", 16, 1); // 显示字符串,表示当前调节的是输出电流
				OLED_Refresh();
				OLED_ShowString(0, 16, "   ", 16, 1); // 显示字符串,清除原来的标志
				OLED_Refresh();
			}
		}
		if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET) // 如果按下PB2引脚的按键
		{
			while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET)
				;
			if (K_mode == 0) // 如果电流系数模式指示为假
			{
				K = K + 0.100f;					   // 电流系数增加0.1
				if (K >= 2.0f)					   // 如果电流系数超过2.0
					K = 2.0f;					   // 电流系数设为2.0
				OLED_ShowNum(56, 16, K, 2, 16, 1); // 显示数字,表示电流系数的整数部分
				OLED_Refresh();
				OLED_ShowNum(80, 16, (uint16_t)(K * 100) % 100, 2, 16, 1); // 显示数字,表示电流系数的小数部分
				OLED_Refresh();
			}
			else // 如果电流系数模式指示为真
			{
				Io = Io + 0.100f;				   // 输出电流增加0.1
				if (Io >= 4.0f)					   // 如果输出电流超过4.0
					Io = 4.0f;					   // 输出电流设为4.0
				OLED_ShowNum(56, 0, Io, 2, 16, 1); // 显示数字,表示输出电流的整数部分
				OLED_Refresh();
				OLED_ShowNum(80, 0, (uint16_t)(Io * 100) % 100, 2, 16, 1); // 显示数字,表示输出电流的小数部分
				OLED_Refresh();
			}
			Is1 = (float)Io / (K + 1);			 // 计算并网电流
			OLED_ShowNum(56, 32, Is1, 2, 16, 1); // 显示数字,表示并网电流的整数部分
			OLED_Refresh();
			OLED_ShowNum(80, 32, (uint16_t)(Is1 * 100) % 100, 2, 16, 1); // 显示数字,表示并网电流的小数部分
			OLED_Refresh();
		}
		if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET)
		{
			while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET)
				;
			if (K_mode == 0) // 如果电流系数模式指示为假
			{
				K = K - 0.100f; // 电流系数减少0.1
				if (K <= 0.5f)
					K = 0.5f;
				OLED_ShowNum(56, 16, K, 2, 16, 1);
				OLED_Refresh();
				OLED_ShowNum(80, 16, (uint16_t)(K * 100) % 100, 2, 16, 1);
				OLED_Refresh();
			}
			else
			{
				Io = Io - 0.100f;
				if (Io <= 1.0f)
					Io = 1.0f;
				OLED_ShowNum(56, 0, Io, 2, 16, 1);
				OLED_Refresh();
				OLED_ShowNum(80, 0, (uint16_t)(Io * 100) % 100, 2, 16, 1);
				OLED_Refresh();
			}
			Is1 = (float)Io / (K + 1);
			OLED_ShowNum(56, 32, Is1, 2, 16, 1);
			OLED_Refresh();
			OLED_ShowNum(80, 32, (uint16_t)(Is1 * 100) % 100, 2, 16, 1);
			OLED_Refresh();
		}
		/* USER CODE END WHILE */

		/* USER CODE BEGIN 3 */
	}
	/* USER CODE END 3 */
}

/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
	RCC_OscInitTypeDef RCC_OscInitStruct = {0};
	RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

	/** Configure the main internal regulator output voltage
	 */
	HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST);

	/** Initializes the RCC Oscillators according to the specified parameters
	 * in the RCC_OscInitTypeDef structure.
	 */
	RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
	RCC_OscInitStruct.HSEState = RCC_HSE_ON;
	RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
	RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
	RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV2;
	RCC_OscInitStruct.PLL.PLLN = 85;
	RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
	RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
	RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
	if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
	{
		Error_Handler();
	}

	/** Initializes the CPU, AHB and APB buses clocks
	 */
	RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
	RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
	RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
	RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
	RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

	if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
	{
		Error_Handler();
	}
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
 * @brief  This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void)
{
	/* USER CODE BEGIN Error_Handler_Debug */
	/* User can add his own implementation to report the HAL error return state */
	__disable_irq();
	while (1)
	{
	}
	/* USER CODE END Error_Handler_Debug */
}

#ifdef USE_FULL_ASSERT
/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line)
{
	/* USER CODE BEGIN 6 */
	/* User can add his own implementation to report the file name and line number,
	   ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
	/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

视频演示效果:live.csdn.net/v/353123

本文已同步发表在知乎:基于STM32G474RCT6单相逆变器并联运行系统 - 知乎 (zhihu.com)

你可能感兴趣的:(stm32,嵌入式硬件,单片机)