超精密温度計の製作⑤7セグLEDに表示

 ここまでの実験で、小数点第4位まで表示しました。室温ならば、25.1234のような桁数です。これを7セグメントLEDで表示するには、6桁分必要です。しかし、市販品には4桁か8桁がほとんどです。秋月電子通商の74HC595を使った7セグメント表示器は、1桁ずつ並べて、任意の桁が構成できます。

 ESP32は3.3Vで動作するので、青色もありますが、順方向電圧の低い赤色と緑色のLEDが実装されて製品を入手しました。使ってみると、緑色でも明るすぎるほどでした。

接続

 SPIのタイミングで74HC595は利用できます。LATCHはCEもしくはSS(5番)と同じタイミングです。SCK(18番)はクロックで、データを送るSDIはMOSI(23番)につなぎます。

 ESP32もMOSIから最初のLEDのSDIにデータを入れ、SDOからそのままデータを次のLEDのSDIへ送ります。これを6個分繰り返します。
 LATCH、SCK、GND、3.3Vはそれぞれ全部共通につなぎます。
 

 こちらの資料が詳しいです。


単独でテストするスケッチ

 表示できるかをテストします。

#include <SPI.h>

const byte sck   = 18; // CLK
const byte latch = 5;  // CE
const byte sdi   = 23; // MOSI
const byte digits[] = {
  0b11111100, // 0
  0b01100000, // 1
  0b11011010, // 2
  0b11110010, // 3
  0b01100110, // 4
  0b10110110, // 5
  0b10111110, // 6
  0b11100000, // 7
  0b11111110, // 8
  0b11110110, // 9
};
const byte  dot   = 0b00000001;
const byte  blank = 0b00000000;
const byte  minus = 0b00000010;  // -

void setup() {
  pinMode(latch, OUTPUT);
  digitalWrite(latch, 1);
  pinMode(sck, OUTPUT);
  pinMode(sdi, OUTPUT);
  SPI.begin();
  SPI.setBitOrder(LSBFIRST);
  SPI.setDataMode(0);
  Serial.begin(9600);
  Serial.println("Starting");
}

void loop() {
  float Temp=0.1237;
  // Serial.println(Temp,4);
  String sTemp = String(round(Temp*10000) / 10000, DEC);
  // Serial.println(sTemp);
  int seisuu = sTemp.indexOf(".");
  // Serial.println(seisuu);

  digitalWrite(latch, 0);
  if (Temp > 0.0) {
    if (seisuu == 2) {  // 23.4567
      SPI.transfer(digits[String(sTemp.charAt(0)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(1)).toInt()] ^ dot);
      SPI.transfer(digits[String(sTemp.charAt(3)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(4)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(5)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(6)).toInt()]);
    }
    if (seisuu == 1) {     // 1.2345
      SPI.transfer(blank); // blank
      SPI.transfer(digits[String(sTemp.charAt(0)).toInt()] ^ dot);
      SPI.transfer(digits[String(sTemp.charAt(2)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(3)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(4)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(5)).toInt()]);
    }
  }else{  // minus
    if (seisuu == 3) {     // -12.3456
      SPI.transfer(minus); // -
      SPI.transfer(digits[String(sTemp.charAt(1)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(2)).toInt()] ^ dot);
      SPI.transfer(digits[String(sTemp.charAt(4)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(5)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(6)).toInt()]);
    }
    if (seisuu == 2) {     // -1.2222
      SPI.transfer(blank); // blank
      SPI.transfer(minus); // -
      SPI.transfer(digits[String(sTemp.charAt(1)).toInt()] ^ dot);
      SPI.transfer(digits[String(sTemp.charAt(3)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(4)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(5)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(6)).toInt()]);   
    }
  }
  digitalWrite(latch, 1);
  delay(5000);
}


 読み取った温度データTempを、零下かどうかで判断し、さらに整数部分が2桁か1桁かで表示を別個に用意しました。

 USB電流計で測ると、定常状態で10mAぐらい、適当な数字を表示したとき70~80mAぐらい、全部点灯したとき100~120mAでした。

全体のスケッチ

 前回まで、TMP117bとBLETMP117のタブがありました。これに7segという名称でタブを追加します。三つで一つのスケッチになります。includeや変数の宣言はどこにあっても共通になります。関数はどこからでも呼べます。setup()とloop()は1か所だけです。

TMP117bのスケッチ

 前回から変更名はないです。

#include <Wire.h>
#define TMP117address 0x48
#define TemperatureRegiste 0x00
#define ConfigurationRegister 0x01

float read_tempdata() {
    Wire.beginTransmission(TMP117address); 
        Wire.write((byte)TemperatureRegiste);
    Wire.endTransmission();
    Wire.requestFrom(TMP117address, 2);
    //wait for response
    while(Wire.available() == 0);
    int T = Wire.read();
    T = T << 8 | Wire.read() ; 
    return ( -(T & 0b1000000000000000) | (T & 0b0111111111111111) ) * 7.8125 /1000.0;
}

