• 締切済み

PIC16F84でデジタルスピードメーターを作る

micariの回答

  • micari
  • ベストアンサー率85% (12/14)
回答No.6

> この程度理解出来てればOKでしょうか? おおむね OK だと思います。 ただし TMR0 は 8 ビットなので、255 までしかありません。そのあとは、オーバーフローして、0 に戻ります。ステップ数ということでいえば、0 も含みますので、256 です。また「カウント数はプリスケーラの ... 設定可能」とあるのは、そのうちの任意の値を設定できるわけでないことに注意してください。 F レジスタという名称はよくわかりませんが (ファイル・レジスタのこと ?) TMR0 レジスタにはちがいないので、たぶんそのとおりでしょう。 「クロック入力毎にTMR0のFレジスタの値に+1される」については、外部クロックを選択していて、プリスケーラを使っていなければ、そのとおりです。 また、TMR0 に値を書き込むと、プリスケーラはクリアされます。プリスケーラの値は読み出すことができませんし、TMR0 に値を書き込むのは、初期設定時を除いてどうかと思いますが、そんなに気にしないのであれば OK です。 > でも・・・スピードメーターを作る場合にこれをどう利用するか??が問題ですよね。 全体の構成は、もっとも重要なところで、楽しいところでもあり、苦しいところでもあるので、仕事でもなければ、他人が口を出すのはどうかと思います。 しかし、すでに口を挟んでしまっているようなので、もう少し口を挟ませてもらうことにします。 > 表示部分のプログラムは割り込みが発生したときに ... > ... 呼び出すようにすれば良いですよね? 表示部分は、インタバルタイマの割り込みが発生したときに、単に表示するためのデータを出力するだけでいいと思います。 データの内容を気にする必要はありませんし、他のルーチンから呼び出す必要もありません。 お望みのものは、早い話が、周波数カウンタのようなものだと思います。 周波数カウンタには、大別して、ダイレクト・カウンタとレシプロカル・カウンタのふたつの方法があります (わからなければ、調べてください) 一定時間内で入力パルスの個数を数えるのか、入力パルスの間隔の時間を数えるのかのちがいです。最初の質問内容からは、レシプロカル・カウンタの動作に近いと思うのですが、いかがですか。以下は、そのつもりで書きます。 入力パルスは、割り込みで処理をすればいいと思います。入力パルスが入ったなら、前回のパルスからの時間をメモリのどこかに保存して、表示内容更新要求のフラグを立てるだけでいいと思います。ちなみに、表示内容更新要求のフラグというのは、そういうのがすでにあるわけではありません。メモリのどこかに作ります。前回からの時間というのは、別の、インタバルタイマの割り込みでインクリメントしていけばいいと思います。入力パルスの割り込みでは、それをメモリの別の領域にコピーして、前回からの時間をカウントしているメモリをクリアして、表示内容更新要求のフラグを立てればいいと思います。仮りに、もっと分解能が必要なら、TMR0 を読み出して演算するとか、そもそものインタバルタイマの間隔を考え直すとか、してください。入力パルスにチャタリングが入る可能性があるのなら、チャタリングを除去する工夫も必要です。 一方、メインルーチンでは、表示内容更新要求のフラグが立っていれば、そのフラグをクリアして、前回からのパルスの時間を、表示するための数値に変換 (BCD 変換も含む) し、さらに、数値を、表示するためのセグメントデータに変換して、メモリのどこかに、表示するためのデータとして、書き込むだけです。メインルーチンで、表示するためのルーチンを呼び出す必要はありません。放っておけば、そのうちに勝手に表示してくれます。 また、割り込みルーチン内の処理は、必要最小限にするほうがいいと思います。 こんなイメージですが、どうでしょうか。 なお、ダイレクト・カウンタとしての動作なら問題ないかと思いますが、レシプロカル・カウンタとしての動作なら、止まっているときはパルスが入らないので、最後のパルスが入ったときの値が更新されない可能性があります。たとえば、止まっているのに 1 km/h などと表示されるとか。強制的に、少なくともある時間内で表示内容を更新するような機能を加えたほうがいいかもしれません。 また、レシプロカル・カウンタのときは、逆数を計算する必要がありますが、PIC のように乗除算命令のない CPU で、アセンブラで割算をするのは面倒です。これは、何とか考えてください。さもなければ、割算をしないでテーブル変換にすることもできますし、いっそのこと、ダイレクト・カウンタにする手もあります。 いずれにしろ、インタバルタイマの割り込み間隔を、計算ができるだけ楽になるように選択してください。

motokichi
質問者

補足

