【概要】
PIC16F877に新たに追加された機能で、意外と知られていないのが、プログラム
でプログラム内容そのものを書き換えが出来るようになったということです。
つまり、これまでは、PIC16F84を始めとして、プログラム自身では、データメモリ
だけしか書き換えをすることが出来ませんでしたが、PIC16F8xxシリーズでは、
プログラムメモリがフラッシュメモリであり、かつプログラムで、このメモリに書き
こみが出来るようになっています。
これを使うと、これまで256バイトしかなかったデータEEPROMが、一挙に最大
8kワード(14ビット幅)まで拡大することになります。
(尤もプログラム自身があるのでこれより少なくはなりますが)
プログラムメモリへのRead/Write手順は、EEPROMデータメモリと類似の手順と
なっていますが、書き込み完了待ちの方法が大きく異なっています。
つまり、一旦書き込み指令を出すと、PIC自身がHALTモード、すなわち停止状態
となり、メモリへの書き込みが完了すると自動的に停止した次の命令からプログラ
ムの実行を再開します。
これに対し読み出し手順はEEPROMデータメモリと同じ手順となっています。
しかしアドレスもデータも1バイト以上の幅がありますから、そこのところが少し
異なっています。
【レジスタの詳細内容】
プログラムメモリのRead/Writeに関連するレジスタには下記があります。
EECON1 :Read/Write制御レジスタ
EECON2 :Read/Writeシーケンス制御レジスタ
EEDATA :データ下位バイト
EEDATH :データ上位バイト(データは14ビット幅)
EEADR :アドレス下位バイト
EEADRH :アドレス上位バイト(アドレスは13ビット幅)
≪EECON1レジスタの詳細≫
制御用レジスタではEECON1が重要な働きをしています。その中身は
下図のようになっていて、EEPGDビットがEEPROMのデータメモリとプログラム
メモリの区別を行うビットとなっています。
【Read/Writte手順詳細】
実際にプログラムメモリにRead/Writeする手順は下記のフロー図のように
します。
読出しは高速で1命令の実行時間内で読出し動作を完了するので、待ち合わせ
などをする必要は全くありません。
しかし書込みの方は、4〜10msec程度の時間を必要とし、この待ち合わせの間
は、PICは停止状態となりますので、使い方に注意が必要です。
特に高速処理で、一定時間内の実行を必要とするような処理中で書込みを行う
のは危険です。
【C言語プログラム例】
実際にCCS社のC言語によるプログラムでプログラムメモリにRead/Writeする
には下記関数を使用します。
組込み関数書式
機能内容
long data = READ_PROGRAM_EEPROM(long adrs) プログラムメモリのadrs番地の内容を読出しdataに代入する。
adrs、dataはいずれもlongかlong intで定義されていること。WRITE_PROGRAM_EEPROM (long adrs, long data) プログラムメモリのadrs番地にdataというデータを書き込む。
adrsとdataはいずれもlongかlong intで定義されていること。
≪プログラム例≫
下記リストは実際のプログラム例で、0x1E00番地から順にアドレスと同じデータ
を256バイト書きこみ、その後それを読み出して液晶表示器に表示するという
動作をします。
この例の回路は下図のようになっていて、液晶表示器は専用のライブラリと
なっています。
////////////////////////////////////////////////////////////
// This program is program memory read/write test program.
// This test executed on PIC16F877 that is flash memory.
///////////////////////////////////////////////////////////
#include <16f877.h>
#use delay(CLOCK=10000000) //10MHz
//////// Port define and link LCD library
#include <lcd_lib3.c>
////////////// main routine
main() {
long adrs,data;
lcd_init(); //initialize LCD
////main process
printf(lcd_data,"Start EEPROM test");
for (adrs=0x1E00;adrs<0x1F00;adrs++) {
data=adrs;
write_program_eeprom(adrs,data);
}
lcd_clear();
for(adrs=0x1E00;adrs<0x1F00;adrs++) {
data=read_program_eeprom(adrs);
lcd_cmd(2); //cursor at home
printf(lcd_data,"%4LX %4LX",adrs,data);
delay_ms(500);
}
}
【アセンブラプログラム例】
上記のC言語の例と同じ機能をアセンブラ言語で作成した例です。
液晶表示器のサブルーチンは専用となっています。
この液晶表示器をポートDで使うときに注意が必要なのは、ポートE
にポートDの使い方を設定する必要があるのを忘れないようにする
ことです。
全体のリストは下記でダウンロードすることが出来ます。
★ プログラムEEPROM Read/writeテストプログラムリスト
この中で、EEPROMのRead/Writeをするサブルーチンの部分は下記
リストのようになっていて、上記のフローチャートの通りの手順と
なっています。
(注)下記リストには漢字スペースが混じっていますのでそのままでは使えません。
(1) 変数定義部
並べる順序はこの通りでなければなりません。ADRH EQU 020H ;EEPROM address upper
ADRS EQU 021H ;EEPROM address lower
DATH EQU 022H ;EEPROM data upper
DATL EQU 023H ;EEPROM data lower
(2) Readサブルーチン
サブルーチン内で何度もバンクの切替をしますので、変数指定
は間接アドレスとして取り出しています。従って変数の並び順
は(1)の通りになっていなければなりません。
;*****************************************
; program memory read subroutine
; address set in ADRH,ADRS
; return with set data in DATH,DATL
;*****************************************
READ_EEMEM
BCF STATUS,IRP ;bank0 for indirect address
MOVLW ADRH ;start from 0CH
MOVWF FSR ;set indirect pointer
BSF STATUS,RP1
BCF STATUS,RP0 ;bank2
MOVF INDF,W ;get address upper
MOVWF EEADRH ;set EEPROM address upper
INCF FSR,F ;next
MOVF INDF,W
MOVWF EEADR ;set EEPROM address lower
INCF FSR,F
BSF STATUS,RP0 ;bank3
BSF EECON1,EEPGD ;set program memory
BSF EECON1,RD ;start read
NOP ;HALT dumy
NOP
BCF STATUS,RP0 ;bank2
MOVF EEDATH,W ;get upper data
MOVWF INDF ;save to DATH
INCF FSR,F ;next
MOVF EEDATA,W ;get lower data
MOVWF INDF
BCF STATUS,RP1 ;bank0
RETURN
(3) Writeサブルーチン
書きこみサブルーチンでは、途中のNOP命令の所で数msecの間
HALT(停止)モードとなりますので実行時間では注意が必要
です。;********************************************
; program memory write subroutine
; address set in ADRH,ADRS
; data set in DATH,DATL
;********************************************
WRITE_EEMEM
BCF STATUS,IRP ;set bank0 for indirect
MOVLW ADRH
MOVWF FSR ;set indirect
BSF STATUS,RP1 ;bank2
BCF STATUS,RP0
MOVF INDF,W ;get upper address
MOVWF EEADRH ;set upper address
INCF FSR,F ;next
MOVF INDF,W ;get lower address
MOVWF EEADR ;set lower address
INCF FSR,F ;next
MOVF INDF,W ;get upper data
MOVWF EEDATH ;set upper data
INCF FSR,F ;next
MOVF INDF,W ;get lower data
MOVWF EEDATA ;set lower data
BSF STATUS,RP0 ;bank3
BSF EECON1,EEPGD ;program memory
BSF EECON1,WREN ;write enable
MOVLW 0x55 ;write sequence
MOVWF EECON2
MOVLW 0xAA
MOVWF EECON2
BSF EECON1,WR ;write start
NOP ;HALT NOP
NOP
BCF EECON1,WREN ;write disable
BCF STATUS,RP0
BCF STATUS,RP1 ;bank0
RETURN