Arduinoで指数表示する


Arduinoを使って[真空度計](https://www.ajvs.com/new/product_info.php?products_id=809)を作りたいな。と思うとき、ありますよね。
一般的な真空度の単位である[Torr](https://ja.wikipedia.org/wiki/%E3%83%88%E3%83%AB)は、指数表示の**オーダー**が重要な場面が多いです。でも、Arduinoのフォーマット指定子では、進数表示はサポートされていますが、指数表示がサポートされて[いません](http://www.musashinodenpa.com/arduino/ref/index.php?f=1&pos=931)。なので、指数表示する関数がどこかにあるかなと思い検索しましたが、あまりヒットしなかったので、記事にします。
## 真空度計
今回作った真空度計の仕組みはシンプルです。[PKR251](https://www.idealvac.com/files/brochures/Pfeiffer_PKR_251_Pirani_ColdCathode.pdf)という、真空装置に取り付けることで、真空度を電圧で返してくれる装置があります。これから返ってきたアナログ電圧を、ArduinoでAD変換して、電圧→真空度関数に代入、LCDに表示するだけです。お手軽ですね！

![2019-05-10_16.30.20.png](https://cdn.discordapp.com/attachments/575215439257403392/576310151645233162/2019-05-10_16.30.20.png)

## Arduino Due
12bitでAD変換したいな、と思ったので、[Arduino Due](https://www.switch-science.com/catalog/1096/)を用いました。Arduino Dueの記事もあまり見なかったので、いいかなと思います。注意点は

> 注意!他の主なArduinoボードと違って、Arduino Dueは3.3 V版です。
各I/Oピンに入力できる最大電圧は3.3 Vです。I/Oピンに5 Vを入力するとボードにダメージを与える可能性があります。
>>[Arduino Due - スイッチサイエンス](https://www.switch-science.com/catalog/1096/)


です。先程のPKR251は**8.5V**まで電圧を返せるので、1/3に分圧をしてから、Dueに入れる必要があります。その結果、分解能は下がりますが、Arduino Unoを用いて作った場合より、2.67倍の分解能があります。(Arduino Unoも1/2に分圧はするため。)

## LCD
LCDの表示はLiquid Crystal関数で表示できます。Arduinoはお手軽でいいですね。

## 指数表示を表示する部分を含んだコード


```c
#include <LiquidCrystal.h>
LiquidCrystal Lcd1(12, 11, 7, 6, 5, 4);//正面右側、スイッチ側
LiquidCrystal Lcd2(14, 15, 18, 19, 20, 21);//正面左側、USB側
​
// Pinの型がわからないので、それを関数に含められないが、
// Digital電圧を受け取ってTorに変える関数
float VoltageToTor(float v){
  float calib=0.2;//calibの値は非線形っぽいのでいずれ関数化する必要あり
  /*
  -2Torrのあたりでは0.19くらいがちょうどいいが、-5~-6Torの時はこれでは引きすぎているようだ
  実際に電圧を電圧計で測ったときは、理想電圧より0.5Vほど大きな値になっていたので、引いている
  使っているケーブルのインピーダンスの問題もあるかもしれないので要測定
  */
  float p = pow(10, 1.667 * (v-calib) * 3 - 11.46);
  return p;
}
// 指数表示するために元の値をポインタで参照しながら、割った回数かかけた回数で指数表示
int floatToExpo(float *p){
  int cnt = 0;
  if(*p > 10){
    while(1){
      if(*p < 10){
        break;
      }
      *p /= 10;
      cnt++;
    }
  } else if(*p < 1) {
    // p1が1よりより小さい時、10かけて1.3e-1などの表示にする
    while(1){
      if(*p > 1){
        break;
      }
      *p *= 10;
      cnt--;
    }
  }
  return cnt;
}
​
void setup() {
  // シリアル接続を開始する
  Lcd1.begin(2, 12);
  Lcd2.begin(14, 21);
}
​
void loop() {
  // A1-4からの入力を標準の分解能で読み取り（12ビット）
  analogReadResolution(12);
  float v1, v2, v3, v4;//A1~4で入力された電圧値
  float p1, p2, p3, p4;//それより求まる真空度
  v1 = analogRead(A1) * 3.3 / 4096;
  v2 = analogRead(A2) * 3.3 / 4096;
  v3 = analogRead(A3) * 3.3 / 4096;
  v4 = analogRead(A4) * 3.3 / 4096;
  p1 = VoltageToTor(v1);
  p2 = VoltageToTor(v2);
  p3 = VoltageToTor(v3);
  p4 = VoltageToTor(v4);
​
  // ch1の表示
  // LCDに圧力を指数表示したい
  int cnt1 = floatToExpo(&p1);
  Lcd2.print("ch1 : ");
  Lcd2.print(p1, 2);
  Lcd2.print("e");
  if(cnt1>0){
    Lcd2.print("+");
  }
  Lcd2.print(cnt1, DEC);
  Lcd2.setCursor(0, 1);// 多分改行
  //ch2の表示
  int cnt2 = floatToExpo(&p2);
  Lcd2.print("ch2 : ");
  Lcd2.print(p2, 2);
  Lcd2.print("e");
  if(cnt2>0){
    Lcd2.print("+");
  }
  Lcd2.print(cnt2, DEC);
  //ch3の表示
  int cnt3 = floatToExpo(&p3);
  Lcd1.print("ch3 : ");
  Lcd1.print(p3, 2);
  Lcd1.print("e");
  if(cnt3>0){
    Lcd1.print("+");
  }
  Lcd1.print(cnt3, DEC);
  Lcd1.setCursor(0, 1);// 多分改行
  //ch4の表示
  int cnt4 = floatToExpo(&p4);
  Lcd1.print("ch4 : ");
  Lcd1.print(p4, 2);
  Lcd1.print("e");
  if(cnt4>0){
    Lcd1.print("+");
  }
  Lcd1.print(cnt4, DEC);
​
  // シリアルモニタを過度に使用しないようにするための少しのディレイ
  delay(500);
  Lcd1.clear();
  Lcd2.clear();
}
```