目次
前
次
ファームウエア仕様検討
ファームウエアの仕様を検討します。
ヒューズリセッターは、何度も使うことがないので、次の3機能が
実現できればよいと判断しました。
- 電源制御とパラレルモードへの遷移
- チップイレーズ
- ヒューズバイト書込み
機能は、ファームウエアが担当しますが、処理シーケンスはパーソナル
コンピュータから指定します。
パーソナルコンピュータとは、シリアルインタフェースで接続します。
最近のパーソナルコンピュータは、インタフェースI/OがUSBだけという
ので、その場合、USB/シリアル変換器を接続して対応します。
シリアルインタフェースを利用する場合は、プロトコルを決めます。
プロトコルは、以下とします。
- データ転送速度 9600bps
- データ長 8ビット
- ストップビット 1ビット
- パリティ なし
- フロー制御 なし
USB/シリアル変換器とマイコンを接続するために、簡易レベルコンバータを
利用。レベルコンバータの回路図は、以下。
ファームウエアを考える場合、ハードウエアがどうなっているか明らかに
しておかなければなりません。マイコンから制御する回路の図面は以下。
3チャネルのコネクタで、マイコンと接続します。
各チャネルに、必要な機能を割当てます。
ハードウエアの仕様が固まったので、3機能に分割して処理内容を検討します。
- 電源制御とパラレルモードへの遷移
- チップイレーズ
- ヒューズバイト書込み
電源制御とパラレルモードへの遷移
電源制御は、+12V、+5Vを端子に出力するか否かを制御します。
ポートBの7ビット、6ビットに1か0を出力すればよいので、個別に
該当ビットに1か0を出力します。
5V出力 PORTB &= ~(1 << con_5V) ;
12V出力 PORTB &= ~(1 << con_12V) ;
5V停止 PORTB |= (1 << con_5V) ;
12V停止 PORTB |= (1 << con_12V) ;
パラレルモードへの遷移は、次の信号線をすべて0にしてから
XTAL1に最低6回Hパルスを出力します。
PAGEL
XA1
XA0
BS1
XTAL1は、他の処理でも、1パルスを出力するがあるのでN回
(Nは、1〜255)出力できるようにします。
void send_pulse(UBYTE x)
{
UBYTE i ;
/* loop */
for ( i = 0 ; i < x ; i++ ) {
/* high */
PORTC |= (1 << XTAL1) ;
/* low */
PORTC &= ~(1 << XTAL1) ;
}
}
電源の接続と切断は、パラメータ指定で選べるようにした方が
ミスは少なくなるので、ひとつにまとめておきます。
void transfer_pgm(UBYTE x)
{
/* set parallel mode */
PORTC &= 0x0f ;
/* transfer program mode */
if ( x == ON ) {
/* enable +5V */
PORTB &= ~(1 << con_5V) ;
/* send pulse */
send_pulse(8);
/* delay */
delay_ms(1);
/* enable +12V */
PORTB &= ~(1 << con_12V) ;
} else {
/* disable +12V */
PORTB |= (1 << con_12V) ;
/* delay */
delay_ms(1);
/* disable +5V */
PORTB |= (1 << con_5V) ;
}
/* delay */
delay_ms(1);
}
電源の接続と切断を、パーソナルコンピュータから制御するため
コマンドを用意します。
電源接続 'R'コマンド
電源切断 'r'コマンド
コマンドには、デリミタとして'\r'を付加します。
チップイレーズ
チップイレーズは、プログラムROM、EEPROMの内容をクリアします。
また、LockBitを解除します。
LockBitの設定で、FuseByteを設定可能か禁止を指定可能。
LockBitの解除では、FuseByte設定を可能。
チップイレーズのためのシーケンスは、以下。
- (XA1,XA0,BS2,BS1)=(1,0,0,0)に指定
- チップイレーズコマンド(0x80)を出力
- XTAL1に、Hパルスを1つ出力
- WRに、Lパルスを1つ出力
- 時間待ち
- RDY/BUSYが、Hになることを確認
シーケンスを、一つにまとめます。
void erase_chip(void)
{
/* select command XA1 = 1 , XA0 = 0 */
/* BS1 = 0 */
set_signal(2,0);
/* command */
PORTA = 0x80 ;
/* XTAL1 pulse */
send_pulse(1);
/* wr pulse */
send_wr(ON);
send_wr(OFF);
/* delay */
delay_ms(1);
/* check */
while ( !(PINC & (1 << RDY_BUSY)) ) ;
}
XA1とXA0、BS2とBS1はペアで利用されるので、まとめて1と0を
指定できるようにします。
void set_signal(UBYTE xa,UBYTE bs)
{
/* XA handling */
PORTC &= ~(1 << XA1);
PORTC &= ~(1 << XA0);
if ( xa == 1 ) { PORTC |= (1 << XA0); }
if ( xa == 2 ) { PORTC |= (1 << XA1); }
/* BS handling */
PORTC &= ~(1 << BS1);
PORTB &= ~(1 << BS2);
if ( bs == 1 ) { PORTC |= (1 << BS1); }
if ( bs == 2 ) { PORTB |= (1 << BS2); }
if ( bs == 3 ) {
PORTB |= (1 << BS1);
PORTB |= (1 << BS2);
}
}
WRは、H、Lを出力できるようにします。
void send_wr(UBYTE x)
{
if ( x == ON ) { PORTC &= ~(1 << nWR); }
else { PORTC |= (1 << nWR); }
}
ヒューズバイト書込み
ヒューズバイトは、3バイトあります。
3バイトはユーザー指定なので、これらはパーソナルコンピュータ
から設定することにします。
ヒューズバイトの1バイト設定シーケンスは、以下です。
- (XA1,XA0,BS2,BS1)=(1,0,0,0)に指定
- ヒューズコマンド(0x40)を出力
- XTAL1に、Hパルスを1つ出力
- (XA1,XA0)=(0,1)に指定
- (BS2,BS1)=(0,0)、(0,1)、(1,0)のいずれかに設定
- ヒューズデータを出力
- XTAL1に、Hパルスを1つ出力
- WRに、Lパルスを1つ出力
- 時間待ち
- RDY/BUSYが、Hになることを確認
ヒューズバイトは3バイトあるので、(BS2,BS1)の組み合わせで、どの
バイトかを指定します。
ヒューズバイトが配列変数fsの中にあるとして、3回繰り返す処理で
記述します。
void set_fuse(void)
{
UBYTE i ;
UBYTE tmp ;
/* send command (Write Fuse)*/
set_signal(2,0);
PORTA = 0x40 ;
send_pulse(1);
/* write bytes */
for ( i = 0 ; i < 3 ; i++ ) {
/* send data */
set_signal(1,i);
PORTA = *(fs+i) ;
send_pulse(1);
/* write data */
send_wr(ON);
send_wr(OFF);
/* delay */
delay_ms(1);
/* check */
while ( !(PINC & (1 << RDY_BUSY)) ) ;
/* return */
set_signal(1,0);
}
}
全ソースコード
複数のマイコンチップに対応できるように、一部を修正しています。
また、シリアルインタフェースとコマンドインタプリタを入れてます。
#include <avr/io.h>
#include <avr/io8535.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#define OFF 0
#define ON OFF+1
typedef unsigned char UBYTE ;
typedef unsigned short UWORD ;
typedef unsigned long ULONG ;
typedef signed char SBYTE ;
typedef signed short SWORD ;
typedef union {
struct {
unsigned char B0:1;
unsigned char B1:1;
unsigned char B2:1;
unsigned char B3:1;
unsigned char B4:1;
unsigned char B5:1;
unsigned char B6:1;
unsigned char B7:1;
} BIT ;
unsigned char DR ;
} FLAGSP ;
volatile FLAGSP x_flags ;
#define SFLAG x_flags.BIT.B0
#define TFLAG x_flags.BIT.B1
#define DFLAG x_flags.BIT.B7
#define BUFSIZE 8
volatile UBYTE sbuf[BUFSIZE] ;
volatile UBYTE sindex;
#define NO 0
#define YES NO+1
#define PAGEL 7
#define XA1 6
#define XA0 5
#define BS1 4
#define nWR 3
#define nOE 2
#define XTAL1 1
#define RDY_BUSY 0
#define con_12V 7
#define con_5V 6
#define MBIT 1
#define BS2 0
#define CKND_644 0
#define CKND_1200 1
#define CKND_t2313 2
#define CKND_328 3
volatile ULONG tickcount ;
volatile UBYTE fs[3] ;
const prog_char msg_h[] PROGMEM = "? help" ;
const prog_char msg_r[] PROGMEM = "R set program mode" ;
const prog_char msg_sr[] PROGMEM = "r exit program mode" ;
const prog_char msg_e[] PROGMEM = "E chip erase" ;
const prog_char msg_p[] PROGMEM = "P set fuse bits" ;
const prog_char msg_sp[] PROGMEM = "p show fuse bits" ;
const prog_char msg_f[] PROGMEM = "F send fuse bits" ;
const prog_char msg_c[] PROGMEM = "C chose chip" ;
const prog_char msg_sc[] PROGMEM = "c show chip" ;
const prog_char chip644[] PROGMEM = "644" ;
const prog_char chip1200[] PROGMEM = "1200" ;
const prog_char chipt2313[] PROGMEM = "t2313" ;
const prog_char chip328[] PROGMEM = "t328" ;
const prog_char asc_code[] PROGMEM = "0123456789ABCDEF" ;
volatile UBYTE lcnt ;
volatile UBYTE cknd ;
/*--------------------------------*/
/* Insert user functions protoype */
/*--------------------------------*/
void user_initialize(void);
UBYTE get_hex(UBYTE x);
void uart_putchar(UBYTE x);
void uart_puts(UBYTE *x);
void crlf(void);
void erase_chip(void);
void send_pulse(UBYTE x);
void send_wr(UBYTE x);
void delay_ms(UBYTE x);
void transfer_pgm(UBYTE x);
void set_fuse(void);
void set_signal(UBYTE xa,UBYTE bs);
void command_interpret(void);
#define MASKFF 0xff
#define MASK0F 0x0f
#define MASKF0 0xf0
/*------*/
/* main */
/*------*/
int main(void)
{
/* disable interrupt */
cli();
/* */
user_initialize();
/* enable interrupt */
sei();
/* loop */
while ( ON ) {
/* watch flag */
if ( SFLAG ) {
/* clear flag */
SFLAG = OFF ;
/* command interpreter */
command_interpret();
}
if ( TFLAG == OFF ) {
/* clear flag */
TFLAG = OFF ;
/* command interpreter */
lcnt++ ;
PORTB &= ~(1 << MBIT);
if ( lcnt & 1 ) { PORTB |= (1 << MBIT); }
}
}
/* dummy */
return 0 ;
}
/*-----------------------*/
/* Insert user functions */
/*-----------------------*/
#define FOSC 8000000
#define BAUD 9600
#define MYUBRR (FOSC/16/BAUD)-1
void user_initialize(void)
{
/* PORT A */
PORTA = 0b00000000 ; /* 00000000 */
DDRA = 0b11111111 ; /* oooooooo */
/* PORT C */
PORTC = 0b00001100 ; /* 00001100 */
DDRC = 0b11111110 ; /* oooooooi */
/* PORT B */
PORTB = 0b11000000 ; /* 11000000 */
DDRB = 0b11111111 ; /* oooooooo */
/* PORT D */
PORTD = 0b00000000 ; /* 00000000 */
DDRD = 0b11111110 ; /* oooooooi */
/* */
x_flags.DR = 0 ;
*(fs+0) = 0xE2 ;
*(fs+1) = 0xD9 ;
*(fs+2) = 0xFF ;
tickcount = 0 ;
lcnt = 0 ;
/* initialize serial */
{
/* clear index */
sindex = 0 ;
/* clear buffer */
*(sbuf+0) = 0 ;
/* set Baud Rate Registers */
UBRR = MYUBRR ;
/* Enable receive interrupt , receive module and transmit module */
UCR = (1 << RXCIE) | (1 << TXEN) | (1 << RXEN) ;
}
/* initialize timer1 */
{
/* clear counter */
TCNT1 = 0 ;
/* set value */
OCR1A = 999;
OCR1B = 1500;
/* select /8 prescale (1MHz) */
TCCR1B = (1 << CS11) ;
/* Enable compare match interruption */
TIMSK = (1 << OCIE1A) ;
}
}
/* timer1 */
ISR(TIMER1_COMPA_vect)
{
tickcount++;
TFLAG = ON ;
}
/* UART receive interrupt */
ISR(UART_RX_vect)
{
UBYTE ch ;
/* get 1 charactoer */
ch = UDR ;
/* store */
*(sbuf+sindex) = ch ;
sindex++ ;
/* judge */
if ( ch == '\r' ) {
SFLAG = ON ;
sindex = 0 ;
}
}
UBYTE get_hex(UBYTE x)
{
volatile UBYTE result ;
/* default */
result = 0 ;
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 uart_putchar(UBYTE x)
{
while ( !(USR & (1 << UDRE)) ) {}
UDR = x ;
}
void uart_puts(UBYTE *x)
{
while ( *x != '\0' ) {
uart_putchar( *x ) ;
x++ ;
}
crlf();
}
void crlf(void)
{
uart_putchar('\r');
uart_putchar('\n');
}
void erase_chip(void)
{
/* select command XA1 = 0 , XA0 = 1 */
/* (BS2,BS1) = (0,0) */
set_signal(1,0);
/* command */
PORTA = 0x80 ;
/* XTAL1 pulse */
send_pulse(1);
/* wr pulse */
send_wr(ON);
send_wr(OFF);
/* delay */
delay_ms(1);
/* check */
if ( cknd != CKND_1200 ) { while ( !(PINC & (1 << RDY_BUSY)) ) ; }
}
void send_pulse(UBYTE x)
{
UBYTE i ;
/* loop */
for ( i = 0 ; i < x ; i++ ) {
/* high */
PORTC |= (1 << XTAL1) ;
/* low */
PORTC &= ~(1 << XTAL1) ;
}
}
void send_wr(UBYTE x)
{
if ( x == ON ) { PORTC &= ~(1 << nWR); }
else { PORTC |= (1 << nWR); }
}
void delay_ms(UBYTE x)
{
ULONG target ;
/* calculate target */
target = tickcount + x ;
/* wait */
while ( target > tickcount ) ;
}
void transfer_pgm(UBYTE x)
{
/* set parallel mode */
PORTC &= 0x0f ;
/* transfer program mode */
if ( x == ON ) {
/* set tiny2313 port value (nWR = 0) */
if ( cknd == CKND_t2313 ) { PORTC &= ~(1 << nWR) ; }
/* enable +5V */
PORTB &= ~(1 << con_5V) ;
/* send pulse */
if ( cknd == CKND_644 ) { send_pulse(8); }
/* delay */
delay_ms(1);
/* enable +12V */
PORTB &= ~(1 << con_12V) ;
/* delay */
delay_ms(1);
/* reset tiny2313 port value (nWR = 1) */
if ( cknd == CKND_t2313 ) { PORTC |= (1 << nWR) ; }
} else {
/* disable +12V */
PORTB |= (1 << con_12V) ;
/* delay */
delay_ms(1);
/* disable +5V */
PORTB |= (1 << con_5V) ;
/* delay */
delay_ms(1);
}
}
void set_fuse(void)
{
UBYTE i ;
UBYTE tmp ;
/* send command (Write Fuse) */
set_signal(2,0);
PORTA = 0x40 ;
send_pulse(1);
/* write bytes */
for ( i = 0 ; i < 3 ; i++ ) {
/* send data */
set_signal(1,i);
PORTA = *(fs+i) ;
send_pulse(1);
/* write data */
send_wr(ON);
send_wr(OFF);
/* delay */
delay_ms(1);
/* check */
while ( !(PINC & (1 << RDY_BUSY)) ) ;
/* return */
set_signal(1,0);
}
}
void set_signal(UBYTE xa,UBYTE bs)
{
/* XA handling */
PORTC &= ~(1 << XA1);
PORTC &= ~(1 << XA0);
if ( xa == 1 ) { PORTC |= (1 << XA0); }
if ( xa == 2 ) { PORTC |= (1 << XA1); }
/* BS handling */
PORTC &= ~(1 << BS1);
PORTB &= ~(1 << BS2);
if ( bs == 1 ) { PORTC |= (1 << BS1); }
if ( bs == 2 ) { PORTB |= (1 << BS2); }
}
void command_interpret(void)
{
UBYTE cmd ;
UBYTE tmp ;
UBYTE chx ;
UBYTE sd[2] ;
char msg[20] ;
/* get command */
cmd = *(sbuf+0) ;
/* transfer program mode */
if ( cmd == 'R' ) { transfer_pgm(ON) ; }
/* exit program mode */
if ( cmd == 'r' ) { transfer_pgm(OFF) ; }
/* perform chip erase */
if ( cmd == 'E' ) { erase_chip() ; }
/* set fuse byte */
if ( cmd == 'P' ) {
/* get channel */
chx = get_hex( *(sbuf+3) ) ;
/* get code */
tmp = get_hex( *(sbuf+1) ) ;
tmp <<= 4 ;
tmp |= get_hex( *(sbuf+2) ) ;
/* deliver */
*(fs+chx) = tmp ;
}
/* show fuse byte */
if ( cmd == 'p' ) {
/* get ascii code */
strcpy_P(msg,asc_code) ;
for ( chx = 0 ; chx < 3 ; chx++ ) {
/* get code */
tmp = *(fs+chx) ;
/* separate */
tmp >>= 4 ;
tmp &= MASK0F ;
*(sd+0) = (UBYTE)msg[tmp];
/* get code */
tmp = *(fs+chx) ;
/* separate */
tmp &= MASK0F ;
*(sd+1) = (UBYTE)msg[tmp];
/* show */
uart_putchar( *(sd+0) );
uart_putchar( *(sd+1) );
crlf();
}
}
/* store fuse byte */
if ( cmd == 'F' ) { set_fuse(); }
/* chose chip type */
if ( cmd == 'C' ) {
cknd = CKND_644 ;
if ( *(sbuf+1) == '1' ) { cknd = CKND_1200 ; }
if ( *(sbuf+1) == '2' ) { cknd = CKND_t2313 ; }
if ( *(sbuf+1) == '3' ) { cknd = CKND_328 ; }
}
/* show chip type */
if ( cmd == 'c' ) {
if ( cknd == CKND_644 ) { strcpy_P(msg,chip644) ; }
if ( cknd == CKND_1200 ) { strcpy_P(msg,chip1200) ; }
if ( cknd == CKND_t2313 ) { strcpy_P(msg,chipt2313); }
if ( cknd == CKND_328 ) { strcpy_P(msg,chip328) ; }
uart_puts((UBYTE *)msg) ;
}
/* help */
if ( cmd == '?' ) {
strcpy_P(msg,msg_h) ; uart_puts((UBYTE *)msg) ;
strcpy_P(msg,msg_r) ; uart_puts((UBYTE *)msg) ;
strcpy_P(msg,msg_sr); uart_puts((UBYTE *)msg) ;
strcpy_P(msg,msg_e) ; uart_puts((UBYTE *)msg) ;
strcpy_P(msg,msg_p) ; uart_puts((UBYTE *)msg) ;
strcpy_P(msg,msg_sp); uart_puts((UBYTE *)msg) ;
strcpy_P(msg,msg_f) ; uart_puts((UBYTE *)msg) ;
strcpy_P(msg,msg_c) ; uart_puts((UBYTE *)msg) ;
strcpy_P(msg,msg_sc); uart_puts((UBYTE *)msg) ;
}
crlf();
}
ATtiny2313を利用したファームウエアの
ソースコードは以下です。
#include <avr/io.h>
#include <avr/interrupt.h>
#define ON 1
#define OFF 0
#define PWR_BIT 4
#define CON_BIT 5
#define D_BIT 6
#define PWR12 2
#define PWR5 1
#define CMD_CHIP_ERASE 0x80
#define CMD_WR_FUSE 0x40
typedef unsigned char UBYTE ;
typedef unsigned int UWORD ;
typedef unsigned long ULONG ;
void usr_init(void);
void send_pwr(UBYTE x);
void send_con(UBYTE x);
void send_dat(UBYTE x);
void send_pcd(UBYTE kind,UBYTE x);
void delay_ms(UBYTE x);
volatile ULONG timcnt ;
volatile UBYTE state ;
volatile UBYTE eflag ;
int main(void)
{
/* initialize */
usr_init() ;
/* enable interrupt */
sei();
/* endless loop */
while ( ON ) {
/* state machine */
switch ( state ) {
/* wait trigger */
case 0 : state = 0 ;
if ( eflag == ON ) {
/* clear flag */
eflag = OFF ;
/* next */
state = 1 ;
}
break ;
/* impress +5V */
case 1 : state = 2 ;
send_pwr( PWR5 ) ;
delay_ms(1);
break ;
/* impress +12V */
case 2 : state = 3 ;
send_pwr( PWR12 | PWR5 ) ;
delay_ms(2);
break ;
/* chip erase <0> */
case 3 : state = 4 ;
send_dat( CMD_CHIP_ERASE );
send_con( 0x13 );
break ;
/* chip erase <1> latch command */
case 4 : state = 5 ;
send_con( 0x93 );
send_con( 0x13 );
break ;
/* chip erase <2> write pulse */
case 5 : state = 6 ;
send_con( 0x11 );
send_con( 0x13 );
break ;
/* chip erase <3> delay */
case 6 : state = 7 ;
delay_ms(10);
break ;
/* Write LOW fuse bit <0> */
case 7 : state = 8 ;
send_dat( CMD_WR_FUSE );
send_con( 0x13 );
break ;
/* write LOW fuse bit <1> latch command */
case 8 : state = 9 ;
send_con( 0x93 );
send_con( 0x13 );
break ;
/* Write LOW fuse bit <2> */
case 9 : state = 10 ;
send_dat( 0xdf );
send_con( 0x0b );
break ;
/* write LOW fuse bit <3> latch data */
case 10: state = 11 ;
send_con( 0x8b );
send_con( 0x0b );
break ;
/* write LOW fuse bit <4> write pulse */
case 11: state = 12 ;
send_con( 0x09 );
send_con( 0x0b );
break ;
/* write LOW fuse bit <5> delay */
case 12: state = 13 ;
delay_ms(5);
break ;
/* Write HIGH fuse bit <0> */
case 13: state = 14 ;
send_dat( CMD_WR_FUSE );
send_con( 0x13 );
break ;
/* write HIGH fuse bit <1> latch command */
case 14: state = 15 ;
send_con( 0x93 );
send_con( 0x13 );
break ;
/* Write HIGH fuse bit <2> */
case 15: state = 16 ;
send_dat( 0xdf );
send_con( 0x0b );
break ;
/* write HIGH fuse bit <3> latch data */
case 16: state = 17 ;
send_con( 0x8b );
send_con( 0x0b );
break ;
/* write HIGH fuse bit <4> write pulse */
case 17: state = 18 ;
send_con( 0x0f );
send_con( 0x0d );
send_con( 0x0f );
break ;
/* write HIGH fuse bit <5> delay */
case 18: state = 19 ;
send_con( 0x0b );
delay_ms(5);
break ;
/* Write EXT fuse bit <0> */
case 19: state = 20 ;
send_dat( CMD_WR_FUSE );
send_con( 0x13 );
break ;
/* write EXT fuse bit <1> latch command */
case 20: state = 21 ;
send_con( 0x93 );
send_con( 0x13 );
break ;
/* Write EXT fuse bit <2> */
case 21: state = 22 ;
send_dat( 0xff );
send_con( 0x0b );
break ;
/* write EXT fuse bit <3> latch data */
case 22: state = 23 ;
send_con( 0x8b );
send_con( 0x0b );
break ;
/* write EXT fuse bit <4> write pulse */
case 23: state = 24 ;
send_con( 0x2b );
send_con( 0x29 );
send_con( 0x2b );
break ;
/* write EXT fuse bit <5> delay */
case 24: state = 25 ;
send_con( 0x0b );
delay_ms(5);
break ;
/* default cmd and data */
case 25: state = 26 ;
send_dat( 0x00 );
send_con( 0x03 );
break ;
/* disable +12V */
case 26: state = 27 ;
send_pwr( PWR5 );
delay_ms(1);
break ;
/* disable +5V */
case 27: state = 0 ;
send_pwr( 0x00 );
delay_ms(5);
break ;
default :
state = 0 ;
break ;
}
}
/* dummy */
return 0 ;
}
void usr_init(void)
{
/* PORTB */
PORTB = 0b00000000 ;
DDRB = 0b11111111 ;
/* PORTD */
PORTD = 0b00000100 ;
DDRD = 0b11111011 ;
/* clear timer counter */
timcnt = 0 ;
/* clear state */
state = 0 ;
/* clear flag */
eflag = OFF ;
/* impress start condition */
send_pwr( 0x00 );
send_con( 0x01 );
send_dat( 0x00 );
/* initialize timer1 */
{
/* select CTC , (10MHz / 8) => 1,250kHz */
TCCR1B = (1 << WGM12) | (1 << CS11) ;
/* clear timer/counter */
TCNT1 = 0 ;
OCR1A = 1249 ;
OCR1B = 2500 ;
/* Enable Compare match interruption */
TIMSK = (1 << OCIE1A) ;
}
/* enable external interrupt */
{
/* select falling edge */
MCUCR = (1 << ISC01) ;
/* Enable external interruption */
GIMSK = (1 << INT0) ;
}
}
void send_pwr(UBYTE x)
{
send_pcd(PWR_BIT,x);
}
void send_con(UBYTE x)
{
send_pcd(CON_BIT,x);
}
void send_dat(UBYTE x)
{
send_pcd(D_BIT,x);
}
void send_pcd(UBYTE kind,UBYTE x)
{
/* impress data */
PORTB = x ;
/* trigger H */
if ( kind == PWR_BIT ) { PORTD |= (1 << PWR_BIT) ; }
if ( kind == CON_BIT ) { PORTD |= (1 << CON_BIT) ; }
if ( kind == D_BIT ) { PORTD |= (1 << D_BIT) ; }
/* dummy delay */
x >>= 1 ;
/* trigger L */
PORTD &= 0x0f ;
}
void delay_ms(UBYTE x)
{
volatile ULONG last ;
last = timcnt + x ;
while ( timcnt < last ) ;
}
/* INT0 interrupt */
ISR(INT0_vect)
{
eflag = ON ;
}
/* TIMER1 interrupt */
ISR(TIMER1_COMPA_vect)
{
timcnt++ ;
if ( timcnt & 1 ) { PORTD &= 0xfe ; }
else { PORTD |= 0x01 ; }
}
目次
前
次