質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.93%

LED点滅制御によるカウント不定

解決済

回答 5

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,690

score 3

前提・実現したいこと

初めて質問させて頂きます。
PICの初心者で、様々な所からご教示頂き勉強中です。
よろしくお願いいたします。

PIC16F1503を使用して下記動作のプログラミングを製作しています。
①PB1を押すとLED1が10秒間点滅しBZがON、LED1が点滅中にPB2を押すとキャンセルされ最初に戻る。
②10秒後LED1が消灯、BZがOFF、LED2が点滅
③PB2を押すとすべてキャンセルされ①に戻る

発生している問題・エラーメッセージ

動作はしているが
①PB1を押した後の、10秒カウントが17秒位ある。
②LED2の点滅が不安定で点滅周期が長かったり、短かったりする。
また、PB2を押さない限りLED2はずっと点滅するはずが、途中から点灯に代わってしまう。
③そもそもこのコードは最適なのか?

該当のソースコード

#define _XTAL_FREQ 2000000

void main(void) {
    //マイコン設定
    OSCCON = 0b01100000; //内部クロック周波数を2MHzに設定
    ANSELA = 0b00000000; //PortA全てのピンをデジタルモードに設定
    ANSELC = 0b00000000; //PortC全てのピンをデジタルモードに設定
    TRISA  = 0b00000000; //PortA全てのピンを入力モードに設定
    TRISC  = 0b00000000; //PortC全てのピンを出力モードに設定

//初期処理:電源ON後、全ての出力を一度OFFにする。    
    LATC0=0; //LED1
    LATC1=0; //LED2
    LATC2=0; //BZ

//RA5:PB1、RA4:PB2  
    while(1){
        if(RA5==1){
            int cnt=0; //PB1がONの時、最初にカウンタに0を代入
            while(cnt<10000 && RA4==0){ //カウント値が30秒以下、PB2 OFFの時、下を実行
                LATC2=1; //BZ ON
                if(cnt%500<250)LATC0=1; //LED1 ON
                else LATC0=0; //LED1 OFF
                __delay_ms(1);
                cnt++;
            }            
            while(cnt==10000){ //カウント値が10秒に達したら下を実行
              LATC0=0; //LED1 OFF
              LATC2=0; //BZ OFF
             while(RA4==0){ //PB2を押さない限り下を実行
                if(cnt%1000<500)LATC1=1; //LED2 ON
                else LATC1=0; //LED2 OFF
                __delay_ms(1);
                cnt++;
                }
            }
            LATC0=0; //LED1 OFF
            LATC1=0; //LED2 OFF
            LATC2=0; //BZ OFF
        }
    }
    return;
}

 試したこと

①の10秒カウントについて
・点滅コードが原因かと思い、LED1の点滅をやめて10間点灯に変更すると正常に10後LED2が点滅した。
・点滅コードを

