前面我們介紹過單片機(jī)的幾種通信協(xié)議,并且初步了解如何操作寄存器進(jìn)而控制芯片的工作等等。那么,今天我們將利用之前的知識(shí)來對(duì)無線收發(fā)模塊編寫驅(qū)動(dòng)程序。
首先,介紹我們今天用到的無線收發(fā)模塊——NRF24L01芯片
nRF24L01簡介 :nRF24L01是由NORDIC生產(chǎn)的工作在2.4GHz~2.5GHz的ISM 頻段的單片無線收發(fā)器芯片。無線收發(fā)器包括:頻率發(fā)生器、增強(qiáng)型“SchockBurst”模式控制器、功率放大器、晶體振蕩器、調(diào)制器和解調(diào)器。輸出功率頻道選擇和協(xié)議的設(shè)置可以通過SPI 接口進(jìn)行設(shè)置。幾乎可以連接到各種單片機(jī)芯片,并完成無線數(shù)據(jù)傳送工作。
管腳圖:

各個(gè)管腳的具體功能可自行參考數(shù)據(jù)手冊,由于高頻信號(hào)對(duì)線路設(shè)計(jì)要求十分嚴(yán)格,我們沒有必要去手焊電路,直接采用現(xiàn)成模塊即可。

接線圖:

從它的接線圖也很容易可以看出它是利用SPI與單片機(jī)進(jìn)行通信的,而且有5根線需要與單片機(jī)I/O口連接。
以上為硬件部分連接,接下來具體講一講 軟件設(shè)計(jì) 。
我們拿到一塊芯片,肯定要先看它的數(shù)據(jù)手冊,了解它是如何工作的,然后還得重點(diǎn)了解一下這塊芯片到底有哪些寄存器,這些寄存器的地址是什么,控制字是什么,時(shí)序圖怎么樣。所以我們從寄存器開始入手。

nRF24L01有多達(dá)25個(gè)寄存器,其中大部分是8位的,有兩個(gè)數(shù)據(jù)緩沖器是32字節(jié)的,還有3個(gè)是40位的(發(fā)送地址和通道0、通道1接收地址),我們選擇其中幾個(gè)寄存器來進(jìn)行說明。
名稱:CONFIG 地址:00H
作用:可以用來決定是否屏蔽發(fā)送完成中斷、接收完成中斷、最大重發(fā)次數(shù)中斷,還有芯片是上電還是掉電,工作在發(fā)射模式還是接收模式等。
名稱:EN_AA 地址:01H
作用:用來使能各個(gè)通道的應(yīng)答
名稱:RX_ADDR 地址:02H
作用:接收地址允許位
名稱:SETUP_AW 地址:03H
作用:用來設(shè)置地址寬度(3、4、5字節(jié))
名稱:SETUP_RETR 地址:04H
作用:建立自動(dòng)重發(fā),高四位決定自動(dòng)重發(fā)的延時(shí),低四位決定重發(fā)次數(shù)
名稱:STATUS 地址:07H
作用:這是一個(gè)狀態(tài)寄存器,從名字可以看出這個(gè)寄存器是描述狀態(tài)的。高4位可讀可寫,最高位保留,其中bit6 ~ bit4分別可以產(chǎn)生接收數(shù)據(jù)中斷、發(fā)送數(shù)據(jù)中斷、最大重發(fā)次數(shù)中斷。bit3~bit1可以判斷是哪個(gè)通道獲得數(shù)據(jù),只能讀不能寫,最低位保留。
名稱:RX_ADDR_P0 地址:0AH
作用:它是數(shù)據(jù)通道0的接收地址,最多5個(gè)字節(jié),從低字節(jié)開始,字節(jié)數(shù)量由前面的SETUP_AW決定,還有10H的發(fā)送地址,需要與這個(gè)地址一致
還有一些其他的寄存器就不多說了。這些寄存器大部分是比較重要的,我們在寫芯片的初始化程序的時(shí)候,就是對(duì)這些寄存器進(jìn)行配置。(注意:我們在寫芯片的驅(qū)動(dòng)程序,基本上是從芯片的初始化開始的,而芯片要初始化,當(dāng)然要搞清楚它的各個(gè)寄存器地址、作用,才能進(jìn)行配置)
上面提到的自動(dòng)重發(fā)可能會(huì)不理解,原來一個(gè)發(fā)送過程并不只是發(fā)送機(jī)獨(dú)自一個(gè)人的事情。一開始, 發(fā)送機(jī)發(fā)送連同身份地址在內(nèi)的數(shù)據(jù)包給接收機(jī),接收機(jī)收到數(shù)據(jù)并確認(rèn)正確后,就以剛才發(fā)送機(jī)發(fā)來的身份地址回發(fā)一個(gè)確認(rèn)信號(hào),而此時(shí)發(fā)送機(jī)會(huì)自動(dòng)切換到接收狀態(tài),當(dāng)收到確認(rèn)信號(hào)與通道0的地址進(jìn)行比較,地址相吻合,就知道對(duì)方收到數(shù)據(jù),這樣一次發(fā)送數(shù)據(jù)才算完畢。當(dāng)然,這個(gè)過程是模塊內(nèi)部自動(dòng)完成的,不用人為干預(yù)。因此這就叫做增強(qiáng)模式。在這個(gè)過程中發(fā)送雙方都最少各有一次發(fā)送和接收的過程。這樣就保證了數(shù)據(jù)可靠收到。如果發(fā)送一次,接收機(jī)沒有收到,模塊具有允許重發(fā),和重發(fā)次數(shù)設(shè)置寄存器,當(dāng)你設(shè)置了允許重發(fā),并設(shè)置好重發(fā)次數(shù)。在發(fā)送機(jī)發(fā)送完-一個(gè)數(shù)據(jù)包,等待會(huì)兒, 如果沒有接收到應(yīng)答信號(hào), 發(fā)送機(jī)就會(huì)重發(fā)一次,如此直到重發(fā)完你設(shè)定的次數(shù),再收不到它就產(chǎn)生一個(gè)中斷信號(hào)給IRQ,告訴模塊沒有發(fā)送成功,由程序根據(jù)情況再?zèng)Q定是否重發(fā)。
除了寄存器之外,還有芯片的一些命令格式也要注意

