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