目次
前
次
予備マシン
mugen2013に利用しているカメラは、OV7670ですが
他にも画像処理ができるマシンを用意して、緊急
事態に備えることにします。
mugenシリーズでは、シリアルインタフェースのカメラ
を利用したこともあるので、制御基板にGameBoyCamera
を接続して、予備マシンにします。(mugen2010のハード
を使うことに。)
制御基板の回路構成は、以下でした。
制御基板に、GameBoyCameraのインタフェース
を用意します。制御をポート8、データ入力を
ポート6(3ビット)、ポート7(0ビット)に担当
させます。
制御基板全体は、次のようにしました。
mugen2010マシンの制御基板には、H8/3048FOneを利用
していましたが、静電気による破損で3年近く、修理
しないでいました。今回、H8/3052Fを採用します。
H8/3052Fは、+5VでフラッシュROMの書換えができる
ことに加えて、内蔵SRAMが8kバイトになってます。
このSRAM容量が増えたことを、活かすファームを
考えます。
フラッシュROMへのダウンロード用に、新たに増設した
回路は、以下です。
スイッチの切り替えで、ファームウエアのダウンロード
と通常動作を切り替えます。
ハードウエア構成を変えたので、接続デバイスの動作を
テストするファームウエアを作成します。
ファームウエアの仕様を考えました。
シリアルでコマンドを送信
ITU0を使い、動作確認用LEDを点滅
ITU1を使い、左右のモータにPWM波形を出力
ITU1を使い、スタートトリガースイッチのクリック判定
EEPROMにデータを入出力
LCDに文字列を転送
GameBoyCamera(GBC)から画像データ取得
個別の動作を定義していきます。
動作確認用LEDを点滅
ITU0の割込みが動いているのかを確認します。
コマンドは、'A'を使い、パラメータに1を指定
すると点滅させ、0を指定すると消灯させます。
TFLAG、AFLAGの2フラグを利用します。
TFLAGは、ITU0の割込みでセットし通知に使います。
TFLAGのリセットは、main関数内部のループ処理で
担当します。
この処理は、次のコードで実現します。
if ( TFLAG == ON ) {
TFLAG = OFF ;
cnt++ ;
tmp = MASKFF ;
if ( cnt & 1 ) { tmp ^= MASKFF ; }
if ( AFLAG == OFF ) { tmp = MASKFF ; }
/* turn on or off LED */
GLED = OFF ;
if ( tmp ) { GLED = ON ; }
}
カウンタcntをインクリメントして、LEDへ出力する
論理値を決定します。もし、消灯指定がされている
と対応する論理値を1にします。(負論理利用)
消灯指定のフラグAFLAGは、次のようにコマンドで
セット、リセットします。
if ( cmd == 'A' ) {
/* get parameter */
tmp = get_hex( *(sbuf+1) );
/* judge */
AFLAG = OFF ;
if ( tmp > 0 ) { AFLAG = ON ; }
}
ITU0の割込みは、コンペアマッチを使います。
割込み周期は1msとします。
void int_imia0(void)
{
UBYTE dummy ;
/* clear flag */
dummy = ITU0.TSR.BIT.IMFA ;
ITU0.TSR.BIT.IMFA = OFF ;
/* increment */
timcnt++ ;
/* judge */
if ( (timcnt & 0x1ff) == 500 ) { TFLAG = ON ; }
}
変数timcntは、システムタイマーとして利用
します。1ms単位のディレイを生成する時
この値を参照します。
LEDの点滅周期は1秒単位です。
1秒ごとの点滅にするため、0.5秒ごとに
点灯、消灯にしています。
変数timcntを利用した1ms単位のディレイは
次の関数で実現します。
void delay_ms(UWORD x)
{
ULONG target ;
/* calculate last value */
target = timcnt + x ;
/* wait */
while ( timcnt < target ) ;
}
システムタイマーは、常にインクリメントされる
ので、現在のカウント値に、希望するディレイの
値を加えて、そこに達するまで待つ仕様です。
LCDの初期化に、delay_msを使うことになる
ので、ここで定義しておきました。
左右のモータにPWM波形を出力
ITU0の割込みが動くことが確認できれば、同じ種類の
割込みを利用して、左右のモータにPWM波形を出力し
回転を制御します。
H8/3052Fに内蔵されているPWM波形生成用モジュールを
使わずに、コンペアマッチ割込みでカウンタを動かし
与えられたDUTY比との比較で、ポートに出力する論理値
を決定します。
左右のDUTY比を設定するコマンドを、'M'とします。
DUTY比は、コマンドに続けて10進2けたで指定します。
左右のどちらか両方のDUTY比にするかは、L、R、Bで
指定します。
この仕様を実現するコードは、以下。
if ( cmd == 'M' ) {
/* get duty ratio */
tmp = get_hex( *(sbuf+1) );
tmp *= 10 ;
tmp += get_hex( *(sbuf+2) );
/* set duty ratio */
i = *(sbuf+3) ;
if ( i == 'R' ) { rduty = tmp ; }
if ( i == 'L' ) { lduty = tmp ; }
if ( i == 'B' ) { rduty = tmp ; lduty = tmp ;}
}
ITU1の割込みは、コンペアマッチを使います。
割込み周期は0.1msとします。
割込み関数では、カウンタを0〜99まで変化させ
指定DUTY比と比較し、出力論理値を確定します。
以下のように、非常に単純です。
void int_imia1(void)
{
UBYTE dummy ;
UBYTE xport ;
/* clear flag */
dummy = ITU1.TSR.BIT.IMFA ;
ITU1.TSR.BIT.IMFA = OFF ;
/* impress */
xport = 0 ;
if ( pcnt < rdutyx ) { xport |= 0x01 ; }
if ( pcnt < ldutyx ) { xport |= 0x04 ; }
PBDR = xport ;
/* increment */
pcnt++ ;
/* judge */
if ( pcnt == 100 ) {
pcnt = 0 ;
rdutyx = rduty ;
ldutyx = lduty ;
}
}
左右のDUTY比は、割込み関数内部で使う変数に
99から0にロールオーバーするときに、再設定
します。これで、1周期中にDUTY比を変更して
も、回転が乱れなくなります。
スタートトリガースイッチのクリック判定
スタートトリガースイッチをクリックしたことを
フラグで通知し、システム側が認識できていると
確認します。
フラグSFLAGで、main関数中のループに通知して
くるので、通知が来たことを端末に出力し、確認
します。
if ( SFLAG == ON ) {
/* clear flag */
SFLAG = OFF ;
/* send event happened */
rs1_puts("Get start trigger");
}
割込み関数内部で、シフトレジスタを使いチャタリング
を除去します。スイッチの論理値が、1から0に変化した
ことをシフトレジスタに格納された値で、判定します。
シフトレジスタの処理を加えた、割込み関数は、以下です。
void int_imia1(void)
{
UBYTE dummy ;
UBYTE xport ;
/* clear flag */
dummy = ITU1.TSR.BIT.IMFA ;
ITU1.TSR.BIT.IMFA = OFF ;
/* impress */
xport = 0 ;
if ( pcnt < rdutyx ) { xport |= 0x01 ; }
if ( pcnt < ldutyx ) { xport |= 0x04 ; }
PBDR = xport ;
/* increment */
pcnt++ ;
/* judge */
if ( pcnt == 100 ) {
pcnt = 0 ;
rdutyx = rduty ;
ldutyx = lduty ;
}
/* shift */
sft <<= 1 ;
sft &= 0x07 ;
/* get start trigger switch */
if ( SW_START == OFF ) { sft |= ON ; }
/* judge */
if ( sft == 0x03 ) { SFLAG = ON ; }
}
EEPROMにデータを入出力
GameBoyCameraは、パラメータを設定しなければならない
ので、何度がテストして、最適なパラメータを決定します。
ファームウエアのコードとして、パラメータを入れてしまうと
環境が変わったときに、再度コンパイル、リンクが必要になり
時間がかかります。それを避けるために、EEPROMにパラメータ
を保存して対応します。
利用しているEEPROMは、3線式のAT93C46です。
H8のポート4の上位4ビットを使い、データ入出力を
制御します。EEPROMとの接続は、以下とします。
- P47 : CS
- P46 : SK
- P45 : DI
- P44 : DO
AT93C46は、1ワード=16ビットのデータを入出力するので
1ワードの入力、出力関数を定義します。
リード、ライトともに、DIにコマンド、アドレスを与える
ので、一つのループで制御ワードにまとめて、ビット操作
します。
void eeprom_put(UBYTE ax,UWORD dx)
{
UWORD tmp ;
UBYTE i ;
/* judge */
if ( ax > 63 ) return ;
/* SB , OP code , dummy */
tmp = 0x140 | (ax & MASK3F) ;
/* enable chip select */
EEPROM_CS = ON ;
/* send address */
for ( i = 0 ; i < 9 ; i++ ) {
/* impress DI */
EEPROM_DI = OFF ;
if ( tmp & 0x100 ) { EEPROM_DI = ON ; }
/* SK : H */
EEPROM_SK = ON ;
/* shift */
tmp <<= 1 ;
/* SK : L */
EEPROM_SK = OFF ;
}
/* send data */
for ( i = 0 ; i < 16 ; i++ ) {
/* impress DI */
EEPROM_DI = OFF ;
if ( dx & 0x8000 ) { EEPROM_DI = ON ; }
/* SK : H */
EEPROM_SK = ON ;
/* shift */
dx <<= 1 ;
/* SK : L */
EEPROM_SK = OFF ;
}
/* disable chip select */
EEPROM_CS = OFF ;
/* delay */
delay_ms(10) ;
}
UWORD eeprom_get(UBYTE ax)
{
UWORD result ;
UWORD tmp ;
UBYTE i ;
/* judge */
if ( ax > 63 ) { return 0 ; }
/* SB , OP code , dummy */
tmp = 0x180 | (ax & MASK3F) ;
/* enable chip select */
EEPROM_CS = ON ;
/* send address */
for ( i = 0 ; i < 9 ; i++ ) {
/* impress DI */
EEPROM_DI = OFF ;
if ( tmp & 0x100 ) { EEPROM_DI = ON ; }
/* SK : H */
EEPROM_SK = ON ;
/* shift */
tmp <<= 1 ;
/* SK : L */
EEPROM_SK = OFF ;
}
/* default */
result = 0 ;
/* get data */
for ( i = 0 ; i < 16 ; i++ ) {
/* shift */
result <<= 1 ;
/* SK : H */
EEPROM_SK = ON ;
/* get data */
result |= EEPROM_DO ;
/* SK : L */
EEPROM_SK = OFF ;
}
/* disable chip select */
EEPROM_CS = OFF ;
return result ;
}
EEPROMのデータを、不用意に書き換えないように
電源を入れただけでは、リードオンリーになって
います。リード、ライトできるように、コマンド
を与えないといけないので、そのための関数を
定義します。
void eeprom_ewen(void)
{
UWORD tmp ;
UBYTE i ;
/* SB , OP code , dummy */
tmp = 0x130 ;
/* enable chip select */
EEPROM_CS = ON ;
/* send */
for ( i = 0 ; i < 9 ; i++ ) {
/* impress DI */
EEPROM_DI = OFF ;
if ( tmp & 0x100 ) { EEPROM_DI = ON ; }
/* SK : H */
EEPROM_SK = ON ;
/* shift */
tmp <<= 1 ;
/* SK : L */
EEPROM_SK = OFF ;
}
/* clear DI */
EEPROM_DI = OFF ;
/* disable chip select */
EEPROM_CS = OFF ;
}
デバイスとやりとりする機能を定義したので、シリアル
インタフェースで使うコマンドを考えます。
1ワード=16ビットの値を、アドレスを指定して
書込むため、コマンド'E'を定義します。
EEPROMにどんなデータが格納されているのかを
表示するため、コマンド’C'を定義します。
E=Edit、C=Clarifyという連想でコマンド名を
決めました。
EEPROMのデータ入出力のためのアドレスとデータを
変数eeprom_adr、eeprom_datに格納して、利用する
ことにします。
アドレスを指定して、データ(16ビット)を格納する
ための処理は、以下とします。
if ( cmd == 'E' ) {
/* get address */
eeprom_adr = 0 ;
eeprom_adr |= get_hex( *(sbuf+1) ); eeprom_adr <<= 4;
eeprom_adr |= get_hex( *(sbuf+2) );
/* get data */
eeprom_dat = 0 ;
eeprom_dat |= get_hex( *(sbuf+3) ); eeprom_dat <<= 4;
eeprom_dat |= get_hex( *(sbuf+4) ); eeprom_dat <<= 4;
eeprom_dat |= get_hex( *(sbuf+5) ); eeprom_dat <<= 4;
eeprom_dat |= get_hex( *(sbuf+6) );
/* store */
if ( eeprom_adr < 0x40 ) { eeprom_put(eeprom_adr,eeprom_dat); }
else { rs1_puts("Address out of area !"); }
}
EERPOM内データは、アドレスが最大63である
ことから、一気に表示します。
if ( cmd == 'C' ) {
/* loop */
for ( i = 0 ; i < 0x40 ; i++ ) {
/* get data */
tmpx = eeprom_get( i );
/* show */
show_value( (tmpx >> 8) & MASKFF );
show_value( tmpx & MASKFF );
rs1_putchar(' ');
/* new line */
if ( (i & MASK07) == 7 ) { rs1_crlf(); }
}
/* new line */
rs1_crlf() ;
}
1ワードを16進4けたで表示し、8ワードごとに
改行して見やすくしています。
LCDに文字列を転送
マシン走行中に、どういう状態になっているのかを
LCDを利用して表示させます。LCDに文字列表示する
ためのピンアサインは、以下とします。
- P43 : LCD_E
- P42 : LCD_RS
- P41 : HC_CLK
- P40 : HC_DAT
LCDとデータ交換するには、4ビットか8ビットの
データバスを使わなければなりません。
接続ピン数を減らすため、8ビットシフトレジスタ
を入れて、8ビットデータを格納してから、LCDに対
して、データ保存させます。
H8からは、書込みだけするので、R/W信号は'L'に
固定してあります。LCDを表示器として利用する
ため、この回路を採用しています。
LCDを制御するためには、コマンドとデータを
与えなければならないので、最下層で動作する
関数を定義します。
void lcd_primitive(UWORD x)
{
UBYTE i ;
UBYTE dd ;
/* get kind */
LCD_RS = OFF ;
if ( x & 0x100 ) { LCD_RS = ON ; }
/* send data */
dd = x & MASKFF ;
for ( i = 0 ; i < 8 ; i++ ) {
/* impress data */
HC_DAT = OFF ;
if ( dd & MASK80 ) { HC_DAT = ON ; }
/* CLK : H */
HC_CLK = ON ;
/* shift */
dd <<= 1 ;
/* CLK : L */
HC_CLK = OFF ;
}
/* impress E */
LCD_E = ON ;
dd <<= 1 ; /* dummy */
LCD_E = OFF ;
/* default */
LCD_RS = OFF ;
HC_DAT = OFF ;
}
コマンド、データの区別は、LCD_RSに与える論理値に
よるので、コマンド、データ用のラッパー関数を
関数lcd_primitiveに被せます。
void lcd_cmd(UBYTE x)
{
lcd_primitive( (UWORD)x );
}
void lcd_dat(UBYTE x)
{
lcd_primitive( x | 0x100 );
}
表示する文字列は、配列lcd_displayに格納します。
利用するLCDは、2行x16桁なので、配列の大きさは
32バイトにして、次のように定義しておきます。
UBYTE lcd_display[32];
行を指定して、文字列を表示する
コマンド'L'を定義します。
行は、0と1だけですが、LCD画面
をクリアしたいので、9行を指定
すると、スペースを表示して対応
します。
行は、コマンド'L'に続けて指定し
行指定の後に、表示したい文字列
を続けます。
main関数のループに、次のコードを入れて
LCDへの文字列表示をテストします。
if ( cmd == 'L' ) {
/* get line number */
lnumber = get_hex( *(sbuf+1) );
/* judge */
if ( lnumber < 2 ) {
/* calculate pointer */
lcd_index = lnumber * 16 ;
/* data transfer */
for ( i = 0 ; i < 16 ; i++ ) {
/* judge */
if ( *(sbuf+2+i) == '\r' ) break ;
/* copy */
*(lcd_display+lcd_index+i) = *(sbuf+2+i) ;
}
/* show strings on LCD */
send_lcd_handler();
}
if ( lnumber == 9 ) {
/* space transfer */
for ( i = 0 ; i < 32 ; i++ ) { *(lcd_display+i) = ' ' ; }
/* show strings on LCD */
send_lcd_handler();
}
}
受信バッファから配列lcd_displayに
文字列を転送後、関数send_lcd_handler
で一気に表示します。
関数send_lcd_handlerは、次のように定義しました。
void send_lcd_handler(void)
{
UBYTE line ;
UBYTE pixel ;
/* line handling */
for ( line = 0 ; line < 2 ; line++ ) {
/* set address */
lnumber = 0x00 ;
if ( line ) { lnumber = 0x40 ; }
lnumber |= MASK80 ;
lcd_cmd( lnumber );
/* calculate line */
lcd_index = 16 * line ;
/* pixel handling */
for ( pixel = 0 ; pixel < 16 ; pixel++ ) {
lcd_dat( *(lcd_display+lcd_index+pixel) );
}
}
}
LCD内部のデータバッファは、連続したアドレスでは
ないので、0行と1行を区別するためのエントリー
アドレスを指定します。
LCDを利用するときは、初期化が必要なので
関数init_lcdに記述して利用します。
void init_lcd(void)
{
/* initialize hardware */
delay_ms(15) ;
lcd_cmd(0x30);
delay_ms(5) ; /* 5ms */
lcd_cmd(0x30);
delay_ms(1); /* 1ms */
lcd_cmd(0x30);
delay_ms(1); /* 1ms */
/* set function */
lcd_cmd(0x38);
/*
Function
001 DL N F * *
DL(Data Length) = 1 (8bits)
N(Row) = 1 (4 row)
F(Font) = 0 (5x7)
001 1 1 0 * *
*/
lcd_cmd(0x08);
/*
Display off
0000 1 D C B
D(Display) = 0 (OFF)
C(Cursor) = 0 (OFF)
B(Blink) = 0 (OFF)
0000 1 0 0 0
*/
lcd_cmd(0x01);
delay_ms(2); /* 2ms */
lcd_cmd(0x0c);
/*
Display on
0000 1 D C B
D(Display) = 1 (ON)
C(Cursor) = 0 (OFF)
B(Blink) = 0 (OFF)
0000 1 1 0 0
*/
}
LCDとのインタフェースは、lcd_primitiveにまとめて
あるので、コマンド、データ転送には、ラッパー関数
であるlcd_cmd、lcd_datを利用します。
ハードウエアの違いを吸収するために、最下層の
関数を定義し、ラッパー関数を利用しているので
他のマイクロコンピュータへの移植が、容易です。
GameBoyCamera(GBC)から画像データ取得
GBCは、128x123の画像データを出力するので
H8/3052Fの内部SRAMの半分を画像データ格納
領域にします。
内部SRAMの半分は、4096バイトなので、この
領域で32ライン分のデータを格納できます。
GBCがどんな画像を撮影したのかは、同じ場所を
4回撮影して、合成します。
32ライン分しか容量がないので、画像データ用
バッファに保存する、ラインのエントリーポイント
を決めて対応します。
MCR_VCマシンでは、画像全体を使うのではなく
上にある64ラインの中から、3あるいは5本
のラインを利用します。
従って、32ライン分程度のバッファ容量で
充分移動処理を実現できます。
GBCは、パラメータを転送して初期化しないと
利用できないので、コマンド'P'をパラメータ
転送に使います。
パラメータは、レジスタ0〜7に設定するので
コマンド'P'に続けて、レジスタ番号を与えます。
レジスタ番号に続けて、16進数2桁でパラメータ
を設定します。
パラメータを再指定して、最適値を求めても電源
オフで消失するので、EEPROMに保存できるように
します。
さらに、カメラで撮影したデータを端末に転送する
ための処理も入れたいので、コマンドに続ける1つ
のパラメータに、次のような意味を与えます。
- 0 register number
- 1 register number
- 2 register number
- 3 register number
- 4 register number
- 5 register number
- 6 register number
- 7 register number
- 8 set entry line
- 9 transfer parameters from EEPROM
- A get graphic data from GBC
- B (no operation)
- C (no operation)
- D show graphic data
- E (no operation)
- F (no operation)
コマンドと続けるパラメータの意味を決めたので
対応するコードを定義します。
if ( cmd == 'P' ) {
/* get register address */
i = get_hex( *(sbuf+1) );
/* store parameter */
if ( i < 8 ) {
tmp = get_hex( *(sbuf+2) ) ;
tmp <<= 4 ;
tmp |= get_hex( *(sbuf+3) ) ;
*(gbcparam+i) = tmp ;
}
/* start line */
if ( i == 8 ) {
tmp = get_hex( *(sbuf+2) ) ;
tmp *= 10 ;
tmp |= get_hex( *(sbuf+3) ) ;
slinex = (tmp << 7);
elinex = slinex + 4095 ;
}
/* transfer parameters from EEPROM to array */
if ( i == 9 ) {
tmp = i ;
for ( i = 0 ; i < 4 ; i++ ) {
/* get parameter from EEPROM */
eeprom_dat = eeprom_get( i ) ;
/* transfer */
*(gbcparam+2*i) = (eeprom_dat >> 8) & MASKFF ;
*(gbcparam+2*i+1) = (eeprom_dat & MASKFF) ;
}
i = tmp ;
}
/* get data from GBC */
if ( i == 10 ) {
reset_gbc();
send_param_gbc();
send_start_gbc();
}
/* display GBC data */
if ( i == 13 ) { show_gbc_data(); }
}
GBCの画像データとパラメータ用配列は
次のように宣言して利用します。
UBYTE gbcdat[4096] ;
UBYTE gbcparam[8] ;
GBCで撮影するためには、シーケンスが必要なので
次の3関数を利用して、リセット、パラメータ設定
撮影という手順を踏みます。
void reset_gbc(void)
{
GBC_XCLK = OFF ;
/* enable XRST */
GBC_XRST = OFF ;
/* XCLK : H */
GBC_XCLK = ON ;
/* XCLK : L */
GBC_XCLK = OFF ;
/* disable XRST */
GBC_XRST = ON ;
}
void send_param_gbc(void)
{
UBYTE loop ;
UBYTE i ;
UBYTE tmp ;
/* loop */
for ( loop = 0 ; loop < 8 ; loop++ ) {
/* get data */
tmp = *(gbcparam+loop);
/* send data */
for ( i = 0 ; i < 8 ; i++ ) {
/* impress SIN */
GBC_SIN = OFF ;
if ( tmp & MASK80 ) { GBC_SIN = ON ; }
/* enable LOAD */
if ( i == 7 ) { GBC_LOAD = ON ; }
/* XCLK : H */
GBC_XCLK = ON ;
/* shift */
tmp <<= 1 ;
/* XCLK : L */
GBC_XCLK = OFF ;
/* set default value */
GBC_LOAD = OFF ;
}
/* set default values */
GBC_SIN = OFF ;
}
}
void send_start_gbc(void)
{
GBC_XCLK = OFF ;
/* enable START */
GBC_START = ON ;
/* XCLK : H */
GBC_XCLK = ON ;
/* XCLK : L */
GBC_XCLK = OFF ;
/* disable START */
GBC_START = OFF ;
/* clear */
gstate = 0 ;
/* enable */
GFLAG = ON ;
}
関数send_start_gbcで、画像データを取得する
シーケンサを起動します。
GBCが撮影した画像を取得するには、シーケンサ
gbc_handlerを使います。
void gbc_handler(void)
{
switch ( gstate ) {
/* wait trigger */
case 0 : if ( GFLAG == ON ) {
GFLAG = OFF ;
gstate = 1 ;
}
break ;
/* wait READ */
case 1 : if ( GBC_READ == ON ) {
gstate = 2 ;
gcnt = 0 ;
gindex = 0 ;
rs1_puts("*** Start ***");
}
break ;
/* judge */
case 2 : if ( gcnt == 15744 ) {
gstate = 3 ;
gcnt = 0 ;
rs1_puts("*** Complete ***");
}
break ;
/* return first state */
case 3 : gstate = 0 ;
break ;
/* */
default : gstate = 0 ; break ;
}
/* store data */
{
/* XCLK : H */
GBC_XCLK = ON ;
if ( GBC_READ == ON ) {
/* start A/D convert */
AD.ADCSR.BIT.ADST = 1 ;
}
/* XCLK : L */
GBC_XCLK = OFF ;
if ( GBC_READ == ON ) {
/* wait A/D conversion */
while ( AD.ADCSR.BIT.ADF == 0 ) ;
AD.ADCSR.BIT.ADF = 0 ;
/* store */
if ( slinex <= gcnt && gcnt <= elinex ) {
*(gbcdat+gindex) = (AD.ADDRA >> 8);
gindex++ ;
}
/* update counter */
gcnt++ ;
}
}
}
GBCがREAD信号で、有効なデータを出力していると
意思表示するので、この信号が'H'のときに、A/D
コンバータを動かします。
A/D変換されたデータは、取得したいライン範囲に
あれば、配列に保存します。
保存した画像データを、端末に数値で出力するため
関数show_gbc_dataを使います。
関数show_gbc_dataの内容は、以下。
void show_gbc_data(void)
{
UWORD loop ;
UBYTE tmp ;
UBYTE msg[3] ;
for ( loop = 0 ; loop < 4096 ; loop++ ) {
/* get data */
tmp = *(gbcdat+loop);
/* separate */
*(msg+0) = tmp / 100 ; tmp /= 100 ;
*(msg+1) = tmp / 10 ;
*(msg+2) = tmp % 10 ;
/* conversion */
*(msg+0) = asc_hex[*(msg+0)] ;
*(msg+1) = asc_hex[*(msg+1)] ;
*(msg+2) = asc_hex[*(msg+2)] ;
/* suppress zero */
tmp = *(gbcdat+loop);
if ( tmp < 100 ) {
*(msg+0) = ' ' ;
} else {
if ( tmp < 10 ) {
*(msg+1) = ' ' ;
}
}
/* send */
rs1_putchar( *(msg+0) ) ; rs1_putchar( *(msg+1) ) ;
rs1_putchar( *(msg+2) ) ; rs1_putchar( ' ' ) ;
/* new line */
if ( (loop % 8) == 7 ) { rs1_crlf() ; }
}
}
画像データの1ピクセルを0〜255の10進で表示します。
8データごとに改行しておきます。
画像として表示するためには、PersonalComputer側の
フリーソフトImageMagickを使います。
ハードウエアをテストするためのファームウエアの
全ソースコードは、以下。
#include "3052.h"
typedef unsigned char UBYTE ;
typedef unsigned short UWORD ;
typedef unsigned long ULONG ;
typedef signed char SBYTE ;
typedef signed short SWORD ;
#define NO 0
#define YES 1
/*----------------*/
/* user variables */
/*----------------*/
#define ITU0_AREG 24999
#define ITU1_AREG 2499
typedef union {
struct {
unsigned char B7:1;
unsigned char B6:1;
unsigned char B5:1;
unsigned char B4:1;
unsigned char B3:1;
unsigned char B2:1;
unsigned char B1:1;
unsigned char B0:1;
} BIT ;
unsigned char DR ;
} FLAGSP ;
FLAGSP x_flags ;
ULONG timcnt ;
#define SFLAG x_flags.BIT.B0
#define AFLAG x_flags.BIT.B1
#define TFLAG x_flags.BIT.B2
#define GFLAG x_flags.BIT.B5
#define UFLAG x_flags.BIT.B6
#define DFLAG x_flags.BIT.B7
#define P4DDR P4.DDR
#define P4DR P4.DR.BYTE
#define P6DDR P6.DDR
#define P6DR P6.DR.BYTE
#define P8DDR P8.DDR
#define P8DR P8.DR.BYTE
#define P7DR P7.DR.BYTE
#define P9DDR P9.DDR
#define P9DR P9.DR.BYTE
#define PADDR PA.DDR
#define PADR PA.DR.BYTE
#define PBDDR PB.DDR
#define PBDR PB.DR.BYTE
#define GLED P6.DR.BIT.B6
#define EEPROM_CS P4.DR.BIT.B7
#define EEPROM_SK P4.DR.BIT.B6
#define EEPROM_DI P4.DR.BIT.B5
#define EEPROM_DO P4.DR.BIT.B4
#define MASKFFFF 0xffff
#define MASKFF 0xff
#define MASKCF 0xcf
#define MASK0F 0x0f
#define MASK3F 0x3f
#define MASK07 0x07
#define OFF 0
#define ON OFF+1
#define MASK80 0x80
#define LCD_E P4.DR.BIT.B3
#define LCD_RS P4.DR.BIT.B2
#define HC_CLK P4.DR.BIT.B1
#define HC_DAT P4.DR.BIT.B0
#define GBC_START P8.DR.BIT.B4
#define GBC_SIN P8.DR.BIT.B3
#define GBC_LOAD P8.DR.BIT.B2
#define GBC_XRST P8.DR.BIT.B1
#define GBC_XCLK P8.DR.BIT.B0
#define GBC_READ P6.DR.BIT.B3
#define SW_START PB.DR.BIT.B4
#define SW_DIR PB.DR.BIT.B5
void init_sci_1(TBaudRate x);
void rs1_putchar(UBYTE x);
void rs1_crlf(void);
void rs1_puts(UBYTE *x);
void show_help(void);
void show_value(UBYTE x);
void lcd_primitive(UWORD x);
void lcd_cmd(UBYTE x);
void lcd_dat(UBYTE x);
void send_lcd_handler(void);
void init_lcd(void);
volatile UBYTE sindex ;
volatile UBYTE sbuf[32];
volatile UBYTE cmd ;
volatile UBYTE cnt ;
volatile UBYTE sft ;
volatile UBYTE asc_hex[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'} ;
volatile UBYTE eeprom_adr ;
volatile UWORD eeprom_dat ;
#define LCDBUFS 32
volatile UBYTE lcd_display[LCDBUFS] ;
volatile UBYTE lnumber ;
volatile UBYTE lcd_index ;
volatile UBYTE pcnt ;
volatile UBYTE rduty ;
volatile UBYTE lduty ;
volatile UBYTE rdutyx ;
volatile UBYTE ldutyx ;
volatile UBYTE gbcdat[4096] ;
volatile UBYTE gbcparam[8] ;
volatile UWORD gindex ;
volatile UWORD slinex ;
volatile UWORD elinex ;
volatile UBYTE gstate ;
volatile UWORD gcnt ;
/*--------------------------------*/
/* Insert user functions protoype */
/*--------------------------------*/
void user_initialize(void);
void init_timer0();
void init_timer1();
UBYTE get_hex(UBYTE x);
void delay_ms(UWORD x);
void eeprom_ewen(void);
void eeprom_put(UBYTE ax,UWORD dx);
UWORD eeprom_get(UBYTE ax);
void reset_gbc(void);
void send_param_gbc(void);
void send_start_gbc(void);
void gbc_handler(void);
void show_gbc_data(void);
/*------*/
/* main */
/*------*/
int main(void)
{
UBYTE tmp ;
UWORD tmpx ;
UBYTE i ;
/* disable interrupt */
DI ;
/* initialize */
user_initialize();
/* enable interrupt */
EI ;
/* opening message */
rs1_puts("Hello");
/* enable EEPROM */
eeprom_ewen();
/* initialize LCD */
init_lcd();
/* loop */
while ( ON ) {
/* command interpreter */
if ( UFLAG == ON ) {
/* clear flag */
UFLAG = OFF ;
/* new line */
rs1_crlf();
/* get command */
cmd = *(sbuf+0) ;
/* judge */
if ( cmd == '?' ) { show_help() ; }
if ( cmd == 'A' ) {
/* get parameter */
tmp = get_hex( *(sbuf+1) );
/* judge */
AFLAG = OFF ;
if ( tmp > 0 ) { AFLAG = ON ; }
}
if ( cmd == 'E' ) {
/* get address */
eeprom_adr = 0 ;
eeprom_adr |= get_hex( *(sbuf+1) ); eeprom_adr <<= 4;
eeprom_adr |= get_hex( *(sbuf+2) );
/* get data */
eeprom_dat = 0 ;
eeprom_dat |= get_hex( *(sbuf+3) ); eeprom_dat <<= 4;
eeprom_dat |= get_hex( *(sbuf+4) ); eeprom_dat <<= 4;
eeprom_dat |= get_hex( *(sbuf+5) ); eeprom_dat <<= 4;
eeprom_dat |= get_hex( *(sbuf+6) );
/* store */
if ( eeprom_adr < 0x40 ) { eeprom_put(eeprom_adr,eeprom_dat); }
else { rs1_puts("Address out of area !"); }
}
if ( cmd == 'C' ) {
/* loop */
for ( i = 0 ; i < 0x40 ; i++ ) {
/* get data */
tmpx = eeprom_get( i );
/* show */
show_value( (tmpx >> 8) & MASKFF );
show_value( tmpx & MASKFF );
rs1_putchar(' ');
/* new line */
if ( (i & MASK07) == 7 ) { rs1_crlf(); }
}
/* new line */
rs1_crlf() ;
}
/* LCD handling */
if ( cmd == 'L' ) {
/* get line number */
lnumber = get_hex( *(sbuf+1) );
/* judge */
if ( lnumber < 2 ) {
/* calculate pointer */
lcd_index = lnumber * 16 ;
/* data transfer */
for ( i = 0 ; i < 16 ; i++ ) {
/* judge */
if ( *(sbuf+2+i) == '\r' ) break ;
/* copy */
*(lcd_display+lcd_index+i) = *(sbuf+2+i) ;
}
/* show strings on LCD */
send_lcd_handler();
}
if ( lnumber == 9 ) {
/* space transfer */
for ( i = 0 ; i < 32 ; i++ ) { *(lcd_display+i) = ' ' ; }
/* show strings on LCD */
send_lcd_handler();
}
}
/* motor test */
if ( cmd == 'M' ) {
/* get duty ratio */
tmp = get_hex( *(sbuf+1) );
tmp *= 10 ;
tmp += get_hex( *(sbuf+2) );
/* set duty ratio */
i = *(sbuf+3) ;
if ( i == 'R' ) { rduty = tmp ; }
if ( i == 'L' ) { lduty = tmp ; }
if ( i == 'B' ) { rduty = tmp ; lduty = tmp ;}
}
/* GBC control */
if ( cmd == 'P' ) {
/* get register address */
i = get_hex( *(sbuf+1) );
/* store parameter */
if ( i < 8 ) {
tmp = get_hex( *(sbuf+2) ) ;
tmp <<= 4 ;
tmp |= get_hex( *(sbuf+3) ) ;
*(gbcparam+i) = tmp ;
}
/* start line */
if ( i == 8 ) {
tmp = get_hex( *(sbuf+2) ) ;
tmp *= 10 ;
tmp |= get_hex( *(sbuf+3) ) ;
slinex = (tmp << 7);
elinex = slinex + 4095 ;
}
/* transfer parameters from EEPROM to array */
if ( i == 9 ) {
tmp = i ;
for ( i = 0 ; i < 4 ; i++ ) {
/* get parameter from EEPROM */
eeprom_dat = eeprom_get( i ) ;
/* transfer */
*(gbcparam+2*i) = (eeprom_dat >> 8) & MASKFF ;
*(gbcparam+2*i+1) = (eeprom_dat & MASKFF) ;
}
i = tmp ;
}
/* get data from GBC */
if ( i == 10 ) {
reset_gbc();
send_param_gbc();
send_start_gbc();
}
/* display GBC data */
if ( i == 13 ) { show_gbc_data(); }
}
}
/* get data from GBC */
gbc_handler();
/* start trigge handling */
if ( SFLAG == ON ) {
/* clear flag */
SFLAG = OFF ;
/* send event happened */
rs1_puts("Get start trigger");
}
/* test handling */
if ( TFLAG == ON ) {
TFLAG = OFF ;
cnt++ ;
tmp = MASKFF ;
if ( cnt & 1 ) { tmp ^= MASKFF ; }
if ( AFLAG == OFF ) { tmp = MASKFF ; }
/* turn on or off LED */
GLED = OFF ;
if ( tmp ) { GLED = ON ; }
}
}
return 0 ;
}
/*-----------------------*/
/* Insert user functions */
/*-----------------------*/
void user_initialize(void)
{
int i ;
/* PORT 6 */
P6DR = 0xf0 ;
P6DDR = 0xf6 ; /* P60 , P63 inputs , others output */
/* PORT 8 */
P8DR = 0x02 ;
P8DDR = MASKFF ; /* all outputs */
/* PORT B */
PBDR = 0x00 ;
PBDDR = MASKCF ; /* PB5,PB4 inputs , others are outputs */
/* PORT A */
PADR = 0 ;
PADDR = MASKFF ; /* all outputs */
/* PORT 4 */
P4DR = 0x00 ; /* disable all */
P4DDR = 0xef ; /* P44 : inputs , others : outputs */
/* initialize timers */
init_timer0();
init_timer1();
/* clear flags */
x_flags.DR = 0 ;
/* clear SCI buffer */
*(sbuf+0) = 0 ; sindex = 0 ;
/* initialize */
timcnt = 0 ;
cnt = 0 ;
pcnt = 0 ;
rduty = 0 ;
lduty = 0 ;
rdutyx = 0 ;
ldutyx = 0 ;
sft = 0 ;
for ( i = 0 ; i < 32 ; i++ ) { *(lcd_display+i) = ' ' ; }
/* */
init_sci_1(br19200);
/* initialize A/D converter
single mode AN0
*/
AD.ADCSR.BYTE = 0x00 ;
}
void init_timer0(void)
{
/* stop timer */
ITU.TSTR.BIT.STR0 = OFF ;
/* TOER : Timer Output Enable Register
7 **** -> 0
6 **** -> 0
5 EXB4 -> 0
4 EXA4 -> 0
3 EB3 -> 0
2 EB4 -> 0
1 EA4 -> 0
0 EA3 -> 0
*/
ITU.TOER.BYTE = 0 ;
/* TIOR : Timer I/O Control Register
7 **** -> 0
6 IOB2 -> 0 GRB is not output compare match register
5 IOB1 -> 0
4 IOB0 -> 0
3 **** -> 0
2 IOA2 -> 0 GRA is not output compare match register
1 IOA1 -> 0
0 IOA0 -> 0
*/
ITU0.TIOR.BYTE = 0 ;
/* TCR : Timer Control Register
7 **** -> 0
6 CCLR1 -> 0 clear TCNT if GRA = TCNT
5 CCLR0 -> 1
4 CKEG1 -> 0 rising edge
3 CKEG0 -> 0
2 TPSC2 -> 0 φ利用
1 TPSC1 -> 0
0 TPSC0 -> 0
*/
ITU0.TCR.BYTE = 0x20 ;
/* TIER : Timer Interrupt Enable Register
7 **** -> 0
6 *** -> 0
5 *** -> 0
4 *** -> 0
3 *** -> 0
2 OVIE -> 0
1 IMIEB -> 0
0 IMIEA -> 1 select compare match interrupt
*/
ITU0.TIER.BIT.IMIEA = ON ;
/* reference */
ITU0.GRA = ITU0_AREG ;
ITU0.GRB = MASKFFFF ;
/* counter */
ITU0.TCNT = 0 ;
/* start timer */
ITU.TSTR.BIT.STR0 = ON ;
}
void init_timer1(void)
{
/* stop timer */
ITU.TSTR.BIT.STR1 = OFF ;
/* TOER : Timer Output Enable Register
7 **** -> 0
6 **** -> 0
5 EXB4 -> 0
4 EXA4 -> 0
3 EB3 -> 0
2 EB4 -> 0
1 EA4 -> 0
0 EA3 -> 0
*/
ITU.TOER.BYTE = 0 ;
/* TIOR : Timer I/O Control Register
7 **** -> 0
6 IOB2 -> 0 GRB is not output compare match register
5 IOB1 -> 0
4 IOB0 -> 0
3 **** -> 0
2 IOA2 -> 0 GRA is not output compare match register
1 IOA1 -> 0
0 IOA0 -> 0
*/
ITU1.TIOR.BYTE = 0 ;
/* TCR : Timer Control Register
7 **** -> 0
6 CCLR1 -> 0 clear TCNT if GRA = TCNT
5 CCLR0 -> 1
4 CKEG1 -> 0 rising edge
3 CKEG0 -> 0
2 TPSC2 -> 0 φ利用
1 TPSC1 -> 0
0 TPSC0 -> 0
*/
ITU1.TCR.BYTE = 0x20 ;
/* TIER : Timer Interrupt Enable Register
7 **** -> 0
6 *** -> 0
5 *** -> 0
4 *** -> 0
3 *** -> 0
2 OVIE -> 0
1 IMIEB -> 0
0 IMIEA -> 1 select compare match interrupt
*/
ITU1.TIER.BIT.IMIEA = ON ;
/* reference */
ITU1.GRA = ITU1_AREG ;
ITU1.GRB = MASKFFFF ;
/* counter */
ITU1.TCNT = 0 ;
/* start timer */
ITU.TSTR.BIT.STR1 = ON ;
}
/*+++++++++++++++++++++++++++++++++++++*/
/* ITU0 interrupt with compare match A */
/* 1ms interval */
/*+++++++++++++++++++++++++++++++++++++*/
void int_imia0(void)
{
UBYTE dummy ;
/* clear flag */
dummy = ITU0.TSR.BIT.IMFA ;
ITU0.TSR.BIT.IMFA = OFF ;
/* increment */
timcnt++ ;
/* judge */
if ( (timcnt & 0x1ff) == 500 ) { TFLAG = ON ; }
}
/*+++++++++++++++++++++++++++++++++++++*/
/* ITU1 interrupt with compare match A */
/* 0.1ms interval */
/*+++++++++++++++++++++++++++++++++++++*/
void int_imia1(void)
{
UBYTE dummy ;
UBYTE xport ;
/* clear flag */
dummy = ITU1.TSR.BIT.IMFA ;
ITU1.TSR.BIT.IMFA = OFF ;
/* impress */
xport = 0 ;
if ( pcnt < rdutyx ) { xport |= 0x01 ; }
if ( pcnt < ldutyx ) { xport |= 0x04 ; }
PBDR = xport ;
/* increment */
pcnt++ ;
/* judge */
if ( pcnt == 100 ) {
pcnt = 0 ;
rdutyx = rduty ;
ldutyx = lduty ;
}
/* shift */
sft <<= 1 ;
sft &= 0x07 ;
/* get start trigger switch */
if ( SW_START == OFF ) { sft |= ON ; }
/* judge */
if ( sft == 0x03 ) { SFLAG = ON ; }
}
/*+++++++++++++++++++++++++*/
/* SCI_1 receive interrupt */
/*+++++++++++++++++++++++++*/
void init_sci_1(TBaudRate x)
{
volatile UWORD i;
/* SCR : Serial Control Register
7 bit TIE -> 0 Transmit Interrupt Enable(disable)
6 bit RIE -> 0 Receive Interrupt Enable(disable)
5 bit TE -> 0 Transmit Enable(disable)
4 bit RE -> 0 Receive Enable(disable)
3 bit MPIE -> 0 Multi Processor Interrupt Enable(disable)
2 bit TEIE -> 0 Transmit End Interrupt Enable(disable)
1 bit CKE1 -> 0 Clock Source (Use Internal Baud Rate Generator)
0 bit CKE0 -> 0
*/
SCI1.SCR.BYTE = 0 ;
/* SMR : Serial Mode Register
7 bit C/nA -> 0 Communication Mode(Asynchronous)
6 bit CHR -> 0 data Charactor (8 bits)
5 bit PE -> 0 Parity Enable(disable)
4 bit O/nE -> 0 Parity Mode(even)
3 bit STOP -> 0 Stop Bit(1 bit)
2 bit MP -> 0 Multi Processor(disable)
1 bit CKS1 -> 0 Clock Source ( φ )
0 bit CKS0 -> 0
*/
SCI1.SMR.BYTE = 0 ;
/* data transfer speed */
SCI1.BRR = x ;
/* wait 1 frame */
for (i = 0; i < 3000 ; i++) ;
/* enable Transmmit and Receive with interrupt */
SCI1.SCR.BYTE = 0x70 ;
}
/*+++++++++++++++++++++++++*/
/* SCI_1 receive interrupt */
/*+++++++++++++++++++++++++*/
void int_rxi1(void)
{
volatile UBYTE ch,dummy ;
/* clear flag */
dummy = SCI1.SSR.BYTE ;
SCI1.SSR.BIT.RDRF = OFF ;
/* get a character */
ch = SCI1.RDR ;
/* store */
*(sbuf+sindex) = ch ;
sindex++ ;
/* check */
if ( ch == '\r' ) {
*(sbuf+sindex) = 0 ;
sindex = 0 ;
UFLAG = ON ;
}
}
/*+++++++++++++++*/
/* SCI_1 putchar */
/*+++++++++++++++*/
void rs1_putchar(UBYTE x)
{
/* wait data transfer */
while ( SCI1.SSR.BIT.TDRE == OFF ) ;
/* put */
SCI1.TDR = x ;
SCI1.SSR.BIT.TDRE = OFF ;
}
/*++++++++++++*/
/* SCI_1 puts */
/*++++++++++++*/
void rs1_puts(UBYTE *x)
{
/* send 1 charactors */
while ( *x ) {
rs1_putchar(*x);
x++ ;
}
/* new line */
rs1_crlf();
}
/*++++++++++++*/
/* SCI_1 crlf */
/*++++++++++++*/
void rs1_crlf(void)
{
rs1_putchar('\r');
rs1_putchar('\n');
}
/*++++++++++++++++++++*/
/* SCI_1 command help */
/*++++++++++++++++++++*/
void show_help(void)
{
rs1_puts("? help");
rs1_puts("A lamp flashing");
rs1_puts("E store data to EEPROM");
rs1_puts("C show EEPROM contents");
rs1_puts("L send strings to LCD");
rs1_puts("M test motor");
rs1_puts("P set GBC parameters");
}
void show_value(UBYTE x)
{
volatile UBYTE msg[2] ;
volatile UBYTE i ;
/* separate */
*(msg+0) = (x >> 4) & MASK0F ;
*(msg+1) = x & MASK0F ;
/* conversion */
*(msg+0) = asc_hex[ *(msg+0) ] ;
*(msg+1) = asc_hex[ *(msg+1) ] ;
/* output */
rs1_putchar( *(msg+0) ) ;
rs1_putchar( *(msg+1) ) ;
}
UBYTE get_hex(UBYTE x)
{
UBYTE result ;
/* 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 delay_ms(UWORD x)
{
ULONG target ;
/* calculate last value */
target = timcnt + x ;
/* wait */
while ( timcnt < target ) ;
}
/*+++++++++++++++++++++++++++++++*/
/* EEPROM enable erase and write */
/*+++++++++++++++++++++++++++++++*/
void eeprom_ewen(void)
{
UWORD tmp ;
UBYTE i ;
/* SB , OP code , dummy */
tmp = 0x130 ;
/* enable chip select */
EEPROM_CS = ON ;
/* send */
for ( i = 0 ; i < 9 ; i++ ) {
/* impress DI */
EEPROM_DI = OFF ;
if ( tmp & 0x100 ) { EEPROM_DI = ON ; }
/* SK : H */
EEPROM_SK = ON ;
/* shift */
tmp <<= 1 ;
/* SK : L */
EEPROM_SK = OFF ;
}
/* clear DI */
EEPROM_DI = OFF ;
/* disable chip select */
EEPROM_CS = OFF ;
}
/*+++++++++++++++++*/
/* EEPROM put data */
/*+++++++++++++++++*/
void eeprom_put(UBYTE ax,UWORD dx)
{
UWORD tmp ;
UBYTE i ;
/* judge */
if ( ax > 63 ) return ;
/* SB , OP code , dummy */
tmp = 0x140 | (ax & MASK3F) ;
/* enable chip select */
EEPROM_CS = ON ;
/* send address */
for ( i = 0 ; i < 9 ; i++ ) {
/* impress DI */
EEPROM_DI = OFF ;
if ( tmp & 0x100 ) { EEPROM_DI = ON ; }
/* SK : H */
EEPROM_SK = ON ;
/* shift */
tmp <<= 1 ;
/* SK : L */
EEPROM_SK = OFF ;
}
/* send data */
for ( i = 0 ; i < 16 ; i++ ) {
/* impress DI */
EEPROM_DI = OFF ;
if ( dx & 0x8000 ) { EEPROM_DI = ON ; }
/* SK : H */
EEPROM_SK = ON ;
/* shift */
dx <<= 1 ;
/* SK : L */
EEPROM_SK = OFF ;
}
/* disable chip select */
EEPROM_CS = OFF ;
/* delay */
delay_ms(10) ;
}
/*+++++++++++++++++*/
/* EEPROM get data */
/*+++++++++++++++++*/
UWORD eeprom_get(UBYTE ax)
{
UWORD result ;
UWORD tmp ;
UBYTE i ;
/* judge */
if ( ax > 63 ) { return 0 ; }
/* SB , OP code , dummy */
tmp = 0x180 | (ax & MASK3F) ;
/* enable chip select */
EEPROM_CS = ON ;
/* send address */
for ( i = 0 ; i < 9 ; i++ ) {
/* impress DI */
EEPROM_DI = OFF ;
if ( tmp & 0x100 ) { EEPROM_DI = ON ; }
/* SK : H */
EEPROM_SK = ON ;
/* shift */
tmp <<= 1 ;
/* SK : L */
EEPROM_SK = OFF ;
}
/* default */
result = 0 ;
/* get data */
for ( i = 0 ; i < 16 ; i++ ) {
/* shift */
result <<= 1 ;
/* SK : H */
EEPROM_SK = ON ;
/* get data */
result |= EEPROM_DO ;
/* SK : L */
EEPROM_SK = OFF ;
}
/* disable chip select */
EEPROM_CS = OFF ;
return result ;
}
void lcd_primitive(UWORD x)
{
UBYTE i ;
UBYTE dd ;
/* get kind */
LCD_RS = OFF ;
if ( x & 0x100 ) { LCD_RS = ON ; }
/* send data */
dd = x & MASKFF ;
for ( i = 0 ; i < 8 ; i++ ) {
/* impress data */
HC_DAT = OFF ;
if ( dd & MASK80 ) { HC_DAT = ON ; }
/* CLK : H */
HC_CLK = ON ;
/* shift */
dd <<= 1 ;
/* CLK : L */
HC_CLK = OFF ;
}
/* impress E */
LCD_E = ON ;
dd <<= 1 ; /* dummy */
LCD_E = OFF ;
/* default */
LCD_RS = OFF ;
HC_DAT = OFF ;
}
void lcd_cmd(UBYTE x)
{
lcd_primitive( (UWORD)x );
}
void lcd_dat(UBYTE x)
{
lcd_primitive( x | 0x100 );
}
void send_lcd_handler(void)
{
UBYTE line ;
UBYTE pixel ;
/* line handling */
for ( line = 0 ; line < 2 ; line++ ) {
/* set address */
lnumber = 0x00 ;
if ( line ) { lnumber = 0x40 ; }
lnumber |= MASK80 ;
lcd_cmd( lnumber );
/* calculate line */
lcd_index = 16 * line ;
/* pixel handling */
for ( pixel = 0 ; pixel < 16 ; pixel++ ) {
lcd_dat( *(lcd_display+lcd_index+pixel) );
}
}
}
void init_lcd(void)
{
/* initialize hardware */
delay_ms(15) ;
lcd_cmd(0x30);
delay_ms(5) ; /* 5ms */
lcd_cmd(0x30);
delay_ms(1); /* 1ms */
lcd_cmd(0x30);
delay_ms(1); /* 1ms */
/* set function */
lcd_cmd(0x38);
/*
Function
001 DL N F * *
DL(Data Length) = 1 (8bits)
N(Row) = 1 (4 row)
F(Font) = 0 (5x7)
001 1 1 0 * *
*/
lcd_cmd(0x08);
/*
Display off
0000 1 D C B
D(Display) = 0 (OFF)
C(Cursor) = 0 (OFF)
B(Blink) = 0 (OFF)
0000 1 0 0 0
*/
lcd_cmd(0x01);
delay_ms(2); /* 2ms */
lcd_cmd(0x0c);
/*
Display on
0000 1 D C B
D(Display) = 1 (ON)
C(Cursor) = 0 (OFF)
B(Blink) = 0 (OFF)
0000 1 1 0 0
*/
}
void reset_gbc(void)
{
GBC_XCLK = OFF ;
/* enable XRST */
GBC_XRST = OFF ;
/* XCLK : H */
GBC_XCLK = ON ;
/* XCLK : L */
GBC_XCLK = OFF ;
/* disable XRST */
GBC_XRST = ON ;
}
void send_param_gbc(void)
{
UBYTE loop ;
UBYTE i ;
UBYTE tmp ;
/* loop */
for ( loop = 0 ; loop < 8 ; loop++ ) {
/* get data */
tmp = *(gbcparam+loop);
/* send data */
for ( i = 0 ; i < 8 ; i++ ) {
/* impress SIN */
GBC_SIN = OFF ;
if ( tmp & MASK80 ) { GBC_SIN = ON ; }
/* enable LOAD */
if ( i == 7 ) { GBC_LOAD = ON ; }
/* XCLK : H */
GBC_XCLK = ON ;
/* shift */
tmp <<= 1 ;
/* XCLK : L */
GBC_XCLK = OFF ;
/* set default value */
GBC_LOAD = OFF ;
}
/* set default values */
GBC_SIN = OFF ;
}
}
void send_start_gbc(void)
{
GBC_XCLK = OFF ;
/* enable START */
GBC_START = ON ;
/* XCLK : H */
GBC_XCLK = ON ;
/* XCLK : L */
GBC_XCLK = OFF ;
/* disable START */
GBC_START = OFF ;
/* clear */
gstate = 0 ;
/* enable */
GFLAG = ON ;
}
void gbc_handler(void)
{
switch ( gstate ) {
/* wait trigger */
case 0 : if ( GFLAG == ON ) {
GFLAG = OFF ;
gstate = 1 ;
}
break ;
/* wait READ */
case 1 : if ( GBC_READ == ON ) {
gstate = 2 ;
gcnt = 0 ;
gindex = 0 ;
rs1_puts("*** Start ***");
}
break ;
/* judge */
case 2 : if ( gcnt == 15744 ) {
gstate = 3 ;
gcnt = 0 ;
rs1_puts("*** Complete ***");
}
break ;
/* return first state */
case 3 : gstate = 0 ;
break ;
/* */
default : gstate = 0 ; break ;
}
/* store data */
{
/* XCLK : H */
GBC_XCLK = ON ;
if ( GBC_READ == ON ) {
/* start A/D convert */
AD.ADCSR.BIT.ADST = 1 ;
}
/* XCLK : L */
GBC_XCLK = OFF ;
if ( GBC_READ == ON ) {
/* wait A/D conversion */
while ( AD.ADCSR.BIT.ADF == 0 ) ;
AD.ADCSR.BIT.ADF = 0 ;
/* store */
if ( slinex <= gcnt && gcnt <= elinex ) {
*(gbcdat+gindex) = (AD.ADDRA >> 8);
gindex++ ;
}
/* update counter */
gcnt++ ;
}
}
}
void show_gbc_data(void)
{
UWORD loop ;
UBYTE tmp ;
UBYTE msg[3] ;
for ( loop = 0 ; loop < 4096 ; loop++ ) {
/* get data */
tmp = *(gbcdat+loop);
/* separate */
*(msg+0) = tmp / 100 ; tmp /= 100 ;
*(msg+1) = tmp / 10 ;
*(msg+2) = tmp % 10 ;
/* conversion */
*(msg+0) = asc_hex[*(msg+0)] ;
*(msg+1) = asc_hex[*(msg+1)] ;
*(msg+2) = asc_hex[*(msg+2)] ;
/* suppress zero */
tmp = *(gbcdat+loop);
if ( tmp < 100 ) {
*(msg+0) = ' ' ;
} else {
if ( tmp < 10 ) {
*(msg+1) = ' ' ;
}
}
/* send */
rs1_putchar( *(msg+0) ) ; rs1_putchar( *(msg+1) ) ;
rs1_putchar( *(msg+2) ) ; rs1_putchar( ' ' ) ;
/* new line */
if ( (loop % 8) == 7 ) { rs1_crlf() ; }
}
}
このファームウエアで、動作テストが完了したなら
画像処理と走行制御を付加して、完成させます。
H8でGameBoyCameraを制御する前に、ATmega168により
動作確認しました。接続は、次のようにしました。
- PC5 START
- PC4 SIN
- PC3 LOAD
- PC2 XRST
- PC1 XCK
- PC0 Vout
- PB5 READ
- PB4 BUSY
- PB3 ITRG(PORTD input)
- PB2 OTRG(PORTD output)
- PB1 LTRG(set target line number)
- PB0 TRG(command)
- PD7 (BUS)
- PD6 (BUS)
- PD5 (BUS)
- PD4 (BUS)
- PD3 (BUS)
- PD2 (BUS)
- PD1 (BUS)
- PD0 (BUS)
GameBoyCameraとのインタフェースは、ポートC
全体とポートBの1ビットを利用します。
他のマイコン、デジタル回路とのインタフェース
は、ポートDをデータバス、ポートBを制御バス
にします。
ATmega168は、GameBoyCameraと一体になったユニット
基板のインタフェースを担当します。
制御、データバスを利用してコマンドや
情報交換できるようにしました。
コマンドの種別は、以下。
- CMD_RESET 0x01 /* send RESET signal to GBC */
- CMD_SETP 0x02 /* send parameters to GBC */
- CMD_START 0x04 /* start take shot */
- CMD_ZERO 0x08 /* clear register address */
- CMD_INCR 0x10 /* register address increment */
GBCの制御コマンドを3種、画像処理の結果を
レジスタに保存しているとして、コマンドを
2種用意しました。これらは、バスに8ビット
のコマンドを出力し、CTRGでATmega168に入力
します。
GBCで3ラインのデータを画像処理し、レジスタ0から5の
各8バイトに格納。偶数アドレスレジスタにはセンター位置
(0〜160の値)、奇数アドレスレジスタにはセンターライン
の幅を格納します。
3ラインをどれにするかは、バスにライン番号を
出力し、LTRGでATmega168に入力します。
バスの方向は、ITRG、OTRGによりATmega168に指示します。
レジスタ0〜5の6バイトの内容を取り出す
には、次のシーケンスを使います。
- CMD_ZEROをバスに出力し、CTRGを与える
- OTRGを与えて、バスにデータを出力させる
- バス上のデータをリード後、ITRGを与える(レジスタ0の値)
- CMD_INCRをバスに出力し、CTRGを与える
- OTRGを与えて、バスにデータを出力させる
- バス上のデータをリード後、ITRGを与える(レジスタ1の値)
- CMD_INCRをバスに出力し、CTRGを与える
- OTRGを与えて、バスにデータを出力させる
- バス上のデータをリード後、ITRGを与える(レジスタ2の値)
- CMD_INCRをバスに出力し、CTRGを与える
- OTRGを与えて、バスにデータを出力させる
- バス上のデータをリード後、ITRGを与える(レジスタ3の値)
- CMD_INCRをバスに出力し、CTRGを与える
- OTRGを与えて、バスにデータを出力させる
- バス上のデータをリード後、ITRGを与える(レジスタ4の値)
- CMD_INCRをバスに出力し、CTRGを与える
- OTRGを与えて、バスにデータを出力させる
- バス上のデータをリード後、ITRGを与える(レジスタ5の値)
GBCを動かして、画像処理中は、BUSY信号が'H'
であることを見て確認します。
このような操作ができるように作成した
ATmega168のファームウエアは、以下です。
#include <avr/io.h>
#include <avr/interrupt.h>
#define OFF 0
#define ON OFF+1
typedef unsigned char UBYTE ;
typedef unsigned short UWORD ;
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 BTRG x_flags.BIT.B0 /* BUS command trigger */
#define LTRG x_flags.BIT.B1 /* set target line number */
#define CTRG x_flags.BIT.B2 /* convert binary */
#define OTRG x_flags.BIT.B3 /* change PORTD output */
#define ITRG x_flags.BIT.B4 /* change PORTD input */
#define RTRG x_flags.BIT.B5 /* READ rising edge flag */
#define ECLKFLAG x_flags.BIT.B6 /* enable XCK signal */
#define LINE_MAX 64 /* maximum line counter */
#define PIXEL_MAX 128 /* maximum pixel counter */
volatile UBYTE param[8] ;
/* graphic data */
volatile UBYTE line_top[PIXEL_MAX] ;
volatile UBYTE line_middle[PIXEL_MAX] ;
volatile UBYTE line_bottom[PIXEL_MAX] ;
/* binary data */
volatile UBYTE bline_top[PIXEL_MAX] ;
volatile UBYTE bline_middle[PIXEL_MAX] ;
volatile UBYTE bline_bottom[PIXEL_MAX] ;
#define NO 0
#define YES NO+1
#define MASK07 0x07
#define MASK80 0x80
#define MASK40 0x40
#define MASK20 0x20
#define MASK10 0x10
#define MASK08 0x08
#define MASK04 0x04
#define MASK02 0x02
#define MASK01 0x01
#define CMD_RESET 0x01 /* send RESET signal to GBC */
#define CMD_SETP 0x02 /* send parameters to GBC */
#define CMD_START 0x04 /* start take shot */
#define CMD_ZERO 0x08 /* clear register address */
#define CMD_INCR 0x10 /* register address increment */
volatile UBYTE cmd ;
volatile UBYTE tline[3] ; /* target line */
volatile UBYTE bsft ; /* BUS command */
volatile UBYTE lsft ; /* target line */
volatile UBYTE osft ; /* output trigger */
volatile UBYTE isft ; /* input trigger */
volatile UBYTE cam_dat ; /* camera data */
volatile UBYTE cstate ; /* camera handling sequencer */
volatile UBYTE xlcnt ; /* line counter */
volatile UBYTE xpcnt ; /* pixel counter */
volatile UBYTE reg[6] ; /* register values */
volatile UBYTE rindex ; /* register index */
#define XCK_H (PORTC |= (1 << PC1))
#define XCK_L (PORTC &= ~(1 << PC1))
#define XRST_H (PORTC |= (1 << PC2))
#define XRST_L (PORTC &= ~(1 << PC2))
#define LOAD_H (PORTC |= (1 << PC3))
#define LOAD_L (PORTC &= ~(1 << PC3))
#define SIN_H (PORTC |= (1 << PC4))
#define SIN_L (PORTC &= ~(1 << PC4))
#define START_H (PORTC |= (1 << PC5))
#define START_L (PORTC &= ~(1 << PC5))
#define BUSY_H (PORTB |= (1 << PB4))
#define BUSY_L (PORTB &= ~(1 << PB4))
/*--------------------------------*/
/* Insert user functions protoype */
/*--------------------------------*/
void user_initialize(void);
void gbc_reset(void);
void put_param(UWORD x);
void gbc_set_param(void);
void gbc_start(void);
UBYTE get_adv(void);
void camera_handler(void);
void bconv_handler(void);
void lnsort(void);
UBYTE dhalf(UBYTE x,UBYTE y);
UBYTE xabs(UBYTE x,UBYTE y);
/*------*/
/* main */
/*------*/
int main(void)
{
user_initialize();
/* enable interrupt */
sei();
/* loop */
while ( ON ) {
/* command interpreter */
if ( BTRG == ON ) {
/* clear flag */
BTRG = OFF ;
/* get command */
cmd = PIND ;
/* judge */
if ( cmd == CMD_RESET ) { gbc_reset(); }
if ( cmd == CMD_SETP ) { gbc_set_param(); }
if ( cmd == CMD_START ) {
gbc_start();
ECLKFLAG = ON ;
BUSY_H ;
}
if ( cmd == CMD_ZERO ) { rindex = 0 ; }
if ( cmd == CMD_INCR ) {
rindex++ ;
if ( rindex == 6 ) { rindex = 0 ; }
}
}
/* store target line number */
if ( LTRG == ON ) {
/* clear flag */
LTRG = OFF ;
/* shift */
*(tline+0) = *(tline+1) ;
*(tline+1) = *(tline+2) ;
/* get line number */
*(tline+2) = PIND ;
/* sort */
lnsort();
}
/* output register data */
if ( OTRG == ON ) {
/* clear flag */
OTRG = OFF ;
/* impress data */
PORTD = *(reg+rindex) ;
/* change output */
DDRD = 0xff ;
}
/* PORTD input */
if ( ITRG == ON ) {
/* clear flag */
ITRG = OFF ;
/* change input */
DDRD = 0x00 ;
}
/* binary conversion */
if ( CTRG == ON ) {
/* clear flag */
CTRG = OFF ;
/* do */
bconv_handler();
}
/* get data from camera */
camera_handler();
}
/* dummy */
return 0 ;
}
void user_initialize(void)
{
UBYTE i ;
/* PORT C */
PORTC = 0b11111100 ; /* 11111110 */
DDRB = 0b11111110 ; /* oooooooi */
/* PORT B */
PORTB = 0b11101111 ; /* 11101111 */
DDRB = 0b00010000 ; /* iiioiiii */
/* PORT D */
PORTC = 0b00000000 ; /* 00000000 */
DDRB = 0b00000000 ; /* iiiiiiii */
/* initialize A/D converter */
{
ADMUX = 0x40 ; /* Vref = AVcc , channel 0 */
ADCSRA = 0x80 ; /* enable A/D conversion */
DIDR0 = 0x01 ; /* PC0 is disable digital inputs */
}
/* initialize timer 0 */
{
/* CTC */
TCCR0A = (1 << WGM01) ;
/* prescaler 1/64 250kHz */
TCCR0B = (3 << CS00) ;
/* set timer0 ouput compare match register A */
OCR0A = 249 ; /* 1kHz */
OCR0B = 255 ;
/* clear counter */
TCNT0 = 0 ;
/* enable interrupt */
TIMSK0 |= (1 << OCIE0A) ;
}
/* clear shift registers */
bsft = 0 ;
lsft = 0 ;
osft = 0 ;
isft = 0 ;
/* target line */
*(tline+0) = 0 ;
*(tline+1) = 0 ;
*(tline+2) = 0 ;
/* set camera parameters */
*(param+0) = 0xa1 ;
*(param+1) = 0xec ;
*(param+2) = 0x05 ;
*(param+3) = 0x00 ;
*(param+4) = 0x01 ;
*(param+5) = 0x00 ;
*(param+6) = 0x01 ;
*(param+7) = 0x03 ;
/* clear pixel data */
for ( i = 0 ; i < PIXEL_MAX ; i++ ) {
/* graphic data */
*(line_top+i) = 0 ;
*(line_middle+i) = 0 ;
*(line_bottom+i) = 0 ;
/* binary data */
*(bline_top+i) = 0 ;
*(bline_middle+i) = 0 ;
*(bline_bottom+i) = 0 ;
}
/* */
cstate = 0 ;
cam_dat = 0 ;
rindex = 0 ;
}
/************************/
/* Timer0 compare match */
/* frequency 1ms */
/************************/
ISR(TIMER0_COMPA_vect)
{
UBYTE tmp ;
/* shift */
bsft <<= 1 ;
lsft <<= 1 ;
osft <<= 1 ;
isft <<= 1 ;
/* get state */
tmp = PINB ;
if ( tmp & MASK01 ) { bsft |= ON ; }
if ( tmp & MASK02 ) { lsft |= ON ; }
if ( tmp & MASK04 ) { osft |= ON ; }
if ( tmp & MASK08 ) { isft |= ON ; }
/* mask */
bsft &= MASK07 ;
lsft &= MASK07 ;
osft &= MASK07 ;
isft &= MASK07 ;
/* judge and generate trigger */
if ( bsft == 0x03 || bsft == 0x01 ) { BTRG = ON ; }
if ( lsft == 0x03 || lsft == 0x01 ) { LTRG = ON ; }
if ( osft == 0x03 || osft == 0x01 ) { OTRG = ON ; }
if ( isft == 0x03 || isft == 0x01 ) { ITRG = ON ; }
}
void gbc_reset(void)
{
XRST_L ; /* XRST : L */
XCK_H ; /* XCK : H */
XRST_H ; /* XRST : H */
XCK_L ; /* XCK : L */
}
#define SIN_BIT 0x400
void put_param(UWORD x)
{
UBYTE i ;
for ( i = 0 ; i < 11 ; i++ ) {
/* impress SIN */
SIN_L ;
if ( x & SIN_BIT ) { SIN_H ; }
/* LOAD */
LOAD_L ;
if ( i == 10 ) { LOAD_H ; }
/* XCK : H */
XCK_H ;
/* shift */
x <<= 1 ;
/* XCK : L */
XCK_L ;
}
LOAD_L ;
}
void gbc_set_param(void)
{
UWORD params[8] ;
UBYTE i ;
for ( i = 0 ; i < 8 ; i++ ) {
/* set address */
*(params+i) = (i << 8) ;
/* add parameter */
*(params+i) |= *(param+i) ;
/* transfer parameter */
put_param( *(params+i) ) ;
}
}
void gbc_start(void)
{
START_H ; /* START : H */
XCK_H ; /* XCK : H */
START_L ; /* START : L */
XCK_L ; /* XCK : L */
}
UBYTE get_adv(void)
{
UBYTE advh ;
UWORD result ;
/* start A/D conversion */
ADCSRA |= (1 << ADSC) ;
/* ? complete conversion */
while ( ADCSRA & (1 << ADSC) ) ;
/* get values */
advh = ADCH ;
/* concatenate */
result = (advh << 8) | ADCL ;
return (UBYTE)(result >> 2);
}
void camera_handler(void)
{
/* READ state */
RTRG = OFF ;
if ( PINB & MASK20 ) { RTRG = ON ; }
/* get data from CAMERA */
switch ( cstate ) {
/* dummy XCK_H */
case 0 : if ( ECLKFLAG == ON ) {
XCK_H ;
cstate = 1 ; /* next state */
}
break ;
/* dummy XCK_L */
case 1 : XCK_L ;
if ( RTRG == ON ) {
cstate = 5 ;
ECLKFLAG = OFF ;
xlcnt = 0 ; /* clear line counter */
xpcnt = 0 ; /* clear pixel counter */
} else {
cstate = 2 ; /* next state */
}
break ;
/* judge */
case 2 : cstate = 0 ; /* first state */
break ;
/* XCLK : H */
case 3 : XCK_H ;
/* next state */
cstate = 4 ;
break ;
/* XCLK : L */
case 4 : XCK_L ;
/* next state */
cstate = 5 ;
break ;
/* store */
case 5 : cam_dat = get_adv();
if ( xlcnt == *(tline+0) ) {
*(line_top+xpcnt) = cam_dat ;
}
if ( xlcnt == *(tline+1) ) {
*(line_top+xpcnt) = cam_dat ;
}
if ( xlcnt == *(tline+2) ) {
*(line_bottom+xpcnt) = cam_dat ;
}
/* next state */
cstate = 6 ;
break ;
/* update pixel counter */
case 6 : xpcnt++ ;
if ( xpcnt == PIXEL_MAX ) {
/* clear pixel counter */
xpcnt = 0 ;
/* next state */
cstate = 7 ;
} else {
/* get data */
cstate = 4 ;
}
break ;
/* update line counter */
case 7 : xlcnt++ ;
if ( xlcnt == LINE_MAX ) {
/* clear line counter */
xlcnt = 0 ;
/* next state */
cstate = 8 ;
} else {
/* get data */
cstate = 4 ;
}
break ;
/* return first state */
case 8 : cstate = 0 ;
/* set conversion trigger */
CTRG = ON ;
/* complete */
BUSY_L ;
break ;
/* */
default : cstate = 0 ;
break ;
}
}
void bconv_handler(void)
{
UBYTE i ;
UBYTE xmax[3] ;
UBYTE xmin[3] ;
UBYTE thv[3] ;
UBYTE lpix[3] ;
UBYTE rpix[3] ;
/* psuedo */
*(xmax+0) = *(line_top+0) ; *(xmin+0) = *(line_top+0) ;
*(xmax+1) = *(line_middle+0) ; *(xmin+1) = *(line_middle+0) ;
*(xmax+2) = *(line_bottom+0) ; *(xmin+2) = *(line_bottom+0) ;
/* search */
for ( i = 1 ; i < PIXEL_MAX ; i++ ) {
/* max */
if ( *(xmax+0) < *(line_top+i) ) { *(xmax+0) = *(line_top+i) ; }
if ( *(xmax+1) < *(line_middle+i) ) { *(xmax+1) = *(line_middle+i) ; }
if ( *(xmax+2) < *(line_bottom+i) ) { *(xmax+2) = *(line_bottom+i) ; }
/* min */
if ( *(xmin+0) > *(line_top+i) ) { *(xmin+0) = *(line_top+i) ; }
if ( *(xmin+1) > *(line_middle+i) ) { *(xmin+1) = *(line_middle+i) ; }
if ( *(xmin+2) > *(line_bottom+i) ) { *(xmin+2) = *(line_bottom+i) ; }
}
/* calculate */
*(thv+0) = dhalf(*(xmax+0),*(xmin+0)) ;
*(thv+1) = dhalf(*(xmax+1),*(xmin+1)) ;
*(thv+2) = dhalf(*(xmax+2),*(xmin+2)) ;
/* conversion */
for ( i = 0 ; i < PIXEL_MAX ; i++ ) {
/* default */
*(bline_top+i) = 0 ;
*(bline_middle+i) = 0 ;
*(bline_bottom+i) = 0 ;
/* top */
if ( *(line_top+i) > *(thv+0) ) { *(bline_top+i) = 1 ; }
/* middle */
if ( *(line_middle+i) > *(thv+1) ) { *(bline_middle+i) = 1 ; }
/* bottom */
if ( *(line_bottom+i) > *(thv+2) ) { *(bline_bottom+i) = 1 ; }
}
/* initialize location */
*(lpix+0) = PIXEL_MAX ; *(rpix+0) = PIXEL_MAX ;
*(lpix+1) = PIXEL_MAX ; *(rpix+1) = PIXEL_MAX ;
*(lpix+2) = PIXEL_MAX ; *(rpix+2) = PIXEL_MAX ;
/* search */
for ( i = 0 ; i < 127 ; i++ ) {
/* top */
*(xmax+0) = *(bline_top+i) ;
*(xmin+0) = *(bline_top+i+1) ;
if ( *(xmax+0) == 0 && *(xmin+0) == 1 ) { *(lpix+0) = i ; }
if ( *(xmax+0) == 1 && *(xmin+0) == 0 ) { *(rpix+0) = i ; }
/* middle */
*(xmax+1) = *(bline_middle+i) ;
*(xmin+1) = *(bline_middle+i+1) ;
if ( *(xmax+1) == 0 && *(xmin+1) == 1 ) { *(lpix+1) = i ; }
if ( *(xmax+1) == 1 && *(xmin+1) == 0 ) { *(rpix+1) = i ; }
/* bottom */
*(xmax+2) = *(bline_bottom+i) ;
*(xmin+2) = *(bline_bottom+i+1) ;
if ( *(xmax+2) == 0 && *(xmin+2) == 1 ) { *(lpix+2) = i ; }
if ( *(xmax+2) == 1 && *(xmin+2) == 0 ) { *(rpix+2) = i ; }
}
/* center */
*(reg+0) = dhalf( *(lpix+0) , *(rpix+0) ) ;
*(reg+2) = dhalf( *(lpix+1) , *(rpix+1) ) ;
*(reg+4) = dhalf( *(lpix+2) , *(rpix+2) ) ;
/* width */
*(reg+1) = xabs( *(lpix+0) , *(rpix+0) ) ;
*(reg+3) = xabs( *(lpix+1) , *(rpix+1) ) ;
*(reg+5) = xabs( *(lpix+1) , *(rpix+1) ) ;
}
void lnsort(void)
{
UBYTE tmp ;
/* first sort */
if ( *(tline+0) > *(tline+1) ) {
tmp = *(tline+0) ;
*(tline+0) = *(tline+1) ;
*(tline+1) = tmp ;
}
if ( *(tline+0) > *(tline+2) ) {
tmp = *(tline+0) ;
*(tline+0) = *(tline+2) ;
*(tline+2) = tmp ;
}
/* second sort */
if ( *(tline+1) > *(tline+2) ) {
tmp = *(tline+1) ;
*(tline+1) = *(tline+2) ;
*(tline+2) = tmp ;
}
}
UBYTE dhalf(UBYTE x,UBYTE y)
{
UWORD result ;
result = x + y ;
result >>= 1 ;
return (UBYTE)result ;
}
UBYTE xabs(UBYTE x,UBYTE y)
{
UBYTE result ;
if ( x > y ) { result = x - y ; }
else { result = y - x ; }
return result ;
}
画像処理、次のシーケンスで実現しています。
- 128x63のうちの3ライン分の情報をバッファに格納
- バッファ中の最大値、最小値を求める
- 最大値と最小値の相加平均を閾値とする
- 閾値を使い、バッファの値を2値化し他のバッファに格納
- 2値化値格納バッファで01と変化する位置を計算
- 2値化値格納バッファで10と変化する位置を計算
- 5、6の値の相加平均をセンターラインの中心位置とする
- 5、6の値の差をラインの幅とする
画像処理の結果は、センターラインの中心位置と幅になる
ので、センターラインの中心位置はピクセル数160未満で
幅は、スタート前に取得しておいた値と比較できます。
センターラインの中央位置、幅の2パラメータから
マシンはセンターラインの上、左、右のどこにいる
のかと、全白、左白、右白のようなマーカーの判定
ができるようになります。
本番の1週間前にアクシデントがあったときは
このマシンを利用します。
目次
前
次