ありがとうございます。 >レシプロカル・カウンタの動作に近いと思うのですが、いかがですか。 そうですね、パルス同士の間隔を計測するのでおっしゃるとおりです。 >入力パルスは、割り込みで処理をすればいいと思います。 割り込みでパルスを受け付けるようにして割り込み発生で前回のパルスからの時間をメモリに入れ、表示内容更新要求のフラグを立てて割り込みから復帰するとう事ですね? しかし、「この表示内容更新要求のフラグを立てる」の意味がさっぱり分かりません。 表示内容を更新してくださいと要求するプログラムを書くということですか? それは具体的にはどのようにするのでしょうか? あと、表示部分のプログラムですが、素人なので分かりやすさを優先したいと思います。 なので「000」~「199」までの表示は 例えば タイマAのカウント結果をnとすると n=1なら「199」を表示するダイナミック点灯のルーチンへ n=2なら「198」を表示するダイナミック点灯のルーチンへ みたいな感じでずら~っと200パターン並べてnの値に応じてプログラムでどのルーチンを実行するかを選択するという方法はどうかな?と思います。 プログラム的にはかなり不細工な書き方になると思いますが、この方が素人には理解しやすいと思うのです。 表示部分に関してこのような書き方はいかがでしょうか?素人の私には到底↓のようなデータの書き込みは無理そうなので・・・。 「前回からのパルスの時間を、表示するための数値に変換 (BCD 変換も含む) し、さらに、数値を、表示するためのセグメントデータに変換して、メモリのどこかに、表示するためのデータとして、書き込むだけです」 やっぱりまだまだ苦しみそうですね・・・(笑)。