for(timer=0;teimer<10;timer++){
LATC0=1;
__delay_ms(500);
LATC1=0;
__delay_ms(500);

にすると、PB2を押してもキャンセルされない時がある。
②の点滅が点灯に代わってしまう事について
カウント上限?になってしまい、計算結果が真のままになってしまって点灯しっぱなしになっているのが原因かと思い、cnt++の下に
if(cnt==2000){
cnt=0;
}
を追加したが関係なかった。

補足情報(FW/ツールのバージョンなど)

MPLABX IDE v5.30を使用

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • thkana

    2020/04/30 21:30

    > コードを見やすく
    なってません。
    https://teratail.com/questions/238564
    あたりも見てみて下さい。

    キャンセル

  • thkana

    2020/05/12 20:26

    > ②LED2の点滅が不安定で点滅周期が長かったり、短かったりする。
    > また、PB2を押さない限りLED2はずっと点滅するはずが、途中から点灯に代わってしまう。

    こっちの方は解決してたんでしたっけ?

    キャンセル

  • GM-DS

    2020/05/13 13:13

    thkana様
    おはようございます。
    LED2の不安定点滅については、実機で内部クロックを変えたコードで確認した所、改善されました。
    すごく大きな誤差ではありませんが、改善され気にならない程度になりました。
    途中から点灯については、cnt を unsigned intにする事により改善されました。勉強不足でした。
    お気に留めて頂きありがとうございます。

    キャンセル

回答 5

+3

__delay_ms(500);
にすると、PB2を押してもキャンセルされない時がある。

delay中に押して離すと、押していないと判定されるからでしょう。

cnt++の下に
if(cnt==2000){
cnt=0;
}
を追加したが関係なかった。

cnt10000を超えているのでcnt==2000が成立することはありません。
while(RA4==0)の前でcnt0にしておけばそのコードでも動くでしょう。

PB2を押さない限りLED2はずっと点滅するはずが、途中から点灯に代わってしまう

cntint(16bit)なので32767を超えるとオーバーフローしてマイナス値になり、マイナス値の間はcnt%1000<500が成立します。

(追記)
時間が合わない件について書き忘れていました。
y_waiwaiさんの回答にもある通り、delay以外の時間も加算されるため細かく刻むほどdelay以外で消費した時間が蓄積され表面化します。
LED点滅と時間カウントにはタイマの使用を検討されてみては?
時間の正確性にあまりこだわらないなら100ms間隔程度にすれば気にならない程度に収まると思いますが、その場合はdelayを伸ばした分ボタンはゆっくり操作する必要があります。

__delay_ms(100);
cnt+=100;

ループが回るたびにLATC0,LATC1,LATC2を設定する必要もないですね…


250msや500msに一度しかLED設定していないので、以下のようにしてLED設定回数を減らし除算もなくすとどうなります?

    while(1){
        if(RA5==1){
            int cnt=0; //PB1がONの時、最初にカウンタに0を代入
            int led=0;
            LATC2=1; //BZ ON
            int ra4 = RA4;
            while(cnt<10000 && ra4==0){ //カウント値が10秒以下、PB2 OFFの時、下を実行
                LATC0=led=1-led;
                for(int i = 0; i < 250 && ra4==0; ++i){
                    __delay_ms(1);
                    cnt++;
                    ra4 = RA4;
                }
            }            
            if(cnt==10000){ //カウント値が10秒に達したら下を実行
                LATC0=0; //LED1 OFF
                LATC2=0; //BZ OFF
                led=1;
                ra4 = RA4;
                while(ra4==0){ //PB2を押さない限り下を実行
                    LATC1=led=1-led;
                    for(int i = 0; i < 500 && ra4==0; ++i){
                        __delay_ms(1);
                        ra4 = RA4;
                    }
                }
            }
            LATC0=0; //LED1 OFF
            LATC1=0; //LED2 OFF
            LATC2=0; //BZ OFF
        }
    }

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/05/13 11:33

    SHOMI様
    おはようございます。
    回答ありがとうございます。

    ご教示頂きましたコードで試した所、10秒カウントは正常でした。
    しっかり点滅もしていました。
    そこで大変申し訳ありませんが①の点滅コードが理解できません。
    これは前置演算と同様な考え方でしょうか?
    led=1-led;→ledは1
    LATC0=led;→LATC0は1
    と言う事でしょうか?
    そうなると、最初LATC0が1になり点灯し、次に250ms後に0になる原理がわかりません。
    本来、初歩的な事なのでしょうが、わかりません。
    申し訳ございませんがご教示願います。

    キャンセル

  • 2020/05/13 11:45

    250ms後はledが1になっているので
    led=1-led;→ledは0
    LATC0=led;→LATC0は0
    です。

    キャンセル

  • 2020/05/13 13:16

    SHOMI様
    大変申し訳ございません。
    そうです。おっしゃる通りです。考えが及びませんでした。

    キャンセル

+2

PICには手を出していないので実験は出来ませんが...

各命令の実行に時間がかかるのは事実ですが、しかし

      while (cnt < 10000 && RA4 == 0) {  //カウント値が30秒以下、PB2 OFFの時、下を実行
        LATC2 = 1;                       // BZ ON
        if (cnt % 500 < 250)
          LATC0 = 1;                          // LED1 ON
        else LATC0 = 0;                       // LED1 OFF
        __delay_ms(1);
        cnt++;
      }


で、__delay_ms()以外の部分の実行に0.7ms掛かっている、というのは単純に「ああそうですか」と受け入れていいレベルを超えていると思います。
点滅の周期も1.7秒くらいなのですか? 同じことですが、17秒の間に10回点滅しているのですか?

・点滅コードが原因かと思い、LED1の点滅をやめて10間点灯に変更すると正常に10後LED2が点滅した。

このときのコードはどのようなものだったのでしょう。

コンパイラの性能がすごく悪くて、割り算がものすごく遅い、とかだと可能性はあるかしら。
if (cnt % 500 < 250)
if( (cnt & 0x100)!=0 )
とかしたら(点滅周期は12msほどずれるけど)どうなるでしょうか。

なお、この部分だけでも元の質問ではLATC2 = 1;のセミコロンがいわゆる全角だったり、cnt1なんていう変数はなかったりします。コンパイルを通るわけがないので、これはあなたが実際にコンパイルして実行しているプログラムではあり得ません。あなたが実際にコンパイルして実行しているプログラム「そのもの」を提示して下さい。そうでないと、実は間違っているのを手で打ち直しているうちに「直して」しまっていて、いくら質問のプログラムを見ても原因が見つからない、なんていう可能性を否定出来なくなってしまいます。

もう一つ気になるのですが、スイッチの接続はどのような回路になっていますか? スイッチの一方をVDD(電源), もう一方をマイコンの入力ピンに繋いだだけ...なんていう回路になっていないでしょうか。(初心者と称する人が「スイッチONで1」としているとしばしばその回路になっているので...)
その場合、スイッチがOFFの場合マイコンの入力ピンは何も繋がっていない状態になりますがそれは「0(Lowレベル)」ではありません。たまたま0になるかも知れませんが、ノイズやちょっとした回路の都合で簡単に1になるかも知れません。不安定...問題になっている症状の1つじゃありませんでしたっけ。
マイコンの入力端子に何も繋がないという使い方は原則として「やってはいけない」と思って下さい。プルアップ/プルダウン回路を内蔵していてそれを使っている、とかいうのなら問題はないのですが、そうでなければマイコン外部にプルアップやプルダウン抵抗を接続して、マイコンの入力ピンの電位が確実に決まっているようにする必要があります。

コメントに関して追記 5/1

●スイッチの配線について
スイッチの配線は色々なサイトを見て勉強し、一応プルダウン?抵抗を接続しGNDに接続しています。

不安定という事象に対しては一番疑われる部分です。配線の間違い、部品の間違い(抵抗値等)、、接触不良、近隣とのショート、極端に長い配線等もありませんね? 「一応」ではなく「大丈夫」といい切れるようにして下さい。

●コンパイラの性能がすごく悪くて、割り算がものすごく遅い、とかだと可能性はあるかしら。
⇒そのような事があるんですか?想像がつきませんでした。

小学校で計算を習う順番を考えてみて下さい。足し算、引き算、掛け算、割り算の順で習うでしょう。その順で「難しい」のです。コンピュータの場合も、特別な計算回路を持っていないマイコンではその順番で計算が面倒になり、時間がかかることは考えられます。

volatile int i,j,result=0;//volatileはどこかで値が変更されているかも知れない、というコンパイラへの指示。これをつけないと計算を端折ることがあるので
//ここでLED ON
for(i=0;i<10000;i++){//ループの回数は違いが判断できて結果が出るまで我慢できるくらいの時間に適当に設定
  for(j=0;j<100;j++)
    result=i+j;    //ここを result=i-j;とかresult=i*jとかresult=i/jとかresult=i%jに替えてみる
  }
}
//ここでLED OFFしてLEDが点灯していた時間を計る
while(1);//停止


