PICで内部タイマーを使わずカウントダウンする方法

このQ&Aのポイント
  • PICのプログラムをアセンブラで組んでいる際に、内部タイマーを使わずに特定の時間をカウントダウンする方法について教えてください。
  • ループを使って特定の時間をカウントダウンする方法について詳しく教えてください。
  • PICの変数が8ビットしかない場合、大きい数字のカウントをするにはどうしたら良いのでしょうか。
回答を見る
  • ベストアンサー

PICで内部タイマーを使わずカウントダウンする方法

こんにちは。 今回、PICのプログラムをアセンブラで組むことになりました。 その中で「100ミリ秒間、あるポートからの入力を監視する」という部分があり、 これを内部タイマーなどは使わずに実装するとします。 自分なりには、 PICのクロック数とループ内のサイクル数で 何回ループを回せばよいのかを予め計算しておいて その回数だけループを回せばよいのかな? と考えました。。。 しかしループ内のサイクルがせいぜい数μSですので、 100mSecとなると10万回単位でループを回さなければなりません。 しかしPICでは変数が8Bitしか無いので255までしかカウントできないと思うのですが、 こういう大きい数字のカウントをしたい場合、どうしたら良いのでしょうか? 宜しくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
noname#252929
noname#252929
回答No.5

他の回答者の回答を見てると、最近はアセンブラ等でソフトを組む人は居ないんだなぁ。と思ってしまいますね。 >「100ミリ秒間、あるポートからの入力を監視する」 とどまっているんじゃなくて、監視し続けなければならないのでしょう。 重い処理なんてはさんだら、性能が落ちちゃいますし、見落としますからね。 ポートの入力は、割り込み信号は上がるのでしょうか?それとも、ポーリングを掛けて見続けていなければならないのでしょうか? これで作り方は変わります。 通常、こういうプログラムの作り方は、一定の処理をダイナミックループで回していて、その中で、各処理を行っていくのが普通です。 なので、ダイナミックループの中にある、サブルーチンの平均所要時間を割り出してやると、ダイナミックループ1回にかかる時間が判ります。 このダイナミックループの中に、カウンタールーチンを作っておいて、何回回ったかを記録してその回数で、時間の経過を測定します。 指定時間内だけポートをチェックするのであれば、そのダイナミックループの中にポートチェックを入れておいて、カウンタールーチンで積算されている内容で、ポートチェックのルーチンに入るのかはいらないのかをすればよいだけです。 割り込み処理があるのなら、カウンタールーチンを、ダイナミックループに入れる必要は無く、割り込み処理の方に入れてやればよいだけです。 当然カウンタールーチンで、割り込みを開放、停止すればそもそもチェックに行く必要もなくなるわけです。 8ビットしかないからと言うのは、他の人も書かれて居る様に、単純に増やせばよいだけの話です。 カウンタ用の1バイトがいっぱいになってたら上位桁用の1バイトにインクリメントしてあげれば、1ビットのカウンタになるでしょう? そんなに難しい話ではないと思います。 nopは、コンパイラによっては、削除されてしまう物もあります。 その辺は仕様書を読まないと判りませんけどね。 nopコードとして入れてくれる物もあるのですけどね。 タイマーなんて持っていないCPUを使う時はこんな方法は良く使って居ましたね。 途中に思い処理が分岐で入ると、そこを通ったか通らなかったかで、タイマーのカウンタの上げ方も変えなければならなかったですからね。 カウンタが足りないだけなら、上の様に増やせばよいだけの話です。

piropiro32
質問者

お礼

皆さん有難うございました。 皆様の仰る通り、気づいてみたら特に難しいものではなかったです。 タイマー的な動作をループのネストで作ると ステップ数を自分で計算しなければいけないので 面倒そうだし精度的にもどうかなと思ったのですが、 目的のものがそれほど精度を要求するものではなかったので、 あとはループの一番内側でポートの状況を毎回見ておく という感じでとりあえず要求を満たすことができました。 ありがとうございました。

