单相逆变电路实战!(基于STM32F103C8T6的单相逆变电路,PID控制输出额定电压)

这篇具有很好参考价值的文章主要介绍了单相逆变电路实战!(基于STM32F103C8T6的单相逆变电路,PID控制输出额定电压)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


我建了一个群,分享我个人做项目的经历和资源,纯个人爱好,一切免费,看自己空闲时间答疑,有想法的可以加QQ群280730348

前言

本篇文章是对单相逆变电路进行实战演练的一次项目,主要实现功能为:

直流电压48V输入,通过STM32F103C8T6单片机输出SPWM波,通过IR2104S驱动模块控制两组对管的开关闭合,通过LCL滤波实现工频正弦波的平滑输出。额定输出电压为24V,额定输出电流为2A,额定输出功率为48W,适合对逆变电路感兴趣的朋友实战演练。

实物图如下:
单相逆变电路实战!(基于STM32F103C8T6的单相逆变电路,PID控制输出额定电压)


一、所需要的主要器件

1、STM32F103C8T6开发板一块
2、0.96寸OLED屏幕一块
3、IRF540N(MOSFET管)四个
4、1mh铁铝硅电感33MM
5、MKP电容10uf(圆柱形)
6、两个IR2104驱动模块
7、交流电计量模块HLW8032

二、硬件电路图

1.单相逆变主电路

单相逆变电路实战!(基于STM32F103C8T6的单相逆变电路,PID控制输出额定电压)
主要原理为:HO3、LO3为IR2104S驱动模块1驱动,HO2、LO2为IR2104S驱动模块2驱动。在任一瞬间,HO3和LO3波形相反,HO2与LO2波形相反,且HO3和HO2波形相反。即整体电路只对应两种工作状态:

第一种工作状态为:直流电流通过Q1mos管流经L6,负载L3再流经Q4最终到达地,在这一工作状态里,若负载上端视为电压正极,则负载上会加上一个正向的电压,也即处于正弦波的正半周期。

第二种工作状态为:直流电流通过Q3mos管流经L3,负载L6再流经Q2最终到达地,在这一工作状态里,若负载上端视为电压正极,则负载上会加上一个反向的电压,也即处于正弦波的负半周期。

2.继电器过流过压保护

单相逆变电路实战!(基于STM32F103C8T6的单相逆变电路,PID控制输出额定电压)
CTRL为单片机控制继电器开关闭合的信号,I+和I-分别连至逆变电路的输出和负载的上端。若CTRL给低电平,9013关闭,继电器磁铁不吸合,I+和I-处于连接状态。若CTRL给高电平,则9013导通,继电器磁铁吸合,I-和FLOAT处于连接状态,电路输出浮空,起到保护作用。

3.辅助电源供电

单相逆变电路实战!(基于STM32F103C8T6的单相逆变电路,PID控制输出额定电压)
12V电源适配器输入,通过7805降压至5V,给单片机和总体供电。

4.IR2104驱动

单相逆变电路实战!(基于STM32F103C8T6的单相逆变电路,PID控制输出额定电压)

芯片输入口主要有四个信号,一个是12V的供电信号,一个是PWM的驱动信号,一个是5V的芯片使能信号,另外一个是数字地。输出口同样有四个信号,分别为HO,VS,LO和模拟地。本驱动的功能是,输入一路PWM信号,在HO和LO口得到互补的PWM波,VS接在对管MOSFET的中间,即上管的S端和下管的D端,利用自举驱动原理驱动上管开关闭合。

三、软件流程图

1.Visio流程图

单相逆变电路实战!(基于STM32F103C8T6的单相逆变电路,PID控制输出额定电压)

2.主函数

代码如下(示例):

