用STC12C5A60S2開發96路信號輸出,可接485 多層主機 ,自制串口通信協議
附件中有PDF版AD原理圖,源代碼 開發文檔。
原創。
上位機對于這些信號機的控制就是基于這塊--96路信號燈板。顧名思義,96路信號燈板可以同時實現對96個信號燈的控制,操作人員只需在上位機電腦端,發送通信協議,單片機做出應答,外接設備軌道信號機實現列車指示作用。 左上角選定單片機型號,數據通信端口號;發送緩沖區發送通信協議,這塊96路信號燈板的通信協議為AB 02 01 07(主機地址,可根據現場實際情況進行更改) 10(端口控制量,十六進制) FF FF FF FF FF FF FF FF FF FF FF FF(十二路控制端口控制96路燈) 00 00 00 00 02(最后一位為奇偶校驗,可根據之前的數據進行更改) CD。 二、96路信號燈板原理圖及PCB圖 96路信號燈板所用的控制原理是:STC12C5A60S2單片機通過操作P0口的電平高低,控制SN74HC573芯片,進而控制四-十六譯碼器CD4514,然后譯碼器控制十二路信號燈的控制芯片SN74HC573和ULN2803,實現信號燈的亮滅。  
單片機源程序如下:
- /*-----------------------------------------------
- 名稱:串口通信
- 日期:2019.6.10
- 內容: 多機通信,第一層機,485通信 本機為輸出功能從機 YN防485信號接收沖突
- ------------------------------------------------*/
- #include<stc12c5a60s2.h> //包含頭文件,一般情況不需要改動,頭文件包含特殊功能寄存器的定義
- #include<intrins.h>
-
- void datapro(); //總數據處理函數
- unsigned char a[20],c[25],b[25],ca[25]; //a[20]暫存數據包,一些計算在這個數組里面完成 c[25],ca[25]串口接收緩沖數據包
- sbit DE=P1^1; //485通信方向控制
- sbit W=P3^7; // 鎖存的地址輸出控制
- sbit LE=P3^6; //地址信號鎖存到573
- sbit XZ=P1^0; //信號控制線
- unsigned char flag=1,i=0,m=0,flag_1=0,flag_2=0; //地址信號鎖存 flag=1 串口發送完標志,i=0,m=0,全局變量 為串口接收數組小標,flag_1=0,flag_2=0串口接收數據接收完標志
- unsigned char address_1; //本機地址
- unsigned char YN=0,k=1; // k 接收數據時 轉義用 ;YN 串口接收狀態值
- unsigned char ZY_1=0,ZY_2=0;
- /*------------------------------------------------
- uS延時函數
- ------------------------------------------------*/
- void DelayUs2x(unsigned short int t)
- {
- while(--t);
- }
- /*------------------------------------------------
- mS延時函數
- ------------------------------------------------*/
- void DelayMs(unsigned short int t)
- {
- while(t--)
- {
- //大致延時1mS
- DelayUs2x(245);
- DelayUs2x(245);
- }
- }
- /*------------------------------------------------
- 串口和心跳定時器初始化
- ------------------------------------------------*/
- void InitUART(void)
- {
- SCON = 0x50; // SCON: 模式 1, 8-bit UART, 使能接收
- TMOD = 0x21; // TMOD: timer 1, mode 2, 8-bit 重裝
- PCON=0X80;
- TH1 = 0xFD; // TH1: 重裝值 253 波特率19200 晶振 11.0592MHz
- TH0 = 0x4b ; // TH0,TL0: 重裝值 15536 定時約50ms
- TL0 = 0xfd ;
- WDT_CONTR=0x3f; //看門狗
- IP =0x10; //串口優先 ,心跳信息次之
- TR1 = 1; // TR1: timer 1 打開
- TR0 = 1; // TR0: timer 0 打開
-
- DE=0; //485通信默認狀態為接收
-
- EA =1; //總中斷開
- ET0 = 1; //定時中斷開
-
-
-
- }
- /*------------------------------------------------
- 校驗情況函數
- ------------------------------------------------*/
- void check(unsigned char x)
- { unsigned char j; //函數功能 告訴上位機奇偶校驗的結果 暫時未用
- unsigned char d=0;
- a[1]=0x01; //ab 01 01 ad_1 x R cd
- a[2]=0x01;
- a[3]=address_1;
- a[4]=x;
-
- d=a[1]+a[2]+a[3]+a[4];
-
- if(d%2==0) a[5]=0x02;
- if(d%2==1) a[5]=0x01; //計算奇偶 奇數 01 偶數 02
-
- DE=1; //使485芯片處于發送狀態
- DelayMs(1);
- flag=1 ;SBUF=0xab; while(flag==1); //發送報文頭
- for(j=1;j<6;j++)
- {
- if(a[j]==0xfe||a[j]==0xab||a[j]==0xcd) { flag=1 ;SBUF=0xfe; while(flag==1); flag=1 ; SBUF=a[j]; while(flag==1); }
- else { flag=1 ;SBUF=a[j]; while(flag==1); }
- }
- flag=1;SBUF=0xcd;while(flag==1); //發送報文尾
- DE=0; //使485芯片回到接收狀態
- }
- /*------------------------------------------------
- 控制輸出函數
- ------------------------------------------------*/
- void control_out(void)
- {
- unsigned char A,j; //函數功能 開關量的輸出
- A=b[4]; //數據幀,,要輸出的字節數
- for(j=0;j<A;j++)
- {
- P0=j; //4-16譯碼地址
- LE=1; //573 使能引腳
- DelayMs(10);
- LE=0; //地址鎖存到地址存儲573芯片
- P0=b[j+5]; //要輸出的數據
- W=0;
- DelayMs(10);
- W=1; //已經鎖存的地址信號輸出
-
- }
- }
- /*------------------------------------------------
- 接收數據處理程序
- ------------------------------------------------*/
- void datapro()
- {
- unsigned char d=0;
- unsigned char j,t;
- if((c[0]==0xab&&c[i-1]==0xcd)||(ca[0]==0xab&&ca[m-1]==0xcd)) // 數據報文頭報文尾確認
- {
-
- if(flag_1==1) {for(j=0;j<25;j++) { b[j]=c[j];c[j]=0;} t=i;i=0;flag_1=0;} //數據存儲區轉移
- else if(flag_2==1) { for(j=0;j<25;j++) { b[j]=ca[j];ca[j]=0;} t=m;m=0;flag_2=0;} // 數據存儲區轉移
-
-
-
- for(j=1;j<(t-2);j++)
- {
- d=d+b[j] ;
- }
- if(d%2==0x00) d=0x02;
- else d=0x01; // 奇偶計算
-
- if(b[t-2]==d) //計算的奇偶與上位機發送過來的數據的奇偶校驗字節相比較
- {
- if(b[1]==0x02&&b[2]==0x01&&b[3]==address_1) {/*check(0x01); */ control_out(); for(j=0;j<25;j++) {b[j]=0;} ;t=0; }
- //上位機發送過來的命令 本機發送給上位機校驗情況,再控制輸出
- else if(b[1]==0x04) { for(j=0;j<25;j++) {b[j]=0;} ;t=0; }
- //上位機發送過來的命令 本機為輸出功能從機,不作反應
- else if(b[1]==0x05||b[1]==0x03){ for(j=0;j<25;j++) {b[j]=0;} ;t=0; }
- //上位機發送過來的多余數據 此為廣播方式進行多級 多機通信弊端
- else if(b[1]==0x01) { for(j=0;j<25;j++) {b[j]=0;} ;t=0;}
- //上位機發送過來的上位機校驗情況命令 ,本機為輸出功能機,該命令是另外功能機的命令,所以不作反應,是廣播通信弊端
-
- }
- else { if(b[1]==0x02) {check(0x02); } //上位機發送過來的命令 校驗失敗
- for(j=0;j<25;j++) {b[j]=0;} ;t=0;
- }
- }
-
- }
- /*------------------------------------------------
- 單片機心跳信息函數
- ------------------------------------------------*/
- void heartb()
- {
- unsigned char d=0;
- if(YN==0)
- {
- DE=1;
- DelayMs(1); // ab 05 ad1 R cd
- flag=1 ;
- SBUF=0xab;
- while(flag==1);
-
- flag=1 ;
- a[1]=0x05;
- SBUF=a[1];
- while(flag==1);
- flag=1 ;
- a[2]=0x01;
- SBUF=a[2];
- while(flag==1);
-
- flag=1;
- a[3]=address_1;
- if(a[3]==0xfe||a[3]==0xab||a[3]==0xcd) {SBUF=0xfe;while(flag==1);} ;
- flag=1 ;
- SBUF=a[3];
- while(flag==1);
- d=a[1]+a[2]+a[3];
- if(d%2==0x00) d=0x02;
- else d=0x01;
- flag=1;
- a[4]=d;
- SBUF=a[4];
- while(flag==1);
- flag=1 ;
- SBUF=0xcd;
- while(flag==1);
- DE=0;
- }
- }
- /*------------------------------------------------
- 主函數
- ------------------------------------------------*/
- void main (void)
- {
- unsigned char j;
- unsigned char x;
- x=5;
- P0M1=0X00;
- P0M0=0XFF;
- address_1=0x04; //本機地址
- for(j=0;j<25;j++)
- {
- a[j]=0;b[j]=0;c[j]=0; ca[j]=0; //數組初始化
- };
- InitUART();
- ES=1;
- b[4]=0x10; //數據長度 16個字節
- b[5]=0x00;
- b[6]=0x00;
- b[7]=0x00;
- b[8]=0x00;
- b[9]=0x00;
- b[10]=0x00;
- b[11]=0x00;
- b[12]=0x00;
- b[13]=0x00;
- b[14]=0x00;
- b[15]=0x00;
- b[16]=0x00;
- b[17]=0x00;
- b[18]=0x00;
- b[19]=0x00;
- b[20]=0x00;
- control_out(); //使所有信號輸出為0
- x=(x-1);
- XZ=1;
- while(1)
- {
-
- DelayMs(10);
- datapro();
-
- }
- }
- /*------------------------------------------------
- 串口中斷程序
- ------------------------------------------------*/
- void UART_SER (void) interrupt 4 //串行中斷服務程序
- {
- unsigned char Temp; //定義臨時變量
- if(RI) //判斷是接收中斷產生
- {
-
- RI=0; //標志位清零
- Temp=SBUF;
-
- if(flag_1==0) // flag_1==1 表示按照協議接收到了一串完整的數據
- {
- YN=1; //YN=1表示串口處于接收狀態
- if(i==0&&Temp!=0xab){ YN=0;} //如果 接收到的第一個字節不是報文頭0xab,則放棄接收該字節
- else{
- if(Temp==0xfe)
- { if(k==1) {k++;ZY_1=0XFE;}
- else { k=1; ZY_1=0; c[i]=Temp;i++; } //轉義 處理
- }
-
- else {c[i]=Temp;
- if(c[i]==0xcd&&ZY_1!=0xfe) {flag_1=1; k=1;YN=0;} ; //判斷是否處于報文尾
- if(ZY_1==0xfe)if(c[i]==0xcd||c[i]==0xab){k=1; ZY_1=0;};
- i++;
- };
-
-
-
- }
- }
- else if(flag_2==0)
- {
- YN=1;
- if(m==0&&Temp!=0xab){ YN=0;}
- else{
- if(Temp==0xfe)
- { if(k==1) {k++;ZY_2=0XFE;}
- else { k=1;ZY_2=0;ca[m]=Temp;m++; } //轉義
- }
- else { ca[m]=Temp;
- if(ca[m]==0xcd&&ZY_2!=0xfe) {flag_2=1; k=1; YN=0;}
- if(ZY_2==0xfe){ if(ca[m]==0xcd||ca[m]==0xab){k=1;ZY_2=0;}; }
- m++;
- }
-
- } ;
-
- }
- }
-
-
-
- if(TI){flag=0; TI=0;}
- }
- /*------------------------------------------------
- 心跳中斷程序
- ------------------------------------------------*/
- void timer0(void) interrupt 1
- { static unsigned char n=0 ;
- n++;
- if(n==110) {WDT_CONTR=0x3f;/* heartb(); n=0;*/ } // 6秒 喂看門狗,發送心跳信息
- if(n==220) {WDT_CONTR=0x3f; heartb(); n=0; }
-
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
全部資料51hei下載地址:
96路信號燈開發源程序.7z
(25.97 KB, 下載次數: 30)
2019-6-11 02:40 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
96路信號燈開發文檔.docx
(224.07 KB, 下載次數: 19)
2019-6-10 10:31 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|