7segのスケッチ

 最初の表示テスト用スケッチから、setup()を取り去りました。この中身はBLETMP117のsetup()に移します。また、loop()を関数disp7segLED(float temp)に名称を変更しました。 

#include <SPI.h>

const byte sck   = 18;  st byte latch = 5;  // CE
const byte sdi   = 23; // MOSI
const byte digits[] = {
  0b11111100, // 0
  0b01100000, // 1
  0b11011010, // 2
  0b11110010, // 3
  0b01100110, // 4
  0b10110110, // 5
  0b10111110, // 6
  0b11100000, // 7
  0b11111110, // 8
  0b11110110, // 9
};
const byte  dot   = 0b00000001;
const byte  blank = 0b00000000;
const byte  minus = 0b00000010;  // -
float temp;

void disp7segLED(float temp) {
  float Temp=temp;
  String sTemp = String(round(Temp*10000) / 10000, DEC);
  int seisuu = sTemp.indexOf(".");

  digitalWrite(latch, 0);
  if (Temp > 0.0) {
    if (seisuu == 2) {  // 23.4567
      SPI.transfer(digits[String(sTemp.charAt(0)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(1)).toInt()] ^ dot);
      SPI.transfer(digits[String(sTemp.charAt(3)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(4)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(5)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(6)).toInt()]);
    }
    if (seisuu == 1) {     // 1.2345
      SPI.transfer(blank); // blank
      SPI.transfer(digits[String(sTemp.charAt(0)).toInt()] ^ dot);
      SPI.transfer(digits[String(sTemp.charAt(2)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(3)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(4)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(5)).toInt()]);
    }
  }else{  // minus
    if (seisuu == 3) {     // -12.3456
      SPI.transfer(minus); // -
      SPI.transfer(digits[String(sTemp.charAt(1)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(2)).toInt()] ^ dot);
      SPI.transfer(digits[String(sTemp.charAt(4)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(5)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(6)).toInt()]);
    }
    if (seisuu == 2) {     // -1.2222
      SPI.transfer(blank); // blank
      SPI.transfer(minus); // -
      SPI.transfer(digits[String(sTemp.charAt(1)).toInt()] ^ dot);
      SPI.transfer(digits[String(sTemp.charAt(3)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(4)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(5)).toInt()]);
      SPI.transfer(digits[String(sTemp.charAt(6)).toInt()]);   
    }
  }
  digitalWrite(latch, 1);
}

BLETMP117のスケッチ

 setup()が少し膨らみました。loop()から上記のdisp7segLED(float temp)関数を呼びます。

  Wire.write((byte)0x02); // high とWire.write(0x20); // lowは、測定する温度の傾向によって、更新頻度や平均化する測定数を変更してください。連載の1回目に大まかな説明があります。

/*
    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp
    Ported to Arduino ESP32 by Evandro Copercini
    updates by chegewara
*/

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h> // See the following for generating UUIDs: // https://www.uuidgenerator.net/ #define SERVICE_UUID "1c3b07d0-7106-4114-add9-43bd176d104e" #define CHARACTERISTIC_UUID "e819baa6-6d98-4090-937b-88dd2ca0a7da" BLECharacteristic *pCharacteristic; void setup() { Wire.begin(); Wire.setClock(400000); Wire.beginTransmission(TMP117address); Wire.write((byte)ConfigurationRegister); Wire.write((byte)0x02); // high Wire.write(0x20); // low Wire.endTransmission(); Serial.begin(9600); Serial.println("Starting BLE work!"); pinMode(latch, OUTPUT); digitalWrite(latch, 1); pinMode(sck, OUTPUT); pinMode(sdi, OUTPUT); SPI.begin(); SPI.setBitOrder(LSBFIRST); SPI.setDataMode(0); Serial.println("7segLED ready"); BLEDevice::init("ESP32-TMP117 peripheral"); BLEServer *pServer = BLEDevice::createServer(); BLEService *pService = pServer->createService(SERVICE_UUID); pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ); float temp = read_tempdata(); Serial.println("temp sensor ready"); pCharacteristic->setValue((uint8_t*)&temp,1); pService->start(); // BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); pAdvertising->addServiceUUID(SERVICE_UUID); pAdvertising->setScanResponse(true); pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue pAdvertising->setMinPreferred(0x12); BLEDevice::startAdvertising(); } void loop() { temp = read_tempdata(); Serial.println(temp,4); pCharacteristic->setValue(temp); pCharacteristic->notify(); disp7segLED(temp); delay(2000); }

 実行例です。

前へ

超精密温度計の製作④BLEペリフェラルに

次へ

IEEE754 単精度浮動小数点数の形式:binary32 の変換