/*
STM32F103C8T6
iic通信0.96寸OLED显示屏;显示中英文、数字、图片
18B20温度传感器
HC-SR04超声波传感器

OLED接线定义:
					VCC--3.3V/5V
					GND--GND
					SCL--PB8
					SDA--PB9
*/
#include "stm32f10x.h"
#include <stdbool.h>
#include "string.h"
#include "sys.h"  
#include "delay.h"
#include "oled.h"
#include "stdio.h"
#include "timer.h"
#include "usart.h"
#include "usart2.h"
#include "led.h"
#include "show.h"
#include "main.h"
#include "pid.h"
#include "key.h"
float jiaozheng=1.0023f;
/*电能数据采集参量设置*/            
extern u32 Voltage_Parameter_Reg,Voltage_Reg,Current_Reg,Current_Parameter_Reg,Power_Parameter_Reg,Power_Reg;
extern u8 Data_Updata_Reg;
extern u16 PF_Reg;
float ACVotage,ACCurrent,ActivePower,ApparentPower,PowerFactor,ElectricEnergy;
u8 Pre_Data_Updata_Reg;
u16 UpdataCount;
u32 PFCount,PF_OneDegree;
u8 buf[5]={11,12,12,12,12};
/*实际电路运行中需要用到的一些电路参数*/
u8 gonglv_status=1;                     //功率状态标志位,为1时是额定48W输出,为2时是额定24W输出,为3时是额定12W输出
u8 dianya_status=1;                     //电压状态标志位,为1时是调节整数位输出,为2时是调节小数位输出
u8 work_mode=0;                         //工作模式为0,代表启动界面;工作模式为1,代表模式选择界面;
u8 mode_status=1;                       //=1代表指向额定电压输出,=2代表指向额定功率输出,=3代表指向初始启动界面
u8 key_value=0;                         //按键键值,1-4分别代表control,choice,add,reduce
float duty=1000.0f;                     //逆变电路的调制系数
float AC_Target=240.0f;                 //逆变电路输出目标值
float gonglv_Target=232.0f;             //功率追踪位
float PID_flag=0;                       //PID使能控制位
float kp_v=0.04;                          //P环调节系数
float kp_p=0.04;
float dianzu=11.20f; 
/*第一次进入界面使能*/
u8 mode_1=0;
u8 mode_2=0;
u8 mode_3=0;
u8 mode_4=0;
int main(void)
{	
    u16 i=0;
    u8 x=0,y=0;	
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级 		 		
	delay_init();           //延时
	uart_init(9600);        //串口初始化
	uart2_init(4800);	 	//串口初始化为115200
	TIM3_Int_Init(3600-1,1-1);//10KHZ
	TIM4_Int_Init(3600-1,2-1);//10KHZ
	BOOST_PWM_Init();
	LED_Init();             //LED初始化
	KEY_Init();
	init_PID();             //初始化PID参数
	OLED_Init();			//初始化OLED  
	OLED_Clear();
	loop:
    GPIO_SetBits(GPIOB,GPIO_Pin_5);		//关闭继电器
	qidong_view(); 		
	TIM_Cmd(TIM1,DISABLE);
	PID_flag=0;
	duty=0;
	AC_Target=240.0f;
	while(1)
	{
	    key_value=KEY_Scan(0);
		if(key_value==1)
		{
		   work_mode=1;
		   TIM_Cmd(TIM1,ENABLE);
		   GPIO_ResetBits(GPIOB,GPIO_Pin_5);
		   for(i=1;i<=1000;i++)
		  {
			  duty=i;
			  delay_ms(1);
		  }
           break;			
		}
	}
	choice_view();
	while(1)
	{
		key_value=KEY_Scan(0);//扫描键值
		/*选择初始界面函数*/
		if(work_mode==0)
		{			
			goto loop;
		}
		/*选择界面处理函数*/
        else if(work_mode==1)
		{
			if(mode_1==0)choice_view(),mode_1=1,PID_flag=0,duty=600;
			if(key_value==2)
			{
				mode_status+=1;
				if(mode_status==4)
				{
					mode_status=1;
				}
			}
			else if(key_value==1)
			{
				mode_1=0;
				if(mode_status==1)work_mode=2;
				else if(mode_status==2)work_mode=3;
				else if(mode_status==3)work_mode=0;
			}
			if(mode_status==1)
			{
				OLED_ShowString(90,2,"<-",16);
				OLED_ShowString(90,4,"  ",16);
				OLED_ShowString(90,6,"  ",16);
			}
			else if(mode_status==2)
			{
				OLED_ShowString(90,2,"  ",16);
				OLED_ShowString(90,4,"<-",16);
				OLED_ShowString(90,6,"  ",16);
			}
			else if(mode_status==3)
			{
				OLED_ShowString(90,2,"  ",16);
				OLED_ShowString(90,4,"  ",16);
				OLED_ShowString(90,6,"<-",16);
			}
		}
		/*选择电压界面处理函数*/
		else if(work_mode==2)
		{
			if(mode_2==0)dianya_view(),mode_2=1;
			if(key_value==2)
			{
				dianya_status+=1;
				if(dianya_status==3)
				{
					dianya_status=1;
				}
			}
			else if(key_value==1)
			{
				mode_2=0;
				PID_flag=1;
				work_mode=4;				
			}
			else if(key_value==4&&dianya_status==1)
			{
				AC_Target+=10;
			}
			else if(key_value==4&&dianya_status==2)
			{
				AC_Target+=1;
			}
			else if(key_value==3&&dianya_status==1)
			{
				AC_Target-=10;
			}
			else if(key_value==3&&dianya_status==2)
			{
				AC_Target-=1;
			}
			if(dianya_status==1)
			{
				OLED_ShowString(90,2,"<-",16);
				OLED_ShowString(90,4,"  ",16);
			}
			else if(dianya_status==2)
			{
				OLED_ShowString(90,2,"  ",16);
				OLED_ShowString(90,4,"<-",16);
			}
		    OLED_ShowNum(56,2,(int)AC_Target/10,2,16);
	        OLED_ShowNum(56,4,(int)AC_Target%10,1,16);
			OLED_ShowNum(56,6,(int)AC_Target/10,2,16);OLED_ShowNum(80,6,(int)AC_Target%10,1,16);
		}
		/*选择功率界面处理函数*/
		else if(work_mode==3)
		{
			if(mode_3==0)gonglv_view(),mode_3=1;
			if(key_value==2)
			{
				gonglv_status+=1;
//				if(gonglv_status==3)
//				{
//					gonglv_status=1;
//				}
				if(gonglv_status==4)
				{
					gonglv_status=1;
				}
			}
			else if(key_value==1)
			{
				mode_3=0;
				PID_flag=1;
				work_mode=4;
                if(gonglv_status==1)gonglv_Target=232.0f;
                else if(gonglv_status==2)gonglv_Target=164.0f;
                else if(gonglv_status==3)gonglv_Target=116.0f;				
			}
//			else if(key_value==4&&gonglv_status==1)
//			{
//				gonglv_Target+=10;
//			}
//			else if(key_value==4&&gonglv_status==2)
//			{
//				gonglv_Target+=1;
//			}
//			else if(key_value==3&&gonglv_status==1)
//			{
//				gonglv_Target-=10;
//			}
//			else if(key_value==3&&gonglv_status==2)
//			{
//				gonglv_Target-=1;
//			}
//			if(gonglv_status==1)
//			{
//				OLED_ShowString(90,2,"<-",16);
//				OLED_ShowString(90,4,"  ",16);
//			}
//			else if(gonglv_status==2)
//			{
//				OLED_ShowString(90,2,"  ",16);
//				OLED_ShowString(90,4,"<-",16);
//			}
//			OLED_ShowNum(56,2,(int)gonglv_Target/10,2,16);
//	        OLED_ShowNum(56,4,(int)gonglv_Target%10,1,16);
//			OLED_ShowNum(56,6,(int)gonglv_Target/10,2,16);OLED_ShowNum(80,6,(int)gonglv_Target%10,1,16);
			if(gonglv_status==1)
			{
				OLED_ShowString(90,2,"<-",16);
				OLED_ShowString(90,4,"  ",16);
				OLED_ShowString(90,6,"  ",16);
			}
			else if(gonglv_status==2)
			{
				OLED_ShowString(90,2,"  ",16);
				OLED_ShowString(90,4,"<-",16);
				OLED_ShowString(90,6,"  ",16);
			}
			else if(gonglv_status==3)
			{
				OLED_ShowString(90,2,"  ",16);
				OLED_ShowString(90,4,"  ",16);
				OLED_ShowString(90,6,"<-",16);
			}
		}
		/*参数选择界面*/
		else if(work_mode==4)
		{
			if(mode_4==0)canshu_view(),mode_4=1;
			if(key_value==1)
			{
				mode_4=0;
				PID_flag=0;
				work_mode=1;			
			}
				/*显示电压电流数据*/
	        OLED_ShowNum(40,0,(u32)(ACVotage*100)/100,2,16);
	        OLED_ShowNum(64,0,(u32)(ACVotage*100)%100,2,16);
	        OLED_ShowNum(40,2,(u32)(ACCurrent*100)/100,2,16);
	        OLED_ShowNum(64,2,(u32)(ACCurrent*100)%100,2,16);
	        OLED_ShowNum(40,4,(u32)(ApparentPower*10)/10,3,16);
	        OLED_ShowNum(72,4,(u32)(ApparentPower*10)%10,1,16);
		}
        ACVotage=(Voltage_Parameter_Reg*1.88/Voltage_Reg)*jiaozheng;//电压有效值
		if(ACVotage<=2)
		 ACVotage=0;
		ACCurrent=(Current_Parameter_Reg*1.0/Current_Reg)*0.4893;//电流有效值
		if(ACCurrent<0.1)//无电压时电压又飘移
		{
			ACCurrent=0;
			ApparentPower=0;
			ActivePower=0;
			PowerFactor=0;
		}
		if(ACVotage>2&&ACCurrent>0.1)//空载时电流有飘移
		{
		
		
			ApparentPower=ACVotage*ACCurrent;//视在功率
			ActivePower=Power_Parameter_Reg*1.88/Power_Reg;//有功功率
			PowerFactor=ActivePower/ApparentPower;//功率因数
		}
        printf ("电压有效值:%f\r\n",ACVotage);
		printf ("电流有效值:%f\r\n",ACCurrent);
        printf ("视在功率:%f\r\n",ApparentPower);
		printf ("有功功率:%f\r\n",ActivePower);
		printf ("功率因数:%f\r\n",PowerFactor);
		if(Pre_Data_Updata_Reg!=(Data_Updata_Reg&0x80))
		{
			UpdataCount++;
			Pre_Data_Updata_Reg=Data_Updata_Reg&0x80;
		}
		PFCount=UpdataCount*65536+PF_Reg;//脉冲信号个数
		PF_OneDegree=1000000000/Power_Parameter_Reg;
		PF_OneDegree=PF_OneDegree*3600/1.88;//1度电对应的脉冲个数;
		ElectricEnergy=(float)PFCount/(float)PF_OneDegree;//电能
		printf ("电能:%f\r\n",ElectricEnergy);
		delay_ms(50);		
	}

主代码里面主要是对于界面的显示和模式的切换,以及处理交流电压和交流电流等参数数据。

3.定时器中断函数

#include "timer.h"
#include "inverter.h"
#include "main.h"
#include "pid.h"
#include "usart.h"
#include "string.h" 
	 
#define BOOST_TIMx TIM1
#define BOOST_Plus 0//初始化占空比为0.5%,高电平有效时的低电平占空比 
#define BOOST_ARR (3600-1)//重装载值1000
#define BOOST_PSC (1-1)//分频系数2
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=0; //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,DISABLE);
	
	//主输出使能
	TIM_CtrlPWMOutputs(BOOST_TIMx,ENABLE);
}
//定时器7中断服务程序		    
void TIM2_IRQHandler(void)
{ 	
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//是更新中断
	{	 			   
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update  );  //清除TIM7更新中断标志    
		TIM_Cmd(TIM2, DISABLE);  //关闭TIM7 
	}	    
}
 	 
