PIC16F726を使った割込み処理時のLED点灯について

このQ&Aのポイント
  • PIC16F726を使用して割込み処理を行ってLEDの点灯を行うプログラムを作成しましたが、正常に動作しない現象が発生しています。
  • 割込み処理のIF文を変更した場合、LEDの点灯が行われません。設定の間違いではないかと思われますが、コンパイラのバグの可能性も考えられます。
  • 使用環境はMPLAB IDE v8.30とHI-TECH C v9.71aです。同様の現象について詳しい方のご意見をお待ちしています。
回答を見る
  • ベストアンサー

コンパイラのバグ?

コンパイラのバグ? 現在、PIC16F726を用いて各モジュールのテストをしています。 割込み処理を行ってLEDの点灯を行う下記のようなプログラムを作ったのですが、正常に動作し無い時があります。 void interrupt isr(void) { if(TMR2IF && TMR2IE){ //正常に動作する方 ; } // if(TMR2IE && TMR2IF){ //異常な動作を起こす方 // ; // } if(T0IE && T0IF){ PORTA = 0xf ; //LED点灯 while(1) ; T0IF = 0 ; } } 上記のとおり上のIF文で動作させた時はLEDはちゃんと点灯するのですが、下のIF文で動作させるとLEDが点灯しません。 割込み自体は発生しているようなので設定が間違えているということは無いようなので、コンパイラのバグなんじゃないかと思っています。 環境は MPLAB IDE v8.30 HI-TECH C v9.71a を使っています。  どなたかこの様な現象についてご存知の方はいらっしゃらないでしょうか。 よろしくお願いします。

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

  • ベストアンサー
  • bug_bug
  • ベストアンサー率78% (36/46)
回答No.3

アセンブルされたコードを読む限り, コンパイラのバグで無いコトが分かります. タイマ割り込みのみの利用であれば, MPLABのデバッガをシュミレータに設定し, アセンブラレベルでステップ実行してPC(プログラムカウンタ)が期待の動作をしているかを確認すれば10分程度で原因の特定が可能かと思います. 気になるポイントとしてはコード全体のボリュームが不明ですが, 関数ネストが深くなっていませんか? ほとんどのPIC16Fはハードウェアスタックが8層しかないので, 一般的に割り込みブランチ時のコールなども含めたワーストでの試算が必要です.

t_and_d
質問者

お礼

返事が遅くなり申し訳ありません。 その後、ステップ実行を行って原因を探って見たところ どうもPORTレジスタを触るべきところでTRISレジスタを触っているようです。 試しにコンパイラのVER下げて、v9.65をインストールして使用してみたところ正常に動作したので、 やはり何かしらのバグなんじゃないかと思います。 とりあえずメーカに連絡してみようと思います。 どうもありがとうございました。

その他の回答 (2)

  • BuriBuri4
  • ベストアンサー率28% (150/525)
回答No.2

C/C++、Javaでは && 条件で連結した場合、条件が非成立になった段階でテストが打ち切られ以降の条件はテストされません。 TMR2IE && TMR2IF の場合、TMR2IEがfalseであればTMR2IFはテストされません。 正常動作の為にTMR2IFがテストされる必要がある…って事は無いですか?

t_and_d
質問者

補足

回答ありがとうございます。 >TMR2IE && TMR2IF の場合、TMR2IEがfalseであればTMR2IFはテストされません。 >正常動作の為にTMR2IFがテストされる必要がある…って事は無いですか? これに関しては今のところそれらしい記述は発見できていません。 テストの順番はデータシートに書いてあった例を真似しています。 下に書いたのがその内容です。 void interrupt tc_int(void) {   if (T0IE && T0IF) {    T0IF=0;    ++tick_count;   } }

  • salsberry
  • ベストアンサー率69% (495/711)
回答No.1

コンパイラのバグである可能性はありますが、断定はできません。TMR2IEやTMR2IFが何らかの副作用を持つマクロだったりすれば、その評価順で結果が変わることもあり得ます。 TMR2IEおよびTMR2IFの定義と、コンパイラが出力したコード (正常・異常の両方) を示してください。

t_and_d
質問者

お礼

回答ありがとうございます。 T0IE、T0IF、TMR2IE、TMR2IFはコンパイラが用意していたヘッダーファイルに定義されていたもので、内容は下記のとおりです。 volatile bit T0IE @ ((unsigned)&INTCON*8)+5; volatile bit T0IF @ ((unsigned)&INTCON*8)+2; volatile bit TMR2IE @ ((unsigned)&PIE1*8)+1; volatile bit TMR2IF @ ((unsigned)&PIR1*8)+1; アセンブラコードはこんな感じです if(TMR2IF && TMR2IE){ //正常に動作する方 08A 1283 BCF 0x3, 0x5 08B 1303 BCF 0x3, 0x6 08C 1C8C BTFSS 0xc, 0x1 08D 288F GOTO 0x8f 08E 2890 GOTO 0x90 08F 2896 GOTO 0x96 090 1683 BSF 0x3, 0x5 091 1303 BCF 0x3, 0x6 092 1C8C BTFSS 0xc, 0x1 093 2895 GOTO 0x95 094 2896 GOTO 0x96 095 2896 GOTO 0x96 if(TMR2IE && TMR2IF){ //異常な動作を起こす方 08A 1683 BSF 0x3, 0x5 08B 1303 BCF 0x3, 0x6 08C 1C8C BTFSS 0xc, 0x1 08D 288F GOTO 0x8f 08E 2890 GOTO 0x90 08F 2896 GOTO 0x96 090 1283 BCF 0x3, 0x5 091 1303 BCF 0x3, 0x6 092 1C8C BTFSS 0xc, 0x1 093 2895 GOTO 0x95 094 2896 GOTO 0x96 095 2896 GOTO 0x96

関連するQ&A

  • PICマイコンでGIEビットが1に出来ません。(コンパイラのバグ?)

    質問は初めてです。 GIEビットが1にセット出来ません。 デバッグでは、 GIE = 1; の文が無視され飛び越えます。 デバッグのwatchで監視してもセットされないのが確認出来ます。 マイコンに書き込んで実行させても割り込みが発生してないのが分かります。 環境はMAPLAB IED v8.46 と HI-TECH PICC の無料版?です。 ↓プログラム全てを書くとやたら長いのでIOなどの設定している関数だけ表示します↓ void Ioport(){ PORTA = 0x00; //ポートA初期化 PORTB = 0x00; //ポートB初期化 PORTC = 0x00; //ポートC初期化 TMR0 = 0x00; //タイマ0初期化 OSCCON = 0x60; //外部クロック20MHz使用 OSCTUNE = 0x00; //動作クロックのチューン無し CM1CON0 = 0x00; //コンパレータ無効でデジタルIOモード可能 CM2CON0 = 0x00; ANSEL = 0x00; //デジタルIOモード ANSELH = 0x00; OPTION = 0x08; //RBプルアップ有効、TMR0を命令クロック、 //プリスケーラをTMR0に使わない T0IF = 0; //フラグ タイマ0初期化 T0IE = 1; //割り込みタイマ0可能 GIE = 1; //割り込み全体可能(ココが飛ばされます) TRISA = 0b11000000; //出力:0~4LED7セグメントのブロック用5つ WPUB = 0b11100111; //0~2プルアップ設定 3赤外線受信4赤外線送信 TRISB = 0b11101111; //0~2ボタン3つ 出力:4赤外線送信 TRISC = 0b00000000; //0~7LED7セグメントのパーツ用8つ //GIE = 1; ココに書くとコンパイラがエラーを起こします。 } void main(void){ Ioport();     //GIE = 1; ココに書くとセットしてくれて正常に動作します。 } 他に GIE = 1; を書く場所によっては、 Ioport()関数の最後に書くと、 67.23 ";" expected 71.1 undefined identifier "portBRead" 77.9 void function can't return a value 81.9 void function can't return a value 85.9 void function can't return a value 88.9 void function can't return a value 91.9 void function can't return a value と、的外れ的なコンパイルエラーが出ます。 そして、 main()関数のIoport()関数の後に書くと、 何故か正常動作し実際に書き込んでも正常に動作します。 後 書く順番によっては T0IF = 0; GIE = 1; T0IE = 1; と書くとGIEビットは1にセットされるが、T0IEビットは無視され飛び越えます。 新規projectで再度試しましたが同じでした。 これは、コンパイラのバグなのでしょうか? 解決策の回答をお願いします。

  • 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ヶ月ぐらいやってますがうまくいきません。 良ければご回答をお願いします。

  • コンパイラのバグ?それとも

    下のようなコードを書いて、たとえば java PossibleCompilerMalfunction Hello のように実行すると、 Hello と表示されることを期待していたのですが、 null と表示されてしまいます。 (JDK1.5を使っています) final String t = args[0]; の部分を final String t = "Hello"; のように書き換えると、 Hello と表示されます。 つまり、コンパイル時に「t」の値が決まっていなければ nullになってしまうようです。 これってコンパイラのバグでしょうか。 あるいは私の考えに間違いがあるのでしたら、 指摘していただけるとありがたいです。 public class PossibleCompilerMalfunction { public static void main(String[] args) { final String t = args[0]; MyClass mc = new MyClass() { void foo() { System.out.println(t); } }; } static abstract class MyClass { MyClass() { foo(); } abstract void foo(); } }

    • ベストアンサー
    • Java
  • 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 タイマー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; } } }

  • 割り込みのカウントの仕方

    c言語、PICともに素人です。 あるサイトのプログラムで、割り込みを使いLEDを点滅させるというものがありました。 割り込み時毎にLEDへの出力を反転させているだけです。 しかし、これだとLEDの点滅が速いのでもう少し遅くしようと、割り込み10回で出力を反転させるようなプログラムを組みました。 #include "pic.h" #include "delay.h" __CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & CP_OFF); int a; void main(void) {  GIE = 1;  T0IE = 0;  T0CS = 0;  PSA = 0;  OPTION_REG |= 0x07;  TMR0 = 0x00;  TRISA = 0x00;  TRISB = 0x00;  a = 0;  T0IE = 1;  while(1); } void interrupt peko(void) {  if(T0IF)  {   if(a==10)   {    T0IF = 0;    PORTA ^= 0xff;    PORTB ^= 0xff;    a=0;   }   else   {    a++;   }   return;  } } aという変数をおいて、最初a=0にしておきます。 割り込みが発生するたびにaに+1していき、aが10に達した時処理をし、aを0に戻す。 これで点滅速度が1/10ぐらいになるだろうと思ったのですが、全く変わりません。 点滅はします。 一体何が違うのでしょうか。 ご教授お願いします。

  • 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 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としているので) 二週間粘りましたが、まったく解決できず困っています。 何がいけないのでしょうか。 ご教授お願いします。

  • x86用Sun Studio12におけるコンパイラのバグでしょうか?

    今、x86用Solaris10にStudio12をインストールして、C++のプログラムを作ったのですが、仮想継承を定義すると正常な動作をしません。 調べたところ、どうやら基底クラスから継承している関数のポインタが基底クラスとそれを呼び出す派生クラスでずれてしまっていることが原因のようでした。 試しにsparc用Solaris10+Studio12でも同じプログラムを動作させ、調査したところ、こちらは上述の現象もなく、正常に動作しています。 これはx86用Studio12についているコンパイラのバグなのでしょうか? また、サポート契約なしに、このバグ報告をSunに行う方法がありましたら教えてください(サイト(http://jp.sun.com/)を見ましたが該当事象に対するパッチ及びバグ報告方法について記載が見つかりませんでした。 どなたかご教示いただけないでしょうか。

  • CCSコンパイラにてLED点灯プログラムが作成したい

    タイトルにもあるようにCCSコンパイラにてLED点灯プログラムを作成したいのですが、プログラムが上手く組めません。 ハードウェアとしては、PORT_A0にスイッチを接続。 PORT_B0にLEDを接続。 PICは16F873を使用。 動作は、電源を入れた状態でLEDは消灯している状態。 スイッチを1度押すとLEDは点灯(スイッチはモメンタリーを使用) スイッチを離してもLEDは点灯したまま。 もう一度スイッチを押すとLEDは消灯。 これらの動作を繰り返すプログラムを割り込みを使用せずに作成したいのですが、上手くできません。 void main() 以降の{}の中がわかりませんので、 もし宜しければ、教えてください。 #include <16f873.h> #ZERO_RAM #define setup_adc_ports(NO_ANALOG) #use delay(clock = 20000000) void main() { }