みたいな実験をして調べてみるといいかも。
手元のArduino UNO(クロック16MHz)では+,-が約2秒 *が2.5秒に対し/と%は15.7秒かかりました。
PICで質問のプログラムの条件に置き換えると
・クロック2MHzで速度1/8(かかる時間は8倍)
・繰り返し回数10000で1/100
・CPUの作りも違ってAVRは1クロック1命令、PICは4クロック1命令が基本で4倍時間がかかる
とすると単純に換算して(相当いい加減な見積もりですが)5秒くらい。つまり10秒ループのはずが15秒とかの実行時間はあり得る、ということになりそうです。(意外と大きいなぁ)

だとすると、

●実験したコードは単純に
if(cnt%500<250)
LATC0=0;
else LATC0=1;
を抜いただけです。

これについては、そこを抜くのではなく

if(cnt%500<250)
LATC0=1;
else LATC0=1;


による点きっぱなしも試してみた方がよさそうですね。「点滅」の影響なのか、割り算が遅いのか。

それはそれとして

●17秒の間に10回点滅しているのですか?
⇒10回以上点滅していました。

これは重要な事実です。点滅周期の情報がありませんが、点滅が10回を超えるということがあるなら、単純にループに時間がかかっているのとは別の現象ですから。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/05/11 14:04

    ikadzuchi様
    回答ありがとうございます。
    <PICに手を出されていないということでご存知ないかもしれませんが、PICは1命令に4クロック掛かりますので、0.7msは2MHzで350命令。
    とありますが、おっしゃる通りわかりませんでした。独自で調べましたら4クロックの意味は分かりましが「0.7msは2MHzで350命令」と言うのはどのような計算なのでしょうか?350と言うのは1サイクルで350命令処理しているという事でしょうか?

    質問ばかりで大変申し訳ございません。

    キャンセル

  • 2020/05/11 20:47

    「350命令」は私じゃありませんが、
    2MHzクロック(2000000クロック/秒)、1命令に4クロックが費やされるなら、0.7msの間には350個の命令が実行できる/350命令が必要な動作には0.7msかかる、ということです。

    キャンセル

  • 2020/05/12 08:55

    thkana様
    おはようございます。
    回答ありがとうございます。
    350命令の計算わかりました。
    ありがとうございました。

    キャンセル