void TIM2_Int_Init(u16 arr,u16 psc)
{	
	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//TIM7时钟使能    
	
	//定时器TIM7初始化
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); //使能指定的TIM7中断,允许更新中断
	
	TIM_Cmd(TIM2,ENABLE);//开启定时器7
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;		//子优先级2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
}
void TIM3_IRQHandler(void)
{ 	
	static u16 jishu=0;
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)//是更新中断
	{	
        inverter_spwm();
		if(jishu==400)
		{
		  jishu=0;
          if(PID_flag==1)
		  {
             if(mode_status==1)duty=PID_X(ACVotage*10,AC_Target,kp_v,2,1200);
		     else if(mode_status==2)duty=PID_X(ACVotage*10,gonglv_Target,kp_p,2,1200); 
             //else if(mode_status==2)duty=PID_X(ACVotage*10,sqrt((gonglv_Target/10)*11.2)*10,kp_p,2,1200);			  
          }
	    }
		jishu++;
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIM7更新中断标志    
	}	    
}
 	 
void TIM3_Int_Init(u16 arr,u16 psc)
{	
	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//TIM3时钟使能    
	
	//定时器TIM7初始化
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
	
	TIM_Cmd(TIM3,ENABLE);//开启定时器3
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
}
 void TIM4_IRQHandler(void)
{ 	
	if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)//是更新中断
	{	
		TIM_ClearITPendingBit(TIM4, TIM_IT_Update  );  //清除TIM7更新中断标志    
	}	    
}
void TIM4_Int_Init(u16 arr,u16 psc)
{	
	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//TIM3时钟使能    
	
	//定时器TIM7初始化
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
	
	TIM_Cmd(TIM4,ENABLE);//开启定时器3
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
}
 /*选择通道函数*/
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;           
	}
}

