第14回 EEPROM(2) 〜タイマー設定値保存機能を追加する〜

今回はEEPROMを利用してタイマー設定時間を保存する機能を追加します。

目次

追加機能の仕様を決める

EEPROMのデータ読み書き、初期設定の方法がわかりましたので、早速これらの機能を使ってタイマー設定時間の保存機能を追加しましょう。

デバッグしやすいように、引き続きタイマー時間単位は「秒」とします。

仕様としては以下のようにしたいと思います。

  1. 初期設定値は5秒にする
  2. 電源投入後、EEPROMからタイマー設定値を読み込み、設定されているタイマー時間をLEDの点滅で表現する
  3. スタートボタンが押されるまで、タイマー増減ボタンの処理をする(これは実装済み)
  4. スタートボタンが押されたら、EEPROMにタイマー値を保存する

(3)はすでに実装済みですので、(1)、(2)、(4)の機能を実装していきます。

(1)初期設定値

タイマー設定値はEEPROMのアドレス0に保存することにします。

初期設定値を5秒にしますので、以下のようにmain関数の前にかけばOKです。

__EEPROM_DATA (0x05, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);

(2)電源投入後の処理

電源投入後、最初にEEPROMからタイマー設定値を読み込みます。

アドレス0にタイマー設定値を保存しましたので、以下のように読み出せばOKです。

unsigned char timerValue = eeprom_read(0);

また、読み込んだタイマー設定値をLEDの点滅回数で表現しますが、これはすでにタイマー値の増減のところでプログラムを作成しましたので、それを流用することにします。

(4)スタートボタンが押されたらタイマー設定値を保存

スタートボタンが押されたら、タイマー設定値を保存します。プログラムするのが面倒なので、タイマー値を変更しない場合でも保存することにします。(本当はタイマー値が変更された場合のみEEPROMに保存処理する、というのがいいと思います)

これはEEPROMのアドレス0にtimerValueを保存すればいいので、

eeprom_write(0, timerValue);

とかけばOKです。

タイマー設定値保存機能を追加したプログラム

前回までに作成したプログラムに、タイマー設定値を保存する機能を追加します。追加内容は上に説明した内容ですので、特に解説は必要ないと思います。

だんだんプログラムが長くなってきましたね…

/*
 * File:   main.c
 * 変更履歴
 *    2016.11.20: スイッチ制御部分を追加
 *    2016.12.05: 時間計測とブザー制御部分を追加
 *    2017.01.15: 設定時間が来たらLEDをPWM制御に変更
 *    2017.07.29: 時間設定ボタン処理を追加
 *    2017.07.30: EEPROMにタイマー時間の保存、読み出し機能を追加
 */

#include <xc.h>

// 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

// EEPROM初期データ定義
// アドレス0はタイマー設定値の初期値、残りはダミーデータ
__EEPROM_DATA (0x05, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);


