簡易數控直流電源設計 1 設計任務設計出有一定輸出電壓范圍和功能的數控電源。 2 設計要求 (1)輸出電壓:范圍0~+9.9V,步進0.1V,紋波不大于10mV; (2)輸出電壓值由LCD顯示; (3)由“+”、“-”兩鍵分別控制輸出電壓步進增減; (4)輸出電壓可預置在0~9.9V之間的任意一個值; (5)自制鍵盤設置電壓值。 3 設計原理與總體方案 3.1 總體設計方案 鑒于目前數控直流源一般采取運放構成的電流-電壓轉換電路與單片機結合,設計方案大多為開環系統,主控制器僅用于數字給定及顯示,沒有對輸出電流進行檢測和控制。本文在傳統電路設計的基礎上,利用控制系統中反饋與控制原理,引入電流負反饋,在采樣電阻上獲取和電流成正比的采樣電壓,并接人運算放大器的反向輸入端,實現負反饋,形成恒流輸出的閉環控制系統; 軟件方面,將具有全局尋優能力但收斂速度慢的遺傳算法和具有收斂速度快且局部尋優能力強的直接搜索法結合在一起,設計基于遺傳算法和直接搜索策略的混合優化算法,充分利用了遺傳算法的全局搜索能力并以此作為優化過程的“粗調”,同時利用直接搜索法良好的局部搜索能力作為優化過程的“微調”,集中了兩者的優點,而克服了兩者的弱點,得到的目標函數值較遺傳退火策略更優,而且一致性更好,用于PID參數整定是具有整定速度快,調節時間短,穩態誤差小等優點。同時結合PID算法,形成軟件閉環,實現對輸出電流的精確控制。 系統工作原理如下:由鍵盤預置電壓值,輸入到單片機;采樣電阻采集的電壓信號經D/A轉換器送入單片機,當兩值之差絕對值為零或不大于設定值時,不作任何調整;當兩值之差大于設定值時,運用PID算法進行調整,送人D/A轉換,調整輸出電壓,直到差值在允許的范圍內。單片機控制液晶顯示電流的設定值、實際輸出值和電壓步進值。 3.2 顯示模塊選擇 LCD(Liquid Crystal Display)顯示器是利用液晶顯示技術來進行圖像表現的顯示裝置,從液晶顯示器的結構來看,無論是筆記本電腦還是桌面系統,采用的LCD顯示屏都是由不同部分組成的分層結構。LCD顯示器按照控制方式不同可分為被動矩陣式LCD及主動矩陣式LCD兩種。 LCD由兩塊玻璃板構成,厚約1mm,其間由包含有液晶材料的5μm均勻間隔隔開。因為液晶材料本身并不發光,所以在顯示屏兩邊都設有作為光源的燈管,而在液晶顯示屏背面有一塊背光板(或稱勻光板)和反光膜,背光板是由熒光物質組成的可以發射光線,其作用主要是提供均勻的背景光源。 背光板發出的光線在穿過第一層偏振過濾層之后進入包含成千上萬液晶液滴的液晶層。液晶層中的液滴都被包含在細小的單元格結構中,一個或多個單元格構成屏幕上的一個像素。在玻璃板與液晶材料之間是透明的電極,電極分為行和列,在行與列的交叉點上,通過改變電壓而改變液晶的旋光狀態,液晶材料的作用類似于一個個小的光閥。在液晶材料周邊是控制電路部分和驅動電路部分。當LCD中的電極產生電場時,液晶分子就會產生扭曲,從而將穿越其中的光線進行有規則的折射,然后經過第二層過濾層的過濾在屏幕上顯示出來。 3.3鍵盤選擇 鍵盤實際上是一組開關的集合:當開關按下時,兩根導線接通;當開關釋放時,兩根導線斷開。我們通過鍵盤的輸入設置預置值。 3.3.1高低電平翻轉矩陣鍵盤 矩陣鍵盤又稱行列鍵盤,它是用四條I/O線作為行線,四條I/O線作為列線組成的鍵盤。在行線和列線的每個交叉點上設置一個按鍵。這樣鍵盤上按鍵的個數就為4*4個。這種行列式鍵盤結構能有效地提高單片機系統中I/O口 最常見的鍵盤一般由16個按鍵組成,在單片機中正好可以用一個P口實現16個按鍵功能。當無按鍵閉合時,P3.0~P3.3與P3.4~P3.7之間開路。當有鍵閉合時,與閉合鍵相連的兩條I/O口線之間短路。判斷有無按鍵按下的方法是:第一步,置列線P3.4~P3.7為輸入狀態,從行線P3.0~P3.3輸出低電平,讀入列線數據,若某一列線為低電平,則該列線上有鍵閉合。第二步,行線輪流輸出低電平,從列線P3.4~P3.7讀入數據,若有某一列為低電平,則對應行線上有鍵按下。綜合一二兩步的結果,可確定按鍵編號。但是鍵閉合一次只能進行一次鍵功能操作,因此須等到按鍵釋放后,再進行鍵功能操作,否則按一次鍵,有可能會連續多次進行同樣的鍵操作。 識別按鍵的方法很多其中,最常見的方法是掃描法 按鍵按下時,與此鍵相連的行線與列線導通,行線在無按鍵按下時處在高電平。如果所有的列線都處在高電平,則按鍵按下與否不會引起行線電平的變化,因此必須使所有列線處在電平。這樣,當有按鍵按下時,改鍵所在的行電平才回由高變低。才能判斷相應的行有鍵按下。 3.3.2獨立按鍵式鍵盤 獨立按鍵式直接用I/O口線構成的單個按鍵電路,其特點式每個按鍵單獨占用一根I/O口線,每個按鍵的工作不會影響其他I/O口線的狀態。獨立按鍵的典型應用如圖所示。獨立式按鍵電路配置靈活,軟件結構簡單,但每個按鍵必須占用一個I/O口線,因此,在按鍵較多時,I/O口線浪費較大,不宜采用。 獨立按鍵的軟件常采用查詢式結構。先逐位查詢沒跟I/O口線的輸入狀態,如某一根I/O口線輸入為低電平,則可確認該I/O口線所對應的按鍵已按下,然后,再轉向該鍵的功能處理程序。 獨立按鍵數量少,可根據實際需要靈活編碼。矩陣鍵盤,按鍵的位置由行號和列號唯一確定,因此可以分別對行號和列號進行二進制編碼,然后兩值合成一個字節,高4位是行號,低4位是列號。相比較而言高低電平反轉矩陣鍵盤占用的I/O接口少,實現的鍵數較多,比較符合我們的設計需求。 3.4主控芯片選擇 51系列是基本型,包括8051、8751、8031、8951.這四個機種區別,僅在于片內程序儲存器。8051為4KBROM,8751為4KBEPROM,8031片內無程序儲存器,8951為4KBEEPROM。其他性能結構一樣,有片內128B RAM,2個16位定時器/計數器,5個中斷源。其中,8031性價比較高,又易于開發,目前應用面廣泛。 51系列單片機的特點:8位cpu;片內帶振蕩器,頻率范圍為1.2MHz~12MHz;片內帶128B的數據存儲器;片內帶4KB的程序存儲器;程序存儲器的尋址空間為64KB;片外數據存儲器的尋址空間為64KB;128個用戶位尋址空間;21個字節特殊功能寄存器;4個8位的I/O并行接口:P0、P1、P2、P3;兩個16位定時、計數器;兩個優先級別的五個中斷源;一個全雙工的串行I/O接口,可多機通信;111條指令,包含乘法指令和除法指令;片內采用單總線結構;有較強的位處理能力;采用單一+5V電源。
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3001.tmp.png 圖1 MCS-51基本結構圖 4 硬件電路設計 總體設計圖:
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3002.tmp.jpg 圖2 電路設計圖 4.1 DAC電路 一個8位D/A轉換器有8個輸入端(其中每個輸入端是8位二進制數的一位),有一個模擬輸出端。輸入可有2^8=256個不同的二進制組態,輸出為256個電壓之一,即輸出電壓不是整個電壓范圍內任意值,而只能是256個可能值。下圖是DAC0832的邏輯框圖和引腳排列。 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3012.tmp.jpg 圖3 DAC0832的邏輯框圖和引腳排列 D0~D7:數字信號輸入端。 ILE:輸入寄存器允許,高電平有效。 CS:片選信號,低電平有效。 XFER:傳送控制信號,低電平有效。 WR1:寫信號1,低電平有效。 WR2:寫信號2,低電平有效。 IOUT1、IOUT2:DAC電流輸出端。 Rfb:是集成在片內的外接運放的反饋電阻。 Vref:基準電壓(-10~10V)。 Vcc:是源電壓(+5~+15V)。 DAC0832輸出的是電流,所以須經過一個外接的運算放大器轉換成電壓。 AGND:模擬地 NGND:數字地,可與AGND接在一起使用。 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3013.tmp.jpg 圖4 DAC電路 4.2矩陣鍵盤模塊 在鍵盤中按鍵數量較多時,為了減少I/O口的占用,通常將按鍵排列成矩陣形式,如圖4所示。在矩陣式鍵盤中,每條水平線和垂直線在交叉處不直接連通,而是通過一個按鍵加以連接。這樣,一個端口(如P1口)就可以構成4*4=16個按鍵,比之直接將端口線用于鍵盤多出了一倍,而且線數越多,區別越明顯,比如再多加一條線就可以構成20鍵的鍵盤,而直接用端口線則只能多出一鍵(9鍵)。由此可見,在需要的鍵數比較多時,采用矩陣法來做鍵盤是合理的。 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3024.tmp.jpg 圖5 矩陣式鍵盤
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3035.tmp.jpg 圖6 鍵盤電路設計 4.3 顯示部分 1602液晶也叫1602字符型液晶,它由若干個5X7或者5X11等點陣字符位組成,每個點陣字符位都可以顯示一個字符,每位之間有一個點距的間隔,每行之間也有間隔,起到了字符間距和行間距的作用。1602LCD是指顯示的內容為16X2,即可以顯示兩行,每行16個字符液晶模塊(顯示字符和數字)。 1602采用標準的16腳接口,其中:第1引腳:GND為電源地;第2引腳:VCC接5V電源正極;第3引腳:V0為液晶顯示器對比度調整端;第4引腳:RS為寄存器選擇,高電平1時選擇數據寄存器、低電平0時選擇指令寄存器;第5引腳:RW為讀寫信號線,高電平(1)時進行讀操作,低電平(0)時進行寫操作;第6引腳:E(或EN)端為使能端,高電平(1)時讀取信息,負跳變時執行指令;第7~14引腳:D0~D7為8位雙向數據端。第15~16腳:空腳或背燈電源。第15引腳背光正極,第16引腳背光負極。 表1 液晶1602A各個管腳的介紹 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3045.tmp.jpg 圖7 LCD電路設計 4.4 自制電源模塊 自制電源輸出+12V、-12V及+5V的電壓 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3046.tmp.jpg 圖8 自制電源 4.5 主控芯片 AT89C51 提供以下標準功能:4k 字節Flash 閃速存儲器,128字節內部RAM,32 個I/O 口線,兩個16位定時/計數器,一個5向量兩級中斷結構,一個全雙工串行通信口,片內振蕩器及時鐘電路。同時,AT89C51可降至0Hz的靜態邏輯操作,并支持兩種軟件可選的節電工作模式。空閑方式停止CPU的工作,但允許RAM,定時/計數器,串行通信口及中斷系統繼續工作。掉電方式保存RAM中的內容,但振蕩器停止工作并禁止其它所有部件工作直到下一個硬件復位。 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3057.tmp.jpg 圖9 主控芯片電路 4.6 放大電路 放大電路是增加電信號幅度或功率的電子電路。應用放大電路實現放大的裝置稱為放大器。它的核心是電子有源器件,如電子管、晶體管等。為了實現放大,必須給放大器提供能量。常用的能源是直流電源,但有的放大器也利用高頻電源作為泵浦源。放大作用的實質是把電源的能量轉移給輸出信號。 放大電路本身的特點: 一、有靜態和動態兩種工作狀態,所以有時往往要畫出它的直流通路和交流通路才能進行分析; 二、電路往往加有負反饋,這種反饋有時在本級內,有時是從后級反饋到前級,所以在分析這一級時還要能"瞻前顧后"。在弄通每一級的原理之后就可以把整個電路串通起來進行全面綜合。
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3058.tmp.jpg 圖10 放大電路
5 軟件設計流程 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3068.tmp.jpg 圖11 軟件設計流程圖 注:在穩壓輸出端用萬用表的電壓檔測輸出電壓,將會基本等于從鍵盤的輸入電壓。
6 仿真 6.1 仿真問題及解決 (1)D/A轉換電路沒有正常工作; 問題原因:D0-D7接口出現錯誤。 (2)步進0.1的程序出現問題; 問題原因:沒有寫入浮點型函數。
6.2 仿真結果及分析 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3069.tmp.jpgfile:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps307A.tmp.jpg 圖12 輸入3.2V電壓時的仿真輸出值 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps307B.tmp.jpgfile:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps308C.tmp.jpg 圖13 輸入5.9V電壓時的仿真輸出值 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps308D.tmp.jpgfile:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps309D.tmp.jpg 圖14 輸入6.3V電壓時的仿真輸出值 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps309E.tmp.jpgfile:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps309F.tmp.jpg 圖15 輸入8.3V電壓時的仿真輸出值 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps30B0.tmp.jpgfile:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps30B1.tmp.jpg 圖16 輸入9.1V電壓時的仿真輸出值
表2 測得的數據和從鍵盤輸入的數據 數據分析: 誤差不超過0.03 誤差分析: (1)電路中元器件的影響 (2)外界對輸出電壓的干擾,導致輸出有誤差
參考文獻 [1]唐俊瞿,許雷,張群瞻.單片機原理與應用[M].北京:冶金工業出版社,2003 [2]李廣弟,朱月秀,冷祖祁.單片機基礎[M].北京:北京航空航天大學出版社,2007 [3]李光飛.單片機課程設計實例指導[M].北京:北京航空航天大學出版社,2004.9 [4]張洪潤,蘭清華.單片機應用技術教程[M].北京:清華大學出版社,1997.11 [5]李華.MCS—51系列單片機實用接口技術[M]..北京:北京航空航天大學出版社,1993 [6]李朝青.單片機原理及接口技術[M]..北京:北京航空航天大學出版社,1998
附錄 仿真圖 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps30C2.tmp.jpg
源程序 #include<reg51.h> /*頭文件以及變量定義*/ #include<math.h> #define uchar unsigned char #define uint unsigned int sbit rs=P2^4; sbit rw=P2^5; sbit ea=P2^6; uchar num,i,key,j=0; float a2; uchar keyscan(void); uchar code table[6]="Please"; uchar code table1[16]=" enter letter..."; uchar code table2[16]="0123456789abcde."; float table3[6]; uchar code table4[8]="volt(v):"; uchar code table5[6]="error!"; uchar table6[6]; void delay(uint z) { uint x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); }
void write_com(uchar com) { rs=0; rw=0; P0=com; delay(5); ea=1; delay(5); ea=0; } void write_date(uchar date) { rs=1; rw=0; P0=date; delay(5); ea=1; delay(5); ea=0; } void disvol() { write_com(0x80+0x40); //寫電壓 for(num=0;num<8;num++) { write_date(table4[num]); delay(10); } }
void init() { delay(5); write_com(0x38); write_com(0x0c); write_com(0x06); write_com(0x01); write_com(0x80); for(num=0;num<6;num++) { write_date(table[num]); delay(20); } write_com(0x80+0x40); for(num=0;num<0x10;num++) { write_date(table1[num]); delay(20); } } void diserr() { write_com(0x80+0x40); for(num=0;num<6;num++) { write_date(table5[num]); delay(20); } delay(2000); }
void he_zhi() { uint a1,a3,c11,c12; float b1,b2,b3,b4,c1,c2,h; if(table3[0]!='.') //整數加點 { if(!table3[1]) { if(j==1) { table3[1]='.'; } }
if(!table3[2]) { if(j==2) { table3[2]='.'; } }
if(table3[1]=='.') { b1=table3[0]; b2=table3[2]/10; b3=table3[3]/100; h=b1+b2+b3; a2=h*256/10; a3=a2; a1=a3+1; c1=a2-a3; c2=a1-a2; c11=1000*c1; c12=1000*c2; if(c11>c12) { P1=a1; } else { P1=a3; } //光標顯示位 if(j==1) { write_com(0x80+0x49); } if(j==3) { write_com(0x80+0x4b); } if(j==4) { write_com(0x80+0x4c); }
}
else if(table3[2]=='.') { b1=table3[0]*10; b2=table3[1]; b3=table3[3]/10; b4=table3[4]/100; h=b1+b2+b3+b4; if(h<=10) { a2=h*256/10; a3=a2; a1=a3+1; c1=a2-a3; c2=a1-a2; c11=1000*c1; c12=1000*c2; if(c11>c12) { P1=a1; } else { if(a3==256) { P1=255; } else { P1=a3; } } if(j==2) { write_com(0x80+0x4a); }
}
else { write_com(0x01); diserr(); } } else { write_com(0x01); diserr(); } }
if(table3[0]=='.') { write_com(0x01); diserr(); }
}
void qingchu(uchar p) { uchar z; for(z=0;z<=5;z++) { table3[z]=p; } } void jia(uchar dat) //步進函數 { switch(dat) { case 0: write_date(table2[1]); break; case 1: write_date(table2[2]); break; case 2: write_date(table2[3]); break; case 3: write_date(table2[4]); break; case 4: write_date(table2[5]); break; case 5: write_date(table2[6]); break; case 6: write_date(table2[7]); break; case 7: write_date(table2[8]); break; case 8: write_date(table2[9]); break; case 9: write_date(table2[0]); break; } table3[2]++; if(table3[2]==10) table3[2]=0; } void jian(uchar dat) { switch(dat) { case 0: write_date(table2[9]); break; case 1: write_date(table2[0]); break; case 2: write_date(table2[1]); break; case 3: write_date(table2[2]); break; case 4: write_date(table2[3]); break; case 5: write_date(table2[4]); break; case 6: write_date(table2[5]); break; case 7: write_date(table2[6]); break; case 8: write_date(table2[7]); break; case 9: write_date(table2[8]); break; } table3[2]--; if(table3[2]==-1) table3[2]=9; }
void main() { init();
delay(4500); write_com(0x01); write_com(0x80+0x40); write_com(0x0f); disvol(); i=0x80+0x48;
while(1) { key=keyscan(); delay(100); switch(key) { case 0xee:write_com(i); write_date(table2[0]);table3[j]=0;j++; // table2[16]="0123456789abcde." i++; break;//0 case 0xde:write_com(i); write_date(table2[1]);table3[j]=1;j++; i++; break;//1 case 0xbe:write_com(i); write_date(table2[2]);table3[j]=2;j++; i++;break;//2 case 0x7e:write_com(i); write_date(table2[3]);table3[j]=3;j++; i++;break;//3 case 0xed:write_com(i); write_date(table2[4]);table3[j]=4;j++; i++;break;//4 case 0xdd:write_com(i); write_date(table2[5]);table3[j]=5;j++; i++;break;//5 case 0xbd:write_com(i); write_date(table2[6]);table3[j]=6;j++; i++;break;//6 case 0x7d:write_com(i); write_date(table2[7]);table3[j]=7;j++; i++;break;//7 case 0xeb:write_com(i); write_date(table2[8]);table3[j]=8;j++; i++;break;//8 case 0xdb:write_com(i); write_date(table2[9]);table3[j]=9;j++; i++;break;//9 case 0xe7:write_com(i); write_date(table2[15]);table3[j]='.';j++; i++;break; case 0xbb:write_com(0x80+0x48+2); jia(table3[2]); break;//加 case 0x7b:write_com(0x80+0x48+2); jian(table3[2]); break;//減 case 0xd7:he_zhi(); i=0x80+0x48; j=0; break; case 0xb7:write_com(0x01); qingchu(0); j=0; disvol(); write_com(0x80+0x48); i=0x80+0x48; break;
} } } uchar keyscan(void) { uchar cord_h,cord_l; P3=0x0f; cord_h=P3&0x0f; if(cord_h!=0x0f) { delay(100); if(cord_h!=0x0f) { cord_h=P3&0x0f; P3=cord_h|0xf0; cord_l=P3&0xf0; return(cord_h+cord_l); } }return(0xff); }
|