定时器一主要是用来输出互补的PWM波,定时器二和定时器四无明显作用,定时器三主要是控制SPWM波的生成以及进行PID运算。定时器三时钟频率为20KHz,在其中断里面定义了一个暂态变量,每进入400次中断循环复位一次,这样没执行一次中断改变一次PWM的占空比,即可实现SPWM波的生成。PID由于我们的信号采集模块每隔50ms发一次数据,所以选择50Hz的频率进行一次PID的运算。

4.逆变器SPWM函数

#include "inverter.h"
#include "timer.h"
#include "main.h"
#define length 400

u16 sinData[length]=
{
1800,1821,1842,1864,1885,1906,1927,1949,1970,1991,2012,2033,2054,2075,2096,2117,
2137,2158,2179,2199,2219,2240,2260,2280,2300,2320,2339,2359,2378,2397,2416,2435,
2454,2473,2491,2510,2528,2546,2563,2581,2598,2615,2632,2649,2666,2682,2698,2714,
2730,2745,2760,2775,2790,2805,2819,2833,2847,2860,2873,2886,2899,2911,2924,2935,
2947,2958,2969,2980,2990,3001,3010,3020,3029,3038,3047,3055,3063,3071,3078,3085,
3092,3098,3105,3110,3116,3121,3126,3130,3134,3138,3142,3145,3148,3150,3152,3154,
3156,3157,3158,3158,3159,3158,3158,3157,3156,3154,3152,3150,3148,3145,3142,3138,
3134,3130,3126,3121,3116,3110,3105,3098,3092,3085,3078,3071,3063,3055,3047,3038,
3029,3020,3010,3001,2990,2980,2969,2958,2947,2935,2924,2911,2899,2886,2873,2860,
2847,2833,2819,2805,2790,2775,2760,2745,2730,2714,2698,2682,2666,2649,2632,2615,
2598,2581,2563,2546,2528,2510,2491,2473,2454,2435,2416,2397,2378,2359,2339,2320,
2300,2280,2260,2240,2219,2199,2179,2158,2137,2117,2096,2075,2054,2033,2012,1991,
1970,1949,1927,1906,1885,1864,1842,1821,1800,1778,1757,1735,1714,1693,1672,1650,
1629,1608,1587,1566,1545,1524,1503,1482,1462,1441,1420,1400,1380,1359,1339,1319,
1299,1279,1260,1240,1221,1202,1183,1164,1145,1126,1108,1089,1071,1053,1036,1018,
1001,984,967,950,933,917,901,885,869,854,839,824,809,794,780,766,
752,739,726,713,700,688,675,664,652,641,630,619,609,598,589,579,
570,561,552,544,536,528,521,514,507,501,494,489,483,478,473,469,
465,461,457,454,451,449,447,445,443,442,441,441,441,441,441,442,
443,445,447,449,451,454,457,461,465,469,473,478,483,489,494,501,
507,514,521,528,536,544,552,561,570,579,589,598,609,619,630,641,
652,664,675,688,700,713,726,739,752,766,780,794,809,824,839,854,
869,885,901,917,933,950,967,984,1001,1018,1036,1053,1071,1089,1108,1126,
1145,1164,1183,1202,1221,1240,1260,1279,1299,1319,1339,1359,1380,1400,1420,1441,
1462,1482,1503,1524,1545,1566,1587,1608,1629,1650,1672,1693,1714,1735,1757,1778
};