//
// メイン関数
// 
void main(void) {

    // PICマイコン設定
    OSCCON = 0b01011010;  // 内部クロック周波数を1MHzに設定
    ANSELA = 0b00000100;  // RA2ピンをアナログ、それ以外のピンはデジタルに設定
    TRISA  = 0b00001100;  // RA2とRA3を入力、それ以外は出力に設定

    // ADコンバータ設定
    ADCON0 = 0b00001001;  // RA2(AN2)をADコンバータピンに設定し、ADコンバータ機能をEbableにする
    ADCON1 = 0b10000000;  // 結果数値は右寄せ、ADコンバータクロックはFOSC/2、基準電圧はVDD
    
    // 変数宣言
    unsigned short timer;   // 時間計測
    unsigned short duty;    // PWMのデューティーサイクル
    unsigned short i;       // for文で使う変数

    // LEDを点灯する
    LATA5 = 1;
    
    // ブザーをOFFにする
    LATA4 = 0;
    
    // タイマー時間変数
    // EEPROMに保存してある値を使用する
    // timerValueは1バイトにしています
    unsigned char timerValue = eeprom_read(0);
    
    // 設定時間を表現するために現在の設定時間を
    // LEDの点滅回数で表現する
    //
    // ちょっと待ち時間を置いて、
    __delay_ms(800);
    // いったんLEDを消して、
    RA5 = 0;
    __delay_ms(500);
    // 設定時間分LEDを点滅して、
    for(i=0; i<timerValue; i++) {
        RA5 = 0;
        __delay_ms(200);
        RA5 = 1;
        __delay_ms(200);
    }
    // ちょっとの間LEDを消して、
    RA5 = 0;
    __delay_ms(800);
    // LEDを点灯する
    RA5 = 1;
    
    // スイッチが押されたらタイマースタートする
    // タイマースタート前にタイマー時間設定ボタンが押されたらその処理を行う
    while(RA3){

        // ADコンバータ読み取り開始
        GO = 1;
        
        // 読み取り完了待ち
        while(GO);
        
        // 読み取りが終わると結果の数値はADRESレジスタに入っている
        // ADRESの数値に応じてタイマー時間の増減を行う
        //
        // タイマー時間を減らすスイッチの処理
        // (ADコンバート値が250未満の場合)
        if( ADRES < 250 ) {
            
            // タイマー時間を減らす
            timerValue--;

            // タイマー時間をLEDの点滅回数で表現する
            //
            // いったんLEDを消して、
            RA5 = 0;
            __delay_ms(500);
            // 設定時間分LEDを点滅して、
            for(i=0; i<timerValue; i++) {
                RA5 = 0;
                __delay_ms(200);
                RA5 = 1;
                __delay_ms(200);
            }
            // ちょっとの間LEDを消して、
            RA5 = 0;
            __delay_ms(800);
            // LEDを点灯する
            RA5 = 1;
            
        } else {

            // タイマー時間を増やすスイッチの処理
            // (ADコンバート値が250以上750未満)
            if( 250 <= ADRES && ADRES < 750 ) {
                
                // タイマー時間を増やす
                timerValue++;
                
                // タイマー時間をLEDの点滅回数で表現する
                // 点滅制御方法は減らす場合と同じ
                RA5 = 0;
                __delay_ms(800);
                for(i=0; i<timerValue; i++) {
                    RA5 = 0;
                    __delay_ms(200);
                    RA5 = 1;
                    __delay_ms(200);
                }
                RA5 = 0;
                __delay_ms(800);
                RA5 = 1;
            }
        }
    }
    
    // タイマー設定値をEEPROMに書き込む
    eeprom_write(0, timerValue);
    
    // タイマー計測開始
    //
    // LED点滅処理
    for(timer=0; timer<timerValue; timer++){
        // LEDを950ms消灯する
        LATA5 = 0;
        __delay_ms(950);
        // LEDを50ms点灯する
        LATA5 = 1;
        __delay_ms(50);            
    }
    
    // ブザーをONにする
    LATA4 = 1;

    // LEDをPWM制御してスムーズな点滅制御をする
    // PWM機能のピン割り当て設定
    APFCONbits.CCP1SEL = 1;     // PWM機能をRA5ピンに設定
    CCP1CONbits.CCP1M = 0b1100; // PWM機能を有効、active-highに設定
    CCP1CONbits.P1M = 0b00;     // RA2ピンはGPIOに設定

    // 周期(1ms)とデューティーサイクル(0.5ms)の設定
    T2CONbits.T2CKPS = 0b00;    // プリスケーラを1:1に設定
    PR2 = 249;                  // 周期を1msに設定 (249 + 1) x 4 x 1us = 1000us = 1ms
    CCPR1L = 500/4;             // デューティーサイクルを0.5msに設定
    CCP1CONbits.DC1B = 500;

    // PWM制御スタート
    T2CONbits.TMR2ON = 1;

    // LEDをPWM制御
    // デューテー比は10%〜100%の制御にする
    while(1) {
        // 5% -> 100%の制御
        for(duty=50; duty<=1000; duty++) {
            CCPR1L = duty / 4;          // 上位8ビット
            CCP1CONbits.DC1B = duty;    // 下位2ビット
            __delay_ms(1);
        }
        // 100% -> 5%の制御
        for(duty=1000; duty>=50; duty--) {
            CCPR1L = duty / 4;          // 上位8ビット
            CCP1CONbits.DC1B = duty;    // 下位2ビット
            __delay_ms(1);
        }

    }
    
    // 以下の命令は実行されない
    return;

}

更新履歴

日付 内容
2017.7.30 新規投稿
2018.12.2 プログラムテンプレートをMPLABX IDE v5.10のものに変更
通知の設定
通知タイミング
guest
0 コメント
本文中にフィードバック
全てのコメントを見る
目次