那么要如何來理解上面這張表呢?我們可以看一下。指令R_REGISTER和指令W_REGISTER的前三位可以確定是讀還是寫,如果是000就是讀,如果是001就是寫,后面的5位是寄存器的地址。合起來就構(gòu)成了一個(gè)8位字節(jié),就可以確定對(duì)哪個(gè)寄存器進(jìn)行讀或?qū)懥?。我們可以將R_REGISTER宏定義為0x00,如果某個(gè)寄存器A的地址為0x12,那么指令(R_REGISTER+A)不就是對(duì)寄存器A進(jìn)行讀的操作嗎?那有人可能會(huì)問,萬一寄存器地址很大,他們加起來不就會(huì)讓高三位超過000和001嗎?在這里是不可能的,后面的5位地址可以有32個(gè)寄存器,而這塊芯片沒有這么多寄存器,因此不會(huì)超過。前兩個(gè)指令也就很好理解了。
后面的幾個(gè)指令都是專用指令,只要發(fā)送相應(yīng)的代碼,就會(huì)執(zhí)行右邊說明的操作,比如發(fā)送指令W_RX_PAYLOAD,那么就是往TX FIFO寄存器里寫數(shù)據(jù)。也很好理解。
指令和寄存器都介紹完了,因此,我們可以先建一個(gè)頭文件,把各個(gè)寄存器的地址和指令先用宏定義好。(部分截圖如下)

這些寄存器的名稱、作用和地址都是從數(shù)據(jù)手冊上可以直接獲取的,我們以宏的形式將它們封裝好。
然后是它的時(shí)序圖


上圖就是NRF24L01模塊與單片機(jī)建立通訊的時(shí)序圖??炊?,是用單片機(jī)控制這個(gè)模塊,與它建立通訊的基礎(chǔ)條件。很多串行通訊設(shè)備都采用這種方式,也叫SPI.它一般有四根連線:第一根是片選信號(hào)線,單片機(jī)可以同時(shí)連接多個(gè)功能相同或不同的模塊,為了節(jié)省輸入輸出(I/0)信號(hào)線的資源,一般都將多個(gè)模塊連接在相同的SCK、MOSI、 MIS0線 上,這叫串行總線。那單片機(jī)發(fā)出指令后,模塊怎么知道指令是發(fā)給自己的而不是發(fā)給其它模塊的呢?這就靠每個(gè)模塊上和單片機(jī)專線連接的CSN片選信號(hào)線,平時(shí)CSN是 高電位的,當(dāng)把這根線的電位拉低那一時(shí)刻,模塊就知道單片機(jī)要給自己發(fā)指令了。
從時(shí)序圖上我們可以看出 ,讀操作的時(shí)候,主機(jī)先發(fā)送指令位,同時(shí)接收從機(jī)的狀態(tài)寄存器數(shù)據(jù),然后再接收從機(jī)發(fā)送的數(shù)據(jù)。寫操作時(shí),一樣是主機(jī)先發(fā)送指令位,同時(shí)接收從機(jī)的狀態(tài)寄存器數(shù)據(jù),然后再發(fā)送你要的數(shù)據(jù)。
而且,根據(jù)經(jīng)驗(yàn),在利用SPI通信時(shí),我們至少要寫這兩部分的程序,一個(gè)是發(fā)送/接收一個(gè)字節(jié),這一部分的寫法是固定的,完全可以照抄。另一個(gè)是根據(jù)時(shí)序,對(duì)芯片的讀寫操作。
但是在這里,稍稍有點(diǎn)不同的是,因?yàn)橛袃蓚€(gè)寄存器是32個(gè)字節(jié)的,還有3個(gè)是5個(gè)字節(jié)的,其他的都是8位的寄存器,因此,這些寄存器的讀寫程序要單獨(dú)寫。根據(jù)以上分析,我們可以寫出如下4個(gè)程序。
uint SPI_RW(uint dat) //利用SPI單獨(dú)寫一個(gè)字節(jié),并返回狀態(tài)值
/ 這是最基本的一個(gè)函數(shù),幾乎所有函數(shù)都要調(diào)用這個(gè)函數(shù),它就是將一個(gè)8位字節(jié)從高位開始 ,一位一位的放到數(shù)據(jù)總線上,由于左移位后會(huì)補(bǔ)0,因此低位也可以順便接收來自MISO總線上的數(shù)據(jù),作為返回值。 /

