打算設(shè)計一套一主二從的多機通信系統(tǒng)。主機發(fā)送自己的供電狀態(tài)給從機,讀取從機的掃描的按鍵數(shù)據(jù)。由于系統(tǒng)功能比較簡單,考慮到modbus協(xié)議相對來說挺復雜,所以設(shè)計了一個簡化的通信協(xié)議:1、主機、從機UART均為模式1。主機發(fā)送2個字節(jié)的數(shù)據(jù)給從機,第1個字節(jié)為地址字節(jié),尋址,第2個字節(jié)是數(shù)據(jù)字節(jié),用來將主機的供電狀態(tài)發(fā)給從機,并讀取從機按鍵狀態(tài)。2個從機,有時候2臺都接入系統(tǒng),有時候只有1臺接入系統(tǒng)。此為設(shè)計功能要求。
設(shè)計中,在程序初始化時,主機發(fā)送一次數(shù)據(jù)給從機0x01,啟動通信。然后進入while(1)循環(huán)。在循環(huán)中,定時讀取供電狀態(tài),調(diào)用串口驅(qū)動函數(shù)。通信過程:啟動通信后,主機接收從機的數(shù)據(jù),1,接收成功,解析地址,地址解析相符的話,解析數(shù)據(jù),有數(shù)據(jù),執(zhí)行數(shù)據(jù),并再次發(fā)送數(shù)據(jù)給0x01,無數(shù)據(jù),尋址另一臺從機。2、接收成功,解析地址,不相符,尋址另一臺從機,3、計時時間內(nèi),未收到數(shù)據(jù),認為接收失敗,尋址另一臺從機。
串口接收2個字節(jié)為1幀數(shù)據(jù),接收2個字節(jié)完成后,即認為數(shù)據(jù)接受完成,置位幀接收完成標志。
從機接收主機發(fā)來的2個字節(jié)的數(shù)據(jù),同樣進行地址、數(shù)據(jù)解析,完成后,回發(fā)數(shù)據(jù)給主機。
上述為通信流程。帖程序:
主機程序:
main.c:
- # define _MAIN_C
- # include "config.h"
- # include "tmr_uart.h"
- # include "action.h"
- # include "main.h"
- uchar8 OCBuf[]={0xFF,0xFF};
- bit OCflag=0; //過流標志
- //uchar8 Powflag;
- uchar8 PowSta=0xFF; //供電狀態(tài)標志
- uchar8 PowCNTR=0; //供電采集計數(shù)
- uchar8 TxdBuf[2]={0xFF,0xFF}; //發(fā)送緩沖
- uchar8 buf[2];
- bit Txdflag=0; //字節(jié)發(fā)送標志
- uchar8 RxdBuf[2]; //接收緩沖
- uchar8 cntRxd=0; //接收計數(shù)
- bit RxFr_Succ=0; //幀接收成功標志。
- bit TxFr_Succ=0; //幀發(fā)送成功標志
- bit RxFr_Fail=0; //幀接收失敗標志
- uchar8 sl_select=0; //從機選擇索引
- void main()
- {
- ROE=1; RA3=1; RA2=1; RA1=1; //釋放所有輸出
- Buz=0; //蜂鳴器響
- DelayX50ms(5); //
- Buz=1; //蜂鳴器關(guān)
- P1=0x00; //數(shù)據(jù)管全亮,檢測數(shù)據(jù)管是否正常
- DelayX50ms(5);
- P1=0xFF; //關(guān)閉數(shù)據(jù)管
- DIR_485=0; //485通信處于接收狀態(tài)
- ConfigTimer0(); //配置定時器0
- ConfigUART(); //配置UART
- UartSend(0x01); //發(fā)送數(shù)據(jù)給從機0x01.
- while(1)
- {
- OCProtect(); //檢測過流保護
- PowCheck(10); //檢測供電狀態(tài)
- UartDriver(); //串口驅(qū)動
- }
- }
- //串口驅(qū)動
- void UartDriver()
- {
- switch(sl_select)
- {
- case 0: if(RxFr_Succ) //接收數(shù)據(jù)成功
- {
- RxFr_Succ=0;
- UartReceive(); //串口讀數(shù)據(jù)
- UartAction(0xF1); //接收數(shù)據(jù)解析(含地址)
- if((buf[1]>=0x03)&&(buf[1]<=0x11)) //buf[1]>=0x03,且小于0x11,表示有數(shù)據(jù)
- {
- UartSend(0x01); //繼續(xù)發(fā)數(shù)據(jù)給0x01從機
- }
- else //無數(shù)據(jù)
- {
- sl_select++; //從機選擇索引+1
- UartSend(0x02); //給0x02發(fā)數(shù)據(jù)
- }
-
- }
- if(RxFr_Fail) //接收數(shù)據(jù)失敗,(此從機不在線)
- {
- RxFr_Fail=0;
- UartSend(0xF2); //給0x02發(fā)數(shù)據(jù)
- sl_select++; //從機選擇索引+1
- }
- break;
- case 1: if(RxFr_Succ) //接收數(shù)據(jù)成功
- {
- RxFr_Succ=0;
- UartReceive();
- if((buf[1]>=0x03)&&(buf[1]<=0x11)) //有數(shù)據(jù)
- {
- UartSend(0x02); //繼續(xù)給從機0x02發(fā)數(shù)據(jù)
- }
- else //無數(shù)據(jù)
- {
- sl_select--; //從機索引-1
- UartSend(0x01); //發(fā)送數(shù)據(jù)給0x01
- }
- }
- if(RxFr_Fail) //數(shù)據(jù)接收失敗(此從機不在線)
- {
- RxFr_Fail=0;
- UartSend(0x01); //發(fā)送數(shù)據(jù)給0x01
- sl_select--; //索引-1
- }
- break;
- default:sl_select=0; break;
- }
- }
- //串口發(fā)送函數(shù),只發(fā)送2個字節(jié).
- void UartSend(uchar8 addr)
- {
- uchar8 len=0;
- DIR_485=1;
- TxdBuf[0]=addr; //將要發(fā)送的從機的地址裝入發(fā)送緩沖內(nèi)
- while(len<2)
- {
- Txdflag=0;
- SBUF=TxdBuf[len++];
- while(!Txdflag);
- }
- TxFr_Succ=1; //置位發(fā)送成功標志
- DelayX10us(5);
- DIR_485=0;
- }
- //串口接收函數(shù)
- void UartReceive()
- {
- uchar8 len=0;
- uchar8 buf[2];
- while(len<2)
- {
- buf[len++]=RxdBuf[len++];
- }
- DelayX10us(5);
- }
- //串口中斷函數(shù)
- void InterruptUART() interrupt 4
- {
- if(RI)
- {
- RI=0;
- RxdBuf[cntRxd++]=SBUF;
- if(cntRxd>=2)
- {
- cntRxd=0;
- RxFr_Succ=1; //接收成功
- RxFr_Fail=0;
- TxFr_Succ=0;
- }
- }
- if(TI)
- {
- TI=0;
- Txdflag=1;
- }
- }
- //T0中斷函數(shù)
- void InterruptTimter0() interrupt 1
- {
- static uchar8 i=0; //1yá÷Ë÷òy
- static uchar8 j=0; //供電索引
- static uchar8 k=0; //串口發(fā)送計時
- TH0=0xF8;
- TL0=0xCC; //2ms
- //過流檢測,同時躲過電機啟動瞬間的尖峰電流
- OCBuf[0]=(OCBuf[0]<<1)|GL1;
- OCBuf[1]=(OCBuf[1]<<1)|GL2;
- if((OCBuf[0]==0x00)||(OCBuf[1]==0x00))
- {
- i++;
- OCBuf[0]=0xFF;
- OCBuf[1]=0xFF;
- if(i>=2)
- {
- i=0;
- OCflag=1;
- }
- }
- //供電狀態(tài)檢測
- PowSta=(PowSta<<1)|DcBat;
- j++;
- if(j>=8)
- {
- j=0;
- PowCNTR++;
- }
- //通信接收計時,TxFr_Succ為發(fā)送成功標志,RxFr_Succ為接收成功標志(置位表示接收成功,不置位不代表接收失敗).RxFr_Fail接收失敗標志,(置位表示接收失敗,不置位不代表接收成功)
- if((TxFr_Succ)&&(!(RxFr_Succ))) //數(shù)據(jù)發(fā)送成功,但尚未接收到,開始計時
- {
- k++;
- if(k>=20) //計時40ms
- {
- k=0;
- RxFr_Fail=1; //接收失敗,(從機不在線)
- TxFr_Succ=0; //
- }
-
- }
- else //計時清0,從數(shù)據(jù)發(fā)送成功開始計時,數(shù)據(jù)未發(fā)送成功,不計時,k清0,數(shù)據(jù)接收
- { //成功后,k清0.
- k=0;
- }
- }
- 定時器,UART,過流檢測,供電狀態(tài)檢測,延時函數(shù)
- # define _TMR_UART_C
- # include "config.h"
- # include "tmr_uart.h"
- # include "main.h"
- //T0配置函數(shù)
- void ConfigTimer0()
- {
- TMOD&=0xF0;
- TMOD|=0x01;
- TF0=0;
- TH0=0xF8;
- TL0=0xCC;
- ET0=1;
- TR0=1;
- EA=1;
- }
- /*UART配置函數(shù)*/
- void ConfigUART()
- {
- SCON=0x50; //ÅäÖÃ′®¿úÎa·½ê½1£¬8λUART,2¨ìØÂê¿é±ä
- TMOD&=0x0F; //ÇåáãT1¿ØÖÆÎ»¡£
- TMOD|=0x20; //ÅäÖÃT1ÎaÄ£ê½2.
- TH1=0xFD;
- TL1=TH1; //2¨ìØÂê9600
- ES=1; //¿aÆô′®¿úÖD¶Ï
- ET1=0; //½ûÖ1T1ÖD¶Ï
- TR1=1; //Æô¶ˉT1
- }
- /*過流檢測函數(shù)*/
- void OCProtect() //n*40ms½øDDò»′Î1yá÷ÅD¶Ï
- {
- if(OCflag) //ÖμÎa0x00,±íê¾òѾ-2úéú1yá÷¡£
- {
- ROE=1;RA3=1;RA2=1;RA1=1; //½«¿ØÖƼìμçÆ÷òy½Åè«2¿à-¸ß£¬êí·ÅËùóD¼ìμçÆ÷¡£
- while(1)
- {
- Buz=!Buz;
- DelayX50ms(5); //·äÃùÆ÷ÿ¸ô1SÏìò»′Ρ£
- }
- }
- }
- //供電狀態(tài)檢測函數(shù)
- void PowCheck(uchar8 t)
- {
- if(PowCNTR>=t)
- {
- PowCNTR=0;
- if(PowSta==0xFF)
- {
- TxdBuf[1]=0x12; //將供電狀態(tài)變量賦給發(fā)送緩沖
- }
- else if(PowSta==0x00)
- {
- TxdBuf[1]=0x13; //將供電狀態(tài)變量賦給發(fā)送緩沖
- }
- else;
- }
- }
- /*延時函數(shù)*/
- void DelayX50ms(uchar8 t) //@11.0592MHz
- {
- uchar8 i, j,k;
- i = 5;
- j = 121;
- for(k=0;k<t;k++)
- {
- do
- {
- while (--j);
- }
- while (--i);
- }
- }
- //延時函數(shù)
- void DelayX10us(uchar8 t)
- {
- do{
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- }while(--t);
- }
- # define _ACTION_C
- # include "config.h"
- # include "action.h"
- # include "main.h"
- //串口數(shù)據(jù)解析函數(shù)
- void UartAction(uchar8 addr)
- {
- if(buf[0]!=addr) //ê×Ïèo˶ÔμØÖ·£¬2»êÇ′ó»úF1·¢à′μÄêy¾Y£¬Ö±½ó·μ»Ø
- {
- return;
- }
- switch(buf[1])
- {
- case 0x03:ReturnPos(addr);break;
- case 0x04:ROE=0;RA3=0;RA2=0;RA1=0; LedDisp(1); break; //C1PÎaμíμçÆ½
- case 0x05:ROE=0;RA3=0;RA2=1;RA1=0; LedDisp(2); break; //C2PÏòí·Æ½òÆ
- case 0x06:ROE=1;RA3=0;RA2=1;RA1=0; LedDisp(5); break; //C5P±3°åéÏéy
- case 0x07:ROE=0;RA3=1;RA2=1;RA1=0; LedDisp(11);break; //1#Y6 é23μ
- case 0x08:ROE=0;RA3=0;RA2=1;RA1=1; LedDisp(7); break; //C2NÏò½ÅƽòÆ
- case 0x09:ROE=1;RA3=0;RA2=1;RA1=1; LedDisp(10);break; //C5N±3°åϽμ
- case 0x0A:ROE=0;RA3=0;RA2=0;RA1=1; LedDisp(6); break; //C1NϽμ
- case 0x0B:ROE=1;RA3=1;RA2=0;RA1=0; LedDisp(13);break; //2#Y4 Ñüéy
- case 0x0C:ROE=1;RA3=0;RA2=0;RA1=0; LedDisp(4); break; //C4P×óÇã
- case 0x0D:ROE=0;RA3=1;RA2=1;RA1=1; LedDisp(12);break; //1#Y7 Ëéé23μ
- case 0x0E:ROE=0;RA3=1;RA2=0;RA1=1; LedDisp(8); break; //C3Ní·½μ½Åéy
- case 0x0F:ROE=1;RA3=1;RA2=0;RA1=1; LedDisp(14);break; //2#Y5 Ñü½μ
- case 0x10:ROE=0;RA3=1;RA2=0;RA1=0; LedDisp(3); break; //C3Pí·éy½Å½μ
- case 0x11:ROE=1;RA3=0;RA2=0;RA1=1; LedDisp(9); break; //C4NóòÇã
- case 0xFF:ROE=1;RA3=1;RA2=1;RA1=1; LedDisp(19);break; //êí·ÅËùóD¼ìμçÆ÷
- default:ROE=1;RA3=1;RA2=1;RA1=1;Dis_Pin=0xFF;break;
- }
- }
- //LED顯示函數(shù)
- void LedDisp(uchar8 temp)
- {
- switch(temp)
- {
- case 1: Dis_Pin=0x9F;break; //9F:1001 1111 ÏÔê¾1
- case 2: Dis_Pin=0x31;break; //31:1010 1110 ÏÔê¾2
- case 3: Dis_Pin=0x15;break; //15: ÏÔê¾3
- case 4: Dis_Pin=0x9C;break; // ÏÔê¾4
- case 5: Dis_Pin=0x54;break; // ÏÔê¾5
- case 6: Dis_Pin=0x8F;break; // ÏÔê¾1.
- case 7: Dis_Pin=0x21;break; // ÏÔê¾2.
- case 8: Dis_Pin=0x05;break; // ÏÔê¾3.
- case 9: Dis_Pin=0x8C;break; // ÏÔê¾4.
- case 10: Dis_Pin=0x44;break; // ÏÔê¾5.
- case 11: Dis_Pin=0x50;break; // ÏÔê¾6
- case 12: Dis_Pin=0x40;break; // ÏÔê¾6.
- case 13: Dis_Pin=0x1F;break; // ÏÔê¾7
- case 14: Dis_Pin=0x0F;break; // ÏÔê¾7.
- default: Dis_Pin=0x00;break;
- }
- }
- //復位函數(shù)
- void ReturnPos(uchar8 addr)
- {
- if(RW5==0)
- {
- ROE=1;RA3=0;RA2=1;RA1=0; LedDisp(5); //±3°åéÏéy
- while(RW5==0)
- {
- ReAction(addr);
- }
- }
- else if(RW5==1)
- {
- ROE=1;RA3=0;RA2=1;RA1=1; LedDisp(10); //±3°åϽμ
- while(RW5==1)
- {
- ReAction(addr);
- }
- }
- //×óóòÇãD±¸′λ
- if(RW4==0)
- {
- ROE=1;RA3=0;RA2=0;RA1=0; LedDisp(4); //×óÇã
- while(RW4==0)
- {
- ReAction(addr);
- }
- }
- else if(RW4==1)
- {
- ROE=1;RA3=0;RA2=0;RA1=1; LedDisp(9); //óòÇã
- while(RW4==1)
- {
- ReAction(addr);
- }
- }
- //ǰoóÇãD±¸′λ
- if(RW3==0)
- {
- ROE=0;RA3=1;RA2=0;RA1=0; LedDisp(3); //ǰÇã
- while(RW3==0)
- {
- ReAction(addr);
- }
- }
- else if(RW3==1)
- {
- ROE=0;RA3=1;RA2=0;RA1=1; LedDisp(8); //oóÇã
- while(RW3==1)
- {
- ReAction(addr);
- }
- }
- if(RW2==0)
- {
- ROE=0;RA3=0;RA2=1;RA1=0; LedDisp(2); //Ïòí·Æ½òÆ
- while(RW2==0)
- {
- ReAction(addr);
- }
- }
- else if(RW2==1)
- {
- ROE=0;RA3=0;RA2=1;RA1=0; LedDisp(7); //Ïò½ÅƽòÆ
- while(RW2==1)
- {
- ReAction(addr);
- }
- }
- if(RW1==0)
- {
- ROE=0;RA3=0;RA2=0;RA1=1; LedDisp(6); //Ïòí·Æ½òÆ
- while(RW1==0)
- {
- ReAction(addr);
- }
- }
- ROE=1;RA3=1;RA2=1;RA1=1; //1رռìμçÆ÷êä3ö¡£
- }
- //復位解析函數(shù),復位期間,也要一直與從機進行通信,并解析數(shù)據(jù).
- void ReAction(uchar8 addr)
- {
- UartSend(addr);
- switch(sl_select)
- {
- case 0:if(RxFr_Succ)
- {
- RxFr_Succ=0;
- UartReceive();
- if(buf[0]!=addr)
- {
- return;
- }
- if((buf[1]==0xFF)||(buf[1]==0x03))
- {
- sl_select++;
- }
- else
- break;
- }
- case 1:if(RxFr_Succ)
- {
- RxFr_Succ=0;
- UartReceive();
- if(buf[0]!=addr)
- {
- return;
- }
- if((buf[1]==0xFF)||(buf[1]==0x03))
- {
- sl_select--;
- }
- else
- break;
- }
- default:break;
- }
- }
復制代碼
|