花 1 小時,開源設計 LoRa 檢測電池容量

RimeLink發表於2020-02-05

提示1:銳米所有 LoRa 產品嚴格遵循國標標準的 LoRaWAN 協議
提示2:您可以免費複製,修改和商用本專案,請註明銳米原創
提示3:如果您有其他 LoRa 需求或建議,歡迎聯絡銳米 support@rimelink.com

電池容量

LoRa 檢測電池容量

測量電池電壓,計算電池容量,基於 LoRa 傳送到伺服器,App 可實時演示。
LoRa LoRaWAN Arduino 物聯網 開源設計

元件和材料

LoRa 擴充套件板LoRa 擴充套件板 x 1 採購連結


Arduino Pro MiniArduino Pro Mini x 1 採購連結


電池盒電池盒 x 1 採購連結


南孚 7 號電池7 號電池 x 2 採購連結


天線天線 x 1 採購連結


杜邦線杜邦線 x 6 採購連結


下載燒錄器下載燒錄器 採購連結


數字萬用表數字萬用表 採購連結

軟體和網路

LoRa閘道器 LoRa閘道器 採購連結


LoRaServerLoRaServer 下載連結


LoRaAppLoRaApp 下載連結


Arduino IDEArduino IDE 下載連結

專案介紹

超過 80% 的 LoRa 終端基於電池供電,儘管我們最大化降低功耗,然而電池終將有耗盡的那一天。計算電池容量,對於 LoRa 終端的維保意義重大。

相比傳統的檢測技術,LoRa 檢測電池容量的優點為:

  • 零額外成本,基於 MCU 自身的 ADC 計算
  • 無接線工作,直接測量電池電壓
  • 簡單直觀,App 實時檢視電池容量
  • 精度高,誤差小於 1%

本專案開源設計 LoRa檢測電池容量的核心—軟體和硬體,使用者可以直接使用在自己的 LoRa 終端產品中。
同時,簡介了 LoRa 網路元件,輕鬆構建一個商用的物聯網。

技術細節

元器件介紹

LoRa 擴充套件板
這是專為 Arduino 而設計的 LoRa 擴充套件板,既可以安裝在 Arduino UNO 上,也能使用杜邦線連線到 Arduino Pro Mini。

它能達到空曠 10km 的通訊距離,休眠電流僅 1.3uA。精心設計的軟體庫,使其開發極為容易:

  • 傳送資料
LoRa.write("123", 3);
  • 接收資料
if (LoRa.availabe()) { 
    len = LoRa.read(buf, MAX_LEN); 
}

Arduino Pro Mini

Arduino Pro Mini 是最小的開發板,它功耗極低(休眠 0.1uA),便宜簡單,接線方便。


天線
470MHz 膠棒天線,增益 3.5dB,特別適合中國 LoRa 頻段範圍(470~510MHz)。

硬體接線

如下圖所示,使用杜邦線連線 Arduino Pro Mini,LoRa 擴充套件板和電池盒。
ArduinoProMiniLoRaBattery

通訊邏輯

如下圖所示,LoRa 檢測電池電壓和容量,App 實時顯示。

為此,需要配置如下的網路元件:

執行效果

如下圖所示,LoRa 終端每分鐘檢測電池電壓和容量,通過 LoRa 傳送訊息,App 顯示電池電壓和容量。
執行效果

行業第一的超低功耗—休眠僅 1.4uA

如下圖所示(實物拍攝),ArduinoLoRa+ 的低功耗可達 1.4uA,這不僅是行業第一的超低功耗,而且達到了器件極限
低功耗可達 1.4uA
如下圖所示,2 節 5 號鹼性電池容量約 2890mAH,在典型的採集應用中(設每 10 分鐘採集)電池可工作近 6 年。
終端電池壽命計算器
在這裡插入圖片描述

Arduino 程式碼

給 Arduino Pro Mini 下載程式請參考 《ArduinoLoRa 休眠極限 1.4uA參考連結

編譯本工程需要新增 LoRa 驅動庫 下載連結

使用 Arduino IDE 開啟工程,點選"Sketch -> Include Library -> Add .ZIP Library…"

Arduino 的 zip 庫安裝路徑一般為:C:\Users\Administrator\Documents\Arduino\libraries

Arduino 的程式碼簡潔,容易理解,下載連結

  • DEBUG 設定為 0 禁止除錯功能;設定為 1 它將通過 8 和 9 兩個引腳列印除錯資訊(使用“USB轉串列埠”連線到 PC)
  • getVccVoltage() 通過 ADC 將 Vcc 與內部 1.1 參考電壓進行比較來計算Vcc 的電壓。
  • getBatteryCapacity() 將 Vcc 電壓轉換成電池容量
#include <lora.h>

lora LoRa;
const int ledPin = 13;  // choose the pin for the LED

#define DEBUG    0

#if DEBUG
#include <SoftwareSerial.h>
SoftwareSerial debugSerial(8, 9);  // 8=RX, 9=TX
#endif

