奇奇怪怪的無線說話之術:對岸的LoRa傳輸模組(三)

硬體

前言

上次的Blog有提到:目前的韌體已經可以正常的收發,唯有不定時會出現發送與接收不一致的異常。判斷可能是Arduino內的接收方式與我們認知的有些不同。
正常收到的數據
收到的數據不完整,顯示ERROR
這段期間我嘗試了許多作法,比如更改接收的函式,嘗試將接收端的接收間隔延長…等等,但都無助於解決問題。
也因為這段時間要忙專題和大專院校的事情,很少時間專注於自己的研究,所以這篇Develop Blog(應該算吧?)才會那麼晚出來。

測試步驟

為了解決這一系列的問題,我自己列了一套測試步驟:

  1. Arduino + AS32 -> CP2102 + AS32 TX測試
  2. CP2102 + AS32 -> Arduino + AS32 RX測試
  3. Arduino + AS32 <> Arduino + AS32 TRX測試

CP2102

上面的一跟二是確認這兩顆模組的傳輸方式以及效果如同說明書所述,並且確認兩顆模組運作正常,排除硬體面的問題。
AS32模組與CP2102的接法如下:(採用模式0,將MD0與MD1接地,使其保持0)
CP2102 + AS32模組接法

測試步驟一

  • Arduino 連接 AS32 當作傳輸端,燒錄傳輸程式
  • CP2102 連接 AS32 當作接收端,開啟任一Serial Monitor檢視資料接收狀況

測試結果如下:
測試步驟一

測試步驟二

  • CP2102 連接 AS32 當作傳送端,開啟任一Serial Monitor並傳輸封包
  • Arduino 連接 AS32 當作接收端,燒錄接收程式,開啟另一Serial Monitor檢視資料接收狀況

測試結果如下:
測試步驟二

經過交叉的測試,在單一封包,不固定時間發送的情況下,兩顆模組並未有任何掉包的情況產生,所以可以排除硬體面的問題。

測試步驟三

  • 一 Arduino 連接 AS32 當作傳輸端,燒錄傳輸程式
  • 另一 Arduino 連接 AS32 當作接收端,燒錄接收程式,開啟另一Serial Monitor檢視資料接收狀況

測試結果如下:
測試步驟三
再連續且不中斷傳輸的情況下,反而發生了資料錯位的問題。(就卡在這裡阿阿阿阿阿qwq

解決方法

先放出程式碼(關鍵部份)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
currentMillis = millis();
if(currentMillis - preMillis >= interval_ms)
{
preMillis = currentMillis;

if((PINB & (1 << PB4)) == 0)
{
// read message
while(readCount < 5)
{
readBuffer[readCount] = Serial1.read();
readCount++;
}

Serial1.flush();

PORTB ^= (1 << PB5);

Serial.print("Received ");
Serial.print(++_count);
Serial.print(" Times.\tBuffer: ");

if(readBuffer[readCount - 2] == '\r' &&
readBuffer[readCount - 1] == '\n')
Serial.print(readBuffer);
else
Serial.println(readBuffer);

readCount = 0;
memset(readBuffer, 0, 10);

PORTB ^= (1 << PB5);
}
}

將其中第四到第六行的判斷改成如下:

1
2
3
4
5
6
7
8
preMillis = currentMillis;

// get current AUX state and set previous AUX state
preState = state;
state = (PINB & (1 << PB4)) >> 4;

// compare two states if they're from high to low
if(preState == 1 && state == 0)

運行結果:
運行結果

好欸,成功了!!!

原因

首先是判斷狀態的部份:(意即原本的第6行)

1
if((PINB & (1 << PB4)) == 0)

這行判斷式的意思為:如果PB4腳位輸入為低準位(LOW),則進入IF判斷式內運行。

註:PB4對應Arduino Mega的腳位是第10腳位,對應Arduino Uno的腳位則是第12腳位。

但這樣寫會有一個問題:這樣真的會是我們原先需要的結果嘛?

這個寫法可能在Arduino的世界沒太多人見過,這是使用AVR單晶片暫存器的寫法,相較於Arduino Core,除了執行速度有稍微提升以外,可以叫出Arduino Core反而無法實現的功能。(Ex:更多的中斷)

將上面的暫存器內的值變成8位元後來看一下:

1
2
3
4
5
        7 6 5 4 3 2 1 0
PINB 0 0 0 0 0 0 0 0
PB4 0 0 0 0 0 0 0 0
& ---------------------
0 0 0 0 0 0 0 0 -> 0

看起來什麽問題,但如果PB4是1呢?

1
2
3
4
5
        7 6 5 4 3 2 1 0
PINB 0 0 0 0 0 0 0 0
PB4 0 0 0 1 0 0 0 0
& ---------------------
0 0 0 1 0 0 0 0 -> 10

欸不是,怎變成10了?
很顯然的,我忘了把數字「往右移」回來,所以他不是真正要的狀態。
更改的方式只須在後面新增一段往右位移的程式碼即可:

1
if(((PINB & (1 << PB4)) >> 4) == 0)

關於位元移位的操作:可以去Google搜尋:bitwise Operator 位元運算子

但這樣還是無從解決問題。因為關鍵在於:AS32的AUX腳位的邏輯判斷,以及Arduino Core的Serial處理方式!!
先來看一下AS32的Datasheet:
AS32 Lora Module Datasheet 節錄

當接收到由發送端傳來的訊號時,AUX腳位會先從高準位(HIGH)變成低準位(HIGH),然後才會開始透過TX腳發送收到的訊號內容給MCU。
上面那樣的Code其實是沒什麽問題,但關鍵在於Serial.read()這一段程式碼。
它會先檢查一段時間,如果在RX腳位沒收到任何字元,會回傳數字-1給主程式。
而我上面的寫法並沒有考慮準位的變化,反而讓Arduino判斷到低準位就開始直接收訊息,因此出現了資料錯位的情況。
解決方式如同上面所述,加入上次準位的判斷,這樣子就可以解決問題了。

運行結果

就算到2000多次,還是一樣可以完美收到封包的內容了呢!

後記

既然問題解決了,那應該也可以規劃實驗傳輸距離的部份了,但在這之前,我還想先知道一個部份:訊號強度(RSSI)。
有了RSSI,就可以知道當下訊號狀況是好還是差。如果可以取得這個資料,那在傳輸距離的實驗上會有一大部份的幫助。
另外在這裡我也想感謝伴伴學的幾位學友,如果沒有你們幫忙,這個問題也不會解決,我可能會卡的很久,包含這一篇Blog。

開發照片

開發照片

參考資料

Comments

Unable to load Disqus, please make sure your network can access.