• 締切済み

PICでタイマー割込み(mikroC Vr8.2)

再三お世話になります。大概の問題もこちらで、 解決できて来ましたが、流石に今回はそうも行かないのではと 覚悟しております。 タイトルにありますPICと言えば、CCS社のコンパイラーが 王道と聞いておりますが、素人の浅はかで、 マイナーな方を選択した為、 お手上げ状態に陥っています。 質問の概要はサーボモータの制御信号生成が最終目的です。 まずその基本となる、前段部分として、一定巾周期のパルス毎に、 制御パルスを送り、希望通りの信号をLEDの点滅で確認出来るかと したものです。内容は(PIC16F887,8MHZ内部クロック使用、 1:8プリスケール、TIMER1とのコンペアマッチ割込みと、 TIMER0の割込みの2つのタイマー使用)TIMER1からは、 割り込み発生後、1秒毎にPORTB-1を点灯する信号を出し、 もう一方TIMER0から、0.5秒ごとにPORTB-1を消灯させる。 と言うものです。 後で気づきましたが、この時間設定では正確なものなら、 まず1秒後に点灯、次の1秒までの間に、もう一方で 0.5秒毎に消灯信号が出ているため、1秒後には お互い打ち消し合って本来ずっと消灯する 結果になるはずですが、実験では、0.1sec~0.5sec間隔の 点滅が、ある周期ごとに繰り返されます。 両方同時に割り込み処理が働き、命令サイクルのずれから、 点滅現象になるのではと推測します。 希望として、1秒の割込みの後に、 0.5秒の割込みが来るようにしたいのですが、 思うようになりません。 そこで、そのソースコードを記述しましたので 稀少mikroCをご使用の方に 検証とご教示が叶えられれば、最高に幸せです。 何卒宜しくお願いいたします。             記 unsigned count,count1 = 0; void interrupt() { //timer1 interrupt if(PIR1.CCP1IF == F) { PIR1.CCP1IF = 0; count++; if(count == 5) { PORTB.F1 = 1; count = 0; } } //timer0 interrupt if(INTCON.TMR0IF == 1) { INTCON.TMR0IF = 0; TMR0 = 216; count1++; if(count1 == 100) { PORTB.F1 = 0; count1 = 0; } } } void main() { ANSEL = 0; ANSELH = 0; TRISB = 0; PORTB = 0; PIE1.CCP1IE = 1; PIR1.CCP1IF = 0; CCP1CON = 0x0B; CCPR1L = 0x50; CCPR1H = 0xC3; T1CON = 0x31; OPTION_REG = 0x87; TMR0 = 216; INTCON = 0xA0; INTCON.PEIE = 1; INTCON.GIE = 1; while(1){} } 以上です。

  • kodoku
  • お礼率80% (101/125)

みんなの回答

  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.2

ANo.1です。趣旨は分かりました。PICは詳しくないので具体的なコードは書けませんが、基本的なやり方を答えます。 やり方は2つです。 ・タイマー1つで行う方法 タイマを0.5msインターバルで使って、40回(20ms)に一回ON指示、その2回(1ms)、3回(1.5ms)あるいは4回(2ms)後にOFF指示をします。 タイマをインターバルにするには割込みハンドラの最初で割り込みを再設定します。なお、設定の関係で正確な0.5msが出せなくて20ms周期の精度が悪いということなら、再設定ごとにカウントを補正して対応します。 例えば4.9msか5.3msしか設定できないなら、再設定ごとに5.3, 4.9, 4.9, 4.9のシーケンスで設定します。 注意は、一回のタイマハンドラ処理が0.5msを超えるとこの方法では破綻する点です。 ・タイマー2つで行う方法 タイマ0は20msインターバルで使い、タイマ1は1ms、1.5msあるいは2msのアラームで使います。 初めにタイマ0を設定・起動し、ハンドラではタイマ0アップならタイマ0の再設定(インターバル利用の為)、ON指示をしてタイマ1を設定・起動します。タイマ1アップなら(タイマ1は再設定せずに)OFF指示だけします。 サーボモータの代わりにLEDを使って確認するにしても、基本的な制御を同じにしないと検証にならないと思います。1sと0.5sじゃなく上記のタイミングのままでやってみた方が良いでしょう。パルスは見えなくても1ms、1.5ms、2msで明るさが変わることで分かると思います。

  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.1

本当にしたいことの趣旨が分からないので本当の解決になるか分かりませんが、2つの周期が連動する必要があるなら2つのタイマーを使うのではなく1つのタイマーで駆動することで解決すると思います。 質問の例では0.5秒ごとタイマー割込みを設定して、1秒ごとの処理は2回に一回、0.5秒ごとの処理は毎回実行すれば良いでしょう。

kodoku
質問者

補足

早速、お目に留めていただき、回答ありがとうごさいます。 本題の趣旨が伝わりにくかった事の不手際、誠に申し訳ございません。 このソースコードは質問中にもありますが、サーボモータを制御 するため、異なる2つのパルス出力をLEDで目視確認しようとした ものです。一般的にサーボモータの回転角を変えるには、 メーカー製品によっても若干異なりますが、 規則正しい20msec周期毎に1msec・1.5msec・2msecの パルスを送ることで、それぞれのパルスに応じて、位置角度が 右、中央、左と変化することは、一般的知れてます。実験では、 実際に20msecに対して1msecや2msecのパルス信号を目視確認するには 困難です。そこでタイマー割り込みによる動作確認が目視出来る様に 設問中では、20msecの部分を1秒に充当させ、1msec~2msecに該当する 位置パルスとして0.5秒に置き換えて現したものです。 正確なパルスを得、それぞれが干渉し合わない様に する為にも2つのタイマー使用が理想かと思われます。 ですが、2つのタイマー割り込みを別々にずらして使用する為の コード記述が分かっておりません!  また、実験成果を見るためにも、1秒と0.5秒の時間組合せも マズイかとも、考えているところでありますが、 要するに、1秒のタイマー割込み終了後、0.5秒のタイマー割込みを 発生させ、その結果を1つのPORTに出力するコード構成が知り得たくて ご教示願い出た次第でございます。

関連するQ&A

  • picのタイマ1発振開始時間に関して

    マイコン Pic16F1939を使用して回路を組み、タイマ1を外部に取り付けた水晶で 動作させています(pic自体は内部オシレータで8MHzで動作させ、Timer1は正確な 1秒を取得するために使用しています) 使用している水晶は32768Hzの時計用のものです。 タイマ1が0.5秒ごとにオーバーフローするように設定し、割込みの関数で液晶の 点滅処理をおこなっています。 水晶の両端はそれぞれコンデンサが添付画像のような接続でつながっています。 また、関連部分のプログラムの抜き出しは以下のようになっています。 // 割込み処理 static void interrupt isr(void) { if (PIR1bits.TMR1IF) { // 32Khz水晶 割込み Int_Timer1(); } ~ 省略 ~ } // タイマー1割り込み(32khz水晶) : 0.5秒ごと void Int_Timer1(void) { PIR1bits.TMR1IF = 0; // 次の割り込み許可のためクリア // 0.5秒で次の割り込みが発生するように設定 TMR1H = 0b11000000; TMR1L = 0b00000000;     ~ 点滅処理 ~     ~省略~ return; } そして以下の初期設定用関数 InitTimer1()と InitInterrupt()を main()の始めに呼んでいます。 // Timer1 setting 32kHz , external crystal void InitTimer1(void) { T1CONbits.TMR1CS1 = 1; T1CONbits.TMR1CS0 = 0; T1CONbits.T1CKPS1 = 0; T1CONbits.T1CKPS0 = 0; T1CONbits.nT1SYNC = 1; T1CONbits.T1OSCEN = 1; T1CONbits.TMR1ON = 1; } // 割込み初期化 void InitInterrupt(void) { PIE1bits.TMR1IE=1; // enable timer 1 interrupt INTCONbits.PEIE=1; INTCONbits.GIE=1; } 質問なのですが、実際に液晶が点滅するまでに2秒ほどかかっています。 どこかのホームページでタイマ1の水晶の発振が安定するまでに 数msecかかるというような情報が書いてあったので、ずいぶん 遅いなと感じ2つのコンデンサの容量を10pF~200pFくらいのあいだで色々 変更して試しているのですが、2秒より早く点滅開始となることはありませんでした。 これは、上記プログラムの問題なのでしょうか? それとも2秒ほどかかって発振するのは仕方ない(Picの仕様)なのでしょうか? どなたかご存知の方いらっしゃいましたらご回答をお待ちしております。

  • 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); }

  • PIC 16F54 でTMR0割り込みを使いたい。

    最近PICによる電子工作を学び始めた初心者です。 値段が安いことにひかれて 16F54 を使っていろいろ学んでいこうと思ったのですが、TMR0割り込みを使ったプログラムを組もうとしたところ、行き詰まってしまいました。 他の 16F84A やその他のネットで紹介されている PIC の場合、INTCONレジスタのT0IEをセットしたり、T0IFをクリアにしたり、RETFIEで元の位置に戻ったりすると思うのですが、16F54にはINTCONレジスタも RETFIE命令もありません。 試しに、MPLABでINTCONレジスタの設定は無しにして、RETFIE命令は書き込んでアッセンブルしてみたらRETFIE命令に警告が出たものの、どうにか成功しました。 そこで試しにデバックしてみると、T0IEをセットしていないので当然なのですが、TMR0はカウントされるものの、割り込みは発生しませんでした。16F84Aや16F88等のPICも数百円で買えるので素直にこれらをチョイスすれば良いのでしょうが、百円を切る低コストの16F54に魅力を感じるし、何より疑問を解決しないまま、財力に任せて解決とすることに抵抗があります。 どなたかこんな私を助けてください。

  • 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; } } }

  • PIC16F627Aを低電圧で動かすには

    PIC16F627Aです 電池で駆動するプログラムを書いていてうまく動かないので 5V安定化電源につないだら動きました。 確かめるために BポーがをHIにするところでストップするようにして確かめました。 4.4Vでは動作しません。5Vでは動作します。 プログラムは下記です。 このPICは3Vから動作すると思いますが低電圧で 動かすために特別な設定が必要なのでしょうか。 あるいは小生の設定に問題があるのでしょうか。 ご教授ください。   TRISA = 0xFF;   TRISB = 0x01; CCP1CON = 0x0C; PR2 = 0x19; CCPR1L = 0x0C; CCP1CON = PWM_STOP;   T2CON = 0x0C; T1CON = 0x01; TMR1L = 0; TMR1H = 0; TMR1IF = 0; TMR1IE = 1; PORTA = 0x00; PORTB = 0xFF;   ここで4.4V(電池)ではPORTB がHIになりません。   5V電源ではHIになります。   電圧チェックおよびダイオード発光で確認しました while(1) {;}; 以下省略

  • 2度目の投稿となります。

    2度目の投稿となります。 現在、社員研修でPIC18F2550を使ったプログラミングを行っているのですが、下記内容についてうまく動作しません。 大変恐縮ですが、原因についてアドバイス頂けますと幸いです。 作成環境はMPLAB V8.36、MPLAB C18コンパイラV3.33 です。 <質問内容> ◎タイマ1がうまく動作しない。 やりたい事は、  (1)タイマ0(8bit)を使い割り込みを発生させ、ポートから信号ON/OFF(PWM信号を出したい)。  (2)タイマ1(16bit)を使いCCP1/2のコンペアマッチ割り込みを行ない、CCP1ポートからPWM信号ON/OFF(サーボモータの動作用PWM信号を出したい)。 (1),(2)を同時進行で動作させたい、というものです。 シミュレーションで確認したところ、タイマ0/1のカウントアップ動作自体は確認できているのですが、タイマ1が8bitのところでオーバーフロー?して、タイマ0と同時に0にリセットされてしまいます。 以下に作成コードを掲載します。 --【以下、コード抜粋】-- //===《初期設定》=== //---<ヘッダーファイル>--- #include<p18f2550.h> //---<コンフィグレーション>--- //---<関数宣言>--- //---<割り込みの定義関連>--- //===《動作プログラム》=== //---<メイン関数>--- void main() { ioport_settei(); //サブルーチン「ioport_settei」実行(入出力ポート初期設定) interrupt_settei(); //サブルーチン「interrupt_settei」実行(割り込み初期設定) tmr_ccp_settei(); //サブルーチン「tmr_ccp_settei」実行(タイマ&CCPモード初期設定) while(1) //繰り返し(ずっと繰り返す) { } } //---<サブルーチン>--- void ioport_settei(void) //[入出力ポート初期設定] {省略} void interrupt_settei(void) //[割り込み初期設定] { INTCONbits.GIE = 1; //グローバル割り込み設定:許可 INTCONbits.PEIE = 1; //周辺割り込み設定:許可 INTCONbits.TMR0IE = 1; //タイマ0割り込み設定:許可 PIE1bits.TMR1IE = 1; //タイマ1割り込み設定:許可 PIE1bits.CCP1IE = 1; //CCP1割り込み設定:許可 PIE2bits.CCP2IE = 1; //CCP2割り込み設定:許可 } void tmr_ccp_settei(void) //[タイマ&CCPモード初期設定] { TMR0H = 0; TMR0L = 0; TMR1H = 0; TMR1L = 0; T0CON = 0b11001000; //タイマ0設定(有効,8bit,内部クロック,プリ1倍) T1CON = 0b10000001; //タイマ1設定(有効,16bit,内部クロック,プリ1倍) CCP1CON = 0b00001001; //CCP1設定(Compare mode,RC2=0,割り込み発生) CCP2CON = 0b00001011; //CCP2設定(Compare mode,スペシャルイベントトリガ,割り込み発生) CCPR1 = 3750; //CCP1 Duty値初期設定(PWM(ON時間)=1.5ms…ニュートラル位置) CCPR2 = 50000; //CCP2 Duty値初期設定(PWM(周期)=20ms) } //---<割り込み処理関数>--- #pragma code void isr(void) { if(INTCONbits.TMR0IF == 1) { INTCONbits.TMR0IF = 0; } } となります。 大変恐縮ですが、原因が判る方がいらっしゃいましたら、ご教示のほどよろしくお願い致します。

  • PICの割り込み機能

    現在電子工作をしており、それにPIC16F84Aを使っています。 正直アセンブリはよくわからないので、C言語でプログラムを作っています。 コンパイラはPICCLITEで、LEDの点灯・消灯に関するプログラムです。 機能としては ・RA0に入力があったときRB0につないであるLEDが消灯しているならLEDを点灯。 ・RA0に入力があったときRB0につないであるLEDが点灯しているならLEDを消灯。 ・RA1に入力があったときLEDが点灯しているなら5秒後にLEDを消灯。 というものを目指しています。 1つ目、2つ目の項目はif文で簡単に実現できましたが、割り込みがうまくいかず、 消えている状態でRA1に入力を入れたときなぜか5秒後に点灯してしまいます。 だからRB0の出力を逆にしてみたんですがうまくいかず・・・。 ハード的には、RB0には反対側から5Vをかけ、 RB0=0の時は点灯 RB0=1の時は消灯 としています。 またセラロックは10MHzのものを使用しています。 現在のプログラムとしては #include "pic.h" #define XTAL_FREQ 10MHZ #define MHZ*1000 void DelayUs(unsigned char cnt){ //時間待ち関数  unsigned char i;  i=(cnt)/(12MHZ/(XTAL_FREQ))|1;  while(--i!=0) continue; } void DelayMs(unsigned int cnt){ //時間待ち関数  unsigned char i;  do{   i=4;   do{    DelayUs(250);   }while(--i);  }while(--cnt); } int cnt,SW; //SWが0なら消灯 //SWが1なら点灯 void interrupt isr(void){ //割り込み関数  if(T0IF==1){   T0IF=0;   cnt--;  }  if(cnt==0){   RB0=1; //消灯   SW=0;   cnt=190;   T0IE=0;   GIE=0;  } } main() {  TRISA=0xFF; //入出力設定  TRISB=0x00;  PORTA=0x00;  PORTB=0x00;  SW=0;  OPTION=0x87; //プリスケーラの設定  TMR0=0x00;  T0IF=0;  T0IE=1;  cnt=190;  while(1){   if(RA0==1){    DelayMs(60); //チャタリング防止    if(RA0==1){     if(SW==0){      RB0=0;      SW=1;     }    else{     RB0=1;     SW=0;    }   }  }  if(RA1==1){   DelayMs(60); //チャタリング防止    if(RA1==1 && SW==1){     TMR0=0;     T0IF=0;     T0IE=1; //割り込み許可     GIE=1; //全体割り込み許可    }   }  } } インターネット上での割り込みのプログラムをいくつか見てみたのですが、 どれもすべて動作を終えて、あとはwhile(1)で割り込みを待つだけ というプログラムばかりでした。 僕のは基本的にRA0の入力によってLEDを点灯・消灯させつつ RA1の入力で割り込みを開始。 5秒後に消えたら割り込みを禁止する。 という仕様にしたいのですが・・・・・・。 1ヶ月ぐらいやってますがうまくいきません。 良ければご回答をお願いします。

  • picタイマ0割り込みについて

    タイマ0割り込みについて教えて下さい。 解説書などに、割り込みルーチンの最初の部分で (1)割り込みフラグ(TMR0IF)を消す (2)TMR0を再設定する と書かれていますが、なぜ(2)を割り込みルーチンの最初で行うのでしょう? これでは、 ・1秒ごとに割り込みを発生させたい ・割り込みルーチンの作業時間は0.5秒 だとすると、結果的に割り込み発生は0.5秒ごとになってしまいます。 TMR0再設定は割り込みを抜ける時(retfie の直前)に行えば、ほぼ希望通りの間隔で、割り込みを発生させられると思うのですが、それはルール違反なのでしょうか?

  • PIC アセンブラ TMR0の使い方がいまいちわかりません。

    *文字数制限の為コメントや繰り返し処理プログラムの一部を省きました。解りにくくてすみません。ココに載せてくれとかあったらそっちに全部載せます。 目標としてはPICでデジタル時計を作りたいのですが、手始めに正確な1秒を作って7セグを0から9まで表示しそれを繰り返す。と言うものをやってみようと思いプログラムしましたがウンともスンとも言いません。 流れとしては 初期処理 ↓ TMR0割り込みが発生するまで無限ループ ↓ 割り込みが発生したら割り込み回数をカウントし(12,8MHzクロック、プリスケーラを256設定で1250回フラグをカウントすると1秒)1秒間分カウントが終わったら7セグの表示を切り替え無限ループに戻る どの数字まで表示したかは任意のレジスタに1を立てて判断する。PICはPIC16F628AなのでTMR1とかもあるんですが気分的にTMR0だけで時間を作ってみたかったのでTMR1とかは使ってません。で、3回くらいやり直してプログラムを作ったんですが全然動きません。 1、何処が悪いんでしょうか? 2、また、PIC16F628Aでは16番ピンがクロックの入力として使えますが その設定方法があってるかわかりません。 コンフィグ設定で OSCをHSにしてポートの設定でRA7を入力にしておけば良いんでしょうか?プログラム中の記述で合ってますでしょうか? 3,7セグをカウントアップするだけのプログラムなのに こんなに長くなる物なんですか? (プログラムが下手だから?アセンブラだから?) 4、1秒のカウント方法ですがプログラム中の記述で正確に1秒をカウントしてますか?(計算間違ってますでしょうか?) 以下、プログラムになります。 list p=pic16f628a include "p16f628a.inc" __CONFIG _LVP_OFF &_MCLRE_ON &_BODEN_OFF &_PWRTE_ON &_WDT_OFF &_HS_OSC time0 equ d'30' ;time4まで作る tcount equ d'43' count0 equ d'35' ;count7まで作る koko0 equ d'43' koko1 equ d'44' org 0 goto start org 4 goto wari start bcf intcon,gie movlw b'00000111' movwf cmcon bsf status,rp0 movlw b'00000111' movwf option_reg movlw b'10100000' movwf trisa clrf trisb bcf status,rp0 bcf status,z bcf intcon,t0if movlw b'00001000' movwf count0 ;この間に1から6の同じ処理が入ります。 movlw b'00000000' movwf count7 time movlw .30 movwf time0 bsf intcon,gie bsf intcon,t0ie clrf tmr0 roop btfsc tcount,0 call segout swapf count0,0 movwf portb swapf portb,0 movwf count0 ;この間に1から5が入ります swapf count6,0 movwf portb swapf portb,0 movwf count6 goto roop wari bcf intcon,t0ie bcf intcon,t0if incf time0,1 btfss status,z goto modori bcf status,z movlw .255 movwf time0 incf time1,1 bcf status,z goto modori bcf status,z movlw .255 movwf time0 movlw .255 movwf time1 incf time2,1 bcf status,z goto modori bcf status,z movlw .255 movwf time0 movlw .255 movwf time1 movlw .255 movwf time2 incf time3,1 bcf status,z goto modori bcf status,z movlw .255 movwf time0 movlw .255 movwf time1 movlw .255 movwf time2 movlw .255 movwf time3 incf time4,1 bcf status,z goto modori bcf status,z movlw .30 movwf time0 movlw b'00000001' movwf tcount modori bsf intcon,t0ie retfie segout clrf tcount btfss koko0,0 goto seg1 ;この中間にseg2からseg6が入ります。 btfss koko0,7 goto seg8 btfss koko1,0 goto seg9 nop goto seg0 seg1 bsfkoko0,0 movlw b'00000010' movwf count0 movlw b'00000100' movwf count1 movlw b'00000000' movwf count2 movlw b'00000000' movwf count3 movlw b'00000000' movwf count4 movlw b'00000000' movwf count5 movlw b'00000000' movwf count6 movlw b'00000000' movwf count7 nop return ;この中間にseg2からseg9が入ります seg0 clrf koko1 clf koko0 movlw b'00001000' movwf count0 movlw b'00000100' movwf count1 movlw b'00000010' movwf count2 movlw b'00000001' movwf count3 movlw b'10000000' movwf count4 movlw b'01000000' movwf count5 movlw b'00000000' movwf count6 movlw b'00000000' movwf count7 return end

  • PIC Timer0割り込み されない

    12F609でTimer0割り込みが実行されません。 実行されないというか、動作的に割り込みハンドラが呼ばれていない感じです。 以下がプログラムです。 void main(void) //メインプログラム { T0IE = 0; GPIO = 0; T0CS = 0; PSA = 0; PS0 = 1; PS1 = 1; PS2 = 1; TMR0 = 0; TRISIO = 0x00; a = 0; GP4 = 1; T0IE = 1; GIE = 1; while(1) } void interrupt blink(void) //---割り込みハンドラ--- { if(T0IF==1) { T0IF = 0; if(a%15==0) { GP4 ^= 1; a=0; } a++; } } 以上です。 割り込み15回ごとにGP4の出力を反転させるプログラムです。 が、反転されずGP4は1のままになってしまいます。 (初期時にGP4=1としているので) 二週間粘りましたが、まったく解決できず困っています。 何がいけないのでしょうか。 ご教授お願いします。

専門家に質問してみよう