錢(qián)光明 康日 鄧朝豐
摘要:nRF52840是NORDIC公司近年推出的一個(gè)無(wú)線芯片,具有CORTEX-M4內(nèi)核,支持多種接口和無(wú)線協(xié)議。該文基于該芯片設(shè)計(jì)了一個(gè)2.4GHz教學(xué)演示實(shí)驗(yàn),幾個(gè)從節(jié)點(diǎn)首先與一個(gè)主節(jié)點(diǎn)同步,然后在各自的時(shí)槽內(nèi)向主節(jié)點(diǎn)發(fā)送數(shù)據(jù)包。文中給出了收發(fā)程序的詳細(xì)設(shè)計(jì),意在幫助學(xué)生盡快地熟悉這一芯片,盡快入門(mén)。
關(guān)鍵詞:時(shí)槽;任務(wù);事件;主節(jié)點(diǎn);從節(jié)點(diǎn)
中圖分類號(hào):TP3? ? ? ? ? ?文獻(xiàn)標(biāo)識(shí)碼:A
文章編號(hào):1009-3044(2021)04-0234-03
Abstract: nRF52840 is a wireless chip in recent years. With a CORTEX-M4 core, it supports many interfaces and several wireless protocols. In this paper, a 2.4GHz teaching demonstration experiment is designed with this chip. First, several slave nodes get synchronized with a master node, then send packets to the master in their own time slots. The detailed design of transmitting and receiving program is presented to help students get familiar with this chip and get started as quickly as possible.
Key words: time slot; task; event; master node; slave node
1引言
從nRF24L01到nRF52840,NORDIC推出了一系列無(wú)線收發(fā)芯片。在nRF52840中,包括CORTEX-M4內(nèi)核和無(wú)線收發(fā)模塊,支持多種接口,支持藍(lán)牙和IEEE 802.15.4等多種無(wú)線結(jié)構(gòu)[1]。但是,開(kāi)發(fā)者要使用和熟悉nRF52840,還是需要花費(fèi)時(shí)間的,尤其是官方提供的固件程序。該芯片與以往nRF24L01相比,無(wú)線收發(fā)的具體實(shí)現(xiàn)和有關(guān)的命名,都有了很大的不同[1-2]。本文使用淘寶網(wǎng)購(gòu)的nRF52840硬件模塊[3],每一個(gè)模塊充當(dāng)一個(gè)無(wú)線節(jié)點(diǎn),一個(gè)主節(jié)點(diǎn),幾個(gè)從節(jié)點(diǎn)。設(shè)計(jì)了一個(gè)傳統(tǒng)的2.4GHz收發(fā)包演示實(shí)驗(yàn)[4],即從節(jié)點(diǎn)在獲得與主節(jié)點(diǎn)同步后,在各自的時(shí)槽內(nèi),向主節(jié)點(diǎn)發(fā)送各自的數(shù)據(jù)包。該實(shí)驗(yàn)在芯片硬件和官方基本固件程序的基礎(chǔ)上進(jìn)行設(shè)計(jì),不使用其他軟件模塊和第三方程序,從而有利于熟悉芯片的工作原理,把握底層運(yùn)行指標(biāo)。
2 nRF52840的2.4GHz無(wú)線狀態(tài)轉(zhuǎn)換圖
nRF52840遵循圖1來(lái)進(jìn)行2.4GHz無(wú)線收發(fā)[1]。圖中的英文名詞可分為三類。
第一類是每一個(gè)方框中的名詞,代表狀態(tài),例如TX代表發(fā)送狀態(tài)。一共有九個(gè)狀態(tài):TXDISABLE(發(fā)送取消狀態(tài)),RXDISABLE(接收取消狀態(tài)),DISABLED(已取消狀態(tài)),TXRU(發(fā)送準(zhǔn)備狀態(tài)),RXRU(接收準(zhǔn)備狀態(tài)),TXIDLE(發(fā)送空閑狀態(tài)),RXIDLE(接收空閑狀態(tài)),TX(發(fā)送狀態(tài)),RX(接收狀態(tài))。
第二類是方框外帶斜杠的名詞,代表事件(EVENT)或稱事件標(biāo)志。一共有三類事件:/DISABLED(已取消事件),/READY(準(zhǔn)備好事件),/END(結(jié)束事件)。
第三類是方框外不帶斜杠的名詞,代表任務(wù)(TASK)或稱命令。一共有五類任務(wù):DISABLE(取消任務(wù)),TXEN(發(fā)送準(zhǔn)備任務(wù)),RXEN(接收準(zhǔn)備任務(wù)),START(啟動(dòng)任務(wù)),STOP(停止任務(wù))。注意這里的“任務(wù)”,實(shí)際上是一種命令,它與操作系統(tǒng)中的“任務(wù)”概念非常不同。
在本文下面的程序中,會(huì)有這些狀態(tài)、任務(wù)和事件的使用舉例。
3 同步數(shù)據(jù)包的發(fā)送和接收
為使得每個(gè)從節(jié)點(diǎn)不沖突,只在各自的時(shí)槽中發(fā)包,必須先同步。所有從節(jié)點(diǎn)復(fù)位后,首先處于接收狀態(tài)。然后復(fù)位主節(jié)點(diǎn),由主節(jié)點(diǎn)發(fā)出同步數(shù)據(jù)包beacon。
這里,先明確一下實(shí)驗(yàn)中的收發(fā)次序:主節(jié)點(diǎn)發(fā)beacon,所有從節(jié)點(diǎn)接收。beacon完畢后,進(jìn)入時(shí)槽1,從節(jié)點(diǎn)1發(fā)數(shù)據(jù)包1,主節(jié)點(diǎn)收;時(shí)槽1完畢后,進(jìn)入時(shí)槽2,從節(jié)點(diǎn)2發(fā)數(shù)據(jù)包2,主節(jié)點(diǎn)收;后面的時(shí)槽以此類推。實(shí)驗(yàn)中,每個(gè)時(shí)槽寬度設(shè)為1600μs。
圖2是主節(jié)點(diǎn)發(fā)beacon的程序段。圖中,為了使printf 語(yǔ)句能正常使用,并通過(guò)串口調(diào)試助手在PC機(jī)上輸出有關(guān)信息,那么,在初始化階段需要設(shè)置好串口,我們使用官方提供的函數(shù)APP_UART_FIFO_INIT來(lái)完成。
接下來(lái),本程序段中的packet_build_send函數(shù)用于準(zhǔn)備包、發(fā)包、并等待包發(fā)送完畢。準(zhǔn)備在存儲(chǔ)器中的數(shù)據(jù)包(數(shù)組packet存放)需要由S0、LENGTH、S1和PAYLOAD這四個(gè)部分組成,其中S0域、S1域和LENGTH域都是可選的,這三個(gè)域加上數(shù)據(jù)域PAYLOAD,總長(zhǎng)不超過(guò)258個(gè)字節(jié)。LENGTH域一般用來(lái)表示數(shù)據(jù)域PAYLOAD的長(zhǎng)度(字節(jié)數(shù))。本實(shí)驗(yàn)中,不設(shè)S0域和S1域,LENGTH域?yàn)橐粋€(gè)字節(jié),設(shè)為255,而PAYLOAD則為255個(gè)字節(jié)。
我們將PAYLOAD的首字節(jié)設(shè)為nodenum,代表發(fā)包節(jié)點(diǎn)的編號(hào),主節(jié)點(diǎn)編號(hào)為0。從節(jié)點(diǎn)1的編號(hào)為1,從節(jié)點(diǎn)2的編號(hào)為2,以此類推。包數(shù)組packet中,packet[0]=LENGTH,packet[1]=nodenum。
packet_build_send函數(shù)中先準(zhǔn)備好一個(gè)包(充當(dāng)beacon),然后將包地址賦給NRF_RADIO->PACKETPTR這一指針,接下來(lái)按圖3的順序發(fā)包并等待發(fā)送結(jié)束。圖3中,先發(fā)出TXEN任務(wù),然后等待/READY事件。再發(fā)出START任務(wù),然后等待/END事件。一旦出現(xiàn)/END事件,就表明發(fā)送完畢。
再回到圖2。radio_disable函數(shù)中,會(huì)通過(guò)DISABLE任務(wù),使模塊回到DISABLED狀態(tài)。然后,prepare_for_receive函數(shù)為接收數(shù)據(jù)包做準(zhǔn)備,該函數(shù)主要是發(fā)出RXEN任務(wù),并等待/READY事件。接下來(lái),調(diào)用nrfx_timer_enable函數(shù),以啟動(dòng)定時(shí)器TIMER_LED0,進(jìn)入時(shí)槽1。該定時(shí)器的定時(shí)周期,就定為時(shí)槽的寬度。當(dāng)然,需要先初始化該定時(shí)器,主要利用nrfx_timer_us_to_ticks函數(shù)將時(shí)槽寬度1600μs轉(zhuǎn)換為ticks,另外,還需在TIMER_LED0所配備的事件處理函數(shù)timer_led_event_handler0中,將時(shí)槽控制變量slotend加1。
對(duì)于從節(jié)點(diǎn),其接收beacon的程序段則如圖4所示。prepare_for_receive函數(shù)為接收beacon做好了準(zhǔn)備,接著,發(fā)出START任務(wù),進(jìn)入RX接收狀態(tài),并等待/END事件標(biāo)志。/END一旦變?yōu)?,則說(shuō)明收到了一個(gè)包。如果CRCSTATUS為1(說(shuō)明CRC校驗(yàn)正確)且packet[1]=0(說(shuō)明該包來(lái)自主節(jié)點(diǎn)master),就認(rèn)為正確收到了beacon,便通過(guò)nrfx_timer_enable函數(shù),啟動(dòng)定時(shí)器TIMER_LED1,進(jìn)入時(shí)槽1。當(dāng)然,TIMER_LED1也需要初始化,定時(shí)周期也是1600μs。如果CRCSTATUS和packet[1]都出錯(cuò),說(shuō)明收到的不是正確的beacon,程序則回到loop位置,繼續(xù)接收。
4 從節(jié)點(diǎn)輪流發(fā)包
進(jìn)入時(shí)槽1后,從節(jié)點(diǎn)1發(fā)包,主節(jié)點(diǎn)接收。從節(jié)點(diǎn)發(fā)包的程序段如圖5所示。slotnum++的結(jié)果,在時(shí)槽1中為1,時(shí)槽2中為2,以此類推。顯然,slotnum的值代表時(shí)槽的編號(hào)。任何一個(gè)時(shí)槽中,從節(jié)點(diǎn)發(fā)包都用圖5。對(duì)于從節(jié)點(diǎn)1,其節(jié)點(diǎn)編號(hào)nodenum=1,從圖中的if語(yǔ)句可知:只有當(dāng)nodenum和slotnum相等,即節(jié)點(diǎn)編號(hào)和時(shí)槽編號(hào)相等時(shí),發(fā)包函數(shù)packet_build_send才會(huì)被調(diào)用。該發(fā)包函數(shù)準(zhǔn)備數(shù)據(jù)包時(shí),會(huì)將nodenum賦值給packet[1]。
現(xiàn)在看看時(shí)槽控制變量slotend的使用。每個(gè)時(shí)槽開(kāi)始時(shí),slotend=0。定時(shí)周期1600μs后,通過(guò)中斷,TIMER_LED1所配備的事件處理函數(shù)timer_led_event_handler1被調(diào)用,該函數(shù)中slotend將被置為1,表明一個(gè)時(shí)槽的時(shí)間結(jié)束。
從時(shí)槽1開(kāi)始,主節(jié)點(diǎn)接收數(shù)據(jù)包的程序段如圖6所示。主節(jié)點(diǎn)的定時(shí)器命名為T(mén)IMER_LED0,如前所述,其定時(shí)周期也是1600μs,時(shí)槽控制變量slotend的用法與圖5相同。圖6中,一開(kāi)始主節(jié)點(diǎn)發(fā)出START任務(wù),進(jìn)入RX接收狀態(tài),等待從節(jié)點(diǎn)發(fā)包。當(dāng)/END事件到來(lái)時(shí),表明收到了包,進(jìn)一步判斷該包是否正確(CRC檢查),是不是想要的包(nodenum和slotnum是否相等),并用printf語(yǔ)句輸出相關(guān)信息。無(wú)論是否收到數(shù)據(jù)包,也無(wú)論收到的包正確與否,都要等待時(shí)槽結(jié)束,一旦slotend=1,就進(jìn)入下一時(shí)槽。
收發(fā)雙方的時(shí)間一定要注意配合。圖中每一個(gè)語(yǔ)句的執(zhí)行都需要時(shí)間,尤其是printf語(yǔ)句,輸出信息越長(zhǎng),耗時(shí)就越長(zhǎng)。所以,如果要增加發(fā)送方或接收方printf的輸出信息,則需細(xì)心調(diào)試。要保證發(fā)送方發(fā)出數(shù)據(jù)時(shí),接收方一定要已經(jīng)準(zhǔn)備好。
5結(jié)束語(yǔ)
有些程序段在上面并未列出,其中主要有串口的初始化和定時(shí)器的有關(guān)函數(shù),實(shí)驗(yàn)者可依據(jù)官方和商家有關(guān)資料,先學(xué)會(huì)這兩方面的知識(shí)。上述實(shí)驗(yàn)演示效果良好,在此基礎(chǔ)上,可以進(jìn)一步改進(jìn)和加深。例如,beacon的包可以短一些,從節(jié)點(diǎn)可以采用競(jìng)爭(zhēng)方式發(fā)包,發(fā)包數(shù)據(jù)可以嘗試加密等。
參考文獻(xiàn):
[1] nRF52840 Product Specification v1.1[Z], 2019. https://infocenter.nordicsemi.com/index.jsp
[2] nRF24L01+Product Specification v1.0[Z], 2008. https://infocenter.nordicsemi.com/index.jsp
[3] nRF52840 Eval Kit 用戶手冊(cè) v1.0.2[Z], 2019. https://www.waveshare.net/w/upload/a/a8/NRF52840-Eval-Kit-user-manual-cn.pdf.
[4] 錢(qián)光明,易超.短距離無(wú)線網(wǎng)的一個(gè)教學(xué)實(shí)驗(yàn)設(shè)計(jì)[J].計(jì)算機(jī)時(shí)代,2020,27(6): 109-111.
【通聯(lián)編輯:代影】