超精密温度計の製作⑤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); }
実行例です。