有機ELのディスプレイがよさそうなので、準天頂衛星”みちびき”に
対応したGPS受信機[AE-GYSFDMAXB]とで、有機ELの使い方学習を
兼ねて、遊んでみました。
取りあえず回路図を以下に
実用で使えそうです………。
・配線は簡単ですので….。同時モニター用のUARTとXBee は接続しなくて
良いです、これはArduinoをエディットしていないときにモニターする時や
他の目的でデーターを使用するときに使います。
・表示切替ボタンはArduinoの外部割り込みピンD2に接続する
割込み機能を使用する方がスイッチを押したときの反応が良いから
確実に切替できます。
・GPS受信機は”MiniGPS”というソフトで、ボーレート変更や不必要な
NMEAデーターを排除したり出来ます、ボーレートは無難に”9600″に設定
他はべつに変更する必要はないようです、
GPS受信機は +5Vを加えるだけでデーターを垂れ流しします、基板裏に
ボタン電池を取り付ければ衛星の補足が早いです、ボーレートを設定したら
GPSとArduinoを接続、TxD ⇒ D7 pin、RxD ⇒ D8 pinに接続、
注意点はGPSからのUART出力は 3.3Vロジックになっていますので
Arduinoは3.3V系を使う事です、この点は”Adafruit Metro Mini 328 – 5V 16MHz”を使う事で5V、3.3Vどちらへでも切り替えられるので良いんです。
・有機ELキャラクターディスプレイの設定
. OELDは”I2C”接続ですので、先にOLEDのピンで、スレーブアドレス
. の設定のために以下のように、半田付けします。
これでArduinoと接続します、あとはスケッチを書くだけ。
・プログラム(スケッチ)作成、素人の作成ですので、どっかからの切り貼り
が多いですが、ご容赦ください。
幸いなことに有機ELディスプレイの部分は、購入した時の説明書にスケッチ
が書かれていました、大助かりです それを一寸改変しました
◆ 大まかな流れは
1・SoftwareSerial.h と I2Cのライブラリ Wire.h をインクルードします
2・GPS用のバッファを取りあえず最大の 255バイト割り当てるように宣言
3・ソフトウエアシリアルポートに”sGps”と言う名前を付けます
1 2 3 4 5 6 |
#include <SoftwareSerial.h> #include<Wire.h> //A4=SDA A5=SCL OLED用 #define BUFFER_SIZE 256 //GPS用バッファ #define OLED_ADRS 0x3C //有機ELのアドレス SA0=L(SA0=Hの場合は0x3D) SoftwareSerial sGps(7,8);//(RX,TX) GPS用UART |
4・各種変数の型を宣言しておきます
5・OLED I2C 初期設定用に、変数名と値(16進数)を宣言する
1 2 3 4 5 6 7 8 9 10 11 |
String Time, h, m, s; //GPS用 int H, M, S; //日本時間修正用 bool isValid; //割り込みピン2-LOW による表示切替保持変数 int Selcount = 0; //OLED I2C 初期設定用の値 int DisplayON = 0x0c, // (0x0c,0x0dならチラつき少ない) ClearDisplay = 0x01, ReturnHome = 0x02; |
6・OLEDに表示用のキャラクタ変数配列を宣言(16文字分)デフォルト文字
として 上の行”Upine “と下の行”DownLine “を入れておく
1 2 3 |
//char型初期表示用文字列 char ULine[] = "UpLine "; char DLine[] = "DownLine "; |
7・void setup() に、割り込みモードを”FALLING” H⇒Lに変化したら
と、I2C、デバック用シリアルポート、GPS用ソフトウエアポート
などをセットアップしてから、OLED初期化関数を呼び出す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
void setup() { pinMode(2, INPUT_PULLUP);//割り込みピンプルアップ attachInterrupt(0, select, FALLING);//2ピンが"L" になったら割り込み Selcount = 0; pinMode(LED_BUILTIN, OUTPUT); //プログラム通過チェックデバッグ用 //OLED GPS Wire.begin();//Wireライブラリを初期化し、I2Cマスタとしてバスに接続 init_oled(); //OLED初期化 Serial.begin(9600); //GPS Serial.println("GPS Logger Start!"); sGps.begin(9600); isValid = false; } |
8・メインループでは、GPSデーターの受信 ⇒ 受信データーの判別と
表示文字列の作成 ⇒ 有機ELディスプレイに表示となります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
void loop() { //GPS データ受信 char GPSbuf[BUFFER_SIZE]; getLine(GPSbuf); //バッファから1行読み込みモジュール呼び出し analyzeData(GPSbuf); //読み込んだ行の分析を呼び出す //OLED 表示制御受信データが"$GPRMC"なら表示 if (strncmp("$GPRMC", GPSbuf, 6) == 0){ //writeCommand(ClearDisplay); //クリアするとちらつく delay(20); disp(); //OLED表示 } if (Selcount > 2){ init_oled(); //OLED初期化 //contrast_max(); } if (Selcount >= 3){ Selcount = 0; } } |
・GPSだけの表示では面白くないので、表示切替へボタンを押す事により
0、上行に正確な現在時間、下行に進行方向(真北から0~359度)を表示
1、上行に対地速度(ノット/時)、下行に進行方向(真北から0~359度)を
2、上行に緯度、下行に経度 を表示
と三段階の切り替えができるように割り込み処理でしました、それと
四段階目で
3、OLED初期化する、(このOLEDはなぜか時々表示がずれるので)
初期化終了時に”0″に戻るようにしました。
1 2 3 4 5 |
//割り込み処理 void select(){ Selcount = Selcount + 1; // if (Selcount > 3){Selcount = 0;} } |
◆ GPS データー処理セクション
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
void loop() { //GPS データ受信 char GPSbuf[BUFFER_SIZE]; getLine(GPSbuf); //バッファから1行読み込みモジュール呼び出し //呼び出した getLine での処理 void getLine(char *GPSbuf){ if(GPSbuf == NULL) return; //データーが無ければ帰る int count = 0; //データーが有ればバッファ位置カウントを 0 にする do { if (sGps.available()) { //ソフトシリアルが利用可能なら GPSbuf[count] = sGps.read(); //char文字列の"count"位置に1バイト読み込む count++; //カウンターをインクルメントして繰り返す } if (count >= BUFFER_SIZE) break; //カウンタがバッファサイズを超えたら止める } while(GPSbuf[count - 1] != 0x0A); //1個前のデーターが 0x0A になるまで繰り返す GPSbuf[count] = '\0'; //受信を止めたらバッファの最後から1個にヌルを書き込む } -- 完璧な1行の受信データーを貰ったら 次の行の analyzeData(1行の受信データー) を呼び出してデーターを分析する |
・GPS NMEAデーターから解析しOLEDキャラに変換する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
void analyzeData(char *GPSbuf){ if(GPSbuf == NULL){ return; } checkValidity(GPSbuf); //"$GPRMC"データーが"A"有効/"V" 無効の判定 if (strncmp("$GPRMC", GPSbuf, 6) == 0){ //バッファ先頭6文字が"$GPRMC"なら } else{ return; //"$GPRMC"でなければ帰る } // 文字変数 char *gpsTime, *gpsState, *gpsLat, *gpsLatDir, *gpsLon, *gpsLonDir, *gpsSpeed, *gpsOrientation, *tmp; if (strncmp("$GPRMC", GPSbuf, 6) == 0) { //何度も"$GPRMC"のチェック strtok(GPSbuf, ","); gpsTime = strtok(NULL, ","); //UT時刻 gpsState = strtok(NULL, ","); //ステータス A=有効 gpsLat = strtok(NULL, ","); //緯度 N,S gpsLatDir = strtok(NULL, ",");//値 度 分.0000 gpsLon = strtok(NULL, ","); //経度 E,W gpsLonDir = strtok(NULL, ",");//値 度 分.00 gpsSpeed = strtok(NULL, ","); //毎時 ***.*ノット gpsOrientation = strtok(NULL, ","); //進行方向 真北から ***.*度 // 利用しないこの後のデータ //地磁気の偏角 **.*度 //偏角が真北からW 西 か E東か //モードA=単独測位 D=DGPS N=無効 //チェックサム Time = gpsTime; //GPSから取得のUT時間をTimeに入れる h = Time.substring(0,2); //文字列Timeの先頭から2文字を取り出す H = h.toInt(); //hを整数化 H = H + 9; //9時間+ if(H >= 24){ H = H - 24; //整数 } m = Time.substring(2,4); //分の取り出し s = Time.substring(4,6); //秒の取り出し //デバッグ用 UART OUT Serial.println(Selcount); //割込みカウンタチェック用 Serial.println(gpsTime); Serial.print("Time = "); Serial.print(H); //時 Serial.print(":"); Serial.print(m); //分 Serial.print(":"); Serial.println(s); //秒 Serial.print("State: "); Serial.println(gpsState); Serial.print("Latitude = "); Serial.print(gpsLatDir); Serial.print(":"); Serial.println(gpsLat); Serial.print("Longitude = "); Serial.print(gpsLonDir); Serial.print(":"); Serial.println(gpsLon); Serial.print("Speed = "); Serial.println(gpsSpeed); //単位はノット(毎時1.852Km) Serial.print("Direction = "); Serial.println(gpsOrientation); //真北から Serial.println(" "); //文字列結合処理とOLED表示用に変換 //日本時間をOLED表示用に変換 int Len; String RealTime; // OLED表示用に修飾と型の変換 RealTime = "RealTime"; if (H < 10 ){ RealTime = RealTime + "0" + H;} //時が一桁の場合0を付ける else {RealTime = RealTime + H;} RealTime.concat(":"); RealTime = RealTime + m; RealTime.concat(":"); RealTime = RealTime + s; if (Selcount == 0){ RealTime.toCharArray(ULine,17); //OED上ラインに表示デフォルト } //速度(ノット/h)をOLED表示用に変換 //1海里=1.852Km String Speed; Speed = "Speed:"; Speed = Speed + gpsSpeed; Speed = Speed + " Not/h"; if (Selcount == 1){ Speed.toCharArray(ULine,17); } //緯度をOLED表示用に変換 String NEWS; String Lat; if (gpsLatDir == "S"){ NEWS = "South"; } else {NEWS = "North";} Lat = NEWS; // N/W Lat.concat(":"); // N/W: Lat.concat(gpsLat); // N/W:*****.**** Lat = Lat + " "; if (Selcount == 2){ Lat.toCharArray(ULine,17); //String型をChar型に変換 } //方位をOLED表示用に変換 String Direction; Len = strlen(gpsOrientation); Direction = "Direction"; // 6桁表示を維持する為に0を頭に付ける if (Len == 6){Direction = Direction + ":";} if (Len == 5){Direction = Direction + ":0";} if (Len == 4){Direction = Direction + ":00";} Direction = Direction + gpsOrientation; if (Selcount == 0 or Selcount == 2){ Direction.toCharArray(DLine,17); //OED下ラインに表示 } //経度をOLED表示用に変換 String Lon; if (gpsLonDir == "W"){ NEWS = "West"; } else {NEWS = "East";} Lon = NEWS; // E/W Lon.concat(":"); // E/W: Lon.concat(gpsLon);//E/W:*****.**** Lon = Lon + " "; if (Selcount == 2){ Lon.toCharArray(DLine,17); //String型をChar型に変換 } delay(10); // 10[ms]待つ } } |
◆ I2CとOLED 表示セクション
その前に、ちょっと前までは I2C って使いにくいからアナログ式のデバイス
を多用していました、やっと I2C の読み書きについて理解が深まったよう
なので自分用への忘備録として、おさらいしておきます。
・まず絶対に必要なのはデバイスのアドレスですね、これが不明な場合は
使う事が出来ないのがI2Cのネックでしょうね、
それと、もと重要なのはGPIOのアドレスです、ジャンク箱からデバイスを
見つけてもデバイスマニュアルが無いと全く使えません、面倒ですね。
その点はアナログは簡単です、精度の点ではI2Cに勝てませんが…。ね
・ハード的なリクエストタイミングは飛ばして又詳細な方法も飛ばします
詳しくは ”ここ” に置いておきます。
・今回のOLEDは一方的に書きこむだけですので簡単に説明します
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
1・ Wire.beginTransmission(デバイスアドレス); //I2C送信セッション開始します 2・Wire.write(書き込み番地 0x40); // 0x40番地に下の1バイト書き込みますよ 3・Wire.write(1バイトデーター); // このデーターを送信して書きこんだよ 4・Wire.endTransmission(); // 書きこんだからI2C送信セッションを終了しますよ これだけの手順が必要です 書きこむ場合はデバイスが同じなら 書き込み番地とデータを変えるだけです 4つの手順は同じです。 2で操作する番地を指定しておいてから、次に3のように書き込みシーケンスを発行。 ※ 読込みなら1度セッションを終わり、続けてリードシーケンスを発行する。 I2Cの読み書きサイクルは必ず 1 のbegin で始まり 4 のend で終わる。 |
・この有機ELデバイスにアクセスする実際
OLEDの表示エリアと文字配列変数は以下のようになっている
char型配列には終端記号として”\0″ヌル記号が付くので
短い文字列を表示する時には、表示最後部にヌル記号の変なキャラが
表示されるので、桁合わせのためスペースを挿入して16文字以上にして
ディスプレイに送るようにする。
タイム表示の時に”時”が 10時以下なら”0″+時を付加して
GPSの進行方向では 4桁から6桁に変化するので、プログラム中で桁合わせの
意味で”Direction”文字列先頭に、”0″か”00″を付加している