【啟動AI Maker世代 】2024 MAI 開發者社群大會(5/16-17)
|

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

   
作者:Ryan Hu

繼第一篇「【Amiccom A8106 RF 無線調光 (2)】 RF 通訊實作(上)」介紹了sample code 的脈絡以及接腳的設定後,第二篇要接著討論發射端的使用以及設定~

發射端(transmitter)

發射端遙控器總共有三個按鍵,上下鍵各一,再外加一個可以記憶此時 PWM 狀態,做出關和亮(亮起來時的狀態是上次全關前的亮度)的功能,遙控器如下圖。

三鍵式遙控器

其中「+」按鈕預計短按控制單一顆燈的 on,長按做亮度遞增的效果,「-」按鈕即為「+」的反向。而最上方的按鈕的功能就如同前述的一樣,可以記錄上一次關燈時的狀態。

「有效」的「按下」

偵測 button 被按這件事我以前是有經驗的,不過還是停留在我知道因為空氣中有很多雜訊,可能導致 input pull-up 的 button state 變成 LOW,明明沒人按,但卻執行被按之後的行為,以前是用「秒數」去決定是否「成功」被按,比如說 state 在 LOW 時維持了 1 秒才算有效。

不過業界不是這樣操作的,直接利用部分程式碼解釋,如下:

#define Button1_SW1 P3_2 // P3_2 is one of the input button pin

unsigned int button1_time_cnt; //global variable

void Timer0ISR (void) interrupt 1 // trigger per 1 ms

{

TF0 = 0; // Clear Timer0 interrupt

TH0 = (65536-t0hrel)>>8; // Reload Timer0 high byte,low byte

TL0 = 65536-t0hrel;

button1_time_cnt <<= 1 ;

button1_time_cnt |= Button1_SW1;

//there are also lots of functions below

//just skip that part...

}

上方的 code 是 timer0 的 ISR,透過 t0hrel 的設定可以將其設為 1 millisec 進來一次,重點是下方的 button1_time_cnt 變數,unsigned int 在此是 2 個 bytes,每 1 millisec 讓這個變數向左平移一個 bit,並且和 Button1_SW1 做 OR 的邏輯運算,如果翻譯成白話就是:

根據 Button1_SW1(P3_2)的 state 為 input pull-up 為 HIGH,因此 button1_time_cnt 為 16 個 1,而因為 timer ISR 的設計,每 1 millisec 就會去檢查一次 Button1_SW1 的 state 並且將其值 assign 給 button1_time_cnt 的 LSB,下次進來 ISR 時又會向左平移,依序執行下去,也就是說,在 main 裡面可以利用 if statement 判斷,button1_time_cnt == 0x0F 時,表示 button1 真的被按了。

這是一個極具彈性的寫法,利用 ISR 有效且精準的掌控 button 被按多久才算是有效,在此為遇到 0x0F 波形時成立(利用示波器真的可以看到)。不過這個寫法是用在短按或是一次性按下的功能,比如說單純 on/off,也就是遙控器最上面那個 button 的功能。

至於長按的部分,目前的寫法是用一開始提到的方式,利用 flag 隨者每 1 millisec ISR 檢查(eg. 判斷 Button2_SW2 是否為 state LOW)而增加,如果 flag 的值比某個值大(自己設定怎樣才算有效的一次長按,在此我是設 1 sec,意即 flag 的值如果 >= 1000 表示長按一次成功)就成立。

RF 傳輸邏輯

當長按一次成功時,transmitter 就會執行發射一次 RF 的動作。首先,發射前總得要知道要挾帶的 data 是什麼,因此得先用個 array 將 data 放進去,以 datasheet 內提到 FIFO mode 的傳輸 packet format 的 playload 最大是 256 bytes,其他像是 preamable,ID code,CRC 在官方的定義的 protocol 都有說明,只不過我要實作的應用不需要用到這麼多功能,我只需要 8 個 bytes 就可以處理完 playload 以及 ID 的需求,以下用部分程式碼來解釋:

#include "globalvar.h" // button2_time_cnt is defined in the header file

#include "function.h"

#define P3_5 1 // if P3_5 is 1, it will be the transmitter

#define period 1000

unsigned char Packet_Tx; // if initialize, this array will be a "constant", which can't be modified in code.

void WriteFIFO(void);

void WriteFIFO(void)

{

unsigned char i;

for (i = 0; i < 8; i++)

RFLIB_WriteReg(TXFIFO_REG + i, Packet_Tx);

}

void main(void)

{

//hardware initialization

//timer0, rf, other settings are done here

if (P3_5)

{

while (1)

{

if (button2_time_cnt >= period)

{

//something here to store the state about the num of light are on

for (i = 0; i < 8; i++)

{

Packet_Tx = 0x11 * (i + 1); // this can be modify, like specify the first two bytes to be the info of ID...

// and third byte will be the state of light...

}

WriteFIFO(); // load data in specific register and wait to transmit

RFLIB_StrobeCmd(CMD_TX); //entry tx & transmit

Delay10us(1);

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

TimeoutFlag = 0;

RFLIB_StrobeCmd(CMD_RX); //entry rx

Delay10us(1);

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

if (TimeoutFlag)

{

RFLIB_StrobeCmd(CMD_STBY); //exit rx mode

continue;

}

RxPacket();

Delay10us(1);

}

}

}

else

{

//the part of receiver

}

}

從 TXFIFO 這個 register 開始往下數 8 bytes 就是我會先放我要傳的 data 的地方(從 0x900 ~ 0x93F 都是可以放 data 的位置,共 64 bytes,實際要如何操作到上述最大 playload 256 bytes 我並沒有研究),一旦 RFLIB_StrobeCmd(CMD_TX)執行,東西就會被打出去(RFLIB_StrobeCmd 這個 function 是原先 sample code 就有寫好,也是去設定某 SFR 讓 RF 動作),接著是我覺得最有趣的部分。

由於並不知道 RFLIB_StrobeCmd 這個 function 裡面到底怎麼寫,因此 while ((RFLIB_ReadReg(MODEC1_REG) & 0x80) == 0x80); 這行會顯得有些莫名其妙。從 datasheet 只知道 MODEC1 這個 register 如果值為 0x80 時為 sleep mode,那表面上看來在我設定完 RFLIB_StrobeCmd(CMD_TX)後,MODEC1 的值應該已經要是 0xC0 的 TX mode 了,這個 while 怎麼樣也不會成立。我後來給自己的解釋是時間差,即真的要將 MODEC1 的值設定成 0xC0 這件事是需要時間的,也就是 transmit 的時間,真的變成 0xC0 才算傳輸完成。

而在 A8106 的 RF protocol 中,transmitter 傳 data 出去後,會把自己設定為 RX mode,去接收是否有來自 receiver 的 ACK bit,如果 Timeout 到了還沒收到就重新在 transmit 一次。

以上是 RF transmit 介紹的精簡版,只挑出了幾個比較大的重點出來,事實上有很多小的眉角需要注意,而且我相信我做到的部分只是 A8016 的冰山一角,這顆埋控能做到的事情絕不如此,有礙於篇幅先停在這裡,下篇會繼續將接收端一併解釋清楚,分享出來,幫自己紀錄。

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

本文為會員限定文章

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

                               

已經是會員? 按此登入

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

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

會員福利
1

免費電子報

2

會員搶先看

3

主題訂閱

4

好文收藏

Hu Ryan

Author: Ryan Hu

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

Share This Post On
468 ad

Submit a Comment

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