今回はEEPROMを利用してタイマー設定時間を保存する機能を追加します。
目次
追加機能の仕様
EEPROMのデータ読み書き、初期設定の方法がわかりましたので、早速これらの機能を使ってタイマー設定時間の保存機能を追加しましょう!
動作確認しやすいように、引き続きタイマー時間単位は「秒」とします。
仕様としては以下のようにしたいと思います。
- 初期設定値は5秒にする
- 電源投入後、EEPROMからタイマー設定値を読み出し、設定されているタイマー時間をLEDの点滅で表現する
- スタートボタンが押されるまで、タイマー増減ボタンの処理をする(これは実装済み)
- スタートボタンが押されたら、EEPROMにタイマー値を保存する
❸はすでに実装済みですので、❶、❷、❹の機能を実装していきます。
❶ 初期設定値
タイマー設定値はEEPROMのアドレス0に保存することにします。
初期設定値を5秒にしますので、以下のようにmain関数の前にかけばOKです。
__EEPROM_DATA (0x05, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
❷ タイマー設定値の読み出しと設定時間の表現
電源投入後、最初にEEPROMからタイマー設定値を読み出します。
アドレス0にタイマー設定値を保存しましたので、以下のように読み出せばOKです。
uint8_t timerValue = eeprom_read(0);
また、読み込んだタイマー設定値をLEDの点滅回数で表現します。
この動作はすでにタイマー値の増減のところでプログラムを作成しましたので、それを流用することにします。
❹ スタートボタンが押されたらタイマー設定値を保存
スタートボタンが押されたら、タイマー設定値を保存します。
タイマー時間の変更がない場合はEEPROMに保存する必要はありませんが、プログラムがちょっと面倒になりますので、変更の有無にかかわらず保存することにします。(本来はタイマー値が変更された場合のみEEPROMに保存処理する、というのがいいですよね…)
この処理は、EEPROMのアドレス0にtimerValueを保存すればいいので、次のように書けばOKです。
eeprom_write(0, timerValue);
タイマー設定値保存機能を追加したプログラム
前回までに作成したプログラムに、タイマー設定値を保存する機能を追加します。
なお、タイマー時間はEEPROMから1バイトデータとして読み出しますので、プログラム内のタイマー時間の変数は1バイト(uint8_t
型)に変更している点に注意していただければと思います。
/*
* PICマイコン電子工作入門 応用編 第14回
* タイマー設定値を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を入力、それ以外は出力に設定(RA3ピンは設定にかかわらず入力ピン)
// ADコンバータ設定
ADCON0 = 0b00001001; // RA2(AN2)をADコンバータピンに設定し、ADコンバータ機能をEbableにする
ADCON1 = 0b10000000; // 結果数値は右寄せ、ADコンバータクロックはFOSC/2、基準電圧はVDD
// ブザーをOFFにする
LATA4 = 0;
// タイマー設定時間をEEPROMから読み出す
// timerValueは1バイトにしています
uint8_t timerValue = eeprom_read(0);
// タイマー時間をLEDの点滅回数で表現する
//
// 動作開始後少し待つ
__delay_ms(500);
// 設定時間分LEDを点滅する
for(uint8_t i=0; i<timerValue; i++) {
LATA5 = 0;
__delay_ms(200);
LATA5 = 1;
__delay_ms(200);
}
// 少しの間LEDをOFFにする少しの間LEDをOFFにする
LATA5 = 0;
__delay_ms(800);
// LEDを点灯する
LATA5 = 1;
// スイッチが押されるまで、タイマー時間増減スイッチ処理を行う
while( RA3 ) {
// ADコンバータ読み取り
GO = 1; // 読み取り依頼
while(GO) { // 読み取り完了待ち
}
// ADRESの数値に応じてタイマー時間の増減を行う
//
// タイマー時間を減らすスイッチの処理(ADRESが250未満の場合)
if( ADRES < 250 ) {
// タイマー時間を減らす(マイナスにならないようにする)
if( timerValue > 0 ) {
timerValue--;
}
// タイマー時間をLEDの点滅回数で表現する
//
// 少しの間LEDをOFFにする
LATA5 = 0;
__delay_ms(500);
// 設定時間分LEDを点滅する
for(uint8_t i=0; i<timerValue; i++) {
LATA5 = 0;
__delay_ms(200);
LATA5 = 1;
__delay_ms(200);
}
// 少しの間LEDをOFFにする少しの間LEDをOFFにする
LATA5 = 0;
__delay_ms(800);
// LEDを点灯する
LATA5 = 1;
} else {
// タイマー時間を増やすスイッチの処理(ADRESが250以上750未満)
if( ADRES < 750 ) {
// タイマー時間を増やす(上限チェックはしない)
timerValue++;
// タイマー時間をLEDの点滅回数で表現する
LATA5 = 0;
__delay_ms(500);
for(uint8_t i=0; i < timerValue; i++) {
LATA5 = 0;
__delay_ms(200);
LATA5 = 1;
__delay_ms(200);
}
LATA5 = 0;
__delay_ms(800);
LATA5 = 1;
}
}
}
// タイマー設定値をEEPROMに書き込む
eeprom_write(0, timerValue);
// LEDをtimerValue分点滅する
for(uint8_t timer=0; timer<timerValue; timer++) {
// LEDを950ms消灯する
LATA5 = 0;
__delay_ms(950);
// LEDを50ms点灯する
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);
}
// LEDをPWM制御してスムーズな点滅制御をする
//
// PWM機能のピン割り当て設定
APFCONbits.CCP1SEL = 1; // PWM機能をRA5ピンに設定
CCP1CONbits.CCP1M = 0b1100; // PWM機能を有効、active-highに設定
CCP1CONbits.P1M = 0b00; // RA2ピンはGPIOに設定
// 周期とデューティーサイクルの設定
// 周期は1ms
// デューティーサイクルは100%から開始するので1msに設定
T2CONbits.T2CKPS = 0b00; // プリスケーラ値を1に設定
PR2 = 249; // 周期を1msに設定 (249 + 1) x 4 x 1us = 1000us = 1ms
CCPR1L = 1000/4; // デューティーサイクルを0.5msに設定
CCP1CONbits.DC1B = 1000 & 0b11;
// PWM制御スタート
T2CONbits.TMR2ON = 1;
// LEDをPWM制御
// デューテー比は10%〜100%の制御にする
while(1) {
// 100% -> 5%の制御
for(uint16_t duty=1000; duty>=50; duty--) {
CCPR1L = (uint8_t) (duty / 4); // 上位8ビット
CCP1CONbits.DC1B = duty & 0b11; // 下位2ビット
__delay_ms(1);
}
// 5% -> 100%の制御
for(uint16_t duty=50; duty<=1000; duty++) {
CCPR1L = (uint8_t) (duty / 4); // 上位8ビット
CCP1CONbits.DC1B = duty & 0b11; // 下位2ビット
__delay_ms(1);
}
}
// 以下の命令は実行されない
return;
}
更新履歴
日付 | 内容 |
---|---|
2017.7.30 | 新規投稿 |
2018.12.2 | プログラムテンプレートをMPLABX IDE v5.10のものに変更 |
2025.5.20 | 変数型をuint8_t型に変更 MPLABX IDE 6.25でプログラム動作確認 |