Location Clockの組み立てとコード書き込み
前回は電子部品を組み込むハードの設計と加工を行いました。
今回はマイコンやら表示機やらモーターやらの電気回路半田付け作業と、構想から若干回路とコードを変えたのでそれらの解説を行っていきたいと思います。
使用していますマイコンはESP8266です。
コードの修正と解説
以前設計したコードから以下の点を変えております。
- 7セグ表示機のNTPサーバー時計
- 原点センサを【フォトマイクロセンサ】⇒【フォトリフレクタ】
7セグ表示機時計の追加は家族からの要望で卓上時計が入用だったので、機能を追加した次第です。
原点センサの変更はハード設計ミスで取り付けることができなかった、、、
設計手順は重要ですね。はい。。。
という事で、スペースを取らない埋め込み型の反射型センサ(フォトリフレクタ)TCRT5000を使うことにしました。
他は基本的には変えていなく、前回のコードのフローチャート通りです。
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 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
#define BLYNK_PRINT Serial #include <WiFiUdp.h> #include <Arduino.h> #include <TM1637Display.h> #include <ESP8266WiFi.h> #include <BlynkSimpleEsp8266.h> //Authコード, Wifi-ID, Wifi-PASS char auth[] = "Authコード"; char ssid[] = "Wifi-id"; char pass[] = "Wifi-pass"; const uint8_t CLK=4;//TM1637クロック const uint8_t DIO=5;//TM1637データ const uint8_t A=14;//ステッピングモーターPIN1 const uint8_t B=12;//ステッピングモーターPIN2 const uint8_t C=13;//ステッピングモーターPIN3 const uint8_t D=15;//ステッピングモーターPIN4 const uint8_t Pin=0;//アナログピン const uint16_t interval=30000;//NTP読み取り間隔(ms) static uint16_t ADC;//フォトリフレクタ値 static float cnt=0;//インクリメントエンコーダー volatile int s=1;//状態フラグ volatile uint16_t target;//目標指令角度 bool flag = 1;//NTP読み取りフラグ unsigned long cnt1 = 0;//経過時間カウント unsigned long cnt2 = 0;//NTP読み取り時間カウント //TM1637ライブラリ転用。NTPサーバーのみ変更 TM1637Display display(CLK, DIO); unsigned int localPort = 2390; // local port to listen for UDP packets IPAddress timeServerIP; // NTP server address const char* ntpServerName = "ntp.nict.jp"; const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets // A UDP instance to let us send and receive packets over UDP WiFiUDP udp; void setup() { Serial.begin(9600); Blynk.begin(auth, ssid, pass); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); Serial.println("Starting UDP"); udp.begin(localPort); Serial.print("Local port: "); Serial.println(udp.localPort()); //ステッピングモーターPin出力設定 pinMode(A, OUTPUT); pinMode(B, OUTPUT); pinMode(C, OUTPUT); pinMode(D, OUTPUT); //TM1637照度設定 display.setBrightness(0x0a); } void loop() { Blynk.run(); switch(s){ //待機 case 0: PinOff(); cnt1=millis();//ループカウント if(flag==1){ cnt2=millis();//NTP読み取り時間 flag=0; } if((cnt1-cnt2)>interval){//NTP読み取り間隔 Serial.println("ON"); ntp(); flag=1; } break; //原点復帰 case 1: ORG(); break; //指令角度受信&移動 case 2: pos(target); Serial.println(target); break; } } void ntp(){ uint8_t h, m; //get a random server from the pool WiFi.hostByName(ntpServerName, timeServerIP); sendNTPpacket(timeServerIP); // send an NTP packet to a time server // wait to see if a reply is available delay(1000); int cb = udp.parsePacket(); if (!cb) { Serial.println("no packet yet"); } else { Serial.print("packet received, length="); Serial.println(cb); // We've received a packet, read the data from it udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); unsigned long secsSince1900 = highWord << 16 | lowWord; Serial.print("Seconds since Jan 1 1900 = "); Serial.println(secsSince1900); // now convert NTP time into everyday time: Serial.print("Unix time = "); // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: const unsigned long seventyYears = 2208988800UL; // subtract seventy years: unsigned long epoch = secsSince1900 - seventyYears; // print Unix time: Serial.println(epoch); // print the hour, minute and second: Serial.print("The JST time is ");// 日本標準時(標準時間+9:00) Serial.print(((epoch % 86400L)+3600*9) / 3600); //標準時+9時間の時差考慮 Serial.print(':'); //9時間の時差調整 h=((epoch % 86400L)+3600*9) / 3600; if(h>=24){ h=h-24; } if (((epoch % 3600) / 60) < 10) { // In the first 10 minutes of each hour, we'll want a leading '0' Serial.print('0'); } Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute) Serial.print(':'); m = (epoch % 3600) / 60; if ((epoch % 60) < 10) { // In the first 10 seconds of each minute, we'll want a leading '0' Serial.print('0'); } Serial.println(epoch % 60); // print the second } Serial.println(h); //TM1637display_on display.showNumberDecEx(h*100+m,0x40,true); } //Blynkサーバーから値読み取り BLYNK_WRITE(V2){ //Blynk Virtual Pin Serial.println("---------------"); target = param[0].asInt(); Serial.printf("location = %d\r\n", target); s=2; } // send an NTP request to the time server at the given address void sendNTPpacket(IPAddress& address) { Serial.println("sending NTP packet..."); // set all bytes in the buffer to 0 memset(packetBuffer, 0, NTP_PACKET_SIZE); // Initialize values needed to form NTP request // (see URL above for details on the packets) packetBuffer[0] = 0b11100011; // LI, Version, Mode packetBuffer[1] = 0; // Stratum, or type of clock packetBuffer[2] = 6; // Polling Interval packetBuffer[3] = 0xEC; // Peer Clock Precision // 8 bytes of zero for Root Delay & Root Dispersion packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; // all NTP fields have been given values, now // you can send a packet requesting a timestamp: udp.beginPacket(address, 123); //NTP requests are to port 123 udp.write(packetBuffer, NTP_PACKET_SIZE); udp.endPacket(); } //原点復帰 void ORG(){ while(s){ FullStep(10); ADC=analogRead(Pin);//フォトマイクロセンサ検知 if(ADC<100){//フォトマイクロセンサ検知でループ抜け s=0; for(int i=0;i<15;i++){ FullStep(10); } } Serial.println(ADC); Serial.println(s); } //フォトマイクロセンサ検知点を原点とする cnt=0; } //ステッピングモーター移動 void pos(uint16_t p){ //現在値の指令値からの差 int diff; diff = target - cnt; if(diff>1){ FullStep(5); }else if(diff<-1){ FullStep2(5); }else{ s=0; } } void FullStep(uint8_t i){ digitalWrite(A, HIGH);digitalWrite(B, LOW);digitalWrite(C, LOW);digitalWrite(D, LOW); delay(i); digitalWrite(A, LOW);digitalWrite(B, HIGH);digitalWrite(C, LOW);digitalWrite(D, LOW); delay(i); digitalWrite(A, LOW);digitalWrite(B, LOW);digitalWrite(C, HIGH);digitalWrite(D, LOW); delay(i); digitalWrite(A, LOW);digitalWrite(B, LOW);digitalWrite(C, LOW);digitalWrite(D, HIGH); delay(i); cnt+=0.7031;//インクリメントエンコーダー } void FullStep2(uint8_t i){ digitalWrite(A, LOW);digitalWrite(B, LOW);digitalWrite(C, LOW);digitalWrite(D, HIGH); delay(i); digitalWrite(A, LOW);digitalWrite(B, LOW);digitalWrite(C, HIGH);digitalWrite(D, LOW); delay(i); digitalWrite(A, LOW);digitalWrite(B, HIGH);digitalWrite(C, LOW);digitalWrite(D, LOW); delay(i); digitalWrite(A, HIGH);digitalWrite(B, LOW);digitalWrite(C, LOW);digitalWrite(D, LOW); delay(i); cnt-=0.7031;//インクリメントエンコーダー } //待機中のステッピングモーター信号OFF void PinOff(){ for(int i=12;i<=15;i++){ digitalWrite(i, LOW); } } |
追加コード:7セグ表示機
時刻を表示するための4桁7セグLED表示機を追加しました(間にコロンがあるもの)。表示機の制御に関してはLEDドライはTM1637を使用しています。
TM1637はI2Cライクなシリアル通信タイプです。信号線はデータとクロックの2線しか使用しないために省配線にぴったりです。TM1637の制御方法に関しては以下の記事で紹介しています。
記事内ではライブラリ不使用で、位置からコードを書いていますが、本記事ではTM1637Display.hライブラリを使用したいと思います。
追加コード:NTPサーバーからの時刻データ取得
NTPサーバーへのアクセスとデータ取得コードに関してはESP8266のサンプルコードを転用しています。
使用しているNTPサーバーは日本標準時(JST)グループの公開サーバーである“ntp.nict.jp”です。
ここで気を付けたいのが、NTPサーバーから時刻データを取得する時、日本のタイムゾーンは標準時間から9時間進んでいるので+9時間の調整を行う必要があります。
1 |
h=((epoch % 86400L)+3600*9) / 3600; |
NTPサーバーからの読み取りと7セグ表示機への時間表示の更新はループカウントを設けてintervalの時間毎に行っています。本コードでは30秒を更新間隔としています。読み取り時は待機状態の時(case0)に読み取るので、ステッピングモーターが動いているときや原点復帰の時はNTPサーバーからの時刻取得や表示機の更新は行わないようにしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//待機 case 0: PinOff(); cnt1=millis();//ループカウント if(flag==1){ cnt2=millis();//NTP読み取り時間 flag=0; } if((cnt1-cnt2)>interval){//NTP読み取り間隔 Serial.println("ON"); ntp(); flag=1; } break; |
追加コード:フォトリフレクタによる原点復帰
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//原点復帰 void ORG(){ while(s){ FullStep(10); ADC=analogRead(Pin);//フォトマイクロセンサ検知 if(ADC<100){//フォトマイクロセンサ検知でループ抜け s=0; for(int i=0;i<15;i++){ FullStep(10); } } Serial.println(ADC); Serial.println(s); } //フォトマイクロセンサ検知点を原点とする cnt=0; } |
フォトリフレクタを使う時に気を付けたいのは“フォトマイクロセンサと比較してアナログ値の振る舞いが逆転する”という事です。
フォトマイクロセンサは遮光されていない時はフォトトランジスタのインピーダンスは小さくなります。逆にフォトリフレクタの場合は反射光によりフォトトランジスタのインピーダンスが小さくなるので原点のドグが被った時にインピーダンスが小さくなるという事です。
という事で、以前のコードと比較して不等号を逆転させています。
POINT
- フォトマイクロセンサ:原点検知時にインピーダンス大
- フォトリフレクタ:原点検知時にインピーダンス小
電気回路組み立て
組み立てということで、まずはESP8266周りを半田付けして電子回路部分を組み立てていきます。そのあとに、前回作成したベースフレームに組み込んでいこうかと思います。
※ステッピングモーターの仕様が5V~だったので5V昇圧DCDCを追加しました。
【電気回路図】
ESP8266周りの半田付け
■ 4桁7セグ表示機の取付
まず7セグ表示機をESP8266に取り付けて単体で動作確認をしていきます。
■ステッピングモータードライバの取り付け
ESP8266の3.3V出力を使用します。しかし、ステッピングモーターの動作電圧は5V~なので昇圧DCDCを取り付けます。(本来だったらモーター用に別電源を設けた方がいいですが、常時回っているわけでもないので今回は目をつぶりました)
■ステッピングモーターの動作確認
モータードライバが取り付けられたら、ステッピングモーターの動作確認を行います。テストプログラムは以前ステッピングモーターを紹介した時に使用したものを使用しました。
■フォトリフレクタの組付け
フォトリフレクタはフォトダイオードと赤外線LEDの組み合わせなので電流調整の抵抗と分圧抵抗を付ける必要があります。今回はユニバーサル基板に抵抗とフォトリフレクタをはんだ付けしてモジュール化しました。
おわりに
電気回路の組み立ては上記で終了です。
ベースに組み込む前にバラックの状態でプログラムを書き込んで動作確認してみましょう。最終的にはIFTTTのLocationとWebhooksを連携させる予定ですが、動作確認では【Locatio】の代わりに【Button wedget】を使用するといいと思います。
次は最終回で加工したベース板に組み付けて動作確認です。
ではまた!
コメント