« パナソニック 充電式エボルタお手軽モデル BK-3LLB 1000mAh 1200サイクル目 | トップページ | コネクタやリレーが入ってこない »

2021年7月 8日 (木)

Arduinoの言語環境は「C++」。 vsprintf()で

Arduinoの言語環境は「C++」。「C」とはちょっと違う。
オブジェクトにクラス、メソッド、継承・・・
  ・・・きちんと理解できていません。
     例題を参考にしてごそごそと。

Win環境だと古~いBorland C++Builderが使い慣れている
んですが、Winという世界でのプログラムはマイコンを使い
こなす環境とは全く違います。

Arduinoでの「C++」らしい処理、こんなページを見つけました。
  ・日記/2020-06-18/Arduino で printf() を使いたい

クラス「Print」に対する実行関数を指定して、
「vsprintf()」で書式指定文字列を付加し、シリアル出力や
液晶表示を行うという手法です。
  ・・・なるほどです。

シリアル出力と先日のI2CインターフェースのACM0802液晶
使って動きを確かめてみました。 (スペースに全角使ってます)

// Wireと液晶制御のヘッダーファイル
#include <Wire.h>        // I2C
#include <j3LCD_ACM0802_I2C.h> // LCD制御ヘッダーファイル

// LCDという名を指定するとともにI2Cアドレスを指定
j3LCD_ACM0802_I2C LCD(0x3C);  // I2Cアドレスを設定

// クラス「Print」へのポインタ 2つ TxとDispという名で
Print *Tx  = &Serial;   // シリアル出力
Print *Disp = &LCD;    // 液晶表示

/*****  セットアップ     *****/
void setup(){
  Serial.begin(9600);  // シリアル通信
  Wire.begin();     // I2C開始
  LCD.begin(8, 2);    // 液晶開始 文字数と行数
}
/***** LOOP   *****/
void loop(){
long t, tn;
  Serial.println(F("Tx TEST")); // タイトル表示
  LCD.print(F("DispTest"));   // 「.print」を使ったいつもの書式で
  t = millis() / 100L;  // 0.1秒
  while(1){
   tn = millis() / 100L;
   if(t != tn){     // 変化?
    t = tn;
    Tx->println(t);    // 0.1秒ごとにシリアル出力
    LCD.setCursor(0, 1); // 液晶表示位置
    Disp->print(t);    // 「->」でオブジェクトに対するprint実行
   }
  }
}

Serial.println()LCD.print()と同じことが、「->」という記述で
実行できます。

これを使って、vsprintfです。

/***** Printクラスへの書式付シリアル出力   *****/
// *cp : &Serial &LCDなど実行する関数のアドレスを入れるポインタ
void cpPrintf_P(Print *cp, const char *s, ...)
{
va_list vp;
char bff[40];          // バッファを確保
  va_start(vp, s);
  vsnprintf_P(bff, sizeof(bff), s, vp); // PSTRで書式を指定
  cp->print(bff);       // cpへ出力
  va_end(vp);
}

実際使うのは「vsnprintf_P」。
 「n」付でバッファのオーバーランを避け、
 「_P」付で書式指定文字でのRAMエリア増大を防いで、
という処理です。
先ほどの出力している3行、こうなります。

  cpPrintf_P(&Serial, PSTR("%ld.%ldsec\r\n"), t/10, t%10);
  LCD.setCursor(0, 1);
  cpPrintf_P(&LCD, PSTR("%6ld.%ld"), t/10, t%10);

書式付指定できるので1秒桁と0.1秒桁の処理が簡単に済ませられます。

ただ、毎回「&Serial」「&LCD」を付けるのが面倒かとも。

2種類しか使わないのなら、それぞれへ出力する、
「TXprintf_P」と「LCDprintf_P」を別個に作っておくほうが
(ちょいプログラムのスペースが無駄にはなるけど)
良いかなぁとも思います。


※関連
2018年2月20日:「vsprintf()」で数値出力を
2021年7月7日:秋月のI2C液晶表示器 ACM0802C-NLW-BBW-IIC 文字表示ライブラリ


|

« パナソニック 充電式エボルタお手軽モデル BK-3LLB 1000mAh 1200サイクル目 | トップページ | コネクタやリレーが入ってこない »

Arduino」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




« パナソニック 充電式エボルタお手軽モデル BK-3LLB 1000mAh 1200サイクル目 | トップページ | コネクタやリレーが入ってこない »