TOP>工作> TT250R用 デジタルタコメーターの製作 (4.ソフト製作(試作1号完成)) |
|||||||
このタコメータ、最終的には回転数の数値表示とバーグラフ表示を考えている。 ・回転数表示 7セグメントデコーダを使うとデータの出力に4bit、ダイナミック点灯制御で1桁あたり1bitなので、4桁表示だと4+4=8bit必要。 ・バーグラフ表示 500rpmで1セグメントとすると、MAX9000rpmで18桁? それにパルス入力の1bitを加えると、単純計算でI/Oは8+18+1=27必要になる。となると40pinのでかいPICが必要になるけど、バイクに乗せるにはちょいとでかい気がする・・。 バーグラフ表示の方法は少し検討することにして、とりあえず28pinの16F886で進めてみることにした。 (まぁ、手持ちの中から適当な大きさでかつ安い石をテキトーに選んだだけでもある、、) さて。正直この製作で自分にとって一番の難関はソフトウェア。 どうやってパルスを拾って回転数に変換するかはぼんやりとしか頭に浮かんでこないけど、とりあえず色々テストプログラムを組みながら考えて行く。 開発環境はmikroElektronikaという会社の出しているmikroBASICを使ってみる。(Ver.7.0.0.2) PICにSWとLCDを下記のように接続した回路をブレッドボードで組む。SWは外部割込みピンに接続。 (クリックで拡大) 測定したい対象信号が最大でも250Hz@15000rpmと比較的低速(周期4msec)なので、20MHz動作のPICなら下記のような方法でパルスの間隔を測れないだろうか? INTピン変化割り込み発生 ↓ タイマ1カウント開始。 ↓ 再びINTピン変化割り込み発生 ↓ タイマ1カウント値の確認 これで、タイマ1の1カウントあたりの時間がわかっていれば、パルスの周期を求めることができるのでは無いかと考えてみた。とりあえず、INTピン変化割り込みの方法、タイマ0の使い方とも良く判らないのでそれぞれで練習してみることにする。
PIC16F886の外部割込みピンは21番ピン(RB0と共用)。 割り込みの許可とINT割り込みの設定はINTCONレジスタで設定する。 mikroBASICでは、割り込み処理は sub procedure interrupt 動作命令 end sub というプロシージャを作って記述するようだ。 で、とりあえずLCDの表示が薄くなる(高速で何度も書き換えるのでチラついているのだろう)等問題は有るもの、とりあえずスイッチを押すごとに数字をカウントアップするソフトは書けた。 正直公開するのは恥ずかしいけど、ソースは下記の通り。なお、全角文字(スペース含む)が含まれているので、コピペ時(する人居るのか??)は注意。 '********************************************** 'Tachometer test program (2009-08-30) by Magokoro 'This program count pulse of INT pin and show it on LCD. '********************************************** program Tachometer ↓変数の宣言 dim text as char[16] dim PUSH as byte ↓割り込み時処理のサブルーチン。INTピンの立上りエッジで割り込み、変数PUSHを+1する。 sub procedure interrupt INTCON = %00010000 'Interrupt is disable PUSH = PUSH + 1 INTCON = %10010000 'Interrupt is enable end sub main: ↓BポートのA/DコンバータをOFFにする。(デフォルトではI/Oとして使えない) ANSEL = 0 'A/D Converter disable ANSELH = 0 'A/D Converter disable ↓LCDのイニシャライズ Lcd_Config(PORTC,7,6,5,4,PORTB,5,6,7) '(data_port,DB7,DB6,DB5,DB4,ctrl_port,RS,RW,E) Lcd_Cmd(Lcd_CURSOR_OFF) ' Turn off cursor ↓INT割り込み(外部割込み)の許可 INTCON = %10010000 'INT pin interrupt enable OPTION_REG = %11111111 'Interrupt on rising edge of INT pin(Default) ↓LCDの1行目にPUSH TIMES;を表示 PUSH = 0 Lcd_Out(1, 1, "PUSH TIMES:") ↓無限ループでLCDに変数PUSHの値を表示し続け、割り込み処理を待つ。 LCD制御の関数実行中に割り込みがかかるとLCDの表示がおかしくなるので、その間は割り込み禁止にしている。 while TRUE 'Endless loop INTCON.7 = 0 ByteToStr(PUSH, text) Lcd_out(2, 1, text) INTCON.7 = 1 delay_ms(10) wend end. '************************************************* ' END OF PROGRAM '************************************************* 左の黄色いプッシュSWを押すたびに数字がカウントアップされる。 (チャタリング対策をしていないので時々2〜3カウントされたりする。)
とりあえずINTピン入力立上りによる割り込みの方法はなんとなくわかったので、その間隔をタイマ1でカウントしてみる事にする。タイマ1の動作方法はT1CONレジスタで設定する。 基準クロックに動作クロック(20MHz)を使用し、プリスケーラ(何クロックで1カウントするか決める)を1:8とすると、1カウントあたりの時間は次で求められる。 T = 1 /( ((20*10^6) / 4) / 8 ) =1.6μsec (これで÷4が入っているのは、基準クロック=PICの動作クロック÷4という仕様なため。) タイマ1は16ビットカウンタなので、カウント値は0〜65535。 ・1000rpm = 16.7Hz = 周期60000μsec = 37500カウント ・15000rpm = 250.0Hz = 周期4000μsec = 2500カウント と、とりあえず目標とする周波数に対して充分な余裕がある。 というわけで、カウント値から周波数を逆算してLCDに表示するプログラムを書いたのが下記。 '********************************************** 'Tachometer test program (2009-08-31) by Magokoro 'This program measure frequency of pulse 'for INT pin and show it on LCD. '********************************************** program Tachometer dim text as char[16] 'LCD Output text ↓タイマ1は16ビットカウンタなのでword型の変数で問題ないが、その後の演算で65535(16bit)を超えてしまうのであらかじめlongwordで定義する。 dim TMR1VALUE as longword 'Timer1 count value (32bit) dim CONVERT as word dim INPUT_FLAG as byte ↓割り込み処理 sub procedure interrupt INTCON.7 = 0 'Interrupt is disable if INPUT_FLAG = 0 then T1CON = %00110001 'Timer1 start (prescaler 1:8) INPUT_FLAG = 1 else T1CON = %00000000 'Timer1 stop ↓16bitカウンタの上位8bitを読み込み、ビットを8ビットシフトした後下位8bitを読み込む。 TMR1VALUE = TMR1H TMR1VALUE = TMR1VALUE << 8 TMR1VALUE = TMR1VALUE + TMR1L WordToStr(TMR1VALUE, text) Lcd_out(1, 1, text) ↓本当は周波数=1/周期Tなので、単純にカウント値×1.6μsecの逆数を取ればよい。しかしプログラム上で小数点のある値を取り扱いたくなかったので、あらかじめ欲しい有効桁数まで10のn乗を掛け、後でそれを割る方法にした。邪道かなぁ。 TMR1VALUE = TMR1VALUE * 16 TMR1VALUE = 100000000 / TMR1VALUE ↓このあたりはデバック用の不要コード CONVERT = TMR1VALUE WordToStr(CONVERT, text) Lcd_out(2, 1, text) TMR1VALUE = TMR1VALUE * 6 CONVERT = TMR1VALUE WordToStr(CONVERT, text) Lcd_out(2, 8, text) INPUT_FLAG = 0 TMR1H = 0 TMR1L = 0 end if INTCON.1 = 0 'INT Interrupt flag clear INTCON.7 = 0 'Interrupt is enable end sub main: ANSEL = 0 'A/D Converter disable ANSELH = 0 'A/D Converter disable INPUT_FLAG = 0 Lcd_Config(PORTC,7,6,5,4,PORTB,5,6,7) '(data_port,DB7,DB6,DB5,DB4,ctrl_port,RS,RW,E) TRISB.0 = 1 'PORTB.0 input OPTION_REG = %11111111 'Interrupt on rising edge of INT pin. PIE1 = %00000000 'Timer1 Interrupt Disable INTCON = 0 'Resister clear INTCON.4 = 1 'INT pin interrupt enable INTCON.7 = 1 'Interrupt enable ↓無限ループ。ここで割り込みがかかるのを待つ。 While TRUE wend end. '************************************************* ' END OF PROGRAM '************************************************* 回路図は下記。(クリックで拡大) この回路図中のC3(7414とPICのINT端子間に入っているパスコン)はプリント基板では不要かもしれない。 実は最初、どうにも正常に作動しない(およそ2倍の値が表示される)ので色々調べると、パルスの立ち上がりでしか割り込みがかからないはずなのに立上り/立下り両方で割り込みがかかっていることが判明。ブレッドボードで実装している関係で、リンギングが起きてそれを検出してしまったようで、パスコンを1つ追加して波形を鈍らせたらあっさり解決。およそ1週間をこれでつぶした。 知っている人にとっては当たり前なのだろうけど、やっぱりブレッドボードはこういうところを気をつけないといけないみたいだ。 で、動作確認。(Youtubeにアップ。いつまで残っているのかは不明) http://www.youtube.com/watch?v=Zc_FvgiHPy8 とりあえず、回転数をLCDに表示するところまでは完成した模様。
現状のプログラムは割り込みがかかる度にLCDの数値を書き直しているのだが、 ・回転数に応じて表示の更新間隔が短くなる ・ちらつく(当然・・・・) という問題があるので、割り込み処理はタイマのカウント値取得のみに書き換え、LCDの表示をmainへ移動させた。あとはLCDに表示している数字を7セグLEDに置き換え、バーグラフをつければ当初の目的は達成な感じ。 今のWebサーバの都合上、TXT、ZIP、PDF等は置けないので、ソースファイルは下にドバッと貼り付けておく。 もしEAGLEデータ、mikroBASICソースファイル等そのものが欲しい人はメールででも連絡してもらえれば対応します。(いつまでPCに残っているかは判らないけど。。。) <3.波形整形 5.LED表示への変更>
LCD表示版のソースファイルは下記。 貼り付け時に半角、タブ等全て無視されていているため、読みづらいのはご勘弁を。
※1 記事を書きながら製作・勉強しています。誤っている箇所やアドバイスありましたら教えてください。質問も分かる範囲でお答えします。一緒に勉強しましょう。 |
|||||||
TOP>工作> |
SEO | [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送 | ||