⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dcdc.c

📁 C51编写的开关电源
💻 C
字号:
#include <absacc.h>
#include <reg51.h>

/*////////////////////////////*/
/*///		常量定义      //*/
/*////////////////////////////*/

/* 定时器初值 */
#define V_T1   0xfd   /*SCOM  9600 baud,  ! notice: crystal 11.0592MHz */
#define V_TH0   0xee  /*   ~ 5ms ,  ! notice: crystal 11.0592MHz */
#define V_TL0   0x00

/* 数码管段驱动寄存器地址 */
#define ADDR_8SEG	XBYTE[0x2000]

/* 数码管位驱动和指示灯驱动寄存器地址 */
#define ADDR_SEL	XBYTE[0x4000]

///ADC0804驱动寄存器地址
#define ADDR_0804  XBYTE[0x6000]

/* 按键 */
sbit KEY1=P1^0;	
sbit KEY2=P1^1;
sbit KEY3=P1^2;
sbit KEY4=P1^3;

/*输出端口*/
sbit PWM_Level=P3^5;

/*////////////////////////////*/
/*///		变量定义      ///*/
/*////////////////////////////*/

/////定义占空比,数值放大了100倍
unsigned int data q;

unsigned int data highlevel;
/////定义电压值,数值放大了10倍
unsigned char data u;
/////定义PWM波一个周期内高电平的时间数值及定时器1中TH1和TL1的值
unsigned int data PWM_High;
unsigned char data PWM_High_TH;
unsigned char data PWM_High_TL;
/////定义PWM波一个周期内低电平的时间数值及定时器1中TH1和TL1的值
unsigned int data PWM_Low;
unsigned char data PWM_Low_TH;
unsigned char data PWM_Low_TL; 


unsigned char flag;
bit sign;
bit calculate_q; 

unsigned int data_0804;

/////表征键盘状态,值1表示按键都已松开,值0表示有键被按下
bit single_key;
/////对应四个按键,用来记录延时
unsigned char delay[4];	

/* 数码管位驱动和指示灯驱动信号输出缓存,定义了一个可位寻址的变量 */
unsigned char bdata output_sel;
sbit led_1 = output_sel^5;
sbit led_2 = output_sel^6;
sbit led_3 = output_sel^7;
sbit led_4 = output_sel^4;

/* 数码管扫描驱动指针,为测试外部存储器(U3 6264),特使用xdata类型 */
unsigned char xdata digi_scaner;

unsigned char xdata Hex_8SEG[4];

/* 测试用计数值十进制表示,为测试外部存储器(U3 6264),特使用xdata类型 */
unsigned char xdata digi[4]; 

bit Kst1,Kst2,Kst3,Kst4;
bit states;
unsigned char workmod;
bit shinetwo;
unsigned char shinefour;

unsigned int idata aad[10]={0,0,0,0,0,0,0,0,0,0};
unsigned int idata sum;
unsigned char data temp;
unsigned char index;

float idata a1,b1,c1,a2,b2,c2;	//对应10.0-8.7,8.7-5.0
float idata qf[5];
unsigned char dotnum;
unsigned int idata vf[5]={99,94,87,71,55};
unsigned int times;
bit autosign;

unsigned char Vo[]={238,234,229,225,220,216,211,206,201,197,192,187,182,178,173,168,163,158,153,148,143,138,133,128,123,118,113,108,103,97,92,88,83,78,73,68,63,58,53,48,43,39,35,30,26,23,20,18,15,13,11};	 //5.0-10.0//
				  //5.0,5.1,5.2,5.3,5.4,5.5,5.6,5.7,5.8,5.9,6.0,6.1,6.2,6.3,6.4,6.5,6.6,6.7,6.8,6.9,7.0,7.1,7.2,7.3,7.4,7.5,7.6,7.7,7.8,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100

/*////////////////////////////*/
/*///		函数定义         /*/
/*////////////////////////////*/

