用 Coolterm 取代 Arduino Serial Plotter

當我試 “MAX30102心率計模块” 時,我用嘅 “SparkFun_MAX3010x_Library” 裏面有個 example 用到 Arduino IDE2 新加嘅 Serial Plotter 功能,可以 plot 紅外線穿透手指嘅能力而測出心率,我覺得好精對好有用,因為一般用 web plot chart 例如 Highcharts 最快只限一秒一個数,用 canvas 嘅 Chart.js 會快啲可以去倒大約 10Hz 但小好多野 set,再快嘅話就要插 com port 快到 1ms 一個数都得。用法好簡單,如果只有一個数,用 Serial.println(value); 放喺 loop 就可以,如果多過一個数,最簡單係用 CSV format 用 comma 隔開幾個数就得。之後可以喺 UI parse 或者柬睇邊個数。

Arduino Serial Plotter

既然預插線用 com port 嘅話,我再上網預吓有無類似嘅 alternative,發現有人介紹 CoolTerm,咁就可以避免開 Arduino IDE2 咁麻煩,要 plot chart 時淨係開佢,一樣都識睇 CSV,可以 parse 或者柬睇邊個数,而且多左可以 zoom x 同 zoom,自訂 icon 方便黚,最重要係可以 save 低 capture 番黎嘅 CSV。

CoolTerm – View Chart

save 低嘅 CSV 可以放上 Google Sheet 或者自己寫 Highcharts 讀佢 plot 番靚個 chart,但要加番 timestamp 個 column 解決每行嘅次序先後上下掉乱嘅問題,而 javascript 識讀 1ms 嘅 timestamp,要用 Arduino 砌好個 CSV format,出黎每行係 1751378429774,26853,10328 咁図,會牽涉到點用 NTP time server 攞 internet 時間,最簡單係用 “Time Library“。

#include <TimeLib.h> // time for ntp
const uint8_t TIMEZONE = 8;
struct tm time_tm;
time_t time_ntp = 0;
uint64_t timestamp_ms();
String pad2digit(uint8_t number);
void fn_ntp_sync(uint8_t timeZone = TIMEZONE);

setup(){
  // ...... after wifi connected 
    fn_ntp_sync();
}
loop(){
    Serial.print(timestamp_ms());
    Serial.print(",");
    Serial.print(ina_power);  //plot chart data1
    Serial.print(",");
    Serial.println(ina_voltage);  //plot chart data2
}

//*******************************************************************************************
// functions
//*******************************************************************************************
void fn_ntp_sync(int timeZone) {
  configTime(0, 0, "pool.ntp.org", "asia.pool.ntp.org");
  uint32_t beginWait = millis();
  while ((millis() - beginWait < 1000) && (time_ntp < 16 * 60 * 60)) {
    delay(200);
    time_ntp = time(nullptr);
    if (time_ntp > 16 * 60 * 60) {
      time_ntp = time_ntp + 1 + (timeZone * 60 * 60);
      setTime(time_ntp);
      gmtime_r(&time_ntp, &time_tm);
      Serial.print("IP: ");
      Serial.println(WiFi.localIP());
      Serial.print("Time: ");
      Serial.println(pad2digit(hour()) + ":" + pad2digit(minute()) + ":" + pad2digit(second()));
    }
  }
}

uint64_t timestamp_ms() {
  return (uint64_t)now() * 1000ULL + (millis() % 1000);
}

String pad2digit(uint8_t number) {
  if (number < 10) {
    String s = String(number);
    return '0' + s;
  } else {
    String s = String(number);
    return s;
  }
}

Reference: