|

【Amiccom A8106 RF 無線調光】 RF 通訊實作(下)

   
作者:Ryan Hu

繼上篇【Amiccom A8106 RF 無線調光】 RF 通訊實作(中) 的部分針對發射器(transmitter)大致分享完後,接著就是接受器(receiver)。如果單就 "接收" 這件事來說,實作並沒有太困難,因為和發射的部分非常類似,所以若搞懂了發射的機制,那接收不會是問題。

不過這次的專案在接收端不只是要做接收,還有一個非常重要的功能 - 學習模式。據我得到的 spec 指示,一個控燈的 receiver 要能 (也最多只能) 記住三隻發射器 (也就是 transmitter),透過 receiver 上的三個 buttons 操作特定的流程 (eg. 長按 button 1),進入學習模式;進入學習模式後,再依特定的流程記錄某一隻特定的發射器 (eg. 進入學習模式後,某發射器發射訊號,receiver 收到後若 button 2 有被 clicked 兩下,那就拉出 ID 資訊記在 flash 裡),最後再操作離開學習模式的流程。

學習模式的大方向如上所述,實際上要注意的事項還真不少,嚴格來說要完成 receiver 的開發相較於 transmitter 是難上許多的。另外,上篇介紹transmitter 時也有個大重點尚未介紹 - 睡眠模式 (sleep mode)。睡眠模式 (sleep mode) 之所以重要是因為 RF 發射是相當耗電的,比 normal mode 時的耗電還要高上好幾倍,如果不想一直換電池的話這是必須的功能,下方介紹時再一併說明。

以前輩當時根據客戶驗收需求給我的指示,開發的先後順序是:基本 RF 收發功能並且能控模擬的 LED 輸出 -> 睡眠模式 (sleep mode) -> 學習模式 (很可惜,由於當時案子似乎沒談清楚,以及介於我快要離職之際,學習模式並沒有碰到)

那就照順序從 receiver 的接收功能繼續下去吧!

接收端 (receiver)

如果大家對於上篇文章有印象,要切換到接收端的 code,首先 P3_5 要先設為 0 (或也可用硬體直接控制),而接收部分的程式碼如下:

unsigned char tmpbuf;

void light_condition_receiver(void);

void RxPacket(void);

void main(void)

{

//hardware initialization...

if(P3_5)

{

while(1)

{

// transmitter code...

}

}else

{

while(1)

{

light_condition_receiver();

}

}

}

void light_condition_receiver()

{

// the variable counts for error bit...

RFLIB_StrobeCmd(CMD_RX);

Delay10us(1);

while((RFLIB_ReadReg(MODEC1_REG) & 0x80)==0x80); //wait receive completed

RxPacket();

// do the light control here...

// status = tmpbuf...;

// state = tmpbuf...;

// if...else if...bunch of code...

WriteFIFO(); // write data to tx fifo

RFLIB_StrobeCmd(CMD_TX); // entry tx

Delay10us(1);

while((RFLIB_ReadReg(MODEC1_REG) & 0x80) == 0x80); //wait receive completed

}

void RxPacket()

{

unsigned char i,recv;

for(i=0; i<8; i++) // transmit only 8 bits in my case.

{

recv = RFLIB_ReadReg(RXFIFO_REG + i);

tmpbuf=recv;

//error checking (bit, byte)...

}

}

提個外話,相較於前篇把 transmit code 寫在 main,這裡的做法我個人比較喜歡,再寫一個 function main 看起來比較乾淨 (我習慣分檔案)

言歸正傳,由於 RF 的發射是廣播 (broadcast) 的方式傳送資料,也就是說當按下發射器並且觸發 RF 發射時,所有通電的 receiver 都會收到這個訊號 (這裡不論強弱),至於該不該收 (也就是該不該接收某發射器傳來的 data 並做相對應的動作) 是根據開發者用程式碼所定義的,就是所謂 ID 的功用。

還記得 transmitter 8 bytes data 透過 Packet_Tx 傳出去,裡頭包含了自定義的資料,即每個 byte 所代表的意義都可以自訂,裡頭就包含了 ID (eg. 7 byte 代表 ID) 以及一些其他重要的資訊。而 light_condition_receiver 這個 function 最主要就是在聽空氣中 RF 的訊號,確定收到後再執行 RxPacket 這個 function 去分析收到的 packet 的內容。

把兩個主要的 function 分別細看,先講 light_condition_receiver() 的部分,如同 transmitter code,這裡也是利用 sample code 寫好的 function - RFLIB_StrobeCmd 做處理,只要把 TX 改成 RX (接收端收資料)RX 改成 TX (接收端發出 ack),其實就大功告成,就不浪費篇幅了。

