📄 main.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 + -