第13回ではハンドル周りに取り付ける機器をLCDのみにし、乱雑だったハンドル周りをすっきりさせた、旅Arduino Ver3を作成します。
第12回はこちらからどうぞ
旅を楽しくするArduino端末Ver3の構成
今回作成する端末は以下の構成とします。
・arduino nano every(制御用マイコン)
・LCD1602(センサー値表示用LCD)
・LCD→I2C変換基板(第12回参照)
・USB2.0充電端子
・BME280(温度・湿度・気圧測定用)
・GPSモジュール:GYSFDMAXB(進路方角取得用)
・DC-DCコンバータ5V,0.5A:M78AR05&ポリスイッチ
・Adafruit INA219 Current Sensor
・ユニバーサル基盤B基板1枚
・抵抗内蔵LED(12V&5V)(通電確認用)
・スイッチ(画面切り替え用)
以上の構成で作成を行います。
制御部はシート下、表示部はハンドル周りとします。
また、第11回&12回で紹介したI2C制御のLCDを使うことで、表示部をLCDだけにして、ハンドル周りをシンプルにしています。
回路
設計図は大幅に変更が加わりました。
3.3Vで動作するものがなくなりましたので、12Vから5Vに降圧した電源をほとんどの電子機器に供給しています。
また、GPS以外の機器はすべてI2C通信で制御しているので、Arduinoに接続される線は非常に少なくなっています。
また、実物に関しては、制御部と表示部を分けた作りにしています。
バッテリーから近いシート下に、制御部をまとめ、そこから屋外配線用の4線ケーブルを用い、ハンドル部まで電源&信号を配線しています。
ちなみに4線の内訳は
① +5V
② GND
③ SCL
④ SDA
となっております。
コード
#include <LiquidCrystal_I2C.h>
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <Adafruit_INA219.h>
#include "SparkFunBME280.h"
#include "Wire.h"
#include "SPI.h"
static const int TXPin = 3, RXPin = 2;
int ModeButton = 4;
static float m_fltCurrentTemperature;
static float m_fltCurrenthumidity;
static float m_fltCurrentPressure;
static float m_fltCurrentVoltage;
static float m_fltCurrentAltitude;
static String m_strCurrentDirection;
TinyGPSPlus gps;
SoftwareSerial ss(TXPin, RXPin);
Adafruit_INA219 ina219;
BME280 Sensor;
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
// LCD Init
lcd.init();
lcd.backlight();
// INA219 Init
while (!Serial) {
delay(1);
}
uint32_t currentFrequency;
if (! ina219.begin()) {
//Serial.println("Failed to find INA219 chip");
while (1) { delay(10); }
}
// BME280 Init
Sensor.settings.commInterface = I2C_MODE;
Sensor.settings.I2CAddress = 0x76;
Sensor.settings.runMode = 3;
Sensor.settings.tStandby = 0;
Sensor.settings.filter = 0;
Sensor.settings.tempOverSample = 1;
Sensor.settings.pressOverSample = 1;
Sensor.settings.humidOverSample = 1;
delay(10);
Sensor.begin();
pinMode(ModeButton,OUTPUT);
Serial.begin(9600);
ss.begin(9600);
ss.println("Connect Success");
}
void loop() {
//Mode 1
if ( digitalRead( ModeButton ) == HIGH ){
//BME280
float fltTemperature;
float fltHumidity;
float fltPressure;
int intTemperatureB;
int intHumidityB;
int intPressureB;
// INA210
float fltVoltage;
int intVoltageB;
float fltShuntVoltage;
float fltBusVoltage;
// GPS
float fltCourse;
float fltAltitude;
String strDirection;
// GPS Control
for (int i=0; i <= 1000; i++){
while (ss.available() > 0){
if (gps.encode(ss.read())){
if (gps.location.isUpdated()){
Serial.println(gps.course.deg());
Serial.println(gps.altitude.meters());
if ( gps.course.deg() != 0 ){
fltCourse = gps.course.deg();
}
if ( gps.altitude.meters() != 0 ){
fltAltitude = gps.altitude.meters();
}
}
}
}
}
strDirection = ConvertDegrees( fltCourse );
//BME280 Contorl
fltTemperature = Sensor.readTempC() * 10;
intTemperatureB = fltTemperature;
fltTemperature = intTemperatureB;
fltTemperature = fltTemperature / 10;
fltHumidity = Sensor.readFloatHumidity();
intHumidityB = fltHumidity;
fltHumidity = intHumidityB;
fltPressure = Sensor.readFloatPressure() / 100;
intPressureB = fltPressure;
fltPressure = intPressureB;
fltShuntVoltage = ina219.getShuntVoltage_mV();
fltBusVoltage = ina219.getBusVoltage_V();
fltVoltage = (fltBusVoltage + (fltShuntVoltage / 1000))* 10;
intVoltageB = fltVoltage;
fltVoltage = intVoltageB;
fltVoltage = fltVoltage / 10;
if( m_fltCurrentTemperature != fltTemperature or m_fltCurrenthumidity != fltHumidity or m_fltCurrentPressure != fltPressure or m_fltCurrentVoltage != fltVoltage or m_fltCurrentAltitude != fltAltitude or m_strCurrentDirection != strDirection ){
lcd.init();
DisplayTmp( fltTemperature, fltHumidity, fltPressure, fltVoltage, strDirection, fltAltitude );
m_fltCurrentTemperature = fltTemperature;
m_fltCurrenthumidity = fltHumidity;
m_fltCurrentPressure = fltPressure;
m_fltCurrentVoltage = fltVoltage;
m_fltCurrentAltitude = fltAltitude;
m_strCurrentDirection = strDirection;
}
}
else if ( digitalRead( ModeButton ) == LOW ){
float fltCurrentkmph = 0;
float fltPowermW = 0;
// GPS Control
for (int i=0; i <= 100; i++){
while (ss.available() > 0){
if (gps.encode(ss.read())){
if (gps.location.isUpdated()){
if ( gps.speed.kmph() != 0 ){
fltCurrentkmph = gps.speed.kmph();
}
}
}
}
}
fltPowermW = ina219.getPower_mW();
String strCurrentkmph = String( fltCurrentkmph );
strCurrentkmph.concat( "[km/h]" );
String strPowermW = String( fltPowermW );
strPowermW.concat( "[mW]" );
lcd.init();
lcd.setCursor(0,0);
lcd.print(strCurrentkmph);
lcd.setCursor(0,1);
lcd.print(strPowermW);
}
delay(1000);
}
String ConvertDegrees( float intCourseDegrees ){
String strDirection;
if ((intCourseDegrees) <= 0) {
strDirection = "XXX";
}
else if ((intCourseDegrees) > 360) {
strDirection = "XXX";
}
else if ((intCourseDegrees) < 11.3) {
strDirection = "N";
}
else if ((intCourseDegrees) < 33.8) {
strDirection = "NNE";
}
else if ((intCourseDegrees) < 56.3) {
strDirection = "NE";
}
else if ((intCourseDegrees) < 78.8) {
strDirection = "ENE";
}
else if ((intCourseDegrees) < 101.3) {
strDirection = "E";
}
else if ((intCourseDegrees) < 123.8) {
strDirection = "ESE";
}
else if ((intCourseDegrees) < 146.3) {
strDirection = "SE";
}
else if ((intCourseDegrees) < 168.8) {
strDirection = "SSE";
}
else if ((intCourseDegrees) < 191.3) {
strDirection = "S";
}
else if ((intCourseDegrees) < 213.8) {
strDirection = "SSW";
}
else if ((intCourseDegrees) < 236.3) {
strDirection = "SW";
}
else if ((intCourseDegrees) < 258.8) {
strDirection = "WSW";
}
else if ((intCourseDegrees) < 281.3) {
strDirection = "W";
}
else if ((intCourseDegrees) < 303.8) {
strDirection = "WNW";
}
else if ((intCourseDegrees) < 326.3) {
strDirection = "NW";
}
else if ((intCourseDegrees) < 348.8) {
strDirection = "NNW";
}
else {
strDirection = "N";
}
return strDirection;
}
void DisplayTmp( float fltTemperature, float fltHumidity, float fltPressure, float fltVoltage, String strDirection, float fltAltitude )
{
String strTemperature = String( fltTemperature );
int inthumidity = fltHumidity;
String strhumidity = String( inthumidity );
int intPressure = fltPressure;
String strPressure = String( intPressure );
String strVoltage = String( fltVoltage );
int intAltitude = fltAltitude;
String strAltitude = String( intAltitude );
String strDisplay = "T";
strDisplay.concat( strTemperature );
strDisplay.concat( " H" );
strDisplay.concat( strhumidity );
strDisplay.concat( " P" );
strDisplay.concat( strPressure );
lcd.setCursor(0, 0);
lcd.print( strDisplay );
strDisplay = "V";
strDisplay.concat( strVoltage );
strDisplay.concat( " A" );
strDisplay.concat( strAltitude );
strDisplay.concat( " " );
strDisplay.concat( strDirection );
lcd.setCursor(0, 1);
lcd.print( strDisplay );
}
前回リファクタリングできなかったので、今回かなりコードを変更しています。
まず、LCDがI2Cになったので、制御回りを変更。
スイッチを入れたので、2画面表示にも対応しました。
また、今まで使用していなかった現在速度(km/h)と、当端末の消費電力(mW)が2画面目に出るようになっています。
(これら二つは日常的にみるものではないので、2画面目に)
結果
今回の実装で一番良かった点は、ハンドル周りに持ってくる表示部が上記の写真の部品だけになったことです。
それに伴い、以前まで使用していた手作りケースをやめ、100均で買ってきた適当なサイズのプラケースを使用しています。小型化できたので、今まではブレーキオイルタンク上に設置していたのを、ミラーねじにかませたプレートの上への設置に変わりました。
まとめ
自分が想像していた最終形が、Ver3で作成できたと思います。
なのでハードウェアの変更は当分行わない予定です。
ただ、今回説明を省いたところとして
1.USB充電(現在はアクセサリーソケット用の充電器を分解して取り付けている)
2.起動タイマーの実装
があります。
1に関しては、現在動作確認中で、後々記事にします。
2に関しては、コードだできている状態で、動作検証がまだです。(上記コードにも含めてません)
上の2点の記事ができたら、再度まとめの記事を作成し、旅Arduinoの連載を締めたいと思います。
旅を楽しくするArduino端末を作る。リンク集
その1-不満点を挙げよう-
その2-不満点をまとめよう-
その3-電圧測定器を作る-
その4-温湿度計を作る-
その5-気圧計を作る-
その6-方位・高度計をGPSで-
その7-12Vバッテリーから電力供給
その8-Ver1作成-
その9-電圧計の誤差とその代替案-
その10-Ver2へアップデート-
その11-LCDをI2Cで制御しよう-
その12-LCDをI2C化-
その13-Ver3へアップデート-
その14-USB充電の仕様に関して-
その15-Arduino言語を用いながらBluetoothで通信できるESP32-
その16-旅Arduino Ver4 スマホアプリ化-
この記事へのコメントはありません。