前回は回路まで完成したので、今回は本体と回路の配線と、LEDの制御プログラムについて紹介する。前回の記事はこちら↓
本体の固定と配線の引き出し
前輪とスタンド二か所を針金で固定する。ベースには2.5mmで穴を開けた。
裏はこんな感じ。
配線
ハーネス(端子の圧着)する。uxcell メスピンコネクタ端子 圧力ライン端子を使った。LED8個分+GND線2本で計10本作製。
電池ボックスの配線もしておく。単三電池4本直列なので、片方の電線をはんだ付けして熱収縮チューブで絶縁する。
基板に通電した様子。Arduino上のLEDが点灯しているので、基板の最低限の配線に間違いはないようだ。
電源電圧を確認する。ちゃんとレギュレータで6V→5Vに降圧できていることが確認できた。にしても、5V出力のレギュレータで出力5.003V(誤差0.1%未満ってすごい・・・)
スイッチをつけ忘れたので追加する。一般的なトグルスイッチだ。
左にパチンってしたときに電源ONするように配線する。配線や基板の固定にはホットボンドを使用した。ネジで固定する方が安心ではあるが、ベースに穴を開けてしまうと見た目が悪くなってしまうので諦める。
ハードウェアは完成!続いてソフトを作っていく。
LED制御プログラムの作成
仕様を再確認する。主にこの二点。
- ヘッドライトとテールライトは常時点灯してね。
- ウィンカーとパトライトは交互に点滅させてね。ただしタイミングはずらしてね。
常時点灯と点滅か、簡単そうじゃん。仮に点滅するLEDは一つで、残りは常時点灯であれば、
setup(){
LED1_ON();
LED2_ON();
LED3_ON();
}
loop(){
winker_LED_ON();
wait(500);
winker_LED_OFF();
wait(500);
}
のように、マイコン初めて動かしました~みたいなコードでよかった。 しかし今回は二種類の点滅パターンが必要だ。これが意外と厄介で、点灯・消灯・ディレイの命令だけではどうも作れそうにない。
タイマーの使用
複数種類の点滅を作るために、タイマーを使う。タイマーとは、メインループの動作とは関係なく延々とカウントしてくれる回路のことで、カウント周期はソフトウェアで設定できる。
Arduino IDEには使いやすいタイマーのライブラリが用意されている。タイマーのライブラリは何種類かあるが、個人的にはMsTimer2がオヌヌメ。タイマーだけでなく、割り込み処理も含んでいるので一定周期で処理を実行したいときにはもってこいのライブラリだ。
ライブラリのインクルード・変数宣言
ゴリゴリ書いていこう。先ほどのMsTimer2をインクルードして、使用する変数たちを宣言する。LED出力ピン設定用変数というのは、追々IO出力する際にピン番号を数値で指定すると何をON/OFFしているのか分からなくなるので文字に置き換えている。
#include <MsTimer2.h>
const int min_freq = 100; //点灯周期の最低時間(ms)
const int analog_read_freq = 10; //VRからアナログ値を読み込む周期(ms)
int analog_read_count = 0; //カウンタ
int old_analog_read_count = 0; //1フレーム前のカウンタ値
int pat_freq = 0; //パトライトの点灯周期
int pat_count = 0; //パトライト点滅時間のカウンタ
boolean pat_state = LOW; //パトライトの点灯状態(LOW or HIGH)を格納
int wink_freq = 0; //ウィンカーの点灯周期
int wink_count = 0; //ウィンカー点滅時間のカウンタ
boolean wink_state = LOW; //ウィンカーの点灯状態(LOW or HIGH)を格納
/***********LED出力ピン設定用変数**********/
int head = 12; //ヘッドライト
int brake = 6; //ブレーキライト
int pat_R = 8; //パトライト(R)
int pat_L = 11; //パトライト(L)
int winker_FR = 9; //フロントウィンカー(R)
int winker_FL = 10; //フロントウィンカー(L)
int winker_LR = 5; //リアウィンカー(R)
int winker_LL = 4; //リアウィンカー(L)
/***********VR入力ピン設定用変数**********/
int pat_volume = 0; //パトライト設定ボリューム
int wink_volume = 5; //ウィンカー設定ボリューム
setup関数の処理
setup関数はArduinoが動きだして一回だけ実行される関数だ。通常のC言語でもメインループに入る前に一度だけ実行すればいい命令を書くと思う。アレがArduinoでは関数化されている。
IOピンの入出力設定と、タイマーの設定を行う。タイマーは1msで設定、割り込み関数はcounter(後述する)に設定している。これで1msごとにcounter関数が無条件に実行されるようになった。
void setup() {
/**********ピン入出力設定***********/
pinMode(head, OUTPUT);
pinMode(brake, OUTPUT);
pinMode(pat_R, OUTPUT);
pinMode(pat_L, OUTPUT);
pinMode(winker_FR, OUTPUT);
pinMode(winker_FL, OUTPUT);
pinMode(winker_LR, OUTPUT);
pinMode(winker_LL, OUTPUT);
/**********ピンタイマー設定***********/
MsTimer2::set(1, counter); //1msecで設定
MsTimer2::start(); //タイマースタート
//常時点灯のLEDを点灯する
digitalWrite(head, HIGH); //ヘッドライト点灯
digitalWrite(brake, HIGH); //ブレーキライト点灯
//点滅LEDの初期状態を設定
digitalWrite(pat_R, pat_state);
digitalWrite(pat_L, !pat_state); //交互に光るので、パトライトRのNOTを設定する
digitalWrite(winker_FR, wink_state);
digitalWrite(winker_FL, wink_state);
digitalWrite(winker_LR, wink_state);
digitalWrite(winker_LL, wink_state);
}
loop関数
コピペミスった?
いいえ。空なんです。割り込み関数を使うと、メインループ関数を空にした方が実装しやすい場合がある。なんだかお作法に反しているような気もするが、実装しやすいのでこれれいい。
void loop() {
}
counter(割り込み)関数
こちらが今回のメイン処理を行うcounter関数。1msごとに以下の処理を実行する。やっていることとしては、
- analog_read_freqミリ秒ごとにADコンバータの値を読み込み、pat_freqとwink_freq に格納する。
- pat_freqミリ秒ごとにパトライトの出力を反転させる。
- wink_freqミリ秒ごとにウィンカーの出力を反転させる。
LED以外にもADコンバータも一定周期で値を読み込みたいため、 ここでは三つのカウンターを使っている。わざわざADコンバータを一定周期にしている理由は、ADコンバータは一般的に処理に時間がかかるため頻繁に使いたくない。なので100msごとくらいに設定している。
LED点滅制御のカウンタは、指定時間 pat_freq , wink_freq それぞれの時間に到達したらカウンタをゼロにクリアすると同時に、出力値を反転する。このようにして、各々の周波数で点滅させている。
//割り込み関数
void counter() {
//可変抵抗読み込みカウンタ制御
if(analog_read_count < analog_read_freq){
analog_read_count++;
}
else{
analog_read_count = 0;
pat_freq = min_freq + analogRead(pat_volume) * 2; //最低100ms,最大1023*2(ms)の間で変更可能
wink_freq = min_freq + analogRead(wink_volume) * 2; //最低100ms,最大1023*2(ms)の間で変更可能
}
//パトライト点滅カウンタ制御
if(pat_count < pat_freq){
pat_count++;
}
else{
pat_count = 0;
pat_state = !pat_state;
digitalWrite(pat_R, pat_state);
digitalWrite(pat_L, !pat_state); //交互に光るので、パトライトRのNOTを設定する
}
//ウィンカー点滅カウンタ制御
if(wink_count < wink_freq){
wink_count++;
}
else{
wink_count = 0;
wink_state = !wink_state;
digitalWrite(winker_FR, wink_state);
digitalWrite(winker_FL, wink_state);//交互に光るので、ウィンカーRのNOTを設定する
digitalWrite(winker_LR, wink_state);
digitalWrite(winker_LL, wink_state);//交互に光るので、ウィンカーRのNOTを設定する
}
}
完成
ざっぱな説明になってしまったが、上記のプログラムを書きこむことでLEDをそれぞれの周期で点滅させられた。
フロントから。
おしり。
電気を消すと雰囲気でる。HONDAが赤く照らされているのがエロい。