/* results are Vcc * 100, So for example, 3V would be 30 */
int getVccVoltage() 
{
  /* Adjust this value to your board's specific internal BG voltage */
  static const long InternalReferenceVoltage = 1075;  // 1.075V measured on the AREF pin 

 /* REFS0: Selects AVcc external reference
  * MUX3 MUX2 MUX1: Selects 1.1V (VBG)
  */
  bitSet(ADMUX, REFS0);
  bitSet(ADMUX, MUX3);
  bitSet(ADMUX, MUX2);
  bitSet(ADMUX, MUX1);

 /* START and WAIT for ADC conversion to complete
  *  
  * ADC start conversion when set the ADSC to 1
  * ADSC will read as 1 as long as a conversion in progress
  * when the conversion is complete, the ADSC returns to 0
  * 
  * add dead time to avoid ENDLESS LOOP if the ADC failed
  * ADC conversion is 115us in normal, so set MAX is 200us
  */
  unsigned long duration = 0;
  unsigned long microseconds = micros();
  bitSet(ADCSRA, ADSC);  // start conversion
  while(bitRead(ADCSRA, ADSC) && (duration < 200))  
  {
    duration = micros() - microseconds;
  }
  int results = (((InternalReferenceVoltage * 1024) / ADC) + 5) / 10; 

  return results;
}

/* argument are Vcc * 100, So for example, 3V would be 300 */
int getBatteryCapacity(int VccVoltage)
{
  /* Adjust this value to your board's specific battery voltage */
  #define BATTERY_MAX_VOLTAGE    300  // 3.0V
  #define BATTERY_MIN_VOLTAGE    180  // 1.8V

  int capacity;

  capacity = (VccVoltage - BATTERY_MIN_VOLTAGE) * 100L / (BATTERY_MAX_VOLTAGE - BATTERY_MIN_VOLTAGE);
  capacity = constrain(capacity, 0, 100);  // constrained between 0 and 100

  return capacity;
}

void setup() 
{
  pinMode(ledPin, OUTPUT);  // declare LED as output
  Serial.begin(115200);  // for LoRa Node
#if DEBUG
  debugSerial.begin(115200); // start software serial port at 115200-8-N-1
#endif  
}

void loop()
{
  int voltage, capacity;
  int array[2];  // voltage, capacity

  voltage = getVccVoltage();
  capacity = getBatteryCapacity(voltage);

#if DEBUG
  debugSerial.print("Vcc: ");
  debugSerial.print(voltage);
  debugSerial.print("V, Battery Capacity: ");
  debugSerial.print(capacity);
  debugSerial.println("%");
#endif  

  array[0] = voltage;
  array[1] = capacity;
  LoRa.write(array, sizeof(array));

  digitalWrite(ledPin, HIGH);  // indicate that have send a LoRa message
  delay(100);
  digitalWrite(ledPin, LOW);

  delay(60000);  // 60 seconds
}

演算法原理

測量內部基準電壓

為了獲得更準確的結果,這需要測量 MCU 內部基準電壓。 為此,請執行以下程式碼:

// Find internal 1.1 reference voltage on AREF pin
void setup ()
{
  analogReference(INTERNAL);
  analogRead(A0);  // force voltage reference to be turned on
}
void loop () { }

然後使用電壓表測量處理器的 AREF 引腳上的電壓。 將該值乘以1000,並將其用作 Arduino 程式碼的 InternalReferenceVoltage 變數。
如下圖,測量得到1.075V,那麼設定 InternalReferenceVoltage 為 1075
測量 MCU 基準電壓
因為 MCU 的個體差異,它們的基準電壓有細微不同。如果要求非常精確測量 Vcc 電壓,這需要將參考電壓儲存在每個 MCU 的 EEPROM 中。這樣,程式可以參考該值以找到計算電壓時要使用的確切數字。

計算 Vcc 電壓

當 ADC 用於測量 Vcc 電壓時,模擬讀數代表的數值含義為:

模擬讀數 / 模擬總長 = 基準電壓 / Vcc 電壓

模擬總長為 1024(Arduino Pro Mini 的 ADC 是 10 位),基準電壓和模擬讀數是已知量,求 Vcc 電壓需要轉換公式為:

Vcc 電壓 = 基準電壓 * 模擬總長 / 模擬讀數

計算電池容量

下圖是實驗用的南孚電池放電曲線,電壓從 1.5V 到 0.9V,分別代表 95% 到 5% 的電量。為簡化計算,我們擬定電量和電壓為線性函式,即:電量(Capacity) 和電壓(Voltage)為

Capacity = (Voltage - 0.9V) / (1.5V - 0.9V) * 100%

考慮 MCU 計算浮點數代價大,我們使用定點數,將電壓放大 100 倍。同時,防止整數除法的精度丟失,先乘法,後除法,因此有:

Capacity = (Voltage - 90) * 100 / (150 - 90)
電池電壓曲線圖

實際應用中,需要根據電池電壓調整下面 2 個數值:BATTERY_MAX_VOLTAGE(最高電壓) 和BATTERY_MIN_VOLTAGE(最低電壓)。在本次實驗中,2 節 7 號電池的最高電壓為 3.0V,最低電壓為 1.8V

相關文章