checkベストアンサー

+1

誰も突っ込まないようなので

●スイッチの配線について
スイッチの配線は色々なサイトを見て勉強し、一応プルダウン?抵抗を接続しGNDに接続しています。

プルダウン(マイコンピンとGNDを抵抗で繋ぐ)すると、その電圧はLOWレベル(GND)側に引っ張りますから、LOWと判断されます。
スイッチの先は、押した時にそれとは識別できるようにしなければ意味がありませんから、VCC(5V)に繋ぎます。
※と言っても、ある程度動いているようですから、実際は正しく配線してあるのだと想像します。

①PB1を押した後の、10秒カウントが17秒位ある。

作業時間が蓄積されて誤差の7秒となっています。
8bitのPICはかなり非力なマイコンです。
現在流通されているマイコンの中でも最弱だと思った方が良いです。
(乗算器が無い&4クロックで1命令を行う)
2MHz駆動にすると、実質(他の多くのマイコンに換算すると)500kHzで駆動している事になります。
なので、内部クロックはもっと高くした方が良いです。例えば2MHz→16MHzに変更しただけで、誤差の7秒が
1秒程度になる事が期待されます。

そして、点滅のループもやはり、「このマイコンは処理能力が低い」という事を意識して書くべきです。
つまり、10000回もループさせたら誤差が大きくなります。
例えば10msを単位として、1000回のループにすれば、誤差は1/10程度になると期待されます。

上記の2つの事を考慮して書けば、7秒の誤差が1/80、つまり、0.1秒程度になるので、全く気になる事が無い範囲になります。

②LED2の点滅が不安定で点滅周期が長かったり、短かったりする。
また、PB2を押さない限りLED2はずっと点滅するはずが、途中から点灯に代わってしまう。