/**** 7段数码显示译码 
    参数:DATA: 需要显示的数字或符号;
	返回值: 7段译码结果 ( D7~0 = PGFEDCBA )
*****/
unsigned char NUMTOSEG7(unsigned char DATA)
{
	unsigned char AA;
  	switch (DATA){ 
		case 0: AA=0xc0;break; /* ‘0’*/
    	case 1: AA=0xf9;break; /* ‘1’*/
    	case 2: AA=0xa4;break; /* ‘2’*/
    	case 3: AA=0xb0;break; /* ‘3’*/
    	case 4: AA=0x99;break; /* ‘4’*/
    	case 5: AA=0x92;break; /* ‘5’*/
    	case 6: AA=0x82;break; /* ‘6’*/
    	case 7: AA=0xf8;break; /* ‘7’*/
    	case 8: AA=0x80;break; /* ‘8’*/
    	case 9: AA=0x90;break; /* ‘9’*/
		case 10: AA=0x88;break; /* ‘A’*/    
		case 20: AA=0x83;break; /* ‘b’*/
		case 21: AA=0x8f;break; /* ‘k’*/
		case 22: AA=0xf1;break; /* ‘j’*/
		case 23: AA=0xc1;break; /* ‘u’*/
    	case 24: AA=0xff;break; /* 消隐 */
    	default: AA=0xff; 
  	}
  	return(AA);
} 

//========  计算PWM波的高低电平持续时间数值  ========
void Caculate_PWM()
{	 
  	PWM_High=65535-highlevel;
	PWM_Low=65535-(3000-highlevel);
	EA=0;
	PWM_High_TH=PWM_High/256;
	PWM_High_TL=PWM_High%256;
	PWM_Low_TH=PWM_Low/256;
	PWM_Low_TL=PWM_Low%256;
	EA=1;
}


//========  粗略计算对应于期望电压的占空比  ========
void Cacult_Q()
{  	float temp_U;
	float temp_Q; 
	temp_U=u;
	temp_U=temp_U/10;
	if(u>=87) temp_Q=c1+b1*temp_U+a1*temp_U*temp_U;
	else temp_Q=c2+b2*temp_U+a2*temp_U*temp_U;
	q=temp_Q*100;	
} 

//=======  闭环自动调节电压  =======
void FeedBackControl()
{
	if(data_0804<Vo[u-50]){
		if(q<9990) q+=1;
	}
	else if(data_0804>Vo[u-50]){
		if(q>10) q-=1;																	          
	} 
}

//=======  开环自动拟合  =======
void AutoFitting()
{ 	
	a1=(0.7*qf[0]-1.2*qf[1]+0.5*qf[2])/0.42;
	b1=-(12.67*qf[0]-22.32*qf[1]+9.65*qf[2])/0.42;
	c1=(57.246*qf[0]-103.356*qf[1]+46.53*qf[2])/0.42;
	a2=(1.6*qf[2]-3.2*qf[3]+1.6*qf[4])/8.192;
	b2=-(20.16*qf[2]-45.44*qf[3]+25.28*qf[4])/8.192;
	c2=(62.48*qf[2]-153.12*qf[3]+98.832*qf[4])/8.192;
} 

//=======  闭环自动检测基准点  =======
void AutoAdjusting()
{
	u=vf[dotnum];
	if(times>=3000){		
		if(dotnum<5){
			qf[dotnum]=q;
			qf[dotnum]/=100;
		}
		dotnum++;
		if(dotnum>=5){
			AutoFitting();
			dotnum=0;
			autosign=0;
			workmod=1;
			u=50;
		}
		times=0;
	}
} 

