關於rs485的一主多從通訊,網上瀏覽量比較多的幾篇CSDN大部分都是說的一主一從通訊(截止到我寫稿爲止),如果你想讓自己的單片機羣真正實現一主多從,那麼這篇正是你所需要的!
我還需要聲明一下,我是做大創的時候,需要用主機去接收不同從機上超聲波傳感器的信息,查了很多相關資料都沒查到。有很多資料說要用modbus協議的,其實那個是工業上完整的數據通信協議,如果只是做個比賽或者項目來接收數據的話,用不到那麼複雜,完全可以自己寫,具體怎麼寫,我會在下面詳細說。主要方式呢就是主機通過輪詢,使對應的從機發送數據,然後主機接收。這也是我第一次寫博客,希望大家多支持哈!
1、首先我需要假定你已經看過並大致瞭解了rs485的一些簡單通訊方法,如一主一從。那麼現在來說一些乾貨吧。485是兩根線,會抑制共模誤差,高電平發送數據,低電平接收,可以理解成水從高處往低處流,並且每次只能一個單片機處於高電平,但是所有處於低電平的單片機都可以接收到總線的數據。所以我們的主路線:
①我們首先給從機編好地址:0、1、2……(自己隨便編就好);
②然後讓主機先處於高電平,從機處低電平;
③之後主機發送某個從機的地址(比如主機想看第0個從機的信息,那就發送0)後拉低,每一個從機接收到主機發送後的數據後(比如0)和自己的地址進行對比,如果相等,拉高,把相應數據發到總線上,發完拉低;若不相等,則不動作。所以每次只會有一個從機會給主機迴應消息;
④等主機接收到信息後開始詢問下一個從機,若在一段時間內未收到消息則再重發該地址進行詢問。
2、貼出來主機代碼:
/*==========master============*/
#include <SoftwareSerial.h>
SoftwareSerial Master(10, 11);
char val[5]={'0','0','N','N','N'}; //定義一個數組,用來將從機地址和信息匹配
char address; //定義從機地址
int DE_RE=2;
void setup() {
Serial.begin(9600); //初始化
Serial.println("Master is ready!");
Master.begin(38400);
pinMode(DE_RE,OUTPUT);
digitalWrite(DE_RE,LOW);
}
void loop()
{
for(int i = 49 ; i < 51 ; i++) //用來對每個從機進行一次大輪詢
{
//==========發送車位序號i=============================================//
digitalWrite(DE_RE,HIGH); //將主機設爲發送狀態
address = i; //給從機發地址,此時是字符式,49對應1的字符串
Master.write(address); //傳喚對應號碼的從機
digitalWrite(DE_RE,LOW); //然後立馬換成接收狀態
delay(500); //等一下從機反應,之前沒有delay,
//maste.available還沒反應過來,就過去了,加個
//delay剛剛好
//或許等從機加了超聲波,還得調delay的時間
//==========接收車位信息到數組val裏===================================//
while(Master.available()) //等從機把數據發過來
{
val[i-49] = Master.read(); //讀車位信息到數組val
}
delay(1000); //小循環
} //整個for循環結束
for(int a = 0 ; a < 5 ; a++) //然後把整個字符串打印出來進行觀察
{
Serial.print(a+1);
Serial.print(val[a]);
}
delay(2000); //最後一整個過程結束後,多等兩秒鐘
}
其次一主多從之間進行通訊時採用軟串口,因爲TX、RX要用到串口顯示(此處是借鑑了一主一從博主的經驗)。另外主機發完地址後,需要delay一會,要不然程序很快就會去拉低+接收,這樣從機還沒來得及發消息,主機就做去詢問下一個了,以致於錯過數據。我這裏delay500那裏是爲了等從機的超聲波傳感器測數據。具體要多久可以自行測試。還有一點,這是數據通信,傳的是字符,如果想傳1,那還得換算成ASCII碼,好像是49吧。
3、貼出來從機代碼:
/* Slave */
#include <SoftwareSerial.h>
SoftwareSerial Slave(10, 11);
char val;
int DE_RE=2;
void setup() {
Serial.begin(38400);
Serial.println("Slave is ready!");
Slave.begin(38400);
pinMode(DE_RE,OUTPUT);
digitalWrite(DE_RE,LOW);
}
void Distance_test() // 量出前方距離
{
//pass
}
void loop()
{
while(Slave.available())
{
val = Slave.read(); //在rs485中讀串口
Serial.write(val); //把地址寫到串口中去
if(val=='1') //如果確定爲自己的地址
{
Distance_test(); //測距離
digitalWrite(DE_RE,HIGH); //拉高
if(Distance < 35)
Slave.write("Y"); //判斷
else Slave.write("N"); //判斷
}
}
}
主從機之間讀取信息是master.read、master.available、Slave.read、Slave.available,而串口的都是Serial.read()什麼的,這裏不要弄混了。不同從機改變一下地址編號即可。
行吧,大體就是這樣了,希望可以幫到大家。有什麼疑問可以直接留言,我看到會及時回覆!也歡迎大家給我指正!