⑴ 單片機多機通訊時,多是主機向從機發送命令後,從機給出應答信號,能不能從機主動給主機發送數據呢,謝謝
主機和從機通訊時,不可以從機主動發數據給主機。一般要主機主動去發布命令,從機去應答,如果從機也主動和主機聯系,那麼會造成主機接收數據錯誤,或者發送數據錯誤!
下面分析下原因。
1、首先說明下單片機多機通訊的原理:簡單點就是多個單片機TXD和RXD連接到一個,主機的TXD連接從機的RXD,從機之前是並聯狀態;復雜的呢就是通過RS485晶元,連接方式和上面一樣的,RS485相對來說傳輸數據抗干擾。
2、主機給從機發送數據,從機怎麼來接收這一幀數據。一般我們是給每個從機都設置一個獨一無二的地址。從機接收到數據首先判斷是不是發送給自己的,就像是收快遞一樣的。不是發給自己的,後面的數據就不處理,或者不接收數據。
3、說明下主機和從機的概念。其實主機、從機都是一樣的設備,作殲如為主機來說,這個設備要主動去和從機的設備去溝通,就好像車間的班長和流水線上的操作工,班長去下發任務,操作工根據任務命令去做事。
主機就是去告訴從機,什麼時間去做什麼事。從機就是等待命令,然後去檢測外部信號,執行命令。
4、主機和從機通訊的時候罩御,能不能從機主動。明白了主機和從機的概念,深入的想一下,為什麼要主機發送命令,從機做出應答呢
。一般是主機會和很多從機進行通信。主機和從機通信一般是有個時間的間隔。比如200ms發送一次,然後切換到下一個從機。
如果主機在發送數據的時候,從機突然主動和主機聯系了,那麼
就會出現數據錯誤了,因為主機在發送數據,發送的過程中肯定會造成來不及處理接收數據,因為單片機同時只能處理一件事情。
所以
主機就是要主動聯系,從機就是要等待主機聯系之後再回應主機。不然就會出現溝通混亂的問氏悶啟題,在編寫程序的時候一定要注意這一點。
⑵ 怎麼設計一個多機通信系統(單片機)
簡單說明用一個主機串口實現上述要求的思路:
從機地址分別為01和02
從機的串口相同引腳相互並聯作為一個串口連接於主機串口,注意接線正確。
主機命令:地址號 + 命令字元串
從機命令:地址號 + 命令字元串
然後在各自收發代碼中利用地址號來區別命令執行
其它請參閱如下網址本人的答復:
http://..com/question/12535506.html
http://..com/question/12522809.html
http://..com/question/11725744.html
http://..com/question/11040704.html
http://..com/question/10941227.html
補充:
串列通訊的基本知識
每台計算機都提供了一個或多個串列埠。它們被依次命名為:COM1、COM2 等等。在標準的 PC 中,滑鼠通常被連接到 COM1 埠。數據機可能連接到 COM2,掃描儀被連接到 COM3,等等。串列埠提供了計算機與這些外部串列設備之間的數據傳輸通道。
串列埠的本質功能是作為 CPU 和串列設備間的編碼轉換器。當數據從 CPU 經過串列埠發送出去時,位元組數據被轉換為串列的位。在接收數據時,串列的位將被轉換為位元組數據。
我的理解:串列口數據通信的實質是ASCII(美國標准信息交換碼)的傳輸。你可理解是傳輸ASCII碼,而實際傳輸的是ASCII碼(其二進制形式,8位組成一位元組)。它又可看成是8位二進制數,例字元A 其二進製表示為 01000001,MSCOMM發送時完全按照此二進制信號發送,由低位至高位傳輸。又能理解為10進制的64。在計算機內通常以16進製表示為41。由2個8位二進制數據組成16位二進制數,通常用於數據的二進制通信。你的程序代碼採用以文本方式取回數據,這是在MSCOMM控制項內部進行解決,而無須VB編程員來處理。
見MSCOMM控制項的:
InputMode 常數
常數 值 描述
comInputModeText 0 (預設)通過 Input 屬性以文本方式取回數據。
comInputModeBinary 1 通過 Input 屬性以二進制方式檢取回數據。
以下是由MICROSOFT提供的關於串列通訊和MSCOMM控制項的一些說明,可能對你答辯有用,供參考。
串列通訊的基本知識
每台計算機都提供了一個或多個串列埠。它們被依次命名為:COM1、COM2 等等。在標準的 PC 中,滑鼠通常被連接到 COM1 埠。數據機可能連接到 COM2,掃描儀被連接到 COM3,等等。串列埠提供了計算機與這些外部串列設備之間的數據傳輸通道。
串列埠的本質功能是作為 CPU 和串列設備間的編碼轉換器。當數據從 CPU 經過串列埠發送出去時,位元組數據被轉換為串列的位。在接收數據時,串列的位將被轉換為位元組數據。
要完成數據的傳輸,還需要進一步一個解釋層。在操作系統一邊,Windows 使用了通訊驅動程序 Comm.drv,以便使用標準的 Windows API 函數發送和接收數據。驅動程序通常由串列設備製造商提供,以便將其硬體與 Windows 連接。在使用 Communications 控制項時,實際上使用了 API 函數,API 函數將被 Comm.drv 解釋並傳輸給設備驅動程序。
作為程序員,只需關心如何與 Windows 打交道。作為 Visual Basic 程序員,只需要關心 Communications 控制項提供的對 Windows 通訊驅動程序的 API 函數的介面。換句話說,只需要設置和監視 Communications 控制項的屬性和事件。
建立串列埠連接
使用 Communications 控制項的第一步是建立與串列埠的連接。下表列出了用於建立串列埠連接的屬性:
屬性 描述
CommPort 設置或返回通訊埠號。
Settings 以字元串形式設置或返回波特率、奇偶校驗、數據位和停止位。
PortOpen 設置或返回通訊埠的狀態。以及打開和關閉埠。
打開串列埠
要打開串列埠,可以使用 CommPort、PortOpen 和 Settings 屬性。例如:
'打開串列埠
MSComm1.CommPort = 2
MSComm1.Settings = "9600,N,8,1"
MSComm1.PortOpen = True
CommPort 屬性確定打開哪個串列埠。假如 COM2 上連接有一個數據機,則在上面的例子中需要將值設置為 2 (COM2) 才能連接到該數據機。CommPort 屬性值可以設置為 1 到 16 之間的任何值(預設值為 1),然而,如果將該值設置為系統中並不存在的 COM 埠,將會產生錯誤。
Settings 屬性可以用來指定波特率、奇偶校驗、數據位數和停止位數。按照預設規定,波特率被設置為 9600。奇偶校驗設置為了進行數據校驗。這通常是不用的,並設置為"N"。數據位數指定了代表一個數據塊的比特數。停止位指出了何時接收到一個完整數據塊。
在指定了要打開的埠,以及如何進行數據通訊之後,就可以使用 PortOpen 屬性建立連接了。它是一個布爾值,即取值范圍為 True 或 False。然而,如果埠無效,或者 CommPort 屬性設置有誤,或者該設備不支持指定的設置,就會產生錯誤;即使沒有產生錯誤,外部設備也不能正常工作。將 PortOpen 屬性設置為 False 即可關閉該埠。
緩沖區內存分配
InBufferSize 和 OutBufferSize 屬性指定了為接收和發送緩沖區分配的內存數量。按照預設規定,它們被分別設置為上圖所示的值。這兩個值設置得越大,應用程序中可用的內存就越少。然而,如果緩沖區太小,就要冒緩沖區溢出的風險,除非採用握手信號。
注意 鑒於現在大多數微機可用的內存量,由於有更多的可用資源,緩沖區內存分配已不那麼至關緊要了。換言之,可以把緩沖區的值設得高一些而不影響應用程序的性能。
RThreshold 和 SThreshold 屬性
RThreshold 和 SThreshold 屬性,表示在 OnComm 事件發生之前,接收緩沖區或發送緩沖區中可以接收的字元數。OnComm 事件被用來監視和響應通訊狀態的變化。如果將每個屬性的值都設置為零 (0),就可以避免發生 OnComm 事件。如果將該值設置為非零的值(比如 1),那麼每當緩沖區中接收到一個字元時,就會產生 OnComm 事件。
Output 屬性被用來向發送緩沖區發出命令和數據。
與 Input 屬性類似,數據可以以文本或二進制格式發送。Output 屬性必須用字元串變體型發送文本,用 Byte 數組變體型發送二進制數據。
可用 Output 屬性發送命令、文字字元串或 Byte 數組數據。
MSComm 控制項
MSComm 控制項通過串列埠傳輸和接收數據,為應用程序提供串列通訊功能。
語法
MSComm
說明
MSComm 控制項提供下列兩種處理通訊的方式:
事件驅動通訊是處理串列埠交互作用的一種非常有效的方法。在許多情況下,在事件發生時需要得到通知,例如,在 Carrier Detect (CD) 或 Request To Send (RTS) 線上一個字元到達或一個變化發生時。在這些情況下,可以利用 MSComm 控制項的 OnComm 事件捕獲並處理這些通訊事件。OnComm 事件還可以檢查和處理通訊錯誤。所有通訊事件和通訊錯誤的列表,參閱 CommEvent 屬性。
在程序的每個關鍵功能之後,可以通過檢查 CommEvent 屬性的值來查詢事件和錯誤。如果應用程序較小,並且是自保持的,這種方法可能是更可取的。例如,如果寫一個簡單的電話撥號程序,則沒有必要對每接收一個字元都產生事件,因為唯一等待接收的字元是數據機的"確定"響應。
每個使用的 MSComm 控制項對應著一個串列埠。如果應用程序需要訪問多個串列埠,必須使用多個 MSComm 控制項。可以在 Windows"控制面板"中改變埠地址和中斷地址。
盡管 MSComm 控制項有很多重要的屬性,但首先必須熟悉幾個屬性。
屬性 描述
CommPort 設置並返回通訊埠號。
Settings 以字元串的形式設置並返回波特率、奇偶校驗、數據位、停止位。
PortOpen 設置並返回通訊埠的狀態。也可以打開和關閉埠。
Input 從接收緩沖區返回和刪除字元。
Output 向傳輸緩沖區寫一個字元串。
OnComm 事件
無論何時當 CommEvent 屬性的值變化時,就產生 OnComm 事件,標志發生了一個通訊事件或一個錯誤。
語法
Private Sub object_OnComm ()
OnComm 事件語法包括下列部分:
部分 描述
object 對象表達式,其值是"應用於"列表中的對象。
說明
CommEvent 屬性包含實際錯誤或產生 OnComm 事件的數碼。注意,設置 Rthreshold 或 Sthreshold 屬性為 0,分別使捕獲 comEvReceive 和 comEvSend 事件無效。
MSComm 控制項常數
Handshake 常數
常數 值 描述
comNone 0 無握手。
comXonXoff 1 XOn/Xoff 握手。
comRTS 2 Request-to-send/clear-to-send 握手。
comRTSXOnXOff 3 Request-to-send 和 clear-to-send 握手皆可。
OnComm 常數
常數 值 描述
comEvSend 1 發送事件。
comEvReceive 2 接收事件。
comEvCTS 3 clear-to-send 線變化。
comEvDSR 4 data-set ready 線變化。
comEvCD 5 carrier detect 線變化。
comEvRing 6 振鈴檢測。
comEvEOF 7 文件結束。
Error 常數
常數 值 描述
comEventBreak 1001 接收到中斷信號
comEventCTSTO 1002 Clear-to-send 超時
comEventDSRTO 1003 Data-set ready 超時
comEventFrame 1004 幀錯誤
comEventOverrun 1006 埠超速
comEventCDTO 1007 Carrier detect 超時
comEventRxOver 1008 接收緩沖區溢出
comEventRxParity 1009 Parity 錯誤
comEventTxFull 1010 傳輸緩沖區滿
comEventDCB 1011 檢索埠 設備控制塊 (DCB) 時的意外錯誤
InputMode 常數
常數 值 描述
comInputModeText 0 (預設)通過 Input 屬性以文本方式取回數據。
comInputModeBinary 1 通過 Input 屬性以二進制方式檢取回數據。
Output 屬性
往傳輸緩沖區寫數據流。該屬性在設計時無效,在運行時為只讀。
語法
object.Output [ = value ]
Output 屬性語法包括下列部分:
部分 描述
object 對象表達式,其值是"應用於"列表中的對象。
value 要寫到傳輸緩沖區中的一個字元串。
說明
Output 屬性可以傳輸文本數據或二進制數據。用 Output 屬性傳輸文本數據,必須定義一個包含一個字元串的 Variant。發送二進制數據,必須傳遞一個包含位元組數組的 Variant 到 Output 屬性。
正常情況下,如果發送一個 ANSI 字元串到應用程序,可以以文本數據的形式發送。如果發送包含嵌入控制字元、Null 字元等等的數據,要以二進制形式發送。
數據類型
Variant
⑶ 單片機多機通信程序
單片機多機通信,一個主機多個從機+一個通信協議就可以了,正常的串口設置就可以,協議可以以數據包形式,如:引導符、從機號、數據長度、指令類型、數據1---數據n、校驗碼、結束符,以主機發送指令從機應答,從機間需由主機協助。
⑷ 單片機多機通訊的最佳連接方式
硬體連接。
1、首先單片機構成的多機系統,常採用匯流排型主從式結構啟唯前,硬體連接。
2、其次所謂主從式,即在數個單片機中,有一個是山轎主機,其餘的是從機;從機要服從主機的調動、支配。串列口方悄清式2、方式3適合於這種主從式通信結構。
3、最後採用不同的通信標准時,還需進行相應的電平轉換,有時還要對信號進行光電隔離;在實際的多機應用系統中,常採用RS-485串列標准匯流排進行數據傳輸。
⑸ C51單片機多機通信C語言
單片機a,b,c.a為主機,bc為從機。a上有一個外部中斷0輸入,按第一次a的兩個LED亮500ms,再按一下,b機的兩個LED燈亮500ms,第三次按下c機的兩個LED燈亮500ms,然後周而復始。兩個數碼管分別顯示0/1/2,和abc(bc由從機反饋)
/*
主從通信基本步驟:
1.主機從機初始化為方式2或者3,從機都置SM2=1,允許中斷
2.主機置TB8=1,發送從機地址
3.所有從機均接收主機發送要定址的從機地址
4.被定址的從機確認地址後,置本機SM2=0,向主機返回地址,供主機核對
5.核對無誤後,主機向被定址的從機發送命令,通知從機接受或者發送數據。
6.本次通信結束後,主從機重置SM2=1,主機可再對其他從機定址
*/
******************************************************************
主機a:
******************************************************************
#include<reg51.h>
#defineucharunsignedchar
#defineuintunsignedint
ucharleddata[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x40,0x00};
ucharMode;
sbitP10=P1^0;
sbitP13=P1^3;
sbitP17=P1^7;
sbitP20=P2^0;
sbitP21=P2^1;
voidUART_init()
{
TMOD=0x20;
TH1=0xfd;
TL1=0xfd;
TR1=1;
SCON=0xd0;
ES=1;
EX0=1;
IT0=1;//INT0下跳觸發
EA=1;
TI=0;
}
voidDelayMs(intms)
{
uchari;
while(ms--)
for(i=0;i<120;i++);
}
voidputc_to_SerialPort(ucharc)
{
SBUF=c;
while(TI==0);
TI=0;
}
voidMasterControl(unsignedcharAddr,unsignedcharComd)
{
TB8=1;
putc_to_SerialPort(Addr);
DelayMs(50);
TB8=0;
putc_to_SerialPort(Comd);
DelayMs(50);
}
Ex0_int(void)interrupt0
{
P0=leddata[Mode];
P20=0;
if(Mode==0)
{
P2=leddata[10];
P10=0;
P13=0;
DelayMs(500);
P10=1;
P13=1;
//MasterControl('b','C');
//MasterControl('c','C');
}
elseif(Mode==1)
{
P10=1;
P13=1;
MasterControl('b','O');
//MasterControl('c','C');
}
elseif(Mode==2)
{
P10=1;
P13=1;
//MasterControl('b','C');
MasterControl('c','O');
}
Mode=(Mode+1)%3;
}
com_int(void)interrupt4
{
if(RI)
{
RI=0;
if(SBUF=='b')
{
P2=leddata[11];
}
if(SBUF=='c')
{
P2=leddata[12];
}
}
}
voidmain(void)
{
P0=0x00;
P1=0xff;
P2=0x00;
UART_init();
Mode=0;
while(1);
}
******************************************************************
從機b:
******************************************************************
#include<reg51.h>
#defineucharunsignedchar
ucharRecData;
sbitP10=P1^0;
sbitP13=P1^3;
voidUART_init()
{
TMOD=0x21;
TH1=0xfd;
TL1=0xfd;
TR1=1;
SCON=0xf0;
ES=1;
PS=1;
EA=1;
}
voidDelayMs(intms)
{
uchari;
while(ms--)
for(i=0;i<120;i++);
}
voidputc_to_SerialPort(ucharc)
{
SBUF=c;
while(TI==0);
TI=0;
}
com_int(void)interrupt4
{
if(RI)
{
RecData=SBUF;
RI=0;
if(RB8==1)//地址
{
if(RecData=='b')//是自己的地址,置SM2=0,准備接受數據
{
SM2=0;
putc_to_SerialPort('b');
}
else//不是自己的地址
{
SM2=1;
}
}
if(RB8==0)//數據
{
if(RecData=='O')
{
P10=0;
P13=0;
DelayMs(500);
P10=1;
P13=1;
}
if(RecData=='C')
{
P10=1;
P13=1;
}
SM2=1;
}
}
}
voidmain(void)
{
P0=0xff;
P1=0xff;
UART_init();
while(1);
}
******************************************************************
從機c:
******************************************************************
#include<reg51.h>
#defineucharunsignedchar
ucharRecData;
sbitP10=P1^0;
sbitP13=P1^3;
voidUART_init()
{
TMOD=0x21;
TH1=0xfd;
TL1=0xfd;
TR1=1;
SCON=0xf0;
ES=1;
PS=1;
EA=1;
}
voidDelayMs(intms)
{
uchari;
while(ms--)
for(i=0;i<120;i++);
}
voidputc_to_SerialPort(ucharc)
{
SBUF=c;
while(TI==0);
TI=0;
}
com_int(void)interrupt4
{
if(RI)
{
RecData=SBUF;
RI=0;
if(RB8==1)//地址
{
if(RecData=='c')//是自己的地址,置SM2=0,准備接受數據
{
SM2=0;
putc_to_SerialPort('c');
}
else//不是自己的地址
{
SM2=1;
}
}
if(RB8==0)//數據
{
if(RecData=='O')
{
P10=0;
P13=0;
DelayMs(500);
P10=1;
P13=1;
SM2=1;
}
if(RecData=='C')
{
P10=1;
P13=1;
SM2=1;
}
}
}
}
voidmain(void)
{
P0=0xff;
P1=0xff;
UART_init();
while(1);
}