//=======  按键事件响应管理  =======
void KeyBoard_Admin()
{
	if(Kst1){
		if(++workmod>2) workmod=0;	
	}
	if(workmod==2){
		if(Kst2){				
			if(++shinefour>4) shinefour=0;
		}
		if(shinefour==0){
			if(Kst3&&q<9000) q+=1000;
			if(Kst4&&q>1000) q-=1000;	
		}else if(shinefour==1){
			if(Kst3&&q<9900) q+=100;
			if(Kst4&&q>100) q-=100;	
		}else if(shinefour==2){
			if(Kst3&&q<9990) q+=10;
			if(Kst4&&q>10) q-=10;	
		}else if(shinefour==3){
			if(Kst3&&q<9999) q+=1;
			if(Kst4&&q>1) q-=1;
		}else{
			if(Kst3){
				if(dotnum<5){
					qf[dotnum]=q;
					qf[dotnum]/=100;
				}
				dotnum++;
			}
			if(Kst4){
				autosign=1;
				times=0;
				dotnum=0;
				workmod=0;
			}
		}
	}else{
		if(Kst2) shinetwo=!shinetwo;
		if(shinetwo){
			if(Kst3&&u<=90) u+=10;
			if(Kst4&&u>=60) u-=10;						
		}else{
			if(Kst3&&u<=99) u+=1;
			if(Kst4&&u>=51) u-=1;			
		}
		calculate_q=1;
	}
	Kst1=Kst2=Kst3=Kst4=0;
}

//=======  指示灯管理  =======
void LedPrint()
{
	if(workmod==2){
		if(shinefour==4){
			digi[0]=24;
			digi[1]=24;
			digi[2]=24;
			digi[3]=dotnum+1;		
		}else{
			digi[0]=q/1000;
			digi[1]=(q-1000*digi[0])/100;
	    	digi[2]=(q-1000*digi[0]-100*digi[1])/10; 
			digi[3]=q-1000*digi[0]-100*digi[1]-10*digi[2];
		}		
	}else{	
		if(autosign) digi[0]=10;
		else digi[0]=20+workmod;
		digi[1]=u/100;
		digi[2]=(u-100*digi[1])/10;
		digi[3]=u-100*digi[1]-10*digi[2];	
		if(digi[1]==0) digi[1]=24;	
	}
}

//========  T0时钟中断服务程序,每5ms被执行一次  ========
timer0() interrupt 1 using 0         
{
	EA=0;  /*关中断*/

	/* 重新对计数器赋初值,并启动定时计数 */
	TR0=0;
	TH0=V_TH0;
    TL0=V_TL0;
    TR0=1;
	EA=1;

	output_sel = 0xf0; /*初值,令数码管驱动位无效,指示灯全灭*/

	//键盘扫描 
	if(single_key){
		if(KEY1==0) delay[0]++;
		if(delay[0]>=10){
			delay[0]=single_key=0;		
			Kst1=1;			
		}
		if(KEY2==0) delay[1]++;
		if(delay[1]>=10){
			delay[1]=single_key=0;
			Kst2=1;			
		}
		if(KEY3==0) delay[2]++;
		if(delay[2]>=10){
			delay[2]=single_key=0;		
			Kst3=1;		
		}
		if(KEY4==0) delay[3]++;
		if(delay[3]>=10){
			delay[3]=single_key=0; 		
			Kst4=1;			
		}
	}
	if(KEY1&&KEY2&&KEY3&&KEY4) single_key=1;
	 
	if(++flag>=100) sign=1;

	if(autosign) times++;
	   
	if(states) ADDR_0804=0;		
	else temp=ADDR_0804; 	
	states=!states;	   		
		
	/* 检测到按键被按下(0)时,相应的指示灯电亮(0)*/ 
	if(workmod==2){
		if(shinefour==0) led_1=0;
		else if(shinefour==1) led_2=0;
		else if(shinefour==2) led_3=0;
		else if(shinefour==3) led_4=0;
		else led_2=led_4=0;
	}else{	
		if(shinetwo) led_3=0;
		else led_4=0;
	}
	if(!single_key) led_1=led_2=led_3=led_4=0;

	
	/* 数码管扫描驱动指针值从1到4重复变换,每5ms间隔对一个数码管进行驱动,20ms一个轮回 */
	if (++digi_scaner>=5) digi_scaner = 1;
	switch (digi_scaner){
		case 1: //驱动第一个数码管
			output_sel |= 0x01;		
			ADDR_8SEG = Hex_8SEG[0];//输出到锁存器U5(在电路图中找)
			break;
		case 2: // 驱动第二个数码管
			output_sel |= 0x02;			
			ADDR_8SEG = Hex_8SEG[1];//输出到锁存器U5
			break;
		case 3: // 驱动第三个数码管
			output_sel |= 0x04;			
			ADDR_8SEG = Hex_8SEG[2];//输出到锁存器U5
			break; 
		case 4: // 驱动第四个数码管 
			output_sel |= 0x08;			
			ADDR_8SEG = Hex_8SEG[3];//输出到锁存器U5
			break;	
	}
	ADDR_SEL = output_sel;     	/*输出到锁存器U6(在电路图中找)*/ 
}