至於 RxPacket(),上圖的 code 不包含 error checking 因此相對簡單許多 (比如說錯幾個 bit 以上要做什麼相對應的處理),先利用全域的 array - tmpbuf,去存從 packet 讀出來的東西,再利用 tmpbuf 裡的資料回 light_condition_receiver 做下一步的執行 (即註解的 light control 區段)

大致上單純接收並解析 RF packet 的實作介紹至此,一樣我相信還有許多功能我沒玩到,不過若有問題或發現,歡迎各位同好朋友可以提出來一同討論,指教交流!

基本上專案進行到這裡,已經可以順利控燈了。不過如同文章開頭所說,若不想要一直更換發射器的電池,那編寫發射端的睡眠模式勢在必行 (接收端倒是沒差,因為控燈的裝置是可以持續插著電的)

睡眠模式 (Sleep mode)

睡眠模式很複雜,至少比我一開始想像的還要困難許多。在分享我開發睡眠模式的過程前,先講有睡眠模式和沒有睡眠模式耗電量的差別,這樣看下去可能會比較有感。根據 A8106 datasheet,在一般板子通電預設的狀態下,MCU 會在 normal modeRF 則會在 sleep mode,在此情形下的耗電量為 5.5 mA (我測的時候的確在 5. mA)

RF TX mode (MCU 仍在 normal mode) 時更是飆高至 17-24 mA 不等。照發射器所使用的電池,如果我沒記錯是 CR2032,容量是 225 mAh,姑且不論電池本身的特性,例如內阻損耗我直接忽略不計 (我甚至記得這種鈕扣電池最大放電電流應該是沒辦法到 17 mA 這麼高...),在不發射 RF 的情況 (RF in sleep mode)225 / 5.5 ~= 41 h (小時),意思是說不到兩天的時間什麼都不做就沒電了,未免太過荒謬...

為了解決這個棘手的問題,A8106 設計了三個 RF in sleep mode (此時 MCU stop mode) 的狀態,分別為 PM1PM2 PM3 (先不算 PM3 without sleep timer 的部分,此三種 mode 皆是有 sleep timer 的情形),就拿我使用的 PM2 做例子 (各個 mode 有些差距在此先不提),耗電量只有 3 uA,整整比原先少了 1700 多倍...,很明顯的高下立判。

而在實作方面,睡眠模式要顧的不外乎兩件事:1. 進入睡眠模式,2. 從睡眠模式醒來。而在我實作的應用中,醒來的唯一目的就是發射 RF,亦即沒要發射就睡,以此方式省電。

然而進入睡眠模式簡單,醒來做事反而難。A8106 有個很有趣的特色 - key interrupt,其三個 port P0, P1, P3 的任何一隻 GPIO 都可以作為外部中斷的媒介,此稱為 key input,可以透過 key interrupt (即外部中斷) 喚醒 A8106 (stop mode -> normal mode) 接著執行這個外部中斷想要執行的程式碼。

若套用到我的實作應用上,上述的 key input 即為使用者按了發射器上的任一按鍵,喚醒 A8106 並且 RF 發射那個按鍵所代表的功能訊息。又若將整個睡眠模式放進原先的程式碼,流程就會變成以下:

通電 -> 進入 RF sleep mode, MCU stop mode -> key input -> key interrupt (RF sleep mode, MCU normal mode) -> 發射 RF -> 進入 RF sleep mode, MCU stop mode

流程看起來簡明扼要,但每一步所要注意的事情可多了...,包括 key input 的設定 (WUN - wake up enable)RF mode MCU mode 設定的先後順序,有沒有足夠的時間給 mode 轉換等等都是問題。由於一開始我一直沒有搞清楚整個睡眠模式的流程,導致我到離職那天都尚未破關,現在也沒東西讓我繼續試,因此我最多只能分享到這,實在有點可惜,若後續的專案有這類的需求 (應該很常會有),屆時我會再分享我的程式碼,並深入解釋其中奧秘 (據說睡眠模式真的很麻煩,各家埋控場奇異的程度比一般的功能都還要高出許多)

安可爾系列也就到此告一的段落,接下來會是全新也是我正在進行的個人專案,下次見!

(本文同步發表於自造者萊恩;責任編輯:葉于甄)

本文為會員限定文章

立即加入會員! 全站文章無限看~

                               

已經是會員? 按此登入

只需不到短短一分鐘...

輸入您的信箱與ID註冊即可享有一切福利!

會員福利
1

免費電子報

2

會員搶先看

3

主題訂閱

4

好文收藏

Hu Ryan

Author: Ryan Hu

對於 IOT 軟硬整合相關有極大興趣,鍾愛無人機,目前獨自完成的專案像是瓦力號、GPS 自動語音導覽系統、NTP 網路自動校時時鐘,喜歡流浪。

Share This Post On

Submit a Comment

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *