第29回 チャレンジ課題(4)

今回はタイマーの動作仕様を変更してみます。

目次

変更後の動作仕様のイメージ

前回、タイマーとしての基本的な機能は実装しましたので、今回は機能を追加したいと思います。

レトルトカレーをお湯で温める場合を想定します。例えば加熱時間が3分の場合、温め終わるちょっと前にご飯を用意しておきたいこともあります。

例えば次のようなイメージです。

レトルトカレーを温め始めたときにタイマーを開始しします。

タイマーを開始してから2分30秒経過すると短い時間ブザーがちょっと鳴って、ご飯を準備する合図にします。

タイマー開始3分後、アラーム音が鳴ってレトルトカレーが温め終わる、という感じです。

動作仕様

タイマーの時間や、途中でアラームを鳴らす時間はご自分の用途に合わせてみてください。

特に用途がない場合、次のような機能を追加してみてください。

3分タイマーで、残り30秒になったら一度ブザーを短い時間鳴らして、
そのあと点滅パターンを変える。3分経過したら、アラーム音を鳴らす。

処理の流れとしては、

  1. 2分30秒、今まで通りのプログラムで時間を計測
  2. ブザーを短い時間鳴らす
  3. 残りの時間は点滅パターンを変えて時間を計測
  4. ブザーを鳴らす

という感じです。

解答例

具体的な動作仕様は次のようにしてみました。

  1. 2分30秒、今まで通りのプログラムで時間を計測
     ➡︎ あとで点滅パターンを変えたいので、この期間は2秒に1回LEDを点滅することにします。
  2. ブザーを短い時間鳴らす
     ➡︎ 300msだけブザーを鳴らします。
  3. 残りの時間は点滅パターンを変えて時間を計測
     ➡︎ 残りの時間は1秒に1回点滅することにします。
  4. ブザーを鳴らす
     ➡︎ 「ピピピッ」と3回アラーム音を鳴らします。

実装方法はいろいろあると思いますが、次のようにプログラムを作成してみました。

  • タイマー時間は変更しやすいように、トータル時間と残り時間を#defineで定義してみました
  • 2秒に1回の点滅は、タイマーのカウントが偶数の時だけLEDを点滅する、という処理にしてみました。偶数の判定はtimer%2 == 0というように2で割った余りが0かどうかでif文で判定しています。
  • 途中でアラーム音を短時間鳴らしますが、この部分のLEDを点滅して時間計測するため、LEDの消灯時間を調整しています。例えばアラーム音を300ms鳴らす場合、LEDの制御は「650ms消灯、50ms点灯」というベタな実装にしています。
    (本来の消灯時間950ms)−(アラーム音の300ms)=650ms

このような実装で次のようにプログラムを作成してみました。

/*
 * PICマイコン電子工作入門 基礎編 第29回
 * チャレンジ課題 解答例
 */

#include <xc.h>

// タイマー時間設定
#define TIMER_TOTAL  180  // トータルのタイマー時間 (秒)
#define TIMER_REMAIN 30   // 動作を変える残りの時間 (秒)
#define ALARM_NOTIFY 300  // 途中のアラーム音の長さ (単位はミリ秒で950ms未満にする)

// PIC12F1822 Configuration Bit Settings
// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF       // Internal/External Switchover (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)
// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF      // PLL Enable (4x PLL disabled)
#pragma config STVREN = OFF     // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)

// クロック周波数指定
// __delay_ms()関数が使用する
#define _XTAL_FREQ 1000000

void main(void) {

    // PICマイコン設定
    OSCCON = 0b01011000;  // 内部クロック周波数を1MHzに設定
    ANSELA = 0b00000000;  // すべてのピンをデジタルモードに設定
    TRISA  = 0b00001000;  // すべてのピンを出力モードに設定(ただしRA3ピンは常に入力モード)

    // ブザーをOFF、LEDをONにする
    LATA4 = 0; // ブザー
    LATA5 = 1; // LED

    // スイッチが押されるまで待つ
    while( RA3 ) {
    }
    
    // 最初は2秒に1回LEDを点滅する
    //  変数timerが偶数の時のみLEDを点滅する
    for(uint16_t timer=0; timer<(TIMER_TOTAL - TIMER_REMAIN); timer++) {
        if(timer%2 == 0) {
            // timerが偶数のときはLEDを点滅して1秒計測
            LATA5 = 0;
            __delay_ms(950);            
            LATA5 = 1;
            __delay_ms(50);
            LATA5 = 0;
        } else {
            // timerが奇数のときは何もしないで1秒計測
            __delay_ms(1000);
        }
    }

    // 途中で一度ブザーを鳴らす
    LATA4 = 1;
    __delay_ms(ALARM_NOTIFY);
    LATA4 = 0;

    // アラーム音の時間分、差し引いてLEDを点滅して時間計測
    __delay_ms(950 - ALARM_NOTIFY);
    LATA5 = 1;
    __delay_ms(50);

    // 残り時間は1秒に1回LEDを点滅
    // ブザーを鳴らすために1回点滅したので、残り時間はマイナス1秒にする
    for(uint16_t timer=0; timer<(TIMER_REMAIN - 1); timer++) {
        LATA5 = 0;
        __delay_ms(950);            
        LATA5 = 1;
        __delay_ms(50);
    }

    // アラーム音を3回鳴らす
    for(uint8_t i=0; i<3; i++) {
        // ピッ
        LATA4 = 1;
        __delay_ms(70);
        LATA4 = 0;
        __delay_ms(70);
        // ピッ
        LATA4 = 1;
        __delay_ms(70);
        LATA4 = 0;
        __delay_ms(70);
        // ピーッ
        LATA4 = 1;
        __delay_ms(70);
        LATA4 = 0;
        // 1回分の音パターンの間を少し空ける
        __delay_ms(800);
    }

    // 動作を止める
    while(1) {
    }
    
    // 以下の命令は実行されない
    return;
}

更新履歴

日付内容
2016.12.5新規投稿
通知の設定
通知タイミング
guest
0 コメント
新しい準
古い順 一番投票が多い
本文中にフィードバック
全てのコメントを見る
目次