當(dāng)然,執(zhí)行一次這個(gè)函數(shù)并不算是一次通信,一次通信至少要發(fā)送兩個(gè)字節(jié),地址和指令,于是有了下面的函數(shù)。
uchar NRF24L01_Read(uchar reg) //讀出一個(gè)寄存器的數(shù)據(jù),發(fā)送寄存器地址(包括讀寫位+地址)用以選擇寄存器,然后執(zhí)行空操作NOP,目的是讀出數(shù)據(jù)。(空操作是一種指令格式,上面有提到)
uint NRF24L01_write_Reg(uchar reg, ucharvalue) //往一個(gè)寄存器里寫一個(gè)字節(jié),并且返回寄存器狀態(tài)值
uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars)
/ 讀出緩沖寄存器里的數(shù)據(jù),最多32個(gè)字節(jié),這個(gè)與上面的讀其實(shí)是類似的,只不過這個(gè)加了個(gè)for循環(huán),目的是讀出多個(gè)字節(jié) /
uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars)
/ 往緩沖寄存器里寫數(shù)據(jù),至多32個(gè)字節(jié) /
以上幾個(gè)程序的編程思路是比較經(jīng)典的編程思路,從發(fā)送字節(jié)開始,到芯片發(fā)送寄存器地址和命令。(源碼將在文末附上)
寫完這幾個(gè)函數(shù),也就完成了工作的一半了。然后我們還要編寫一個(gè)發(fā)射成功的判斷函數(shù)和一個(gè)接收成功的判斷函數(shù),可以通過這個(gè)函數(shù)的返回值來判斷是否接收或者發(fā)送成功。
在main函數(shù)的第一句,我們還可以編寫一個(gè)函數(shù),用來檢測24L01是否存在。當(dāng)然,不寫這個(gè)也可以。
前面部分的編程都只能算是準(zhǔn)備階段,從芯片的初始化開始才能算是真正的編程。
所以,接下來,我們得利用前面寫好的這些函數(shù),來對(duì)芯片進(jìn)行初始化。
初始化主要有以下幾個(gè)方面
(1)設(shè)置接收數(shù)據(jù)長度
(2)寫TX節(jié)點(diǎn)地址
(3)設(shè)置RX節(jié)點(diǎn)地址,主要為了使能ACK
(4)使能通道0的自動(dòng)應(yīng)答(多通道暫不考慮)
(5)使能通道0的接收地址
(6)設(shè)置自動(dòng)重發(fā)間隔時(shí)間和最大自動(dòng)重發(fā)次數(shù)
(7)設(shè)置RF通道為0 收發(fā)必須一致,0為2.4GHz
(8)設(shè)置TX發(fā)射參數(shù),0db增益,1Mbps,低噪聲增益開啟
(9)配置基本工作模式的參數(shù);PWR_UP,EN_CRC,16BIT_CRC,接收模式,開啟所有中斷
這些可以參考數(shù)據(jù)手冊的寄存器部分。
到這里,我們就可以在main函數(shù)里開始調(diào)用前面編寫的程序了。
進(jìn)入main函數(shù),首先是調(diào)用初始化程序,然后就可以讀取緩沖寄存器里的值或者是寫入數(shù)據(jù)。main函數(shù)部分根據(jù)用戶需要編寫。比如發(fā)射機(jī)可以用按鍵按下來發(fā)送數(shù)據(jù),接收機(jī)則通過查看IRQ管腳來判斷是否接收到數(shù)據(jù),接收到數(shù)據(jù)后再執(zhí)行你要的程序,比如控制小燈亮等等。
最后,我們來理一下編程思路
①首先,我們先明確了它是利用SPI的通信方式來對(duì)芯片控制的。不管是什么通信,無非就是讀和寫操作而已。讀和寫無非就是發(fā)送地址+命令。通常有一位是讀寫方向位的,這個(gè)查看手冊就可以知道。因此,肯定要先編寫一個(gè)“發(fā)送函數(shù)”,把字節(jié)發(fā)送出去,其實(shí)也就是單片機(jī)通過MOMI輸出高低電平而已。然后,前面也提到過,發(fā)送一個(gè)字節(jié)是沒有意義的,一次通信至少要包含兩個(gè)字節(jié),第一個(gè)字節(jié)包含了讀寫的方向位以及待操作寄存器的地址,第二個(gè)字節(jié)是具體的命令。我們將發(fā)送這兩個(gè)字節(jié)的語句,結(jié)合時(shí)序“打包”在一起,就是對(duì)芯片寄存器的讀寫函數(shù)了。寫可以理解成先發(fā)送地址(同時(shí)返回狀態(tài)值),再發(fā)送命令。讀可以理解成先發(fā)送地址,再執(zhí)行空語句(執(zhí)行空語句的目的是為了讀出寄存器值)。
②上一步是實(shí)現(xiàn)了對(duì)寄存器讀寫一個(gè)字節(jié),但是我們知道有的寄存器不止一個(gè)字節(jié),比如發(fā)送地址和接收地址都有5個(gè)字節(jié),發(fā)射接收緩沖器有32個(gè)字節(jié)等。因此我們可以編寫一個(gè)函數(shù),連續(xù)讀出或者寫入多個(gè)字節(jié),實(shí)現(xiàn)也很簡單,就是定義一個(gè)數(shù)組,讀的話就把數(shù)據(jù)讀出放入到這個(gè)數(shù)組中,寫的話就是把你數(shù)組里的內(nèi)容寫進(jìn)去。
③以上兩步是如何實(shí)現(xiàn)讀和寫。這還不夠,我們還得搞清楚具體讀寫什么內(nèi)容。這就得回到它的各個(gè)寄存器上去了。我們要根據(jù)手冊的說明,看各個(gè)寄存器有什么用,這在前面已經(jīng)講過了。主要是在初始化程序中比較重要。
④光有讀和寫不夠,我們還得知道每一次通信是否成功。因此,還得編寫兩個(gè)函數(shù)。比如接收,我們要先讀出狀態(tài)寄存器STATUS的值,來判斷是否接收成功,接收成功是會(huì)產(chǎn)生接收中斷的,我們看相應(yīng)的位就能知道有沒有接收成功了。如果接收成功,我們把數(shù)據(jù)轉(zhuǎn)移到我們自己定義的一個(gè)數(shù)組中,方便使用。如果是發(fā)送,我們只要把要發(fā)送的數(shù)據(jù)放在數(shù)組里,然后發(fā)送出去即可,然后還要讀取狀態(tài)寄存器的值,看是否發(fā)送成功,或者是否達(dá)到最大重發(fā)次數(shù),返回相應(yīng)的值。
⑤有了上面的這些基礎(chǔ),我們就可以在main函數(shù)里先進(jìn)行初始化,然后寫我們的發(fā)射程序和接收程序了。在發(fā)射函數(shù)里,每次先配置一下寄存器CONFIG,然后再利用我們前面的程序發(fā)射。接收比較簡單,只要看IRQ是否產(chǎn)生中斷即可。
以上就是整個(gè)編程思路。
-
單片機(jī)
+關(guān)注
關(guān)注
6077文章
45506瀏覽量
671018 -
通信協(xié)議
+關(guān)注
關(guān)注
28文章
1092瀏覽量
42210 -
寄存器
+關(guān)注
關(guān)注
31文章
5611瀏覽量
130065 -
發(fā)生器
+關(guān)注
關(guān)注
4文章
1430瀏覽量
64610 -
nRF24L01
+關(guān)注
關(guān)注
17文章
331瀏覽量
75138
發(fā)布評(píng)論請(qǐng)先 登錄
無線模塊nrf24l01中文資料_引腳圖及引腳定義_電路原理及實(shí)例
nrf24l01無線模塊傳輸距離分析
nRF24L01無線模塊使用教程之經(jīng)典使用程序詳細(xì)資料合集免費(fèi)下載
微雪電子NRF24L01 RF Board 2.4G無線模塊簡介
nrf24l01是什么模塊_nrf24l01工作原理
nRF24L01無線通信模塊使用簡介
使用NRF24L01模塊無線控制的自動(dòng)窗簾
基于NRF24L01和Arduino Nano的無線工業(yè)溫度監(jiān)控
基于nRF24L01的通用無線通信模塊設(shè)計(jì)案例
詳解nRF24L01無線收發(fā)模塊設(shè)計(jì)
評(píng)論