プログラムでは、if(cnt%1000<500)ですけど、変数cntはintです。
その場合、変数範囲の半分はマイナス値です。そうなると余り(%)もマイナス値になります。
よって、cnt++で、マイナス値に切り替わったあたりから暫く(約33秒)は(cnt%1000<500)は真になります。
cntをunsigned intで宣言すれば直ると思います。(とはいえ、数値が一周した瞬間だけ、ちょっと乱れます。)

③そもそもこのコードは最適なのか?

想定したように動いていない時点で・・・
細かい事は、他の方の指摘とダブりそうなので、控えます。
(一番最初なら一通り指摘したと思いますけど)

その代わり、一通り書き換えておいたものを置いておきます。
コンパイルまでは試しましたけど、レジスタを確認した訳でもないし、検証した訳でもありません。

//接続を定義しておくと解り易い
#define    LED1      LATC0
#define    LED2      LATC1
#define    BZ        LATC2
#define    PB1        RA5
#define    PB2        RA4

#define _XTAL_FREQ 16000000
#include <xc.h>

void main(void) {
    OSCCON = 0b01111000; //内部クロック周波数を16MHzに設定
    ANSELA = 0b00000000; //PortA全てのピンをデジタルモードに設定
    ANSELC = 0b00000000; //PortC全てのピンをデジタルモードに設定
    TRISA = 0b11111111; //PortA全てのピンを入力モードに設定
    TRISC = 0b00000000; //PortC全てのピンを出力モードに設定

    //初期処理:電源ON後、全ての出力を一度OFFにする。    
    LED1 = 0;
    LED2 = 0;
    BZ = 0;

    int cnt = 0; //カウンタ
    int mode = 0;//modeは0:全停止 1:LED1点滅、BZオン 2:LED2点滅

    while (1) {
    //入力(sw)処理
        if (PB1 && mode == 0) {    mode = 1;cnt = 0;}
        //modeが0の状態でPB1押されたら、modeを1にしてカウンタも初期化
        if (PB2) {mode = 0;}
        //PB2が押されたら、どんな状態からでもmodeを0


    //出力処理    
        if (mode == 0) {//mode0は全オフ
            LED1 = 0;
            LED2 = 0;
            BZ = 0;
        } else if (mode == 1) {//mode1はLED1点滅、BZオン
            LED1 = (cnt % 50 < 25);
            LED2 = 0;
            BZ = 1;
            __delay_ms(10);
            if (++cnt == 1000){mode = 2;cnt=0;}//10秒になったらmodeを2に
        } else if (mode == 2) {//mode2はLED2のみ点滅
            LED1 = 0;
            LED2 = (cnt < 50);
            BZ = 0;
            __delay_ms(10);
            if(++cnt==100)cnt=0;
        }
    }
}

追記
よく見たら、②は、とっくにSHOMIさんが指摘していましたね。
それなら、後からでしゃばる必要も無かったなぁ・・・

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/05/12 09:08

    nac_tnk様
    おはようございます。
    回答ありがとうございます。

    意味を理解することができました。
    また、ご教示頂いたコードを試してみました。
    正常に動きました。
    そこで、内部クロックやdelayの桁を変えたりしてみた所、16MHzの10msが最適値でした。

    内部タイマを基準にするプログラムはkoujikuu様にご教示いただいたコードの事ですよね。
    直ぐに理解はできなさそうなので、自分なりにしっかり読んでから改めて質問させて下さい。

    キャンセル

  • 2020/05/12 12:24

    内蔵タイマを使う手法も、大きく見て2つに分かれます。
    1つはタイマを回し、横目で見て、処理をする方法、もう一つはタイマ割り込みをかけて、一定周期で起こる割り込み関数で入った回数で時間測ります。
    (koujikuuさんのプログラムは前者です。タイマ割り込みを使う方がより一般的です。多分、割り込み関数では元のプログラムから大きく変わるのでこの例を示したのだと推測します。)

    特に、タイマー割り込みは必須だと思うので、トライしてみてください。

    キャンセル

  • 2020/05/12 13:14

    nac_tnk様
    割り込みですね・・・
    まだまだ知識が足らずたどり着くまでに時間がかかりそうですがトライしたいと思います。
    お忙しい中、長々とお付き合い頂きましてありがとうございました。
    またの機会が有りましたら是非よろしくお願いいたします。

    キャンセル

