PICマイコン(PIC12F675)のEEPROMの使い方

組み込みエンジニア

こんにちは、ENGかぴです。

マイコンのソフト開発をしていると設定した値を保存し次回以降の電源投入で設定値を参照して動作させたいことがあります。PIC12F675はEEPROMを持っておりデータを書き込むことで電源が切れてもデータを保持することができます。

EEPROMの使い方はマイコンによって仕様が異なるためマイコンに合わせて実装する必要がありますが、2つの領域を使ってデータチェックする方法はマイコン問わず応用できるテクニックです。使い方の応用は下記記事にまとめています。

PICマイコン(PIC12F675)のEEPROMの使い方の応用

PIC12F675を使ってマイコンの動きを勉強するためにPIC12F675の機能でできることについてまとめています。

PICマイコン(PIC12F675)で実現できる機能と解説リンクまとめ

PIC12F675のEEPROMの設定

EEPROMは電源が切れてもデータを保存できます。PIC12F675には128バイトのEEPROMが搭載されています。読み込み(READ)や書き込み(WRITE)は1バイトごとにできるようになっています。

書き込みには数5msかかりますが、電圧や周辺の温度などで誤差が出ます。書き込み終了はWRビットで確認することや割り込みによる通知で確認できます。

PIC12F675のEEPROMに関するレジスタについて説明します。

EECON1レジスタ

EECON1レジスタは読み込みと書き込みについて管理を行うレジスタです。

引用:PIC12F675のデータシート(EECON1レジスタ)
引用:PIC12F675のデータシート(EECON1レジスタ)

bit0は1をセットするとEEPROMの内容の読み込みを開始できます。読み込みが終了すると0がセットされます。

bit1は1をセットするとEEPROMへのデータの書き込みを開始できます。書き込みが終了すると0がセットされます。

bit2はEEPROMへの書き込みを開始できるようにするものです。書き込みを行う場合は1をセットします。書き込みを開始できないようにするには0をセットします。

bit3は/MCLRリセット、WDTリセット(スリープ・モード中ではない場合)ブラウンアウトリセットのどれかによってEEPROMへのデータの書き込みが中断されたときに1がセットされます。使用する場合は0でクリアする必要があります。

EECON2レジスタ

EECON2レジスタはEEPROMへの書き込みを開始する時に使用します。書き込みを開始する前に書き込みまでのシーケンス処理を行う必要があります。書き込みまでのシーケンス処理の手順は以下の通りです。

  1. EECON2に0x55を書き込み
  2. EECON2に0xAAを書き込み
  3. EECON1レジスタのWRビット(bit1)をセット

このシーケンスが正確に実行されなければ書き込みは開始できません。このシーケンスを実行している途中で割り込みが入らないように禁止しておくことが推奨されています。

bit7-0に書き込みたいデータをセットします。セットした後でEEPROMの書き込みシーケンスを実行するとデータが書き込まれます。

EEADRレジスタ

引用:PIC12F675のデータシート(EEADRレジスタ)
引用:PIC12F675のデータシート(EEADRレジスタ)

bit6-0にデータの読出しや書き込みを行うアドレスをセットします。セットする範囲は0x00から0x7Fになります。

EEPROMを実装する

EEPROMの動作確認の回路図
EEPROMの動作確認の回路図

スイッチを押した回数をEEPROMに書き込んで置き電源を切った後にスイッチが押された回数をLED1を点灯/消灯を切り替えて表示します。

メイン関数に入ったときはGP2を出力してLED2を点灯させることで動作していることが分かるようにします。

初期化部分を実装する

//-----------------変数定義--------------------------
unsigned char eepData;
 //読み込み用
unsigned char eepChkData;
 //読み込みデータチェック用
