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

📄 main.c

📁 开关稳压电源 开关稳压电源
💻 C
字号:
//文 件 名:main.c
//名    称:开关稳压电源
//功	能:1.实现与CPLD的通信,从而控制PWM的占空比.		2.实现LCD显示相关信息.
//			3.实现对键盘按键的判断和确定相应的操作.		4.实现对电压电流的检测.
//			5.实现过载保护功能,电流过大时,切断PWM输出,当排除过流故障后,自动恢复供电
//			6.实现用PID算法跟踪电压,实现稳压输出
//
//接口分配:	P1.0--键盘输入信号ADC0口			P1.1--输出电流ADC1检测口
//			P1.2--输出电压ADC检测口				P1.3和1.4--锋鸣器控制口
//			P3.7,3.1,3.0--LCD控制端cs,std,sclk	P2.2,2.3,2.5和2.6--与CPLD通信口
//			P3.2--按键中断INT0
//
//作 	者:吕定胜
//创建日期:2007-09-03
//修改日期:2007-09-04


#include <stc12c5410ad.h>
#include "shuju.h"
#include "lcd.h"
#include "cpld.h"

sbit fenmingh = P1^3;
sbit fenmingl = P1^4;
sbit ping = P2^1;

void InitAll(void)
{
	lcdinit();		//LCD显示初始化
	
	outcs = 1;		//给CPLD一个高电平,禁止输出PWM
	P1M0 = 0xFF;
	P1M1 = 0x18;	//设置P1.0~2为高阻输入作ADC输入用,P1.3和1.4为开漏模式,P1.5~7为高阻
	P2M0 = 0x91;
	P2M1 = 0x02;
	P3M0 = 0x78;
	P3M0 = 0x00;
	TMOD = 0x10;	//计时器1工作于方式1,用于后面的保护电路计时用
	IPH = 0x01;
	IP  = 0x01;		//设置按键中断为最高级
	IT0 = 0;		//设置按键中断为下降沿有效
	//初始化各个变量值
	fixoutu = 300;			//开机输出的初始电压为30V
	Ppid->Proportion = 0.36;//比例常数 Proportional Const
	Ppid->Integral=0.01; 	//积分常数 Integral Const
	Ppid->Derivative=0.02;	//微分常数 Derivative的设定
	Ppid->gpwm = pwm[0];	//Ppid->gpwm的初始值为30V副近
	EA  = 1;		//开总中断
	EX0 = 1;		//开键盘中断
}

////检测输出电压和电流////
bit CheckOut(void)
{
	unsigned char  cous;			//采样次数计数用
	float outtemp0 = 0;	
	outu = 0;
	outi = 0;
	for(cous=0;cous<200;cous++)
	{
		ADC_CONTR = 0xE1;			//选择ADC1通道,检测电流值
		EA = 0;
		ADC_CONTR |= 0x08;			//启动AD转换
		while(!(ADC_CONTR&0x10));	//AD转换尚未完成,继续等待
		ADC_CONTR = ADC_CONTR&0xE7;	//清ADC_FLAG,ADC_START,停止AD转换
		EA = 1;
		if(ADC_LOW2&0x02)
			outtemp0 += table1[ADC_DATA];
		else outtemp0 += table0[ADC_DATA];
		delay_50us(1);
	}
	outi = (outtemp0+2000)/4000;	//输出电流求值,扩大100倍保存,比例:5V~2.5A	
	if(outi>248) {flagguo = 1;return 1;}
	
	outtemp0 = 0;
	for(cous=0;cous<200;cous++)
	{
		ADC_CONTR = 0xE2;			//选择ADC2通道
		EA = 0;
		ADC_CONTR |= 0x08;			//启动AD转换
		while(!(ADC_CONTR&0x10));	//AD转换尚未完成,继续等待
		ADC_CONTR = ADC_CONTR&0xE7;	//清ADC_FLAG,ADC_START,停止AD转换
		EA = 1;
		if(ADC_LOW2&0x02)
			outtemp0 += table1[ADC_DATA];
		else outtemp0 += table0[ADC_DATA];
		delay_50us(1);
	}
	outu = (outtemp0*8-outi*500+10000)/20000;		//输出电压求值,扩大10倍保存,比例:5V~40V
	return 0;
}


