目次
前
次
内蔵EEPROM利用
多くのPICには、EEPROMが内蔵されています。
非常勤講師をしていた大学校の学生から、内蔵EEPROMの
アクセスに関して相談を受けたので、調べてみることに。
利用PICはPIC16F688というので、ブレッドボードに
簡単な回路を組んで貰いました。回路図は、以下。
Personal Computerとシリアルケーブルで接続し
端末ソフトを使い、PIC内に用意したコマンド
インタプリタで、内蔵EEPROMをアクセスします。
LEDは、PICが動作していることを示すため
2秒周期で点滅させます。
コマンドインタプリタのコマンドは、以下としました。
- ? ヘルプ
- E 指定アドレスに1バイトのデータ格納
- e 256バイトの内容表示
- C 全領域をゼロで埋める
- S 全領域を16進のFFで埋める
コマンドインタプリタを次のように定義します。
(MikroCを使うことにしてあります。)
/* command interpreter */
if ( RFLAG == ON ) {
/* clear */
RFLAG = OFF ;
/* new line */
crlf();
/* get command */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help() ; }
/* set EEPROM data */
if ( cmd == 'E' ) {
/* get address */
eadrx = get_hex( *(sbuf+1) ) ;
eadrx <<= 4 ;
eadrx |= get_hex( *(sbuf+2) ) ;
/* get data */
edatx = get_hex( *(sbuf+3) ) ;
edatx <<= 4 ;
edatx |= get_hex( *(sbuf+4) ) ;
/* store */
eeprom_byte_write(eadrx,edatx);
}
/* show EEPROM context */
if ( cmd == 'e' ) {
for ( loopx = 0 ; loopx < 256 ; loopx++ ) {
/* set address */
eadrx = (UBYTE)loopx ;
/* get EEPROM data */
edatx = eeprom_byte_read(eadrx);
/* convert */
*(msg+0) = get_asc( (edatx >> 4) & MASK0F );
*(msg+1) = get_asc( edatx & MASK0F );
/* show */
rs_putchar(*(msg+0)) ;
rs_putchar(*(msg+1)) ;
rs_putchar(' ') ;
/* judge new line */
if ( (loopx & MASK0F) == 15 ) { crlf() ; }
}
}
/* clear all EEPROM area */
if ( cmd == 'C' ) {
for ( loopx = 0 ; loopx < 256 ; loopx++ ) {
eeprom_byte_write((UBYTE)loopx,0);
}
}
/* set all EEPROM area */
if ( cmd == 'S' ) {
for ( loopx = 0 ; loopx < 256 ; loopx++ ) {
eeprom_byte_write((UBYTE)loopx,0xff);
}
}
}
1文字で指定されるコマンドを判定し、対応する
処理を実行します。
コマンドインタプリタで利用できる、1バイトの
リード、ライト関数を定義します。
ライト関数
アドレス、データを指定レジスタに転送後
ライト処理を許可し、ライトシーケンスを
起動します。
void eeprom_byte_write(UBYTE xadr,UBYTE xdat)
{
/* set address */
EEADR = xadr ;
/* set data */
EEDATA = xdat ;
/* enable write */
EECON1.EEPGD = OFF ;
EECON1.WREN = ON ;
/* write sequence */
EECON2 = 0x55 ;
EECON2 = 0xaa ;
EECON1.WR = ON ;
/* wait */
while ( EECON1 & (1 << WR) ) ;
/* disable */
EECON1.WREN = OFF ;
}
ライトシーケンス開始をEECON2レジスタで
制御するには、16進の値の書込み順を守ら
なければなりません。
リード関数
アドレスを指定レジスタに転送後、リードを
許可し、データがレジスタに転送されるのを
待ちます。
UBYTE eeprom_byte_read(UBYTE xadr)
{
/* set address */
EEADR = xadr ;
/* enable read */
EECON1 = (1 << RD) ;
/* wait */
while ( EECON1 & (1 << RD) ) ;
return EEDATA ;
}
コマンドインタプリタを使うときは、受信バッファが
必要なので、8バイトの配列と受信割込み発生時に
配列のどこに格納するか、指定する変数が必要です。
次のように確保しました。
volatile UBYTE sbuf[8] ;
volatile UBYTE sindex ;
LEDの点滅には、タイマー0のオーバーフロー割込み
シリアル受信には、受信割込みを使います。
割込みが発生したことを、フラグで通知します。
フラグは、1ビットで扱える論理フラグを使うことに。
符号なし8ビットの変数で、8本のフラグを使えるよう
共用体でビット定義しておきます。
typedef union {
struct {
unsigned B7:1;
unsigned B6:1;
unsigned B5:1;
unsigned B4:1;
unsigned B3:1;
unsigned B2:1;
unsigned B1:1;
unsigned B0:1;
} BIT ;
unsigned char DR ;
} FLAGSP ;
volatile FLAGSP xflags ;
#define RFLAG xflags.BIT.B0
#define TFLAG xflags.BIT.B1
割込みを扱う関数は、次のように定義。
void interrupt(void)
{
UBYTE chx ;
/* generate 1ms */
if ( INTCON.TMR0IF == ON ) {
/* clear flag */
INTCON.TMR0IF = OFF ;
/* initialize */
TMR0 = 6 ;
/* increment */
timcnt++ ;
/* judge */
if ( (timcnt & 0x3ff) == 1000 ) { TFLAG = ON ; }
}
/* receive interrupt */
if ( PIR1.RCIF == ON ) {
/* clear flag */
PIR1.RCIF = OFF ;
/* get 1 charactor */
chx = RCREG ;
/* store */
*(sbuf+sindex) = chx ;
/* increment */
sindex++ ;
/* judge */
if ( chx == '\r' ) {
sindex = 0 ;
RFLAG = ON ;
}
}
}
タイマー0のオーバーフロー割込みは、1msの周期でフラグ
通知しています。受信割込みは、1文字が入力されたなら
受信バッファに保存し、ディリミタ'\r'を検出すると、上位
関数にフラグ通知します。
通信プロトコルは、以下とします。
データ転送速度 9600bps
データ長 8ビット
ストップビット 1ビット
パリティ なし
フロー制御 なし
main関数の中では、フラグを受取ったなら
クリアした後、対応処理を実行します。
全ソースコードは以下。
/* redefine data type */
typedef unsigned char UBYTE ;
typedef unsigned int UWORD ;
typedef unsigned long ULONG ;
#define OFF 0
#define ON OFF+1
#define RX_BIT 5
#define TX_BIT 4
#define MASKFF 0xff
#define MASK0F 0x0f
typedef union {
struct {
unsigned B7:1;
unsigned B6:1;
unsigned B5:1;
unsigned B4:1;
unsigned B3:1;
unsigned B2:1;
unsigned B1:1;
unsigned B0:1;
} BIT ;
unsigned char DR ;
} FLAGSP ;
volatile FLAGSP xflags ;
#define RFLAG xflags.BIT.B0
#define TFLAG xflags.BIT.B1
volatile ULONG timcnt ;
volatile UBYTE sbuf[8] ;
volatile UBYTE sindex ;
volatile UBYTE cmd ;
volatile UBYTE state ;
volatile UBYTE eadrx ;
volatile UBYTE edatx ;
volatile UWORD loopx ;
volatile UBYTE msg[2] ;
/* function prototype */
void init_usr(void);
void rs_putchar(UBYTE x);
void rs_puts(UBYTE *ptr);
void crlf(void);
void show_help(void);
UBYTE get_hex(UBYTE x);
void eeprom_byte_write(UBYTE xadr,UBYTE xdat);
UBYTE eeprom_byte_read(UBYTE xadr);
UBYTE get_asc(UBYTE x);
/* interrupt handler */
void interrupt(void)
{
UBYTE chx ;
/* generate 1ms */
if ( INTCON.TMR0IF == ON ) {
/* clear flag */
INTCON.TMR0IF = OFF ;
/* initialize */
TMR0 = 6 ;
/* increment */
timcnt++ ;
/* judge */
if ( (timcnt & 0x3ff) == 1000 ) { TFLAG = ON ; }
}
/* receive interrupt */
if ( PIR1.RCIF == ON ) {
/* clear flag */
PIR1.RCIF = OFF ;
/* get 1 charactor */
chx = RCREG ;
/* store */
*(sbuf+sindex) = chx ;
/* increment */
sindex++ ;
/* judge */
if ( chx == '\r' ) {
sindex = 0 ;
RFLAG = ON ;
}
}
}
void main(void)
{
/* user initialize */
init_usr();
/* endless loop */
while ( ON ) {
/* command interpreter */
if ( RFLAG == ON ) {
/* clear */
RFLAG = OFF ;
/* new line */
crlf();
/* get command */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help() ; }
/* set EEPROM data */
if ( cmd == 'E' ) {
/* get address */
eadrx = get_hex( *(sbuf+1) ) ;
eadrx <<= 4 ;
eadrx |= get_hex( *(sbuf+2) ) ;
/* get data */
edatx = get_hex( *(sbuf+3) ) ;
edatx <<= 4 ;
edatx |= get_hex( *(sbuf+4) ) ;
/* store */
eeprom_byte_write(eadrx,edatx);
}
/* show EEPROM context */
if ( cmd == 'e' ) {
for ( loopx = 0 ; loopx < 256 ; loopx++ ) {
/* set address */
eadrx = (UBYTE)loopx ;
/* get EEPROM data */
edatx = eeprom_byte_read(eadrx);
/* convert */
*(msg+0) = get_asc( (edatx >> 4) & MASK0F );
*(msg+1) = get_asc( edatx & MASK0F );
/* show */
rs_putchar(*(msg+0)) ;
rs_putchar(*(msg+1)) ;
rs_putchar(' ') ;
/* judge new line */
if ( (loopx & MASK0F) == 15 ) { crlf() ; }
}
}
/* clear all EEPROM area */
if ( cmd == 'C' ) {
for ( loopx = 0 ; loopx < 256 ; loopx++ ) {
eeprom_byte_write((UBYTE)loopx,0);
}
}
/* set all EEPROM area */
if ( cmd == 'S' ) {
for ( loopx = 0 ; loopx < 256 ; loopx++ ) {
eeprom_byte_write((UBYTE)loopx,0xff);
}
}
}
/* 1second pass */
if ( TFLAG == ON ) {
/* clear flag */
TFLAG = OFF ;
/* update state */
state++ ;
/* impress */
PORTC.B2 = (state & 1) ;
}
}
}
/* define function body */
void init_usr(void)
{
/* disable A/D converter */
ADCON1 = 0x07 ;
/* disable Analog comparator */
CMCON0 = 0x07 ;
/* I/O initial state */
PORTA = 0xff ;
PORTC = (1 << RX_BIT);
/* I/O direction */
TRISA = 0 ;
TRISC = (1 << RX_BIT) ;
/* initialize serial interface */
{
sindex = 0 ;
/* BAUD rate */
BAUDCTL.BRG16 = ON ;
SPBRG = 25 ; /* 9600bps */
/* TxD */
TXSTA.TXEN = ON ;
TXSTA.SYNC = OFF ;
TXSTA.BRGH = OFF ;
/* RxD */
RCSTA.SPEN = ON ;
RCSTA.CREN = ON ;
/* enable receive interrupt */
PIE1.RCIE = ON ;
}
/* initialize Timer 0 */
{
/*
4MHz/4 = 1MHz -> 1MHz/4 = 250kHz prescaler = 1:4
all inputs are pull-up .
*/
OPTION_REG = 0x01 ;
/* 256 - 250 = 6 */
TMR0 = 6 ;
/* enable timer0 overflow interrupt */
INTCON.TMR0IE = ON ;
}
/* enable peripheral interrupt */
INTCON.PEIE = ON ;
/* enable general interrupt */
INTCON.GIE = ON ;
/* disable Flash ROM */
EEADRH = 0 ;
EEDATH = 0 ;
/* clear flags */
xflags.DR = 0 ;
/* others */
timcnt = 0 ;
state = 0 ;
eadrx = 0 ;
edatx = 0 ;
}
void rs_putchar(UBYTE x)
{
/* judge */
while ( !TXSTA.TRMT ) ;
/* set data */
TXREG = x ;
}
void rs_puts(UBYTE *ptr)
{
while ( *ptr ) {
rs_putchar( *ptr );
ptr++ ;
}
crlf();
}
void crlf(void)
{
rs_putchar('\r');
rs_putchar('\n');
}
void show_help(void)
{
rs_puts("? help");
rs_puts("E set EEPROM data");
rs_puts("e show EEPROM data");
rs_puts("C clear all EEPROM area");
rs_puts("S set all EEPROM area");
}
UBYTE get_hex(UBYTE x)
{
UBYTE result ;
/* set default */
result = 0 ;
/* convert */
if ( '0' <= x && x <= '9' ) { result = x - '0' ; }
if ( 'A' <= x && x <= 'F' ) { result = x - 'A' + 10 ; }
if ( 'a' <= x && x <= 'f' ) { result = x - 'a' + 10 ; }
return result ;
}
void eeprom_byte_write(UBYTE xadr,UBYTE xdat)
{
/* set address */
EEADR = xadr ;
/* set data */
EEDATA = xdat ;
/* enable write */
EECON1.EEPGD = OFF ;
EECON1.WREN = ON ;
/* write sequence */
EECON2 = 0x55 ;
EECON2 = 0xaa ;
EECON1.WR = ON ;
/* wait */
while ( EECON1 & (1 << WR) ) ;
/* disable */
EECON1.WREN = OFF ;
}
UBYTE eeprom_byte_read(UBYTE xadr)
{
/* set address */
EEADR = xadr ;
/* enable read */
EECON1 = (1 << RD) ;
/* wait */
while ( EECON1 & (1 << RD) ) ;
return EEDATA ;
}
UBYTE get_asc(UBYTE x)
{
UBYTE result ;
/* default */
result = 0 ;
/* range check */
if ( x < 16 ) {
result = x + '0' ;
if ( x > 10 ) { result = x - 10 + 'A' ; }
}
return result ;
}
実際に端末ソフトを利用してのEEPROM処理は
次のようになります。
ヘルプ、EEPROM内容表示、バイト単位の設定
バイト単位設定の内容確認
クリアと内容確認
セットと内容確認
動作チェックをしている状態です。
目次
前
次