unsigned char eepWrData = 0;
//-----------------関数宣言--------------------------
void EepWrite(void);
void EepRead(void);
//-----------------メイン関数------------------------
void main(void) {

//各種初期化

    EepRead();  //EEPROMの読み込み
    
    while(1){
      //メイン処理
    }

EEPROMのデータをメイン関数の無限ループに入る前に処理をすることでEEPROMのデータによる結果を採用してメイン関数内の処理を開始することができます。

EEPROMのデータ読み込みをデータ用とデータチェック用とに分けて読み込みを行うため2種類の変数を宣言しています。

EEPROMを実装する

    while(1){
        CLRWDT();
  
        if( GPIO3 == BIT_SET){
            if( btnOn == BIT_CLR ){
                btnOn = BIT_SET;
                __delay_ms(50); //チャタリング防止
                if(++eepWrData >= LED_CNT_MAX){
                    eepWrData = 0;
                }
                EepWrite(); //EEPROMへの書き込み
            }
        }else{
            btnOn = BIT_CLR;
        }
    }

メイン関数ではボタンが押されたときにGPIO3がHレベルになることでEEPROMに書き込むボタンを押された回数(eepWrData)をEEPROMに書き込む処理を行います。delay_ms関数を使用しているのはボタンのチャタリングを防止するためです。

btnOnの変数はボタンが押された時の処理を一度だけ実行したいためフラグとして管理しています。ボタンを離すとbtnOnのフラグを解除するようにしています。

//-----------eepライト処理---------------------------------
void EepWrite(void){
    
    //書き込みデータ
    EEADR = 0x00;       //アドレス指定
    EEDATA = eepWrData; //書き込みたいデータをセット
    WREN = BIT_SET;     //書き込み許可をセット
    //シーケンス処理のため割り込みを禁止すること
    //処理なし
    EECON2 = 0x55;      //シーケンス
    EECON2 = 0xAA;      //シーケンス
    WR = BIT_SET;       //書き込みセット
    
    while(WR){ 
        //WRが0になるまで待つ
    }
    
    //書き込みデータ(チェック領域)
    EEADR = 0x40;       //アドレス指定
    EEDATA = eepWrData; //書き込みたいデータをセット
    EECON2 = 0x55;      //シーケンス
    EECON2 = 0xAA;      //シーケンス
    WR = BIT_SET;       //書き込みセット 
    
    while(WR){ 
        //WRが0になるまで待つ
    }
    WREN = BIT_SET;     //書き込み許可をクリア
}

EEPROMの書き込み手順に従って実装しています。最初に書き込みたいアドレスを指定しデータをセットします。EEPROMへの書き込みを許可しシーケンスを実行してWRをセットすると書き込みができます。

WRビットが0になったとき書き込みが完了となります。while(WR)でクリアされるまでウェイトしています。

読み込みを行った際にデータが正常であるかをチェックするために2か所同じデータを書き込んでいます。

//-----------eepリード処理---------------------------------
void EepRead(void){
    unsigned char i;
    
    EEADR = 0x00;       //アドレス指定
    RD = BIT_SET;       //読み込み開始
    while(RD){
        //RDが0になるまで待つ
    }
    eepData = EEDATA;   //読み出しデータをセット
    //読み込みデータ(チェック領域)
    EEADR = 0x40;       //アドレス設定
    RD = BIT_SET;       //読み込み開始
    while(RD){
        //RDが0になるまで待つ
    }
    eepChkData = EEDATA;   //読み出しデータをセット
    
    if(eepData == eepChkData){  //データをチェック領域のものと比較
        if(eepData > LED_CNT_MAX){
            eepWrData = 0;
        }else{
            eepWrData = eepData;
        }
        
        for( i = 0; i < eepWrData; i++){
            CLRWDT();
            GPIO2 = BIT_SET;
            __delay_ms(200);
            GPIO2 = BIT_CLR;
            __delay_ms(200);
        }
    }else{
        eepWrData = 0;
    }
}

読み込みの場合はアドレスをセットしてRDビットをセットするとEEPROMのデータが読みだせます。while(RD)でデータの読み出しが完了するまでウェイトしています。

チェック用のアドレスと2か所で比較し、一致するとEPROMのデータが正常であると判断してEEPROMのデータを採用するようにしています。

EEPROMのデータの値の回数(最大回数をLED_CNT_MAXで定義しています)繰り返した後メイン関数に遷移します。回数が多いとWDTが働きリセットする可能性があるため繰り返しの中でWDTをクリアしています。

データをリードしてチェック用のデータと一致した場合読み出したデータの回数分LEDを200msの間隔で点灯/消灯するようにしています。

今回はwhile(WR)やwhile(RD)でウェイトしましたが、ウェイトなしでメイン関数を周回させながらEEPROMに書き込み行う方法としてEEPROM書き込み完了の割り込みを使う方法もあります。

データ用とデータ確認用の2か所を書き込むためフラグを準備したりと管理が煩雑になることから割り込みを使用する方法は使用しません。

ウェイトや割り込みを使用せずにEEPROMの書き込みを行う方法を応用例としてまとめています。

PICマイコン(PIC12F675)のEEPROMの使い方の応用

ソースコード全体

以下のソースコードはコンパイルして動作確認をしております。チェックはしておりますがコメントなど細かな部分で間違っている可能性があります。参考としてお使いいただければと思います。

// CONFIG
#pragma config FOSC = INTRCIO
#pragma config WDTE = ON
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config BOREN = OFF
#pragma config CP = OFF
#pragma config CPD = OFF

#include <xc.h>
//--------------定数定義----------------------------
#define _XTAL_FREQ	4000000
#define	BIT_SET	1
#define	BIT_CLR	0
#define LED_CNT_MAX 20
//-----------------変数定義--------------------------
unsigned char btnOn;
unsigned char eepData;
unsigned char eepChkData;
unsigned char eepWrData = 0;

//-----------------関数宣言--------------------------
void EepWrite(void);
void EepRead(void);

//-----------------メイン関数------------------------
void main(void) {
    ADCON0 = 0;		//AD変換しない
    ANSEL = 0;		//アナログモードは使用しない
    CMCON = 0x07;       //コンパレータは使用しない
    INTCON = 0x00;      
    PIE1 = 0x00;	
    TRISIO = 0x08;      //GP3入力、その他出力
    GPIO = 0x00;	//lowに設定
    OPTION_REG = 0x0f;  //プリスケーラ128 WDTで使用
    
    EepRead();  //EEPROMの読み込み
    GPIO2 = BIT_CLR;
    GPIO1 = BIT_SET;
    
    while(1){
        CLRWDT();
  
        if( GPIO3 == BIT_SET){
            if( btnOn == BIT_CLR ){
                btnOn = BIT_SET;
                __delay_ms(50); //チャタリング防止
                if(++eepWrData >= LED_CNT_MAX){
                    eepWrData = 0;
                }
                EepWrite(); //EEPROMへの書き込み
            }
        }else{
            btnOn = BIT_CLR;
        }
    }
}
//-----------eepライト処理---------------------------------
void EepWrite(void){
    
    //書き込みデータ
    EEADR = 0x00;       //アドレス指定
    EEDATA = eepWrData; //書き込みたいデータをセット
    WREN = BIT_SET;     //書き込み許可をセット
    //シーケンス処理のため割り込みを禁止すること
    //処理なし
    EECON2 = 0x55;      //シーケンス
    EECON2 = 0xAA;      //シーケンス
    WR = BIT_SET;       //書き込みセット
    
    while(WR){ 
        //WRが0になるまで待つ
    }
    
    //書き込みデータ(チェック領域)
    EEADR = 0x40;       //アドレス指定
    EEDATA = eepWrData; //書き込みたいデータをセット
    EECON2 = 0x55;      //シーケンス
    EECON2 = 0xAA;      //シーケンス
    WR = BIT_SET;       //書き込みセット 
    
    while(WR){ 
        //WRが0になるまで待つ
    }
    WREN = BIT_SET;     //書き込み許可をクリア
}
//-----------eepリード処理---------------------------------
void EepRead(void){
    unsigned char i;
    
    EEADR = 0x00;       //アドレス指定
    RD = BIT_SET;       //読み込み開始
    while(RD){
        //RDが0になるまで待つ
    }
    eepData = EEDATA;   //読み出しデータをセット
    //読み込みデータ(チェック領域)
    EEADR = 0x40;       //アドレス設定
    RD = BIT_SET;       //読み込み開始
    while(RD){
        //RDが0になるまで待つ
    }
    eepChkData = EEDATA;   //読み出しデータをセット
    
    if(eepData == eepChkData){  //データをチェック領域のものと比較
        if(eepData > LED_CNT_MAX){
            eepWrData = 0;
        }else{
            eepWrData = eepData;
        }
        
        for( i = 0; i < eepWrData; i++){
            CLRWDT();
            GPIO2 = BIT_SET;
            __delay_ms(200);
            GPIO2 = BIT_CLR;
            __delay_ms(200);
        }
    }else{
        eepWrData = 0;
    }
}
//---------------------end file----------------------------
  

関連リンク

PICマイコンを使ってマイコンのレジスタの設定やMPLAB X IDEのプラグインであるMCCを使用して動作確認したことについてまとめています。

PICマイコン(PIC12F675)で実現できる機能と解説リンクまとめ

PICマイコン(PIC16F1827)で実現できる機能と解説リンクまとめ

GEEKJOB-未経験からITエンジニアに【オンライン無料体験】

最後まで、読んでいただきありがとうございました。

タイトルとURLをコピーしました