//========  T1时钟中断服务程序,用于产生PWM波  ========
PWM_Wave() interrupt 3 using 1
{
	EA=0;  ////关中断
	TR1=0; 	
	if(PWM_Level){ 		
		PWM_Level=0;  			
		TH1=PWM_Low_TH;
		TL1=PWM_Low_TL;	
	}else{
		PWM_Level=1;			
		TH1=PWM_High_TH;
		TL1=PWM_High_TL;  		
	}
	TR1=1;  		
	EA=1;  ////开中断
}


//========  主程序  ========
main()
{
	/* 单片机系统初始化 */
    P1=0XFF;
    P3=0XFF;

    /** 中断工作寄存器初始化 **/
    IE=0X80;
    IP=0X08;

    IT0=0;
    IT1=0;

    /** 定时器工作寄存器初始化 **/
	TMOD=0X11;
	TH1=V_T1;
    TL1=V_T1;
    TH0=V_TH0;
    TL0=V_TL0;
    
    /** 串行通信口工作初始化 ,注:本例中虽未使用到串行通信口,但本段程序无妨保留**/
	SM0=0;		 /*SCOM MODE 1 (8BIT UART VARBR)*/
    SM1=1;
	SM2=0;
	REN=1;
	TI=1;

	/** 全局变量赋初值 **/
	q=2000;
	u=50;	
	sum=0;
	autosign=0;
	dotnum=0;
	sign=1;
	calculate_q=1;
	PWM_Level=0;
	a1=-4.323;b1=64.192;c1=-172.073;
	a2=-0.470;b2=-2.844;c2=118.028;

	single_key=0;
	shinefour=0;
	delay[0]=0;
	delay[1]=0;
	delay[2]=0;
	delay[3]=0;

	/** 开定时器,定时器0中断允许 **/
    TR0=1;
    TR1=1;
	ET0=1;
	ET1=1;
	
	/* 主循环,本例中,在T0中断服务程序未被执行的空余时间里,处理机在以下程序中不断循环 */
	while(1)
	{	
		if(sign){			
			flag=0;
			KeyBoard_Admin();
			if(workmod==0){
				if (++index>=10) index=0;
				sum-=aad[index];
				aad[index]=temp;
				sum+=aad[index];
				data_0804=sum/10;
				FeedBackControl(); 			
			}else if(workmod==1){			
				if(calculate_q){
					calculate_q=0;
					Cacult_Q();						
				}
			}else if(dotnum>=5){
				AutoFitting();
				dotnum=0;
			}
			if(autosign) AutoAdjusting();
			highlevel=q*3/10;								
			Caculate_PWM();				
		}
		LedPrint();
		Hex_8SEG[0] = NUMTOSEG7(digi[0]);			
		Hex_8SEG[1] = NUMTOSEG7(digi[1]);
		Hex_8SEG[2] = NUMTOSEG7(digi[2]);
		if(workmod!=2) Hex_8SEG[2] -= 0x80;		
		Hex_8SEG[3] = NUMTOSEG7(digi[3]);			
	}
} 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -