我單位有一無人值守的機房位于一高山山頂上,上山的路是600多級的臺階。因通信需要,有時要開關某些機器設備,操作上雖然簡單,但要工作人員花10多分鐘爬一趟山,不僅辛苦,而且拖延了時間。為解決此問題,本人利用89C2051單片機,設計了一遙控開關,在山下機房便可對山頂上的設備進行開關機。 一、 原理簡介 該方案的框圖如下: 
山頂機房及山下機房各安裝一塊控制板,兩者之間通過專線MODEM相連。山下控制板主要功能是:將操作人員的開關信息轉換成指令,發送給山頂控制板,并根據山頂控制板發來的電源通斷狀態報告指令,以指示燈的形式顯示給操作人員。山頂控制板主要功能是:通過控制繼電器的吸放來控制設備的電源,該板在接收到山下控制板發來的開關電指令后,驅動繼電器的吸放,并將繼電器的反饋狀態轉換成指令,報告給山下控制板。兩處的專線MODEM由本單位內部的光纖通信設備提供的音頻線路連接。 二、山頂控制板 山頂控制板所包括的主要元件有單片機芯片89C2051,電平轉換芯片MAX232,電源模塊。由于需遙控的通信設備使用-48V電源,山頂控制板也采用 -48V。該板采用了一個成品開關電源模塊,將-48V轉換成+5V。芯片MAX232的功能是把單片機串口的TTL電平轉換成MODEM的RS-232 電平,使單片機能通過MODEM收發數據。2051單片機根據山下控制板發來的指令,通過P1_4腳控制線圈電壓為5V的小繼電器RY1的吸放,進而控制電源繼電器RY2的吸放。電源繼電器RY2為兩組觸點、24V線圈電壓的大繼電器,觸點可承受較大電流。其中的一組觸點用于控制設備電源的通斷,接中間觸點及常閉觸點。繼電器釋放時,設備加電,繼電器吸合時,設備關電。另外一組觸點作為繼電器動作后的反饋,接中間觸點及常開觸點,分別接地及2051的 P1_7腳。當繼電器RY2吸合時P1_7經繼電器接地,為低電平,繼電器釋放時P1_7腳為高平(2051內部有上拉電阻)。單片機2051每秒鐘檢測一次P1_7腳是否接地,以此判定繼電器是否吸合(即是否斷開了設備的電源),隨后將檢測的結果轉換成指令,通過MODEM向山下的控制板匯報,同時本身的斷電指示燈也顯示出設備的加斷電狀態。 山頂控制板的電路圖如下: 
山頂控制板的程序如下: #include "atmelAT89X51.H" #define SYN 'Z' //來自山下控制板數據幀的同步字符 char countdown; //時間計數 char TX_buf[3]; //發送緩沖區 char TX_len; //發送字符串長度 char TX_num; char RX_buf[3]; //接收緩沖區 char RX_len; //接收字符串長度 char RX_num; char CRC(char *buf,char len) //校驗碼生成函數 {char i,temp; temp=0; for(i=0;i<len;i++) temp=temp^buf[i]; return(temp); } void timer0_int() interrupt 1 //定時器0的中斷服務程序 { TL0=0x00; TH0=0x0A6; countdown--; if(countdown==0 || countdown==20) P1_0=!P1_0; //控制CPU運行指示燈的秒閃 if(countdown!=0) return; countdown=40; //過了一秒鐘 P3_7=P1_7; //檢測電源繼電器的吸放狀態,并驅動P3_7的指示燈 if(P1_7) TX_buf[1]=0x13; //高電平,電源繼電器已釋放,設備電源接通 else TX_buf[1]=0x31; //接地,電源繼電器已吸合,設備電源中斷 TX_buf[2]=CRC(TX_buf,2); //生成校驗碼 TX_num=0; SBUF=TX_buf[0]; //向山下控制板報告繼電器的吸放狀態 } void serial_int() interrupt 4 //串口中斷服務程序 { if(TI) //發送觸發了中斷 { TI=0; TX_num++; if(TX_num<TX_len) SBUF=TX_buf[TX_num]; } else //接收觸發了中斷 { RI=0; RX_buf[RX_num]=SBUF; if(RX_num==0 && RX_buf[RX_num]!=SYN) return; //在接收的數據中搜索同步字符 RX_num++; if(RX_num==RX_len) //收完一條指令 { RX_num=0; if(RX_buf[RX_len-1]==CRC(RX_buf,RX_len-1)) //檢查校驗碼是否正確 { if(RX_buf[1]==0x13) P1_4=1; //釋放小繼電器RY1及電源繼電器RY2 if(RX_buf[1]==0x31) P1_4=0; //吸合小繼電器RY1及電源繼電器RY2 } } } } void main() { IE=0x92; TMOD=0x21; //定時器1:模式2,定時器2:模式1 TL1=253; TH1=253; // 9600波特率 TR1=1; //啟動定時器1 SCON=0x50; //串口:模式1 TL0=0x00; TH0=0x0A6; //定時器0定時0.025秒 TR0=1; //啟動定時器0 countdown=40; //1秒=0.025*40 P1_4=1; //釋放繼電器RY1、RY2 TX_buf[0]=0x7E; TX_len=3; RX_num=0; RX_len=3; while(1) ; } 三、 山下控制板 山下控制板的電路圖如下所示,所包括的主要元件有單片機芯片89C2051,電平轉換芯片MAX232,7805穩壓芯片。芯片MAX232的功能是把單片機串口的TTL電平轉換成MODEM的RS-232電平,使單片機能通過MODEM收發數據。需要對山上設備進行開關電操作時,先把連接在2051單片機P1_7腳的斷電開關撥到“開”或“關”的位置,然后連續按下K1按鍵,直到L1、L2、L3三個操作指示燈全亮,接著按一下K2按鍵,L1、L2、 L3指示燈全滅,此時2051單片機檢查P1_7腳的電平,如果是低電平,則向山頂控制板發斷電指令,如果是高電平,則向山頂控制板發加電指令。K1、 K2的其它按鍵組合均不使單片機發送加斷電指令。這里采取斷電開關與按鍵相結合的控制方式,目的是為了防止意外的開關操作,提高安全性。MODEM通信正常的情況下,山下控制板每秒鐘收到一次山頂控制板發來的加斷電狀態報告。當接收到狀態報告后,經單片機分析,如果是斷電狀態,則P1_5腳輸出低電平,點亮斷電指示燈,P1_3腳輸出高低脈沖,驅動蜂鳴器告警提示;如果是加電狀態,斷電指示燈滅,蜂鳴器靜音。如果連續3秒鐘收不到山頂控制板的狀態報告,斷電指示燈將作秒閃、蜂鳴器告警,提示操作人員檢查MODEM線路是否正常。 
山下控制板的程序如下: #include "atmelAT89X51.H" #define SYN 0x7E //山頂控制板發來數據幀的同步字符 char countdown; //時鐘計數 char TTL; //通信中斷的時間門坎值,設置為3秒 bit link_error; //通信中斷標志 bit power_on; //山上設備是否加電的標志 bit km; //按鍵消抖動標志 bit kp; //按鍵操作已處理標志 char TTW; //發送指令前的時間計數 char TX_buf[3]; //發送緩沖區 char TX_len; //發送指令長度 char TX_num; //當前發送的字符序號 char RX_buf[3]; //接收緩沖區 char RX_len; //接收指令長度 char RX_num; //當前接收的字符序號 char CRC(char *buf,char len) //校驗碼生成函數 {char i,temp; temp=0; for(i=0;i<len;i++) temp=temp^buf[i]; return(temp); } void timer0_int() interrupt 1 //定時器0的中斷服務函數 { bit key1,key2; TL0=0x00; TH0=0x0A6; countdown--; if(countdown==0 || countdown==20) { P1_6=!P1_6; //CPU運行指示燈秒閃 if(link_error) P1_5=!P1_5; //通信中斷,斷電指示燈秒閃 else { if(power_on) P1_5=1; //設備加電,斷電指示燈滅 else P1_5=0; //設備關電,斷電指示燈亮 } } if(power_on && !link_error) //當設備加電且通信正常 P1_3=0; //關閉蜂鳴器 else //當設備斷電或通信中斷 { if(countdown==0) P1_3=0; //蜂鳴器告警 if(countdown==5) P1_3=1; if(countdown==10) P1_3=0; if(countdown==15) P1_3=1; } key1=P3_4; key2=P3_5; if(key1==1 && key2==1) { km=0;kp=0; } //兩個按鍵均沒有按下 else { if(km==0) km=1; //設消抖動標志 else { if(kp==0) { kp=1; if(key1==0) //按鍵K1被按下 TTW=(TTW+1)%4; //計算K1連續按下的次數 if(key2==0) //按鍵K2被按下 { if(TTW==3) //如果K1已被連續按了三次 { if(P1_7) TX_buf[1]=0x13; //發加電指令 else TX_buf[1]=0x31; //發關電指令 TX_buf[2]=CRC(TX_buf,2); TX_num=0; SBUF=TX_buf[0]; } TTW=0; //不管K1已按下幾次,K2按下后復位TTW計數器 } } } } if(countdown!=0) return; countdown=40; if(TTL==0) link_error=1; //TTL減到0,表示通信中斷 else TTL--; //每隔1秒對TTL作減1操作 } void serial_int() interrupt 4 //串口中斷服務程序 { if(TI) { TI=0; TX_num++; if(TX_num<TX_len) SBUF=TX_buf[TX_num]; } else { RI=0; RX_buf[RX_num]=SBUF; if(RX_num==0 && RX_buf[RX_num]!=SYN) return; //在接收到的數據中搜索同步字符 RX_num++; if(RX_num==RX_len) //接收到一完成指令 { RX_num=0; if(RX_buf[RX_len-1]==CRC(RX_buf,RX_len-1)) //檢查校驗 { if(RX_buf[1]==0x13) power_on=1; //加電狀態 if(RX_buf[1]==0x31) power_on=0; //斷電狀態 TTL=3; link_error=0; //通信正常,重置TTL值 } } } } void main() { IE=0x92; TMOD=0x21; //定時器1:模式2,定時器0:模式1 TL1=253; TH1=253; //9600波特率 TR1=1; //啟動定時器1 SCON=0x50; //串口:模式1 TL0=0x00; TH0=0x0A6; //定時器0定時0.025秒 TR0=1; //啟動定時器0 countdown=40; //1秒=0.025秒*40 TTL=3; //連續3秒收不到報告,表示通信中斷 TTW=0; km=0; kp=0; link_error=1; power_on=1; TX_buf[0]='Z'; TX_len=3; RX_num=0; RX_len=3; while(1) { if(TTW==0) { P3_7=1; P1_0=1; P1_1=1; } if(TTW==1) P3_7=0; if(TTW==2) P1_0=0; if(TTW==3) P1_1=0; } } 四、MODEM通信線制作 單片機2051與MODEM之間的串口通信電纜只用RX、TX、GND三根線,其他的握手信號均沒有使用,但在制作MODEM一端的接頭時應要按下圖制作: 
|