+1

そもそも、時間のカウントに__delay_msを使ってますが、たとえこの関数で1msきっちりのディレイが得られたとしても、その他の命令の実行時間がそれに加わりますんで、10000回まわすと10秒きっちり、というわけにはいかなくなります

そもそもディレイとかスリープ系の関数というのは、なにもしないでひたすらその時間がすぎるのを待ってるだけ、です。
ですんで、それを前提にコードの動作を追いかけてみてはどうでしょう

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/04/30 15:20

    y_waiwai様
    お忙しい中、回答ありがとうございます。
    カウントの計算をしてdelayで1ms待ってカウントしてとやっていると、カウントは10000しているが点滅用カウントの計算をしているが為に、正確な10秒が得られないと言う事でしょうか?

    キャンセル

  • 2020/04/30 18:38

    for のループを実行する時間、変数をカウントする実行時間、何らかの命令を実行する場合には必ず実行する時間が経過しますね

    キャンセル

+1

__delay_ms() ではなく 内蔵タイマを基準とします
PIC16F84 でテスト PIC16F1503 でも基本的な考え方は同じです (除算は使いません)
SW , LED , BZ の ON/OFF (o,1) は #define で設定しています

#include <xc.h>
#pragma config WDTE=OFF,PWRTE=OFF,CP=OFF,FOSC=HS
#define _XTAL_FREQ 10000000 // 10MHz
#define    FOSC4    ( _XTAL_FREQ / 4 )    // PIC CLOCK

#define    _500ms    ( FOSC4 / 2 )
#define    _10s        ( FOSC4 * 10 )

#define    LED1        RA2 
#define    LED2        RA3 
#define    LED_ON    1
#define    LED_OFF    0
#define    SW1        RB0
#define    SW2        RB1
#define    SW_ON    0
#define    BZ        RA1
#define    BZ_ON    0
#define    BZ_OFF    1

unsigned short long tmr0_cnt3 = 0 ;    // 24bit
unsigned long tmr0_cnt4 = 0 ;            // 32bit
unsigned char blink_flag = 0 ;

void main(void){
    TRISA = 0 ;        // OUTPUT
    TRISB = 0xFF;        // INPUT
    OPTION_REG = 0b01010111;    // TMR0_ON Prescaler 1:256 , PORTB pullup
    LED1=LED_OFF ; LED2=LED_OFF ; BZ=BZ_OFF ;

    while(1){
        if ( SW1 == SW_ON && blink_flag==0 ){ blink_flag=1 ; tmr0_cnt3=0 ; tmr0_cnt4=0 ; }
        if ( SW2 == SW_ON ){ LED1=LED_OFF ; LED2=LED_OFF ; BZ=BZ_OFF ; blink_flag=0 ; }
        if ( T0IF==1 && blink_flag ==1 ){        // tmr0 over flow
            T0IF=0;
            tmr0_cnt3 += 65536;
            if ( tmr0_cnt4 < _10s ){ tmr0_cnt4 += 65536; }
            if ( tmr0_cnt3 >= _500ms ){
                tmr0_cnt3 -= _500ms;
                if ( tmr0_cnt4 < _10s ){ LED1 ^= 1 ; LED2=LED_OFF ; BZ=BZ_ON ; } else { LED2 ^= 1 ; LED1=LED_OFF ; BZ=BZ_OFF ; }
            }    
        }

    } // while
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/05/05 08:28

    koujikuu様
    お忙しい中、ご回答ありがとうございました。
    また、返信遅くなり申し訳ございませんでした。

    コードありがとうございます。
    すぐにコードを理解できません。
    私なりにしっかりと理解をしたいと思っております。
    理解するまで少しお時間をください。
    理解をしてから再度質問をさせていただきたいと思っております。

    ありがとうございました。また質問させていただきます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る