Arduinoをつかったバーサライタの点灯パターンについて解説しています.
回路図,ソースコードはgithubにありますのでお使いください.
バーサライタの点灯パターンの計算についてはバーサライタの点灯パターン計算報告書が素晴らしいので,そちらをごらんください.
点灯プログラムの計算はImgToVWを御覧ください.
ソースコード,回路図はhttps://github.com/jp3cyc/versaWriterをごらんください
Arduinoは計算済みの点灯パターンを配列,ROM,SDに保存しておき,Arduinoでは保存した点灯パターンをLEDに送る役割のみをもちます.
以下のような処理をしています
- LEDを光らせる
- ホールセンサで速度,位置のよみとり
- LEDの点灯時間の調整(1周で40個のパターンが点灯するようにする)
- パターンの角度の保持(文字を表示したときに上下逆転しないようにする)
それぞれの関数について説明します
・LEDを光らせる処理
ポートに信号を送ります.digitalWriteと同じことをやっていす.
digitalWriteより高速に出力できます.
参考:https://ehbtj.com/electronics/speedup-arduino/
1 2 3 4 5 6 7 8 9 |
void ledWrite(unsigned int signal){ //ポートに出力している.digitalWriteを高速化する書き方をしている // 0x800 is center.LED1 is outside. PORTB = PORTB & 0xfc | (signal & 0x003); PORTD = PORTD & 03 | (signal & 0x0fc) ; PORTC = PORTC & 0xf0 | (signal & 0x0f00) >> 8; } |
LEDに信号を出力するプログラムです.
ledWrite関数の引数にLEDが点灯するかしないかを12ビットで指定していて,signalに代入されます.
signalに代入された12ビットの1,0をPORTB,PORTDとPORTCに分けています.
digitalWriteとの違いは高速になるほかに,同時にポートに出力することができることです.
1 |
PORTB = PORTB & 0xfc | (signal & 0x003); |
PORTBに点灯・消灯を8ビットまとめて代入します.
LEDはポートB1,0の2つに接続しているので,PORTBの下位2ビットだけ書き換えたい.
上位6ビットはそのままで,下位2ビットだけ代入しています.
・ホールセンサの取得
ホールセンサの立ち上がり時にPinInterrupt関数を実行します.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void checkPinInterrupt(){ //ホールセンサの立ち上がりを検出している. if(( (PINC & 0x10) == 0x10 ) && ( flag == 1) ){ //立ち上がりのときに1度だけ実行 PinInterrupt(); flag = 0; } if( ((PINC & 0x10) != 0x10) && (flag == 0) ){ flag = 1; } } |
1 |
(PINC & 0x10) == 0x10 ) |
この関数でPORTCからセンサの値を読み込んでいます.
マイコンのPC4にセンサを接続しているので,8ビットまとめて格納されているPINCからPC4に相当する5ビット目のみをマスクして取り出しています.
アンド演算するとフィルタになります.これをマスクとかいいます.
0でアンドをとると何があっても0になり,1でアンドを取ると1だったら1となり0だったら0が出力されます.(計算してみるとわかりやすい)
1 |
( flag == 1) |
if文のなかはセンサの反応とflagが1の時にのみ実行されるようにしています.
センサに反応があった最初の1回だけ実行したいので,このようにflagを立てています.
センサに反応があった時にPinInterrupt()関数を実行しています.(次の章で関数の中身については説明)
白い線の幅が広いので,白い線の上で何度も処理が入ると回転数の計算が大変になりますので,このようにflagを立てています.
本当は立ち上がり割り込みを使う予定でしたが,割り込みポートにセンサを付けるのを忘れていたので,このような処理をしています.
1 2 3 |
if( ((PINC & 0x10) != 0x10) && (flag == 0) ){ flag = 1; } |
この処理はセンサが白い線を読み込んでいない時にflagをリセットしています.
1 |
(flag == 0) |
この処理をしているのは,何度もflag=1をする必要を感じなかったのでこんな感じの処理をしています.
・LEDの点灯時間の処理,パターンの角度の保持
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void PinInterrupt(){ //立ち上がりのときに実行される //位置の初期化 posi=0; // 点灯時間計算 count ++; if(count >= 10 ){ // 回転数は10回の平均をとる time = timer / 400; // 1周は40コマだから400 timer = 0; count = 0; } } |
LEDの点灯時間はバーサライタが1周するときに40パターン表示できるように1周の時間/40とする必要があります.
1周する時間を検出するためにはタイマのカウントと基準位置での検出がひつようです.
タイマのカウントはタイマー割り込みをつかって10マイクロ秒に1回の割り込み処理を行いtimerという名の変数をカウントアップしています.
基準位置の検出はセンサの立ち上がり時の反応を見ています.
時間の計測方法は10周回った時の時間を計測して,10で割ることで1周分の時間を求めています.1周の時間からLEDの点灯時間を求めるのでtimer/40/10=timer/400としています.
位置のリセットは配列の番号のリセットを行うことで処理しています.
メインルーチンで配列に入っている点灯パターンを順番にLEDに送っています.
今の点灯パターンの位置をposiという変数で記憶しています.
そのため点灯パターンの位置を表すposiという変数を0にすることで,メインルーチンでは0の位置から出力をするので,位置を一定にすることができています.
ありがとう