関連するQ&A

  • PIC CLITEでデジタルカウンタを作りたい

    7セグLEDを使って,押しボタンスイッチの押した回数(0~9)を7セグで表示するプログラムをHitec社のPIC CLiteで作りたいのですが,押しボタンを押しても回数がランダムで表示されてしまいます.どういったところを直したらいいでしょうか? ***プログラム*** ボタンスイッチを押したぶんだけ数値をカウントする main{ while(1){ if(RA0==0){   …押しボタンのポート ++a; { if(a>=10){   …10回押したら0になる a=0; } ↓7セグに出力 RB4=a%2; RB5=(a/2)%2; RB6=(a/4)%2; RB7=a/4; } }

  • PICでスピードメーターを作るためのプログラムについて

    PIC16F84Aを使用してスピードメーターを自作することを目指しているのですが、 まだ初心者なのでどういったプログラムを組めばよいのかが分からないのですが自分なりに方法を考えてみました。 それは、 車速パルス間の時間をタイマーで計測し、その結果に応じてあらかじめ用意した表示用のデータを出力する。 データを出力したら次のパルス間の計測結果が出るまで表示を続け、次の計測結果が出たらそれを新たに出力する。 というものです。 一般的なメーターもこういう原理なのかも知れませんが・・・。 「Timer0」「プリスケーラ」「割り込み」というものを使用したりするようですが、 正直言ってこれらの具体的な使用方法が分かりませんのでとりあえずスピードメーターを簡素化?したものを学習用として作ることにしました。 それは PICのピンにタクトスイッチを取り付け(チャタリング対策もする)、入力用にする(割り込みが出来るRA4でいいのかな?)。 RBのポートを7セグ表示用のICへ繋ぐ。 という回路で、 電源を入れるとタイマーが計測をはじめ、タクトスイッチを押すと押すまでの時間に応じて結果をポートBに出力する。 電源ON→スイッチ1回目→結果を出力すると同時に2回目までの計測を開始→スイッチ2回目→結果を出力すると同時に3回目までの計測を開始・・・と続く。 この回路での計測結果と出力データの関係は以下のようにします。(適当に考えたものですが) 計測結果が 10秒以上・・・00を表示(2桁はダイナミック点灯で表示) 9~10秒・・・01を表示(厳密には9秒以上10秒未満) 8~9秒・・・・02を表示(厳密には8秒以上9秒未満、以下同じ) 7~8秒・・・・03を表示 6~7秒・・・・04を表示 5~6秒・・・・05を表示 4~5秒・・・・06を表示 3~4秒・・・・07を表示 2~3秒・・・・08を表示 1~2秒・・・・09を表示 0~1秒・・・・10を表示 というものを試しに作ってみようと思います。 アセンブリ言語を使ってプログラムを作るのですが、 Timer0やプリスケーラ、割り込みをプログラムの流れの中でどのように利用すればよいでしょうか? 出来たらソースを作って頂いてそれで詳しく説明を書いていただけると非常に助かります。

  • PIC 割り込み

     PIC16f873のRB0ピンにパルス波形が常に送られてきているとして、そのHighのときのパルス幅(時間)をタイマー1で測り、その値を常にグローバル変数のHWidthに代入し更新している処理Aがあるとします。  そして、メインの処理Bを走らせている途中で、Widthの値を使いたいというときは、どのような方法を用いればいいのでしょうか? 素人質問で申し訳ありませんが、よろしくお願いします。できたら、サンプルプログラム的なものをあげていただくとありがたいです。

  • ベンツのスピードメーター

    ちょっと古いベンツのスピードメーターの速度計で、30kmと50km付近にある橙色の表示は何でしょうか? なにかの意味があるのでしょうか? 参考画像 http://www.geocities.jp/carclub_jp/w140s500l3.jpg

  • スピードメーター 校正できますか?

    ダイハツMOVE L152Sです。 私のMOVEのスピードメーターは、他の車と一定の車間で走った時のスピード表示と比べても明らかに高い速度を表示します。 自作のマイコン回路へ、スピードパルスを入力し、パルス間隔を測定し、速度へ換算するプログラムを作成したのですが、60km/h時=637rpmの回転とした時、カーナビが表示する車速と同じ速度を出力します。 これらに対して、スピードメーターは7%程度高い速度を表示します。 体感的にはカーナビも正確な速度を出力しているのではないかと思うのですが確かめる方法がありません。 出来れば、正確な速度を表示させたいのです。 1 そもそも スピードメーターはどのように動いているのでしょうか?  電圧計?(今時考えにくいかな・・)   それともステッピングモータか何か? 2 自分で分解して校正できますか? 校正方法は?   例:針を動かすとか、ポテンショメータみたいなのをまわすとか   3 カーナビや車速信号の他に簡単に正確な速度を知る方法はありますか?

  • PICのプログラム

    PIC16F84Aのサンプルプログラムを見ると  MOVWF 01F PORAT B GOTO MAIN でRB0のLEDのみ点灯になってるんですが、自分的にはB'00000001' のほうがわかりやすいと思いこれに変更したのですが上手く出来ません。どういう感じでプログラミングすればいいんでしょうか? RB0からRB7まで1個づつドライブさせたいです。

  • PIC16F1827のEEPROMへの書込み

    PCM V5.0(PIC用CCS社コンパイラ)を Mplab8.92に組込み、PICkit3を使ってプログラムしています。 PIC16F1827のEEPROMへの書込みがうまくいきません。 RAは入力ポートで固定してあります。 RBは出力ポートでLEDが接続してあります。 テストプログラムは一回のみの動作です。 実機で動作させると RAは固定してあるので当然(4)でLEDが点灯しますが、 実機からCPUを抜き取りMplab上でReadすると EEPROMのアドレス0,1,2は異なるデータであり 動作させるたびに違うデータが書込まれています。 しかし (1) a0=35h (2) a1=a6h (3) a2=93h と定数にすると EEPROMのアドレス0,1,2は正しいデータが 書込まれています。 Q1. a0,a1,a2をポート入力とする場合は CPU自体に何か設定する必要があるのでしょうか? それともプログラムに工夫が必要なのでしょうか? いままで使っていたPIC16F88では このようなことはなかったと思うのですが・・・。 ----- テストプログラム ----- a0 = RA; //(1) write_eeprom (0,a0); a1 = RA; //(2) write_eeprom (1,a1); a2 = RA; //(3) write_eeprom (2,a2); if (a0 == a1 && a1==a2) //(4) RB =255; else RB =0;

  • マイコンPIC16F84Aについて質問です

    MPLAB(秋月)のライターを使用して PIC16F84Aにプログラムを製作したいのですがプログラムの組み方がわかりません 内容は、センサー5v~24vがオンしたらLEDが点灯する回路です。 動作確認をしたところ、センサーはオンオフしているのですが、LEDが点灯しません。 プログラムを組む時に、RB0がオンしたらRA0がオンする為の繋がりがイマイチわかりません。 c言語はわからないので、アセンブル命令で教えていただけないでしょうか? 初心者なので全くわかりませんがお願いします。

  • PICアセンブラ言語で車のスピードをLEDバー表示したいのですが

    現在、自作で車のスピードメーターを製作しています。 車速パルスを利用して、スピード表示を10km/h単位で1つのLEDを点灯して、180kmまでの18個のLEDをバー表示したいのですが、どのようにすればその処理が出来るのか分かりません。 どなたか教えていただけないでしょうか。 宜しくお願い致します。

  • PIC16F819

    PIC16F819のADコンバータを使用しています。 RA0からアナログ信号を入力して、PORTBのそれぞれのピンから1bitずつ(計8bit)のデジタル信号を出力させるためのプログラムを書いてみましたが、まったく動作しません。レジスタの設定なども変えてみましたが動作しませんでした。特にPORTBを全てHighにした場合、なぜかRB6とRB7からの出力を確認することができませんでした。 動作しない原因がまったく分からないので困っています。原因が分かる方がおられましたらご教授お願いします。 #include <pic.h> __CONFIG(DEBUGEN&WDTDIS&LVPDIS&HS&PWRTEN); void init_a2d(void){  ADCON0=0x40;  ADCON1=0x40;  ADON=1; } unsigned char read_a2d(unsigned char channel){  channel&=0x07;  ADCON0&=0xC5;  ADCON0|=(channel<<3);  GODONE=1;  while(GODONE)continue;  return(ADRESH); } void main(void){  unsigned char x1;  init_a2d(); //initialise the A2D module  GIE=0; // we don't want interrupts  TRISB=0x00;     // PORTB will be used in output mode  PORTB=0x00;  x1=read_a2d(1); // sample the analog value on RA0  PORTB=x1; }