その他の回答 (5)

回答No.6

(1) (必要なら割り込み停止) ループ {  ループ {   ループ {    監視処理   }  } } (必要なら割り込み許可) (2) 100ms毎に割り込み初期化 割り込みタイミング合わせ 無限ループ {  監視処理  割り込みがかかっていたら抜ける }

  • Tasuke22
  • ベストアンサー率33% (1799/5383)
回答No.4

ネストで回すのと同じ考え方ですが、アセンブラなので違う書き方をすると、 カウンタのカウンタを作ればいいでしょう。 カウンタが0から255に来たら、一回まわったとして別のカウンタをプラス1して 255になったカウンタは0に戻すわけです。 結局、8bitxnのカウンタを自分で作るわけですね。

  • black2005
  • ベストアンサー率32% (1968/6046)
回答No.3

あ、ネストの字下げtabが消えて見にくくなってしまった・・・

  • black2005
  • ベストアンサー率32% (1968/6046)
回答No.2

ループをネストすれば良いのでは? 例えば下記のようにすると255×255回のループになりますね。 足りなければ更に多重化すれば良いです。 下の場合、iとjはunsignedにすることをお忘れなく・・・ for ( i=0 ; i < 0xff ; ++i ) { for ( j=0 ; j < 0xff ; ++j ) {

  • Cupper-2
  • ベストアンサー率29% (1342/4565)
回答No.1

数ミリ秒かかる一連の命令を必要数回せばいい。 ってか、割り込みが発生したらタイミングがずれるのでそのやり方はお勧めできないのが正直なところなんだけどさ。

piropiro32
質問者

補足

ご返信ありがとうございます。 要するに時間稼ぎのための重い処理を挟む、ってことでしょうか? 例えばNOPを沢山書くとか・・・ウェイトを挟むような? ですがそうするとその時間稼ぎしている間に ポートのチェックが疎かになってしまうと思うのですが、 どうでしょうか?

関連するQ&A

  • PICで周波数測定

    PIC(PIC18F47j53)のCCP(4~7)を使って、80KHzの周波数4Chを10msec毎に計測して、USARTで送信しようとしています。 CCPのタイマーはタイマ1を使い、内部のシステムクロック(12MHz)でカウントさせようとしています。 このような処理は可能でしょうか?

  • PIC タイマー0の使い方

    PIC16F886を触り始めたのですが、タイマー割り込みで苦戦しています。 タイマー割り込みを使ったLEDの点滅の間隔が、自分の思った時間にならないのです。 下に今のプログラムを載せておきます。 私の今の考え方はこうです。 ・内部クロックは4MHzに設定してある ・TMR0のカウントはクロックの1/4らしい→1MHzなので周期は1μsec ・プリスケーラは1:128に設定→128μsecでTMR0がカウントアップ ・TMR0の初期値を61に設定→195回のカウントアップでT0IF=1 ・128μsec*195μsec=2496μsec≒0.025msec←タイマー割り込み ・40回カウントすると1秒 と、1秒ごとにLEDのON,OFFが切り替わるはずだと考えているのですが、書き込んで計測したところ、約0.8秒でon,offを繰り返しています。 私の考え方やプログラムに間違いがあるのでしょうか? もしくはPICがハード的に壊れているのでしょうか?(picに5Vをかけても動かず、mainが実行中に点灯するLED(この時点では点いていない)の端子の両端を指で触ると何故か動き出します。) 以下プログラムです。(注釈などは省いたので見難いかもしれません) #include <stdio.h> #include <stdlib.h> #include <xc.h> #include <pic.h> #pragma config FOSC = INTRC_NOCLKOUT #pragma config WDTE = OFF #pragma config PWRTE = OFF #pragma config MCLRE = OFF #pragma config CP = OFF #pragma config CPD = OFF #pragma config BOREN = ON #pragma config IESO = OFF #pragma config FCMEN = OFF #pragma config LVP = ON void interrupt tc_int(void); volatile unsigned int cnt = 0; volatile unsigned int cnt1 = 0; #define sw RB0 #define led RA0 #define led2 RA1 #define led3 RA2 #define _XTAL_FREQ 4000000 void init(void) //初期設定 { OSCCON=0b01101000; // 内部クロック設定 4MHz TRISA=0b00000000; TRISB=0b00000000; TRISC=0b00000000; ANSEL=0x00; /* 割り込み初期設定 */ GIE = 1; // すべての割り込みを許可 T0IE = 0; // タイマー割り込みを禁止 T0CS = 0; // TIMAR0モジュールをタイマーとして使用 PSA = 0; // プリスケーラをTIMER0モジュール用にセット OPTION_REG |= 0x06; // CPUクロックを128分周 TMR0 = 61; // カウンタ値をリセット T0IE = 1; // タイマー割り込みを許可 T0IF = 0; // 割り込みフラグをクリア } int main(void) { init(); sw=1; led=1; led3=0; cnt1=0; LEDflg=0; while(1) { if(cnt1>=10){ led3=~led3; cnt1=0; } } } void interrupt tc_int(void){ // 割り込みハンドラ if(T0IF == 1){ cnt++; TMR0=61; T0IF = 0; // 割り込みフラグをクリア if(cnt>=40){ cnt=0; cnt1++; led2= ~led2; } } }

  • PICでパルス数をカウントする方法

    PICで不規則な幅のパルス数をカウントする為にはどうのようなプログラムになるのでしょうか? ループで入力ポートを監視するのでは出来ないように思うのですがどのような方法を用いると出来ますでしょうか?

  • 電子工作 PIC PIC16F84A アセンブラ

    PIC16F84Aを使用して1番ピン及び2番ピン及び3番ピンが一瞬でも0Vになり、 5秒経過、6番ピンから3秒間出力、始めに戻る。 こんなようなプログラムを作りたいと思っていますが、 なにぶんPIC初心者なものでどうプログラムしたらよいか全くわかりません。 ピン入力に順序は関係なく全て0Vならカウント開始です。 5秒のカウント精度は低くても問題ありません。 5秒カウント中に1、2、3番ピンのいずれかが一瞬でも5Vになったらカウントを中止し、 始めに戻ります。 5秒カウントの6番ピンのステータスは0Vです。 6番ピン出力中は、1~3番ピンの監視は不要です。 6番ピンからの3秒出力の後は出力をやめ始めに戻ります。 開発言語はアセンブラです。

  • 【PICマイコン】一般製品にPICシリーズが使われてるって本当ですか?

    最近PICをはじめて大分アセンブラもなれてきて楽しめるようになってきました。 それで教えてGOOで色々見てるときにPICシリーズのマイコンは一般製品の中にも組み込まれているって書いてあったんですが本当ですか? 僕の中でPICやAVR等はそれなりにコアな趣味を持つ人たちのおもちゃ的な物だと思ってました。 もし本当に入ってるんだったら具体的にどんな製品にどのマイコン(例PIC16F877A等)が使われてるのか教えてください。凄く興味があります。 また、何処のサイトだったか忘れましたが「これからマイコンをはじめるならAVR!PICをやるメリットなし!」ぐらいの勢いで書いてあったんですがその通りなんでしょうか? もひとつ、、PICの勉強をはじめるときにアセンブラかCかで迷ったんですがアセンブラではじめた方がCPUの構造をより理解しやすいとの事でアセンブラで進めてきたんですが、いまいちその実感がわきません。具体的にどういう所でCPUの構造を理解しやすいのでしょうか? それっぽいなぁと思うのはクロックでタイミングを与え、そのタイミング毎に命令を実行しレジスタのBITで条件判断をしたり計算をしたりしてポートに出力する的な部分でしょうか?そもそもCPUの構造ってどういう事なんでしょうか?何て言うか例えて言うならエクセルは仕事で使うから詳しいけどWindowsの設定は全然解りませんみたいな感じです。 よろしくお願いしますm(_)m

  • PIC10F系で参考プログラムを伝授ください。

    PIC10F系でパルス波形検知の参考プログラムを伝授ください。 マイコン初心者です。 ネットと本を数冊読んで、何とかPICマイコンにアセンブラで書き込み スイッチでLEDをオンーオフするぐらいはできるようになりました。 そこからかなりのステップアップかもしれないのですが、 皆さんのご教授をお願いします。 あるパルス波形のみ検知し それ以外は無視する場合、タイマーとかカウントとか 使用したりするみたいですが、 具体的にはどのようなプログラムになるのでしょうか? 検知したい矩形波形は200Khzでデューティー比20%と仮定し 波形入力中は出力をし 内部クロック4MHzを使用したいです。 なるべく、入力する波形の5カウントぐらいで判別したいです。 参考文献等もございましたら、お願いします。 以上、よろしくお願いします。

  • PICアセンブラ、これって変?

    PIC16F84でのアセンブラなのですが、下記のプログラムで・・・。 MAIN     MOVLW B'00000000'     MOVWF PORTB     BTFSC PORTA,3     GOTO  FINISH     GOTO  MAIN FINISH     MOVLW B'11111111'     MOVWF PORTB     END PortAが入力、Bが出力なのですが、MAINでループしながら待機、 PortAの3bitめがHになったらPortBをすべて立てて終了という感じに なると思いますが、上手くいかないんです。 3bit目にあらかじめ+5Vを印加しておくと、一瞬でPortBがすべて立つのですが、 ループ中にやっても何も変化がありません。 ループしていないか、判定ができていないかのどちらかなのですが・・・。 デバッグしてみても、きちんとループ・判定できているのですが いざ焼いてみると動作しません。わかりますでしょうか。

  • PICのPWMの正しい使い方について教えてください

    PIC12F1822用のPWMの基本動作テストプログラムを作りましたが、PWM出力が意図どおりに得られません。 (XC8のテストプログラムを下に添付。テストパターン1/2の切り替えはコメントアウトをお願いします。  アナライザの出力を画像で添付しました。) テスト目的: タイマー0の周期割り込みに合わせて、PWMのデューティー比(または周期)を変更するプログラム   テストパターン 1 : パルスのデューティー比を変えるテスト 質問1: パルスのデューティー比を変えるテストは、PWM設定の一回おきにCCPからのPWMの出力が出ません テストパターン 2 : パルスの周波数を変えるテスト 質問2: 周波数を変えるテストはOKに見えるものの、1回目のPWMがHighとなるのと、割り込みの11回目、13回目あたりでPWM出力が欠落する 【回答のお願い】 どうも、PWMのレジスタ設定に手順、またはタイミングがあるのではないかと思いますが、原因がわからず困っております。 PICに詳しい方からのご指導をよろしくお願いいたします。                                    K.A. ------------------------------------------------------ /* * File: PIC12F1822 PWC * Author: K.A. * * Created on 2014/07/20 * * タイマー0の周期割り込みに合わせて、PWMのデューティー比(または周期)を変更するプログラム * */ #include <stdio.h> #include <stdlib.h> #include <xc.h> #pragma config FOSC=INTOSC, WDTE=OFF, PWRTE=ON, BOREN=ON, MCLRE=OFF #define _XTAL_FREQ 8000000 // クロック8MHz /* * */ // タイマー割込みの処理 int TMR0_Count = 0; // タイマーの割込み発生回数をカウントする変数 void interrupt Timer0(void) { // タイマー0の割込み発生か? Timer0 は 8bitの オーバーフロー・カウンタ if (TMR0IF == 1) { TMR0_Count++; if (TMR0_Count > 5) { TMR0_Count = 0; if (RA5 == 0) RA5 = 1; else RA5 = 0; // RA5は、動作表示用LED } TMR0IF = 0; // タイマー0割込フラグをリセット } } int main(int argc, char** argv) { unsigned int pulse_width = 5; OSCCON = 0b01110010; // 内部クロックは8MHz ANSELA = 0b00000000; // すべてをデジタルI/Oに割当 TRISA = 0b00001000; // すべてのピンは出力に割当てる(RA3は入力専用) PORTA = 0b00000000; // 出力ピンの初期化(全て'0'にする) RA5 = 0; // 動作確認用LED // Timer0  Timer0 は 8bitの オーバーフロー・カウンタ OPTION_REG = 0b00000001; // 内部クロックでTIMER0を使用、プリスケーラカウント値 1:2 // bit5:0=Fosc/4, bit3:0=PreScaler_ON, bit2-0:PreScaler TMR0 = 0; // タイマー0の初期化 (+2cycle) TMR0IF = 0; // タイマー0割込フラグを0にする TMR0_Count = 0; // 割込み発生の回数カウンターを0にする TMR0IE = 1; // タイマー0割込みを許可する GIE = 1; // 1: 全割込み処理を許可する /* PWM */ TRISA2 = 1; // RA2 出力をサスペンド TMR2IF = 0; // TMR2 フラグをクリア CCP1SEL = 0b0; // CCP1/P1Aの機能をRA2に割り当てる CCP1CON = 0x0C; // PWM モード // Period を 設定する xx ms=((PR2)+1)*4*125ns(8MHz)* PreScaler(x1-x64) PR2 = 127; // 4.096ms (プリスケーラが x64 の場合) T2CKPS0 = 0b1; // プリスケーラ 00:x1, 01:x4, 10:x16, 11:x64 T2CKPS1 = 0b1; // CCPR1L = pulse_width >> 2; // パルス幅上位8bit CCP1CON = ((pulse_width & 0x0003) << 4) | 0x0C; // パルは幅下位2bit TMR2ON = 1; // TMR2 カウント開始 while (TMR2IF == 0) { /** / do nothing /**/ } TRISA2 = 0; // RA2に出力を接続 while (1) { if (TMR0_Count == 0) { /**** テストパターン 1 : パルスのデューティー比を変えるテスト ****/ // パルスのデューティー比を変えるテストは、PWM設定の一回おきにCCPがPWMの出力が出ません。 なぜ? pulse_width = pulse_width + 10; if (pulse_width > 500) pulse_width = 5; /**/ /**** テストパターン 2 : パルスの周波数を変えるテスト **** / // 周波数を変えるテストはOKに見えるが、 // 1回目のPWMがHighとなるのと、割り込みの11回目、13回目あたりでPWM出力が欠落する PR2 = PR2 - 8 ; if (PR2 < 8) PR2 = 127; pulse_width = PR2 ; // Duty 25% に相当 /**/ CCPR1L = pulse_width >> 2; CCP1CON = ((pulse_width & 0x0003) << 4) | 0x0C; TMR0_Count++; // 続けて PWMの設定変更をしないためのフラグ代わり } } return (EXIT_SUCCESS); }

  • タイマーを多用するプログラムに適したCPU

    手元のフローチャートを何かしらのプロセッサに 実装できるか検討しています。通常のANDやORに加えて この制御ルーチンには3秒~40秒程度のタイマー分岐や ループが10ヶ所あります。 PIC、FPGA、H8など候補がありますが、 数少ないカウンタを使ってどう対処すべきか悩んでいて、 叩き台となるプロセッサを決めかねています。 これら以外に最適な何かがあれば採用しても構わないと思います。 PLC(シーケンサ)は今回候補から外していますが どなたか良いプロセッサをご存知でしょうか。

  • PICのクロック周波数の決定は?

    手元に、PIC18F2550を使って周波数をカウントする装置があります。 これの基準クロックに16MHzのクリスタルオシレータが使われているのですが、これの安定性や精度を上げるのはどうすればよいでしょうか。 今使っているのは、16.000と書いてありますが、これを16.000000などというように、精度を上げることは意味がありますでしょうか。 また、そもそもの周波数がPICは48MHzまで対応しているので、水晶の発振周波数を40MHzなどにすることも意味がありますでしょうか? 設計の考え方について、教えていただけませんでしょうか。