即將告別大學,學了幾年也沒什么拿得出手的作品。由于學校停課,趁著找工作的空閑索性做個一直掛記在心的單片機數控電源。從策劃到最后作品成型一共前前后后花了4天。先后經歷了兩次坐車到電子市場買元器件,調程序到深夜凌晨3點,焊板子,被熱熔膠燙破手皮。四天幾乎除了吃飯睡覺的幾個小時外都在設計。期間也遇到很多問題。例如:做DA時調不出輸出電壓,反復折騰了一天才解決,原來是單片機管腳有問題,又換了一塊。(燒掉一塊運放,導致又到電子市場買了一塊)。四天下來總算充分完成了設計任務。確實學到了不少,模電這塊還是要加強一下。這個作品完成后決定把所有這幾年積攢下來的一大麻袋電子垃圾全部扔到無線電協會,從此告別電烙鐵,告別大學,開始新生活.
制作過程
完整作品
遠視圖
側視圖
后視圖
內部俯視圖
面板
D/A,A/D數控電源電路板
整機
俯視圖
側視圖
正視圖
一,設計任務:
基本部分:
1,輸出電壓范圍0-25V。
2,電流范圍0-2.5A。
3,用1602液晶顯示電壓值。
4,用矩陣鍵盤實現電壓值輸入(0-9,清除鍵,確認鍵等)。
選設部分:
1, 溫度檢測顯示(可采用4位數碼管或在液晶上顯示)
2, 時間顯示(可采用6位數碼管或在液晶上顯示)
二,系統框圖
三.工作原理:
1.上電復位,讀取24C02中的電壓,送DA轉換輸出電壓,如24C02中電壓為O則設置初始電壓為5V;
2.電壓控制:通過矩陣鍵盤控制單片機產生8位數字信號(0-255),通過P3口送至8位數模轉換芯片(DAC0832)轉換成模擬電流信號,再經運放作I/U轉換,得到控制穩壓電源輸出部分的基準電壓;
3.電流取樣:采用10位模數轉換芯片(TLC1549)作為顯示電流的模數轉換器件,TLC1549的取樣電壓由串聯在電源輸出電路的電流取樣電阻(0.1Ω)分壓取得,并由運放按一定倍數放大后送至Vin(+),TLC1549把轉換結果送至單片機的P2.3口,再由程序將數據處理后送LCD1602顯示當前電流;
4.過流保護:當短路或電流超過設定值2.4A時,單片機自動保存當前使用電壓并關閉輸出;
5.穩壓輸出:采用傳統的串聯穩壓電路,由運放和功率輸出管組成。利用DAC0832控制的基準電壓驅動功率管穩壓輸出,反饋部分是通過電阻R3,VR2將取樣電壓輸入運放的反相端比較,VR2可作小范圍調整;
四,源程序 (初稿)
所有源程序已通過調試,首發于單片機網http://www.zg4o1577.cn,有問題可與QQ:125739409聯系,注意不得用于商業目的,有兩個程序,第一個為數控電源程序,第二個為溫度和時間的程序。
程序一
#include <reg52.h> //52系列頭文件
#define Disdata P0 //液晶數據端口
#define uchar unsigned char //無符號字符8位
#define uint unsigned int //無符號整數8位
uint data dis[4]={0x00,0x00,0x00,0x00};//4個數據單元和一個
uchar code table[]="OUTPUT: . V "; //定義初始上電液晶默認顯示狀態
uchar code table1[]="designed by :";
uchar code table3[]=" Li Xiaojun";
uchar code table2[]="INPUT: . V ";
sbit lcden=P2^7; //定義液晶使能端
sbit lcdrs=P2^5; //定義液晶RS端
sbit rw=P2 ^6; //定義液晶RW端
sbit cs_ad=P2^4;
sbit dout=P2^3;
sbit clk=P2^2; //轉換結束標志位
sbit da_wr=P2^1;
sbit da_cs=P2^0;
sbit beep=P1^7;//蜂鳴器
data int result;//測量變量暫存地址
uchar num,num1,num2,num3,num4,num5;
uchar shii,gei;
uchar shuru;
uchar dagg,dass;
uchar key,temp;
uchar cvc,mma,mmb;
uchar ddf;
uint ddt;
//********延時函數************
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
//*************
void di()
{
beep=0;
delay(100);
beep=1;
}void write_com(uchar com) //液晶寫命令函數
{
lcdrs=0;
P0=com;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
void write_data(uchar date) //液晶寫數據函數
{
lcdrs=1;
P0=date;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
void write_sg(uchar add,uchar date) //寫整數位和小數位函數
{
uint shi,ge;
shi=date/10; //分解出一個2位數的十位
ge=date%10;
write_com(0x80+0x40+add); //設置顯示位置
write_data(0x30+shi); //送去液晶顯示十位
write_data(0x30+ge); //送去液晶顯示個位
}
//void write_da(uchar sps,uchar uru)
//{ uchar yuy,rur;
// yuy=uru;
// rur=0;
// write_com(0x80+sps); //設置顯示位置
//if(cvc==8)
// {
// write_data(0x30+yuy); //送去液晶顯示十位
// write_data(0x30+rur); //送去液晶顯示個位
// }
/// else
// write_data(0x30+rur); //送去液晶顯示十位
// write_data(0x30+yuy);
//}void init()
{
shuru=0;
rw=0;
lcden=0;
shii=0;
gei=0;
dagg=0;
dass=0;
write_com(0x38); //初始化1602液晶
write_com(0x0c);
write_com(0x06);
write_com(0x01);
write_com(0x80); //設置顯示初始坐標 for(num2=0;num2<13;num2++)
{
write_data(table1[num2]);
delay(5);
}
write_com(0x80+40);
for(num3;num3<16;num3++)
{
write_data(table3[num3]);
delay(5);
}
delay(3000);
} //*******************************
void scan1()
{
write_com(0x80);
for(num1;num1<16;num1++)
{
write_data(table2[num1]);
delay(5);
}
// write_da(8,dass);
//write_da(11,dagg); write_com(0x80+0x40); //設置顯示初始坐標
for(num=0;num<16;num++)
{
write_data(table[num]);
delay(5);
}
write_sg(8,shii);
write_sg(11,gei);
}
//****TLC1549轉換處理子函數********void test()
{
data uchar i;
cs_ad=1; //禁止i/o clock
cs_ad=0; //開啟控制電路,使能data out和i/o clock
result=0; //清轉換變量
for(i=0;i<10;i++) //采集10次 ,即10bit
{
clk=0;
result*=2;
if(dout) result++;
clk=1;
}
delay(590);
cs_ad=1; ;;;; //data out 返回到高阻狀態而終止序列
//****數據轉換處理**********
result=result*2;
dis[2]=result/205; //計算整數位
dis[3]=result%205; //余數暫存
dis[3]=dis[3]*10; //計算小數第一位
dis[1]=dis[3]/205;
dis[3]=dis[3]%205;
dis[3]=dis[3]*10; //計算小數第二位
dis[0]=dis[3]/205;
shii=dis[2];
gei=dis[1]*10+dis[0];
write_sg(8,shii);
write_sg(11,gei);
}
//***********************
void test_da()
{
ddf=mma+mmb*0.1-0.7;
ddf=ddf*25.6;
ddt=ddf;
da_wr=0;
da_cs=0;
P3=ddt;
delay(1);
}//*************************
void markey()
{
P1=0xfe;
temp=P1;
temp=temp&0xf0;
if(temp!=0xf0)
{
delay(10);
temp=P1;
temp=temp&0xf0;
if(temp!=0xf0);
{
temp=P1;
switch(temp)
{
case 0xee:
if(cvc==0)
{
write_com(0x80+8);
write_data(0x30+0);
write_data(0x30+1);
di();
cvc++;
key=1;
mma=key;
break;
}
else
write_com(0x80+11);
write_data(0x30+1);
write_data(0x30+0);
key=1;
cvc=0;
di();
mmb=key;
test_da();
break;
case 0xde:
if(cvc==0)
{
write_com(0x80+8);
write_data(0x30+0);
write_data(0x30+2);
di();
cvc++;
key=2;
mma=key;
break;
}
else
write_com(0x80+11);
write_data(0x30+2);
write_data(0x30+0);
key=2;
cvc=0;
di();
mmb=key;
test_da();
break;
case 0xbe:
if(cvc==0)
{
write_com(0x80+8);
write_data(0x30+0);
write_data(0x30+3);
di();
cvc++;
key=3;
mma=key;
break;
}
else
write_com(0x80+11);
write_data(0x30+3);
write_data(0x30+0);
key=3;
cvc=0;
di();
mmb=key;
test_da();
break;
}
while(temp!=0xf0)
{
temp=P1;
temp=temp&0xf0;
}
}
} P1=0xfd;
temp=P1;
temp=temp&0xf0;
if(temp!=0xf0)
{
delay(10);
temp=P1;
temp=temp&0xf0;
if(temp!=0xf0);
{
temp=P1;
switch(temp)
{
case 0xed:
if(cvc==0)
{
write_com(0x80+8);
write_data(0x30+0);
write_data(0x30+4);
di();
cvc++;
key=4;
mma=key;
break;
}
else
write_com(0x80+11);
write_data(0x30+4);
write_data(0x30+0);
key=4;
cvc=0;
di();
mmb=key;
test_da();
break;
case 0xdd:
if(cvc==0)
{
write_com(0x80+8);
write_data(0x30+0);
write_data(0x30+5);
di();
cvc++;
key=5;
mma=key;
break;
}
else
write_com(0x80+11);
write_data(0x30+5);
write_data(0x30+0);
key=5;
cvc=0;
di();
mmb=key;
test_da();
break;
case 0xbd:
if(cvc==0)
{
write_com(0x80+8);
write_data(0x30+0);
write_data(0x30+6);
di();
cvc++;
key=6;
mma=key;
break;
}
else
write_com(0x80+11);
write_data(0x30+6);
write_data(0x30+0);
key=6;
cvc=0;
di();
mmb=key;
test_da();
break;
}
while(temp!=0xf0)
{
temp=P1;
temp=temp&0xf0;
}
}
} P1=0xfb;
temp=P1;
temp=temp&0xf0;
if(temp!=0xf0)
{
delay(10);
temp=P1;
temp=temp&0xf0;
if(temp!=0xf0);
{
temp=P1;
switch(temp)
{
case 0xeb:
if(cvc==0)
{
write_com(0x80+8);
write_data(0x30+0);
write_data(0x30+7);
di();
cvc++;
key=7;
mma=key;
break;
}
else
write_com(0x80+11);
write_data(0x30+7);
write_data(0x30+0);
key=7;
cvc=0;
di();
mmb=key;
test_da();
break;
case 0xdb:
if(cvc==0)
{
write_com(0x80+8);
write_data(0x30+0);
write_data(0x30+8);
di();
cvc++;
key=8;
mma=key;
break;
}
else
write_com(0x80+11);
write_data(0x30+8);
write_data(0x30+0);
key=8;
cvc=0;
di();
mmb=key;
test_da();
break;
case 0xbb:
if(cvc==0)
{
write_com(0x80+8);
write_data(0x30+0);
write_data(0x30+9);
di();
cvc++;
key=9;
mma=key;
break;
}
else
write_com(0x80+11);
write_data(0x30+9);
write_data(0x30+0);
key=9;
cvc=0;
di();
mmb=key;
test_da();
break;
}
while(temp!=0xf0)
{
temp=P1;
temp=temp&0xf0;
}
}
}
P1=0xf7;
temp=P1;
temp=temp&0xf0;
if(temp!=0xf0)
{
delay(10);
temp=P1;
temp=temp&0xf0;
if(temp!=0xf0);
{
temp=P1;
switch(temp)
{
case 0xe7:
if(cvc==0)
{
write_com(0x80+8);
write_data(0x30+0);
write_data(0x30+0);
di();
cvc++;
key=0;
mma=key;
break;
}
else
write_com(0x80+11);
write_data(0x30+0);
write_data(0x30+0);
key=0;
cvc=0;
di();
mmb=key;
test_da();
break;
break;
case 0xd7:
key=11;
write_com(0x80+8);
write_data(0x30+0);
write_data(0x30+0);
write_com(0x80+11);
write_data(0x30+0);
write_data(0x30+0);
di();
cvc=0;
mma=0;
mmb=0;
test_da();
break;
case 0xb7:
key=12;
break;
}
while(temp!=0xf0)
{
temp=P1;
temp=temp&0xf0;
}
}
}
}
//*******主函數*****
void main()
{
init();
scan1();
while(1)
{
markey();test_da();
test();
}
}
<B>程序二</B>
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
uchar code tab[]={ //0-f的極代碼
0xc0,0xf9,0xa4,0xb0,0x99,
0x92,0x82,0xf8,0x80,0x90,
0x88,0x83,0xa7,0xa1,0x86,
0x8e};uchar count,s1num;
uchar miao,shi,fen;
unsigned char code tab1[]={0xc6};
/*********************************端口定義**********************************/
sbit DQ=P2^0; //數據傳輸線接單片機的相應的引腳
sbit beep=P1^3;
sbit s1=P1^2;
sbit s2=P1^0;
sbit s3=P1^1;
/*********************************定義全局變量******************************/
unsigned char tempL=0; //臨時變量低位
unsigned char tempH=0; //臨時變量高位
float temperature;
//溫度值/****************************************************************************
函數功能:延時子程序
入口參數:k
出口參數:
****************************************************************************/
void delay(unsigned int k)
{
unsigned int n;
n=0;
while(n < k)
{n++;}
return;
}
/****************************************************************************
函數功能:數碼管掃描延時子程序
入口參數:
出口參數:
****************************************************************************/
void delay1(uint x)
{
int j,k;
for(j=x;j>0;j--)
for(k=50;k>0;k--);
}void di()
{
beep=0;
delay1(250);
beep=1;
}/****************************************************************************
函數功能:數碼管顯示子程序
入口參數:k
出口參數:
****************************************************************************/
void init()
{
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
EA=1;
ET0=1;
TR0=1;
}
void scan(uchar shi,uchar fen,uchar miao)
{
P2=0xfb;
P0=tab[shi/10];
delay1(1);
P0=0xff;
P2=0xf7;
P0=tab[shi%10];
delay1(1); P0=0xff;
P2=0xef;
P0=tab[fen/10];
delay1(1); P0=0xff;
P2=0xdf;
P0=tab[fen%10];
delay1(1); P0=0xff;
P2=0xbf;
P0=tab[miao/10];
delay1(1); P0=0xff;
P2=0x7f;
P0=tab[miao%10];
delay1(1);
P0=0xff;
}
void keyscan()
{
if(s1==0)
{
delay1(5);
if(s1==0)//確認功能鍵被按下
{ s1num++;//功能鍵按下次數記錄
while(!s1);//釋放確認
di();//每當有按鍵釋放蜂鳴器發出滴聲
if(s1num==1)//第一次被按下時
{
TR0=0; //關閉定時器
}
if(s1num==2)//第二次按下光標閃爍定位到分鐘位置
{
}
if(s1num==3)//第三次按下光標閃爍定位到小時位置
{
}
if(s1num==4)//第四次按下
{
s1num=0;//記錄按鍵數清零
TR0=1; //啟動定時器使時鐘開始走
}
}
}
if(s1num!=0)//只有功能鍵被按下后,增加和減小鍵才有效
{
if(s2==0)
{
delay1(5);
if(s2==0)//增加鍵確認被按下
{
while(!s2);//按鍵釋放
di();//每當有按鍵釋放蜂鳴器發出滴聲
if(s1num==1)//若功能鍵第一次按下
{
miao++; //則調整秒加1
if(miao==60)//若滿60后將清零
miao=0;
}
if(s1num==2)//若功能鍵第二次按下
{
fen++;//則調整分鐘加1
if(fen==60)//若滿60后將清零
fen=0;
}
if(s1num==3)//若功能鍵第三次按下
{
shi++;//則調整小時加1
if(shi==24)//若滿24后將清零
shi=0;
}
}
}
if(s3==0)
{
delay1(5);
if(s3==0)//確認減小鍵被按下
{
while(!s3);//按鍵釋放
di();//每當有按鍵釋放蜂鳴器發出滴聲
if(s1num==1)//若功能鍵第一次按下
{
miao--;//則調整秒減1
if(miao==-1)//若減到負數則將其重新設置為59
miao=59; // write_add(1,miao);//數據改變立即存入24C02
}
if(s1num==2)//若功能鍵第二次按下
{
fen--;//則調整分鐘減1
if(fen==-1)//若減到負數則將其重新設置為59
fen=59;
}
if(s1num==3)//若功能鍵第二次按下
{
shi--;//則調整小時減1
if(shi==-1)//若減到負數則將其重新設置為23
shi=23;
}
}
}
}
}
void display(int k)
{
P1=0xef;
P3=tab1[0];
delay1(1);
P3=0xff;
P1=0x7f;
P3=tab[k%100/10];
delay1(1);
P3=0xff;
P1=0xbf;
P3=tab[k%10];
delay1(1);
P3=0xff;
}/****************************************************************************
函數功能:DS18B20初始化子程序
入口參數:
出口參數:
****************************************************************************/
Init_DS18B20(void)
{
unsigned char x=0;
DQ=1; //DQ先置高
delay(8); //延時
DQ=0; //發送復位脈沖
delay(85); //延時(>480ms)
DQ=1; //拉高數據線
delay(14); //等待(15~60ms)
}/****************************************************************************
函數功能:向DS18B20讀一字節數據
入口參數:
出口參數:dat
****************************************************************************/
ReadOneChar(void)
{
unsigned char i=0;
unsigned char dat=0;
for (i=8;i>0;i--)
{
DQ=1;
delay(1);
DQ=0;
dat>>=1;
DQ=1;
if(DQ)
dat|=0x80;
delay(4);
}
return(dat);
}/****************************************************************************
函數功能:向DS18B20寫一字節數據
入口參數:dat
出口參數:
****************************************************************************/
WriteOneChar(unsigned char dat)
{
unsigned char i=0;
for(i=8;i>0;i--)
{
DQ=0;
DQ=dat&0x01;
delay(5);
DQ=1;
dat>>=1;
}
delay(4);
}/****************************************************************************
函數功能:向DS18B20讀溫度值
入口參數:
出口參數:temperature
****************************************************************************/
ReadTemperature(void)
{
Init_DS18B20(); //初始化
WriteOneChar(0xcc); //跳過讀序列號的操作
WriteOneChar(0x44); //啟動溫度轉換
delay(125); //轉換需要一點時間,延時
Init_DS18B20(); //初始化
WriteOneChar(0xcc); //跳過讀序列號的操作
WriteOneChar(0xbe); //讀溫度寄存器(頭兩個值分別為溫度的低位和高位)
tempL=ReadOneChar(); //讀出溫度的低位LSB
tempH=ReadOneChar(); //讀出溫度的高位MSB
//溫度轉換,把高低位做相應的運算轉化為實際溫度
temperature=((tempH*256)+tempL)*0.0625;
delay(200);
return(temperature);
}/****************************************************************************
函數功能:主程序
入口參數:
出口參數:
****************************************************************************/
void main()
{
float i;
init();
while(1)
{
i=ReadTemperature();
display(i);
scan(shi,fen,miao);
keyscan();
}
}
void timer0() interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
count++;
if(count==20)
{
count=0;
miao++;
if(miao==60)
{
miao=0;
fen++;
if(fen==60)
{
fen=0;
shi++;
if(shi==24)
{
shi=0;
}
}
}
}
}