//PID算法用来调节输出电压
void PIDtiao(void)
{
	float  dError;
	int  tiao;
	Ppid->LastError = (fixoutu-outu);
	Ppid->P = Ppid->Proportion*Ppid->LastError;		//比例控制量
	if(Ppid->LastError>4)							//差距大于0.4V取消积分
		Ppid->SumError = 0;
	else Ppid->SumError += Ppid->LastError;         //积分
	Ppid->I = Ppid->Integral*Ppid->SumError;		//积分控制量
    dError = Ppid->LastError - Ppid->PrevError;   	//当前微分
	Ppid->D = Ppid->Derivative*dError;				//微分控制量
    Ppid->PrevError = Ppid->LastError;
    tiao = (int)(Ppid->P+Ppid->D+Ppid->I);
	Ppid->gpwm += tiao;
	if(Ppid->gpwm>480)	Ppid->gpwm = 480;
 	if(Ppid->gpwm<1)	Ppid->gpwm = 0;
	send(Ppid->gpwm);
	
}

//保护电路
void baohu(void)
{
//	unsigned char i;
	outcs = 1;
	send(0xFFFF);
	fenmingh = 1;
	fenmingl = 0;
	display_coordinate(1,1);
	DisplayListChar("警告!!!!      ");
	display_coordinate(2,1);
	DisplayListChar("机器存在故障!!  ");
	display_coordinate(3,1);
	DisplayListChar("电流过大!!!!    ");
	display_coordinate(4,1);
	DisplayListChar("请排除故障!!    ");
lds:outcs = 1;
	send(0xFFFF);
	timer = 50 ;
	ET1 = 1;
	TH1 = 0x00;
	TL1 = 0x00;
	TR1 = 1;
	WDT_CONTR = 0x37;
	while(timer>1)
	{;}
	TR1 = 0;
	send(Ppid->gpwm);
	outcs = 0;
	delay_50us(6);
	flagguo=CheckOut();
	if(flagguo) goto lds;
	fenmingh = 0;
	clear = 1;
}

//主函数
void main()
{
	WDT_CONTR = 0x37;
	Ppid=&pid;		//设置指针变量
	InitAll();		//整机初始化
	display0();
	while(1)
	{
		if(flagpower)
		{
			flagguo=CheckOut();			//检测输出电压
			if(flagguo) baohu();
	        zhuang1();			
			display();
			PIDtiao();
		}
		else 
		{
			outu_list[0]='0';
			outu_list[1]='0';
			outu_list[3]='0';
			outi_list[0]='0';
			outi_list[2]='0';
			outi_list[3]='0';
			display();
		}
	    WDT_CONTR = 0x37;
	}
}



