質問

現在電子工作をしており、それに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ヶ月ぐらいやってますがうまくいきません。
良ければご回答をお願いします。

通報する

回答 (2件)

訂正

  if ((LEDの状態==0) && (RA1==1)) {//消灯時はRA1は無視

  if ((LEDの状態==1) && (RA1==1)) {//消灯時はRA1は無視
の間違い

>消えている状態でRA1に入力を入れたときなぜか5秒後に点灯してしまいます。
点灯するでしょうね。そういうプログラムになってますから。

>・RA1に入力があったときLEDが点灯しているなら5秒後にLEDを消灯。
>・RA0に入力があったときRB0につないであるLEDが消灯しているならLEDを点灯。
RA1に入力があり、5秒後にLEDを消灯した次の瞬間に、RA0に入力があったら「LEDが消灯しているのでLEDを点灯」する事になります。

こういう場合には、普通
・入力ポートに変化があったら割り込みがかかる
・タイマーにより割り込みがかかる
と言うハード構成にします。

セオリーは「メインでポートを監視する為の無限ループを組まない事」です。

つまり
>どれもすべて動作を終えて、あとはwhile(1)で割り込みを待つだけ
というプログラムにするのが常道なのです。

なので、ネットでさがすと、そういうプログラムばかり見付かる筈です。

以下のような作り方をしましょう。

グローバル変数は「直前のRA0の状態」と「秒カウンタ」と「LEDの状態」を用意します。

int 直前のRA0の状態;
int 秒カウンタ;
int LEDの状態;

main()
{
 ハードの初期化;
 直前のRA0の状態=0;
 秒カウンタ=0;
 LEDの状態=0;
 割り込み許可;
 while(1) {;}
}

void interrupt isr(void)
{
 if (直前のRA0の状態 != 今のRA0) {
  直前のRA0の状態 = 今のRA0;
  if (RA0==1) {
   LED点灯;
   LEDの状態=1;
   秒カウンタ=0;//RA1の入力後の5秒間にRA0が変化したらチャラにする
  } else {
   LED消灯;
   LEDの状態=0;
   秒カウンタ=0;//RA1の入力後の5秒間にRA0が変化したらチャラにする
 }
 if (秒カウンタ==0) {//通常時
  if ((LEDの状態==0) && (RA1==1)) {//消灯時はRA1は無視
   秒カウンタ++;//5秒待ち状態に入る
  }  
 } else {//5秒待ち状態に入っている時
  秒カウンタ++;
  if (秒カウンタ>=500) {//1ミリ秒×500=5秒
   LED消灯;
   LEDの状態=0;//LEDを消す
   秒カウンタ=0;//5秒待ち状態から通常状態に戻る
  }
 }
 割り込みを再許可する
}

割り込み間隔を1ミリ秒にしているのは、チャタリング防止の意味も兼ねていて、エッジノイズやパルスなど、1ミリ秒より短い変化は拾いません。

この回答への補足

お早いご回答ありがとうございます。

>セオリーは「メインでポートを監視する為の無限ループを組まない事」です。

>つまり
>>どれもすべて動作を終えて、あとはwhile(1)で割り込みを待つだけ
>というプログラムにするのが常道なのです。
そーだったんですか・・・・。

とりあえず、このプログラムの通りやってみました、が、
なかなかうまくいきません(汗
最初にRA0につながれているスイッチを押したらそのままLEDがつきっぱなしになっちゃって・・・。
スイッチを押している間消えています。
あと割り込みもうまくいかなかったです・・・。
なかなか消えてくれません。

とりあえずプログラムは
#include "pic.h"

int a; //直前のRA0の状態
int cnt; //秒カウンタ
int LED; //LEDの状態

main()
{
/*初期化始まり
 TRISA=0xFF;
 TRISB=0x00;
 PORTA=0x00;
 PORTB=0x00;

 a=0;
 cnt=0;
 LED=0;
*/初期化終わり

 OPTION=0x87; //割り込みの設定
 TMR0=0x00;
 T0IF=0;
 T0IE=1; //割り込み許可
 GIE=1; //全体割り込み許可
 while(1) {;}
}

void interrupt isr(void)
{
 if (a != RA0) {
  a = RA0;
  if (RA0==1) {
   RB0=0;
   LED=1;
   cnt=0; //RA1の入力後の5秒間にRA0が変化したらチャラにする
  } else {
   RB0=1;
   LED=0;
   cnt=0; //RA1の入力後の5秒間にRA0が変化したらチャラにする
  }
 } //※1
 if (cnt==0) { //通常時
  if ((LED==1) && (RA1==1)) { //消灯時はRA1は無視
   cnt++; //5秒待ち状態に入る
  }
 } else { //5秒待ち状態に入っている時
  cnt++;
  if (cnt>=500) { //1ミリ秒×500=5秒
   RB0=1;
   LED=0; //LEDを消す
   cnt=0; //5秒待ち状態から通常状態に戻る
  }
 }
 T0IE=1; //割り込みを再許可する
 GIE=1;
}

※1…カッコが1つ足りなかったのでおそらくここだと思います。

という感じになっています。

このQ&Aは役に立ちましたか?1 件

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

新しく質問する

注目の記事

おしトピにAndroid版アプリが登場

話題のトピックにさくっとコメントできる「おしトピ」に Android版アプリが登場! もっと身近に使いやすくなりました。
今ならダウンロードで話題の掃除ロボットや全天球カメラが 当たるプレゼントキャンペーンも実施中。


新しく質問する

このカテゴリの人気Q&Aランキング

毎日見よう!教えて!gooトゥディ