void inverter_spwm(void)
{
  static u16 spwm_count=0;
  set_pwm(TIM1,1,(u16)((sinData[spwm_count%length]-1800)*duty/1000+1800),3500);	
  spwm_count++;
  if(spwm_count>=400)spwm_count=0;	  
}

如上图所示,想要实现SPWM波的效果我们就得让PWM波模拟出SPWM波的效果,由于我们单片机不能产生负压信号,所以我们在此处假定PWM波输出占空比为50%的时候,等同于输出电压0V。原理也在于,如果占空比为50%时,那么正压和负压加在负载上的功率一致,相互抵消最终宏观上显现的就是0V的电压。占空比大于50%时,相当于输出正压,小于50%时相当于输出负压。因此只需让PWM波以50%占空比为原点,让其按照正弦规律变化即刻,比如从50%一直升到90%,然后再从90%缓慢降到10%,再升到50%由此就实现了一个正弦规律的变化,在此处还设置了调制系数,通过控制调制系数的大小,可以改变超出50%和低于50%占空比的占空比大小。比如若之前设定为最高75%占空比输出,最低25%输出,改变调制系数的大小,使其最高输出90%占空比,最低10%占空比,这样输出的交流电压幅值就会高。

而改变调制系数也不能直接乘以我们数组里面的占空比,由于我们设置的重装载值是3600,对应的最大占空就为100%,因此以1800为中心点进行正弦规律变化。想要改变上下幅值大小,首先将数组里面执行的当前值减去1800,然后再乘以调制系数,最终再加上一个1800就能得到相对于50%占空比的幅值倍增而不是整体倍增。大家画画图就可以理解了。

