|
- /**********************************************************************************
- 一般的單片機多機通訊的情況是:
- 1.PC向特定單片機發送命令,該單片機收到后回應PC,也就是說不存在幾個單片機同時向PC發數據的情況。
- 2.PC以廣播的形式發送命令,也就是所有單片機都收到命令,在這種情況下一般都是對單片機進行初始設置(此時所有單片機一般都不做應答)
- **********************************************************************************/
- #include<reg51.h>
- #include<string.h>
- #define uchar unsigned char
- #define uint unsigned int
-
- /* 通信命令 */
- #define __START_ 0x0c //起始標志位
- #define __STOP_ 0xc0 //結束標志位
- #define __ACTIVE_ 0x01 // 主機詢問從機是否存在
- #define __GETDATA_ 0x02 // 主機發送讀設備請求
- #define __OK_ 0x03 // 從機應答
- #define __STATUS_ 0x04 // 從機發送設備狀態信息
- /****************************幀格式****************************
- -目的地址-命令字-數據-校驗碼- 至少4個字節
- 主機地址為0x00, 從機地址為1-244,廣播地址255
-
- 轉義字符的處理:
- 0xdb 0xdd 代表 0xdb
- 0xdb 0xdc 代表 0xc0
- 0xdb 0xde 代表 0x0c
- *************************************************************/
- #define MAXSIZE 0x0a // 緩沖區長度10
- uchar send_buf[MAXSIZE]={0xdb,0x0c,0xc0}; // 該緩沖區用于保存設備狀態信息
- //uchar send_buf[MAXSIZE]={0xcd,0xcb,0xbc};
- uchar rec_buf1[MAXSIZE]; // 保存接收到的幀
- uchar rec_buf2[MAXSIZE]; //保存處理過的幀
- uchar dev; // 該字節用于保存本機設備號
- uchar len ; // 該字節用于保存發送設備信息的長度
- uchar type; // 該字節用于保存命令字
- sbit M_DE = P1^0; // 驅動器使能,1有效
- sbit M_RE = P1^1; // 接收器使能,0有效
- void get_status(); // 調用該函數獲得設備狀態信息,函數代碼未給出
- void send_data(uchar type, uchar len, uchar *send_buf); // 發送數據幀
- bit recv_cmd(uchar *type); // 接收主機命令,主機請求僅包含命令信息
- void send_byte(uchar da); // 該函數發送一幀數據中的一個字節,由send_data()函數調用
- uchar Recv_Flag,Recv_Over_Flag; //接受允許標志,接受完成標志
- uchar uart_i; //幀數據計數
- void main()
- {
- /* 系統初始化 */
- dev =0xff; //設備號
- TMOD = 0x20; // 定時器T1使用工作方式2
- TH1 = 0xfd; // 設置初值
- TL1 = 0xfd;
- TR1 = 1; // 開始計時
- PCON = 0x00; // bps不倍增
- SCON = 0x50; // 工作方式1,波特率9600bps,允許接收
- ES = 1; // 開串口中斷
- EA = 1; // 開啟中斷
- M_DE = 0; // 置發送禁止,接收允許
- M_RE = 0;
-
-
- /* 主程序流程 */
- while(1) // 主循環
- {
- if(Recv_Over_Flag==1){
- if(recv_cmd(&type) ==1){
- switch(type)
- {
- case __ACTIVE_: // 主機詢問從機是否存在
- send_data(__OK_, 0, send_buf); // 發送應答信息,這里buf的內容并未用到
- break;
- case __GETDATA_:
- len=strlen(send_buf);
- send_data(__STATUS_, len, send_buf); // 發送設備狀態信息
- break;
- default:
- break; // 命令類型錯誤,丟棄當前幀后返回
-
- }
- Recv_Over_Flag=0; //一定要清零
- uart_i=0; //
- }
- }
-
- }
- }
- /* 該函數接收一幀數據并進行檢測,無論該幀是否錯誤,函數均會返回
- * 函數參數type保存接收到的命令字
- * 當接收到數據幀錯誤或其地址位不為0時(非主機發送幀),函數返回0,反之返回1
- */
- bit recv_cmd(uchar *type)
- {
- bit db = 0; // 當接收到的上一個字節為0xdb時,該位置位
- bit c0 = 0; // 當接收到的上一個字節為0xc0時,該位置位
-
- uchar sum = 0;
- uchar i,j;
- // ES=0;
- M_DE = 1; // 置發送允許,接收禁止
- M_RE = 1;
-
- /* 接收一幀數據 */
- for(i=0,j=0;i<uart_i;i++) // 循環直至幀接收完畢
- {
-
- if(db == 1) // 接收到的上一個字節為0xdb
- {
- switch(rec_buf1[i])
- {
- case 0xdd:
- rec_buf2[j] = 0xdb; // 0xdbdd表示0xdb
-
- db = 0;
- break;
- case 0xdc:
- rec_buf2[j] = 0xc0; // 0xdbdc表示0xc0
-
- db = 0;
- break;
- case 0xde:
- rec_buf2[j] = 0x0c; // 0xdbdc表示0xc0
-
- db = 0;
- break;
- default :
- return 0; // 幀錯誤,返回
- }
- j++;
- }
- else{
- switch(rec_buf1[i]) // 正常情況
- {
- case 0xdb: // 檢測到轉義字符
- db = 1;
- break;
- default: // 普通數據
- rec_buf2[j] = rec_buf1[i]; // 保存數據
- j++; // 計算校驗字節
-
- }
- }
- }
-
- /* 判斷幀是否錯誤 */
- for(i=0;i<j-1;i++)
- sum+=rec_buf2[i];
- sum=sum%256;
- if(sum !=rec_buf2[j-1] ) // 校驗錯誤,返回
- return 0;
-
- if(rec_buf2[0] != dev) // 非訪問本機命令,錯誤,返回
- return 0;
-
- *type = rec_buf2[1]; // 獲得命令字
- return 1; // 函數成功返回
- }
-
- // 該函數發送一幀數據幀,參數type為命令字、len為數據長度、buf為要發送的數據內容
- void send_data(uchar type, uchar len, uchar *send_buf)
- {
- uchar i;
- uchar sum = 0; // 該字節用于保存校驗字節
-
- ES=0; //關串口中斷!!!!
- M_DE = 1; // 置發送允許,接收禁止
- M_RE = 1;
- TI = 0; // 發送幀開始標志
- SBUF = 0x0c;
- while(!TI);
- TI=0;
- send_byte(0x00); // 發送目的地址
- sum+=0x00; //假設主機地址為0x00
- send_byte(type); // 發送命令字
- sum+=type;
- //send_byte(len); // 發送長度
- for(i=0; i<len; i++) // 發送數據
- {
- send_byte(*send_buf);
- sum =sum+ (*send_buf);
- send_buf++;
- }
- sum%=256;
- send_byte(sum); // 發送校驗字節
-
- TI = 0; // 發送幀結束標志
- SBUF = 0xc0;
- while(!TI);
- TI = 0;
- ES=1; //開串口中斷
- }
- //該函數發送一個數據字節,若該字節為0xdb,則發送0xdbdd,若該字節為0xc0則,發送0xdbdc
- void send_byte(uchar da)
- {
- switch(da)
- {
- case 0xdb: // 字節為0xdb,發送0xdbdd
- TI = 0;
- SBUF = 0xdb;
- while(!TI);
- TI = 0;
-
- SBUF = 0xdd;
- while(!TI)
- TI = 0;
-
- break;
- case 0x0c: // 字節為0x0c,發送0xdbde
- TI = 0;
- SBUF = 0xdb;
- while(!TI);
- TI = 0;
-
- SBUF = 0xde;
- while(!TI)
- TI = 0;
-
- break;
- case 0xc0: // 字節為0xc0,發送0xdbdc
- TI = 0;
- SBUF = 0xdb;
- while(!TI);
- TI = 0;
-
- SBUF = 0xdc;
- while(!TI)
- TI = 0;
-
- break;
-
- default: // 普通數據則直接發送
- TI = 0;
- SBUF = da;
- while(!TI);
- TI = 0;
- }
- }
-
- void uart( ) interrupt 4 //串口中斷
- {
- uchar tmp;
-
- if( RI==1 )
- {
- RI = 0;
- tmp = SBUF; //接收數據
- if(tmp==__START_) //幀起始標志
- {
- uart_i=0;
- Recv_Flag=1; //接受數據標志
- }
- else if(tmp==__STOP_) //幀結束標志
- {
- if(Recv_Flag==1)
- Recv_Over_Flag=1;
- Recv_Flag=0;
- }
- else if(Recv_Flag==1) //開始接受幀數據
- {
- rec_buf1[uart_i]=tmp;
- uart_i++;
- }
- if( uart_i >= MAXSIZE ) //超過緩沖區長度
- {
- uart_i = 0;
- Recv_Flag=0;
- Recv_Over_Flag = 1; //接收一幀數據完畢
- }
- }
-
- }
復制代碼
|
|