/////////////////中断服务程序///////////////////////
//外部中断0服务子程序,主要用于完成按键的判断操作安排
void ex0_int(void) interrupt 0
{
	unsigned char i,j;
	ADC_CONTR = 0xE0;			//选择ADC0通道
	do
	{
		ADC_CONTR |= 0x08;			//启动AD转换
		while(!(ADC_CONTR&0x10));	//AD转换尚未完成,继续等待
		ADC_CONTR = ADC_CONTR&0xE7;	//清ADC_FLAG,ADC_START,停止AD转换
		i = ADC_DATA;
		delay_50us1(1);
		ADC_CONTR |= 0x08;			//启动AD转换
		while(!(ADC_CONTR&0x10));	//AD转换尚未完成,继续等待
		ADC_CONTR = ADC_CONTR&0xE7;	//清ADC_FLAG,ADC_START,停止AD转换
		j = ADC_DATA;
	}while(j!=i);
	j &= 0xFC;

	switch(j)
	{
		case 0xEC:
		case 0xF4:
		case 0xF0:	//"开关"
		I_Oput = 0;	//清输入数据标志
		if(flagpower==1)
		{
			outcs = 1;
			send1(0xFFFF);
			flagpower=0;
		}//关电源
		else 
		{
			send1(Ppid->gpwm);
			outcs = 0;
			flagpower=1;
		}//开电源
		break;
		
		case 0xE4://向上
		I_Oput = 0;	//清输入数据标志
		if(fixoutu<360)
	 	{
			fixoutu += 10;
//			i = fixoutu/10-30;
//			Ppid->gpwm=pwm[i];
//			if(Ppid->gpwm+10<510)
//			Ppid->gpwm+=5;
//			send1(Ppid->gpwm);
		}
/*		if(Ppid->gpwm<500)
		{
			Ppid->gpwm += 2;
			send1(Ppid->gpwm);
		}*/
		break;
		
		case 0xD8://向下
		I_Oput = 0;	//清输入数据标志
		if(fixoutu>300) 
		{
			fixoutu -= 10;
//			i = fixoutu/10-30;
//			Ppid->gpwm=pwm[i];
//			if(Ppid->gpwm+10>10)
//			Ppid->gpwm-=10;
//			send1(Ppid->gpwm);
		}
/*		if(Ppid->gpwm>0)
		{
			Ppid->gpwm -= 2;
			send1(Ppid->gpwm);
		}*/
		break;
		
		case 0xC0://切换
		if(ping==1)
		ping=0;
		else 
		ping=1;
		break;
		
		case 0xCC://输入确定
		if(I_Oput&&flagpower==1)
		{
			I_Oput = 0;
			wr_lcd1(0,0x0C);
			inu = buff[0]*10+buff[1];
			if(inu<30||inu>36)
			{
				display_coordinate1(4,6);
				DisplayListChar1("ERROR");
			}
			else 
			{
				fixoutu = inu*10;			
				i = fixoutu/10-30;
				Ppid->gpwm = pwm[i];
				send1(Ppid->gpwm);
			}
		}
		else if(flagpower==1)
		{
			I_Oput=1;
			putcoun = 0;
			buff[0] = 0;
			buff[1] = 0;
			waitin = 1;
		}
		break;
		
		case 0x60:
		
		
		case 0x5C:
		case 0x58:					//按下0
		if(I_Oput==1&&putcoun<2) 
		{
			wr_lcd1(1,0x30);	 	
			buff[putcoun++]=0;
		}
		break;
		
		case 0x3C:					//按下1
	 	if(I_Oput==1&&putcoun<2) 
		{
			wr_lcd1(1,0x31);	 	
			buff[putcoun++]=1;
		}
		break;

		case 0x48:					//按下2
		if(I_Oput==1&&putcoun<2) 
		{
			wr_lcd1(1,0x32);	 	
			buff[putcoun++]=2;
		}
		break;

		case 0x50:
		case 0x54:
					//按下3
		if(I_Oput==1&&putcoun<2) 
		{
			wr_lcd1(1,0x33);	 	
			buff[putcoun++]=3;
		}
		break;

		case 0x8C: 					//按下4 
		if(I_Oput==1&&putcoun<2) 
		{
			wr_lcd1(1,0x34);	 	
			buff[putcoun++]=4;
		}
		break;
		
		case 0x80: 					//按下5
		if(I_Oput==1&&putcoun<2) 
		{
			wr_lcd1(1,0x35);	 	
			buff[putcoun++]=5;
		}
		break;

		case 0x74: 					//按下6
		if(I_Oput==1&&putcoun<2) 
		{
			wr_lcd1(1,0x36);	 	
			buff[putcoun++]=6;
		}
		break;

		case 0x9C: 					//按下7
		if(I_Oput==1&&putcoun<2) 
		{
			wr_lcd1(1,0x37);	 	
			buff[putcoun++]=7;
		}
		break;
		case 0xA8: 					//按下8
		if(I_Oput==1&&putcoun<2) 
		{
			wr_lcd1(1,0x38);	 	
			buff[putcoun++]=8;
		}
		break;

		case 0xB4: 					//按下9
		if(I_Oput==1&&putcoun<2) 
		{
			wr_lcd1(1,0x39);	 	
			buff[putcoun++]=9;
		}
		break;
		
		case 0x68: 				//按下.
		if(ping==1)
		ping=0;
		else 
		ping=1;
		break;

	}
	do
	{
		ADC_CONTR |= 0x08;			//启动AD转换
		while(!(ADC_CONTR&0x10));	//AD转换尚未完成,继续等待
		ADC_CONTR = ADC_CONTR&0xE7;	//清ADC_FLAG,ADC_START,停止AD转换
		i = ADC_DATA;
		i &= 0xF0;
		WDT_CONTR = 0x37;
	}while(i!=0);
}


//定时器1中断服务子程序
void Timer1_int(void) interrupt 3
{
	timer--;
	TH1 = 0x00;
	TL1 = 0x00;
}

⌨️ 快捷键说明

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