四、实物调试图片

1、额定电压输出24V
单相逆变电路实战!(基于STM32F103C8T6的单相逆变电路,PID控制输出额定电压)
单相逆变电路实战!(基于STM32F103C8T6的单相逆变电路,PID控制输出额定电压)

2、额定电压输出16V

单相逆变电路实战!(基于STM32F103C8T6的单相逆变电路,PID控制输出额定电压)
单相逆变电路实战!(基于STM32F103C8T6的单相逆变电路,PID控制输出额定电压)

3、额定电压输出8V
单相逆变电路实战!(基于STM32F103C8T6的单相逆变电路,PID控制输出额定电压)
单相逆变电路实战!(基于STM32F103C8T6的单相逆变电路,PID控制输出额定电压)

总结

这就是单相逆变电路的设计,有不懂的朋友可以评论下方留言,我看到了就会回复文章来源地址https://www.toymoban.com/news/detail-400608.html

到了这里,关于单相逆变电路实战!(基于STM32F103C8T6的单相逆变电路,PID控制输出额定电压)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于stm32F103的蜂鸣器周期发声实验

    蜂鸣器作为一种声音报警器件,应用广泛。本实验基于stm32F103单片机,通过控制蜂鸣器的IO口电平电压,使其周期性地进行电平翻转,从而驱动蜂鸣器发出周期性的鸣叫声。该实验主要运用了stm32的GPIO和定时器TIM的相关功能,不仅可以巩固这些外设的使用,也可以通过改变时间参数,控

    2024年02月21日
    浏览(18)
  • 基于STM32F103——AS608指纹模块+串口打印

    最近用STM32F103做一个智能门锁小玩意,其中用到指纹模块,我这里也单独的写一下笔记,不过我只是了解了基本的,就是我做门禁卡要用到的几个东西,其它还没了解。为了方便,做一下记录。我这里没有用到按键和显示屏,所以还是串口输出输入来控制了 哈哈哈哈 这里就

    2023年04月09日
    浏览(18)
  • 全网最全的MCU面试经(基于STM32F103)

    提示:写本文章的缘由:本人在秋招时复习STM32有关的知识点,便顺势记录下来。本文章的知识均属于各大论坛的大佬回答,其中也有我的一些补充,本文主要以自己对STM32的理解作为框架,并积极整理各个大佬的文章,因此属于借花献佛,也不存在任何牟利,分享的初衷是便

    2024年02月09日
    浏览(17)
  • 基于STM32F103HAL库的声音定位系统

    这是一道学校出的电赛题目,要求在100*100cm的平面上实现定位实现声音定位。由于一米太大了,我们就做了40cm的,下面的讲解我按照40厘米的写。用到的处理器是stm32f103c8t6接下来分享一下调试心得。 硬件部分需要制作发声装置和接收装置,详细可以

    2024年02月14日
    浏览(21)
  • 2021校赛基于stm32f103多功能台灯

    起源 又到了一学期一次的校内电子设计大赛,又到了激动人心的时刻每次电子设计大赛都会出现各种大佬展现他们的作品,对于我这种菜鸟也只能默默观望,但是呢,积极参与还是要有的,记得上一次参加做的基于51的避障小车直接买的套件焊好 然后在烧入程序就直接上战场

    2023年04月20日
    浏览(21)
  • STM32--基于STM32F103的MAX30102心率血氧测量

    本文介绍基于STM32F103ZET6+MAX30102心率血氧测量+0.96寸OLED(7针)显示(完整程序代码见文末链接) 一、简介 MAX30102是一个集成的脉搏血氧仪和心率监测仪生物传感器的模块。它集成了一个红光LED和一个红外光LED、光电检测器、光器件,以及带环境光抑制的低噪声电子电路。 MA

    2024年01月16日
    浏览(21)
  • 基于STM32F103的PWM电机驱动A4950

    A4950的峰值输出电流可达±3.5 A,工作电压为7.6~40v。 优点:相对于L298N模块控制2个电机正反转仅需要4个I/O口,体积小,发热低。 缺点:需要2个PWM引脚才能控制正反转,所以控制2个电机需要4PWM引脚,会使用STM32F103芯片一个定时器的全部PWM通道。 A4950模块是靠输入2路的PWM占空

    2024年02月04日
    浏览(39)
  • 基于STM32F103——SIM900A发送短信+串口打印

    最近用STM32F103做一个智能门锁小玩意,密码输入错误次数多进行验证码解锁,这里我采用SIM900A来通过发送短信输入验证码进行解锁。就是简单的了解了一下在这里也单独的写写这个SIM900A的一写笔记。 。。。。。。还是直接进入主题吧 SIM900A是可以AT指令操作的,所以一般我拿

    2023年04月12日
    浏览(31)
  • stm32f103基于pid的蓝牙循迹小车

    目录 前言 一、霍尔编码器以及定时器计数原理 二、使用pwm占空比对电机速度进行控制 三、使用systick的中断函数进行pid和速度的计算,还有oled的显示 四、常用的测速方法:  五、pid原理 六、oled的实现 七、蓝牙通信 八、3路循迹模块 总结   经过一个月对stm32的学习,终于完

    2024年02月16日
    浏览(13)
  • STM32项目设计:基于stm32f103c8t6智能电梯系统

    资料链接:待更新~ 哔哩哔哩视频链接:https://www.bilibili.com/video/BV17D4y1V7HG/?vd_source=e5082ef80535e952b2a4301746491be0(bilibili:化作尘my) 资料链接:https://pan.baidu.com/s/1qObK7KBl50RmFrAtoX12kw 提取码:iih4 实物链接:https://m.tb.cn/h.5h5mDXI?tk=MdxLWYHgKnz CZ0001 1、OLED显示当前楼层、目标楼层等信息

    2024年02月03日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包