1. 程式人生 > >NRF24L01一對多通訊方法

NRF24L01一對多通訊方法

搞通了2個NRF24L01的互相通訊,一對多實際上就非常容易了。你要記住,一對多通訊,實際上同一時刻也是一對一通訊。一次通訊只需幾個毫秒,如果一個和一個通訊完以後,再和另外一個通訊,然後再和另外一個通訊……這中間如果沒有延時程式的話,對於人的反應來說,就是同時進行的。這個原理就和作業系統一樣,同一時刻,既可以打字聊天,又可以看電影。

下面視訊是瑞生做的一個專案,是一對五,共用到6個NRF24L01模組,一個盒子裡有一個。

上面這個視訊的例項,如果只看NRF24L01的話,可以總結為下面的圖示:

NRF24L01一對多通訊圖

我們知道,2個NRF24L01通訊需要具備4個條件設定相同。

  • 發射接收資料寬度相同(最大32個位元組)
  • 發射接收地址相同(5個8位地址)
  • 發射接收頻道相同(0~125)
  • 發射接收速率相同(2M 1M 250K)

現在假設,主機和5個從機的這四個條件全部設定相同,如果主機發送資料的話,理論上5個從機會收到資料,實際上由於干擾,不會都收到。而且,這時候,如果從機1給主機發送資料的話,從機2~5也會收到資料。所以這樣做是不行的!

一對多,有兩種方式,一種是修改為不同的頻道,一種是修改為不同的地址,也可以修改為不同的頻道+不同的地址。

上面視訊中用到的,是修改為不同的頻道,例如,從機1的頻道是10,從機2的頻道是30,從機3的頻道是50,從機4的頻道是70,從機5的頻道是90(注意,頻道的值可以是0~125,共126個頻道),頻道接近的話,有可能出問題,例如從機1的頻道是20,如果設定從機2的頻道是21的話,主機給從機1傳送資料時,從機2也有可能受到資料。所以要向上面一樣,頻道距離拉開一些。這時候,有人會產生疑問,如果我有幾十個從機,頻道豈不是很接近了,恭喜你,答對了。如果有幾個從機的話,建議不要用不同的頻道,而同一頻道不同的地址,由於地址是5位元組的,所以理論上可以有上億個從機。

從機的頻道定義好了,那麼主機的程式該怎麼寫呢?這個很容易。例如,主機要和從機1通訊,自己就把頻道改為從機1一樣的頻道10,然後就可以傳送資料,這時候,從機2~5由於頻道不同,是收不到資料的。同樣,主機要和從機2通訊,就把自己的頻道改為和從機2一樣的頻道30,然後就可以傳送資料了。到了這個時候了,還會有童鞋問,我怎麼就知道我要和誰通訊?該怎麼改呢?這樣的童鞋還不少,那我就給你解釋下吧。我都不好意思說了,太簡單了。假設我的主機有5個按鍵,按下按鍵1,給從機1傳送資料;按下按鍵2,給從機2傳送資料……以此類推。那麼,主機程式就是下面這個樣子的:

if(KEY==0)//按下KEY1
{
  NRF_CE=0;	//拉低CE引腳
  NRF24L01_Write_Reg(WRITE_REG+RF_CH,10);//修改為從機1的頻道
  NRF_CE=1;	//拉高CE引腳
  NRF24L01_TxPacket(rece_buf);//傳送資料
}
else if(KEY2==0)//按下KEY2
{
  NRF_CE=0;	//拉低CE引腳
  NRF24L01_Write_Reg(WRITE_REG+RF_CH,30);//修改為從機2的頻道
  NRF_CE=1;	//拉高CE引腳
  NRF24L01_TxPacket(rece_buf);//傳送資料
}
else if(KEY2==0)//按下KEY3
{
  NRF_CE=0;	//拉低CE引腳
  NRF24L01_Write_Reg(WRITE_REG+RF_CH,50);//修改為從機3的頻道
  NRF_CE=1;	//拉高CE引腳
  NRF24L01_TxPacket(rece_buf);//傳送資料
}
else if(KEY2==0)//按下KEY4
{
  NRF_CE=0;	//拉低CE引腳
  NRF24L01_Write_Reg(WRITE_REG+RF_CH,70);//修改為從機4的頻道
  NRF_CE=1;	//拉高CE引腳
  NRF24L01_TxPacket(rece_buf);//傳送資料
}
else if(KEY2==0)//按下KEY5
{
  NRF_CE=0;	//拉低CE引腳
  NRF24L01_Write_Reg(WRITE_REG+RF_CH,90);//修改為從機5的頻道
  NRF_CE=1;	//拉高CE引腳
  NRF24L01_TxPacket(rece_buf);//傳送資料
}

話說到這份上,有的童鞋還會有疑問:“那如果我的5個從機要給主機發送資料怎麼辦?按照你上面的程式,主機的頻道是不定的,一會兒這個,一會那個的,從機要想和主機通訊的時候,我怎麼判斷現在主機的頻道和現在從機的頻道相同,不相同不能通訊啊!”。真有童鞋這麼問,還不是少數,這個問題,稍微動一下腦筋就想出來了。請看下面解決方案:

假設有5個大棚,1個機房,機房要無線採集5個大棚的溫度。每個大棚裡,都有一個電路板,板子上有溫度感測器+微控制器+NRF24L01,微控制器通過溫度感測器採集到溫度以後,就通過NRF24L01傳送到機房。這個例子,正好是上面童鞋問到的,大棚要給機房傳送溫度。

解決思路是:主機修改為從機1的頻道以後,傳送資料命令,從機收到命令後,傳送溫度資料給主機,主機再回應從機收到資料;然後主機再把頻道修改為從機2的頻道,傳送資料命令,從機收到命令後,傳送溫度資料給主機,主機再回應從機收到資料….以此類推。

有的人聽了以後,感覺好麻煩,實際上機房按照上面的描述收集5個機房的溫度,也就是一眨眼的功夫。

假設機房每隔5分鐘採集一次大棚溫度,示例程式如下:

main()
{
  //各種初始化配置
  while(1)
  {
    delay()//延時5分鐘(每5分鐘採集一次資料)

    NRF_CE=0; //拉低CE引腳
    NRF24L01_Write_Reg(WRITE_REG+RF_CH,10);//修改為從機1的頻道
    NRF_CE=1; //拉高CE引腳
    rece_buf[0]=0x66;//這是我規定的從機發送溫度命令
    NRF24L01_TxPacket(rece_buf);//告訴從機我要你給我發溫度資料
    NRF24L01_RX_Mode();// 配置為接收模式
    while(IRQ==1);//等待發來資料
    NRF24L01_RxPacket(rece_buf);//接收溫度資料
    wendu[0]=rece_buf[1];//把採集到的溫度資料給了wendu[0]變數
    NRF24L01_TX_Mode();//配置為傳送模式
    rece_buf[0]=0x88;//這是我規定的主機接收到溫度的迴應資料
    NRF24L01_TxPacket(rece_buf);//告訴從機1我收到資料了

    NRF_CE=0; //拉低CE引腳
    NRF24L01_Write_Reg(WRITE_REG+RF_CH,30);//修改為從機2的頻道
    NRF_CE=1; //拉高CE引腳
    rece_buf[0]=0x66;//這是我規定的從機發送溫度命令
    NRF24L01_TxPacket(rece_buf);//告訴從機我要你給我發溫度資料
    NRF24L01_RX_Mode();// 配置為接收模式
    while(IRQ==1);//等待發來資料
    NRF24L01_RxPacket(rece_buf);//接收溫度資料
    wendu[1]=rece_buf[1];//把採集到的溫度資料給了wendu[1]變數
    NRF24L01_TX_Mode();//配置為傳送模式
    rece_buf[0]=0x88;//這是我規定的主機接收到溫度的迴應資料
    NRF24L01_TxPacket(rece_buf);//告訴從機1我收到資料了

    NRF_CE=0; //拉低CE引腳
    NRF24L01_Write_Reg(WRITE_REG+RF_CH,50);//修改為從機3的頻道
    NRF_CE=1; //拉高CE引腳
    rece_buf[0]=0x66;//這是我規定的從機發送溫度命令
    NRF24L01_TxPacket(rece_buf);//告訴從機我要你給我發溫度資料
    NRF24L01_RX_Mode();// 配置為接收模式
    while(IRQ==1);//等待發來資料
    NRF24L01_RxPacket(rece_buf);//接收溫度資料
    wendu[2]=rece_buf[1];//把採集到的溫度資料給了wendu[2]變數
    NRF24L01_TX_Mode();//配置為傳送模式
    rece_buf[0]=0x88;//這是我規定的主機接收到溫度的迴應資料
    NRF24L01_TxPacket(rece_buf);//告訴從機1我收到資料了

    NRF_CE=0; //拉低CE引腳
    NRF24L01_Write_Reg(WRITE_REG+RF_CH,70);//修改為從機4的頻道
    NRF_CE=1; //拉高CE引腳
    rece_buf[0]=0x66;//這是我規定的從機發送溫度命令
    NRF24L01_TxPacket(rece_buf);//告訴從機我要你給我發溫度資料
    NRF24L01_RX_Mode();// 配置為接收模式
    while(IRQ==1);//等待發來資料
    NRF24L01_RxPacket(rece_buf);//接收溫度資料
    wendu[3]=rece_buf[1];//把採集到的溫度資料給了wendu[3]變數
    NRF24L01_TX_Mode();//配置為傳送模式
    rece_buf[0]=0x88;//這是我規定的主機接收到溫度的迴應資料
    NRF24L01_TxPacket(rece_buf);//告訴從機1我收到資料了

    NRF_CE=0; //拉低CE引腳
    NRF24L01_Write_Reg(WRITE_REG+RF_CH,90);//修改為從機5的頻道
    NRF_CE=1; //拉高CE引腳
    rece_buf[0]=0x66;//這是我規定的從機發送溫度命令
    NRF24L01_TxPacket(rece_buf);//告訴從機我要你給我發溫度資料
    NRF24L01_RX_Mode();// 配置為接收模式
    while(IRQ==1);//等待發來資料
    NRF24L01_RxPacket(rece_buf);//接收溫度資料
    wendu[4]=rece_buf[1];//把採集到的溫度資料給了wendu[4]變數
    NRF24L01_TX_Mode();//配置為傳送模式
    rece_buf[0]=0x88;//這是我規定的主機接收到溫度的迴應資料
    NRF24L01_TxPacket(rece_buf);//告訴從機1我收到資料了
  }
}