目次

GameBoyCameraも接続

 手元にあるシリアルインタフェースカメラは、1個だけです。

 大会会場での破損も想定し、GameBoyCameraも接続できるようにします。

  GameBoyCameraの中は、光学系、人工網膜チップ、コネクタが入っています。



 GameBoyCameraは、画像データをアナログ出力してくるので、シリアル
 インタフェースとは別のポートを利用します。

 最初にAVRテストボードを利用し、GameBoyCameraとの接続をテストしました。
 テストボードの回路図は、以下です。





 AVRテストボードは、汎用で使えるようにしてあるため、接続用アダプタを
 用意しています。
 回路図(結線図)は、以下です。



 接続用アダプタには、照明用LEDを駆動する回路も入れました。




A/Dコンバータテスト

 内蔵のA/Dコンバータを利用するので、回路図からチャネル0に  アナログ電圧を接続します。  アナログ出力を可変できるように、次の治具を作りました。  回路は簡単に、OPアンプで電圧フォロワを構成しています。  単電源で利用できるOPアンプLM358を使っています。  5V電圧だと、出力が最大3.5Vになりますが、GameBoyCameraの電圧出力が  最大でも2Vなので、この治具で充分です。  テストファームウエアは、自作のRTOS(Real Time Operating System)である  USOを使い、単純に作りました。  RTOSを入れたのは、A/D変換を1回だけするか、連続で実行するかを  切り分けて使いたかったから。  アナログ電圧出力治具上の可変抵抗器のワイパーを回し、端末ソフト  で、A/D変換の結果を観測できます。  タスクを3つに分割してあります。  連続A/D変換の周期は、1秒にしました。  A/D変換のテストをするため、シリアルインタフェースの通信プロトコルを  次のように定めました。  コマンドは、次の4つにしました。  ソースコードは、以下です。 #include <avr/io.h> #include <avr/io8535.h> #include <avr/pgmspace.h> #include <avr/interrupt.h> #define OFF 0 #define ON OFF+1 #define FOSC 8000000 #define BAUD 9600 #define MYUBRR (FOSC/16/BAUD)-1 typedef unsigned char UBYTE ; typedef unsigned short UWORD ; typedef unsigned long ULONG ; typedef signed char SBYTE ; typedef signed short SWORD ; typedef struct { void (*tsk)(void); UWORD wcount ; } TCBP ; #define TSK_ID_MAX 3 #define TSK_ID0 0 #define TSK_ID1 1 #define TSK_ID2 2 #define TTS_SUSPEND 0 #define TTS_WAIT TTS_SUSPEND+1 #define TTS_READY TTS_SUSPEND+2 volatile TCBP tcb[TSK_ID_MAX]; 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 UFLAG x_flags.BIT.B0 #define WFLAG x_flags.BIT.B1 #define CFLAG x_flags.BIT.B2 #define AFLAG x_flags.BIT.B3 #define BUFSIZE 8 #define PMAX 100 volatile UBYTE sbuf[BUFSIZE] ; volatile UBYTE sindex; volatile UBYTE mcount ; volatile UBYTE pcnt ; volatile UBYTE duty ; volatile UBYTE dutyx ; volatile UBYTE run_tsk ; volatile UBYTE ready ; volatile UBYTE suspend ; volatile UBYTE waitq ; volatile UBYTE bstate ; const prog_char msg_h[] PROGMEM = "? help" ; const prog_char msg_c[] PROGMEM = "C start show" ; const prog_char msg_r[] PROGMEM = "c stop show" ; const prog_char msg_a[] PROGMEM = "A get ADC" ; const prog_char msg_p[] PROGMEM = "P set duty ratio(Pvv)" ; const prog_char msg_sp[] PROGMEM = "p show duty ratio" ; const prog_char msg_first[] PROGMEM = "ADC test" ; #define MSG_HELP 0 #define MSG_CONS 1 #define MSG_CONE 2 #define MSG_ADC 3 #define MSG_PULSE 4 #define MSG_DUTY 5 #define NO 0 #define YES NO+1 #define MASKFF 0xff #define MASK0F 0x0f #define MASKF0 0xf0 #define MASK80 0x80 #define DEBUG TSK_ID0 #define TRIGGER TSK_ID1 #define BLINDRUN TSK_ID2 /*--------------------------------*/ /* Insert user functions protoype */ /*--------------------------------*/ void user_initialize(void); void uart_putchar(UBYTE x); void crlf(void); void uart_puts(UBYTE *x); void first_message(void); UBYTE get_hex(UBYTE x); void start_adc(void); void wait_adc(void); void show_value(UWORD x); UWORD get_adc(void); void send_uart_msg(UBYTE x); /* system call */ void cre_tsk(UBYTE tid,void (*tsk)(void)); void sta_tsk(UBYTE tid,UBYTE sta); void rsm_tsk(UBYTE tid); void sus_tsk(UBYTE tid); void slp_tsk(void); void wai_tsk(UWORD x); void init_os(void); UBYTE is_tsk_ready(UBYTE tid); /* task */ void tsk0_proc(void); void tsk1_proc(void); void tsk2_proc(void); /*------*/ /* main */ /*------*/ int main(void) { TCBP pcur_tsk ; UBYTE tmp ; UBYTE i ; /* disable interrupt */ cli(); /* initialize port and variables */ user_initialize(); /* initialize monitor */ init_os(); /* create task */ cre_tsk(DEBUG ,tsk0_proc); cre_tsk(TRIGGER ,tsk1_proc); cre_tsk(BLINDRUN,tsk2_proc); /* start task task */ sta_tsk(DEBUG ,TTS_READY); sta_tsk(TRIGGER ,TTS_SUSPEND); sta_tsk(BLINDRUN,TTS_SUSPEND); /* enable interrupt */ sei(); /* endless loop */ first_message(); run_tsk = DEBUG ; while ( ON ) { /* RTOS */ pcur_tsk = tcb[run_tsk] ; if ( is_tsk_ready( run_tsk ) == ON ) { (*(pcur_tsk.tsk))(); } run_tsk++; if ( run_tsk == TSK_ID_MAX ) { run_tsk = DEBUG ; } /* cyclic handling and monitering */ if ( WFLAG ) { WFLAG = OFF ; tmp = waitq ; for ( i = 0 ; i < TSK_ID_MAX ; i++ ) { if ( tmp & 1 ) { tcb[i].wcount-- ; if ( tcb[i].wcount == 0 ) { rsm_tsk(i); } } tmp >>= 1 ; } } } /* dummy */ return 0 ; } /*-----------------------*/ /* Insert user functions */ /*-----------------------*/ void user_initialize(void) { /* PORT A */ PORTA = 0b00001000 ; /* 00001000 */ DDRA = 0b11111100 ; /* ooooooii */ /* PORT B */ PORTB = 0b00000000 ; /* 00000000 */ DDRB = 0b11111111 ; /* oooooooo */ /* PORT C */ PORTC = 0b00000000 ; /* 00000000 */ DDRC = 0b11111111 ; /* oooooooo */ /* PORT D */ PORTD = 0b00001100 ; /* 00001100 */ DDRD = 0b11110010 ; /* ooooiioi */ /* initialize flags */ x_flags.DR = 0 ; /* initialize serial */ { /* clear index */ sindex = 0 ; /* set Baud Rate Registers */ UBRR = MYUBRR ; /* Enable receive interrupt , receive module and transmit module */ UCR = (1 << TXEN) | (1 << RXEN) | (1 << RXCIE); } /* initialize ADC */ { /* select channel 0 */ ADMUX = 0 ; /* enable ADC , enable interrupt , select prescaler (/128) */ ADCSR = (1 << ADEN) | (7 << ADPS0) ; } /* initialize timer1 */ { mcount = 0 ; /* select CTC , (presclae /8) 1MHz */ TCCR1B = (1 << CTC1) | (1 << CS11) ; /* clear timer/counter */ TCNT1 = 0 ; OCR1A = 99 ; OCR1B = 110 ; } /* Enable Compare match interruption */ TIMSK = (1 << OCIE1A) ; /* */ pcnt = 0 ; duty = 50 ; dutyx = 50 ; } /* UART receive interrupt */ ISR(UART_RX_vect) { UBYTE ch ; /* get 1 charactoer */ ch = UDR ; /* store */ *(sbuf+sindex) = ch ; sindex++ ; /* judge */ if ( ch == '\r' ) { UFLAG = ON ; sindex = 0 ; } } /* TIMER1 interrupt */ ISR(TIMER1_COMPA_vect) { UBYTE aport ; /* update monitor count */ mcount++ ; /* judge */ if ( mcount == 100 ) { mcount = 0 ; WFLAG = ON ; } /* PWM default */ aport = 0 ; /* judge */ if ( pcnt < dutyx ) { aport |= MASK80 ; } /* impress */ PORTA = aport ; /* increment */ pcnt++ ; if ( pcnt == PMAX ) { pcnt = 0 ; dutyx = duty; } } 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 crlf(void) { uart_putchar('\r'); uart_putchar('\n'); } void uart_puts(UBYTE *x) { while ( *x != '\0' ) { uart_putchar( *x ) ; x++ ; } crlf(); } void first_message(void) { char msg[20]; /* copy */ strcpy_P(msg,msg_first); /* show */ uart_puts((UBYTE *)msg); } void start_adc(void) { ADCSR |= (1 << ADSC) ; } void wait_adc(void) { while ( ADCSR & 0x40 ) ; } void show_value(UWORD x) { UWORD tmp ; UBYTE i ; UBYTE val[4] ; /* store */ tmp = x ; /* separate */ *(val+0) = tmp / 1000 + '0' ; tmp %= 1000 ; *(val+1) = tmp / 100 + '0' ; tmp %= 100 ; *(val+2) = tmp / 10 + '0' ; *(val+3) = tmp % 10 + '0' ; /* show */ for ( i = 0 ; i < 4 ; i++ ) { uart_putchar( *(val+i) ); } /* new line */ crlf(); } void send_uart_msg(UBYTE x) { char msg[20] ; /* set message */ switch (x) { case MSG_HELP : strcpy_P(msg,msg_h) ; break ; case MSG_CONS : strcpy_P(msg,msg_c) ; break ; case MSG_CONE : strcpy_P(msg,msg_r) ; break ; case MSG_ADC : strcpy_P(msg,msg_a) ; break ; case MSG_PULSE : strcpy_P(msg,msg_p) ; break ; case MSG_DUTY : strcpy_P(msg,msg_sp); break ; } /* send */ uart_puts( (UBYTE *)msg ); } /* system call */ void cre_tsk(UBYTE tid,void (*tsk)(void)) { tcb[tid].tsk = tsk; tcb[tid].wcount = 0; } void sta_tsk(UBYTE tid,UBYTE sta) { UBYTE tmp ; tmp = (1 << tid); if ( sta == TTS_READY ) { ready |= tmp; } if ( sta == TTS_SUSPEND ) { suspend |= tmp; } if ( sta == TTS_WAIT ) { waitq |= tmp; } } void rsm_tsk(UBYTE tid) { UBYTE tmp ; tmp = (1 << tid); ready |= tmp; suspend &= ~tmp; waitq &= ~tmp; } void sus_tsk(UBYTE tid) { UBYTE tmp ; tmp = (1 << tid); ready &= ~tmp; suspend |= tmp; waitq &= ~tmp; } void slp_tsk(void) { sus_tsk(run_tsk); } void wai_tsk(UWORD x) { UBYTE tmp ; tmp = (1 << run_tsk); ready &= ~tmp; suspend &= ~tmp; waitq |= tmp; tcb[run_tsk].wcount = x ; } void init_os(void) { ready = 0; suspend = 0; waitq = 0; } UBYTE is_tsk_ready(UBYTE tid) { return( (ready >> tid) & 1 ) ; } void tsk0_proc(void) { UBYTE cmd ; UBYTE val[2] ; /* judge */ if ( UFLAG == OFF ) return ; /* clear flag */ UFLAG = OFF ; /* get command character */ cmd = *(sbuf+0) ; /* one shot */ if ( cmd == 'A' ) { rsm_tsk(TSK_ID1) ; } /* start continuous */ if ( cmd == 'C' ) { rsm_tsk(TSK_ID2) ; } /* exit continuous */ if ( cmd == 'c' ) { sus_tsk(TSK_ID2) ; } /* set duty */ if ( cmd == 'P' ) { *(val+0) = get_hex( *(sbuf+1) ) ; *(val+1) = get_hex( *(sbuf+2) ) ; duty = val[0] * 10 + val[1] ; } /* show duty */ if ( cmd == 'p' ) { /* duty */ *(val+0) = duty / 10 ; *(val+1) = duty % 10 ; uart_putchar( *(val+0) + '0' ); uart_putchar( *(val+1) + '0' ); crlf(); } /* help */ if ( cmd == '?' ) { send_uart_msg(MSG_HELP); send_uart_msg(MSG_CONS); send_uart_msg(MSG_CONE); send_uart_msg(MSG_ADC); send_uart_msg(MSG_PULSE); send_uart_msg(MSG_DUTY); } /* new line */ crlf(); } void tsk1_proc(void) { /* show */ show_value( get_adc() ); /* exit */ slp_tsk(); } void tsk2_proc(void) { /* show */ show_value( get_adc() ); /* cyclic 1000 ms */ wai_tsk(100); } UWORD get_adc(void) { UWORD result ; UBYTE dh ; UBYTE dl ; /* start ADC */ start_adc(); /* wait */ wait_adc(); /* get data */ dl = ADCL ; dh = ADCH ; result = (dh << 8) | dl ; return result ; }  動作させてわかったことをリストします。

GBC利用ファームウエア

 A/D変換のテストができたので、GBC用のファームウエアを作成します。  (GBCの使い方は、他のページを参照してください。)  テスト用ボードとして、ATmega328を利用しました。  このボードの右上にある10ピンコネクタに、ケーブルを利用して  GameBoyCamera用インタフェースボードを接続します。  作成したファームウエアの要点をリストします。  作成したファームウエアは、以下です。 #include <avr/io.h> #include <avr/pgmspace.h> #include <avr/interrupt.h> #define OFF 0 #define ON OFF+1 #define FOSC 16000000 #define BAUD 38400 #define MYUBRR (FOSC/16/BAUD)-1 typedef unsigned char UBYTE ; typedef unsigned short UWORD ; typedef unsigned long ULONG ; typedef signed char SBYTE ; typedef signed short SWORD ; typedef struct { UBYTE direction ; UBYTE rlduty ; UBYTE duty ; } PARAMP ; volatile PARAMP param ; typedef struct { void (*tsk)(void); UWORD wcount ; } TCBP ; #define TSK_ID_MAX 4 #define TSK_ID0 0 #define TSK_ID1 1 #define TSK_ID2 2 #define TSK_ID3 3 #define TTS_SUSPEND 0 #define TTS_WAIT TTS_SUSPEND+1 #define TTS_READY TTS_SUSPEND+2 volatile TCBP tcb[TSK_ID_MAX]; 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 UFLAG x_flags.BIT.B0 #define CFLAG x_flags.BIT.B1 #define AFLAG x_flags.BIT.B2 #define WFLAG x_flags.BIT.B3 #define DFLAG x_flags.BIT.B7 #define BUFSIZE 8 #define START 4 #define SIN 5 #define LOAD 4 #define RST 3 #define XCK 2 #define READ 1 #define PMAX 100 #define DIR_CENTER 0 #define DIR_RIGHT 1 #define DIR_LEFT 2 volatile UBYTE sbuf[BUFSIZE] ; volatile UBYTE sindex; volatile ULONG tickcount ; volatile UBYTE mcount ; volatile UBYTE pcnt ; volatile UBYTE duty[2] ; volatile UBYTE dutyx[2] ; volatile UBYTE direction[2] ; volatile UBYTE led_duty ; volatile UBYTE state ; volatile UBYTE dir ; volatile UBYTE lane ; volatile UBYTE threshold ; volatile UBYTE rdat[8] ; volatile UBYTE sdat[128] ; volatile UWORD img_cnt ; volatile UBYTE bstate ; volatile UBYTE run_tsk ; volatile UBYTE ready ; volatile UBYTE suspend ; volatile UBYTE waitq ; const prog_char msg_h[] PROGMEM = "? help" ; const prog_char msg_c[] PROGMEM = "C reset camera" ; const prog_char msg_r[] PROGMEM = "R set register value" ; const prog_char msg_g[] PROGMEM = "G get image" ; const prog_char msg_s[] PROGMEM = "S default setting" ; const prog_char msg_d[] PROGMEM = "D debug" ; const prog_char msg_p[] PROGMEM = "P set duty ratio(Pdvvc)" ; const prog_char msg_sp[] PROGMEM = "p show duty ratio" ; const prog_char msg_st[] PROGMEM = "START TRIGGER" ; const prog_char msg_gi[] PROGMEM = "Get IMAGE" ; const prog_char msg_cp[] PROGMEM = "COMPLETE" ; const prog_char msg_first[] PROGMEM = "MCR controller" ; #define MSG_HELP 0 #define MSG_RESET 1 #define MSG_REGISTER 2 #define MSG_IMAGE 3 #define MSG_DEFAULT 4 #define MSG_DEBUG 5 #define MSG_ST 6 #define MSG_GI 7 #define MSG_CP 8 #define MSG_PULSE 9 #define MSG_DUTY 10 #define NO 0 #define YES NO+1 #define MASKFF 0xff #define MASK0F 0x0f #define MASKF0 0xf0 #define MASK80 0x80 #define MAX_SIZE 16384 #define ALL_BLACK 0 #define ALL_WHITE 1 #define LEFT_WHITE 2 #define RIGHT_WHITE 3 #define CENTER 4 #define LITTLE_LEFT 5 #define LEFT 6 #define BIG_LEFT 7 #define LITTLE_RIGHT 8 #define RIGHT 9 #define BIG_RIGHT 10 #define CRANK_RIGHT 11 #define CRANK_LEFT 12 #define ILLEAGAL 13 #define LANE_NONE 0 #define LANE_RIGHT 1 #define LANE_LEFT 2 #define DEBUG TSK_ID0 #define TRIGGER TSK_ID1 #define BLINDRUN TSK_ID2 #define MOVE TSK_ID3 /*--------------------------------*/ /* Insert user functions protoype */ /*--------------------------------*/ void user_initialize(void); void uart_putchar(UBYTE x); void crlf(void); void uart_puts(UBYTE *x); void first_message(void); UBYTE get_hex(UBYTE x); void delay_ms(UWORD x); void set_xck(UBYTE x); void set_sin(UBYTE x); void reset_cam(void); void send_cam(UWORD x); void send_start(void); void get_img(UBYTE x); void send_default(void); void start_adc(void); void wai_adc(void); void show_value(UBYTE x); void send_uart_msg(UBYTE x); void update_motor(PARAMP x); void get_threshold(void); void get_sensor(void); UBYTE is_center(UWORD x); UBYTE is_edge(UWORD x); /* system call */ void cre_tsk(UBYTE tid,void (*tsk)(void)); void sta_tsk(UBYTE tid,UBYTE sta); void rsm_tsk(UBYTE tid); void sus_tsk(UBYTE tid); void slp_tsk(void); void wai_tsk(UWORD x); void init_os(void); UBYTE is_tsk_ready(UBYTE tid); void tsk0_proc(void); void tsk1_proc(void); void tsk2_proc(void); void tsk3_proc(void); void straight_move(UBYTE x,UWORD tx); void right_move(UBYTE x); void left_move(UBYTE x); void crank_move(UBYTE xa,UBYTE xb,UBYTE xc); void lane_move(UBYTE xa,UBYTE xb,UBYTE xc); UBYTE is_crank_center(UBYTE x); UBYTE is_lane_edge(UBYTE x); UBYTE convert_code(UBYTE x); /*------*/ /* main */ /*------*/ int main(void) { TCBP pcur_tsk ; UBYTE tmp ; UBYTE i ; /* disable interrupt */ cli(); /* initialize port and variables */ user_initialize(); /* initialize monitor */ init_os(); /* create task */ cre_tsk(DEBUG ,tsk0_proc); cre_tsk(TRIGGER ,tsk1_proc); cre_tsk(BLINDRUN,tsk2_proc); cre_tsk(MOVE ,tsk3_proc); /* start task task */ sta_tsk(DEBUG ,TTS_READY); sta_tsk(TRIGGER ,TTS_READY); sta_tsk(BLINDRUN,TTS_SUSPEND); sta_tsk(MOVE ,TTS_SUSPEND); /* enable interrupt */ sei(); /* endless loop */ first_message(); run_tsk = DEBUG ; while ( ON ) { /* RTOS */ pcur_tsk = tcb[run_tsk] ; if ( is_tsk_ready( run_tsk ) == ON ) { (*(pcur_tsk.tsk))(); } run_tsk++; if ( run_tsk == TSK_ID_MAX ) { run_tsk = DEBUG ; } /* cyclic handling */ if ( WFLAG ) { WFLAG = OFF ; tmp = waitq ; for ( i = 0 ; i < TSK_ID_MAX ; i++ ) { if ( tmp & 1 ) { tcb[i].wcount-- ; if ( tcb[i].wcount == 0 ) { rsm_tsk(i); } } tmp >>= 1 ; } } } /* dummy */ return 0 ; } #/*-----------------------*/ /* Insert user functions */ /*-----------------------*/ void user_initialize(void) { UWORD tmp ; /* PORT B */ PORTB = 0b00000000 ; /* 00000000 */ DDRB = 0b00111111 ; /* iioooooo */ /* PORT C */ PORTC = 0b00001000 ; /* 00001000 */ DDRC = 0b11111100 ; /* ooooooii */ /* PORT D */ PORTD = 0b00001100 ; /* 00001100 */ DDRD = 0b11110010 ; /* oooooioi */ /* initialize flags */ x_flags.DR = 0 ; /* initialize serial */ { /* clear index */ sindex = 0 ; /* set Baud Rate Registers */ tmp = MYUBRR ; UBRR0H = (tmp >> 8) & MASKFF ; UBRR0L = tmp & MASKFF; /* Enable receive interrupt , receive module and transmit module */ UCSR0B = (1 << RXCIE0) | (1 << RXEN0) | (1 << TXEN0) ; UCSR0C = (3 << UCSZ00) ; } /* initialize ADC */ { /* external 2.56V , select channel 0 */ ADMUX = 0 ; /* enable ADC , enable interrupt , select prescaler (/128) */ ADCSRA = (1 << ADEN) | (7 << ADPS0) ; } /* initialize timer0 */ { /* select CTC */ TCCR0A = (1 << WGM01) ; /* (presclae /64) 250kHz */ TCCR0B = (3 << CS00) ; /* clear timer/counter */ TCNT0 = 0 ; OCR0A = 125 ; OCR0B = 250 ; /* Enable Compare match interruption */ TIMSK0 = (1 << OCIE0A) ; } /* initialize timer1 */ { tickcount = 0 ; mcount = 0 ; /* select CTC , (presclae /8) 2MHz */ TCCR1B = (1 << WGM12) | (1 << CS11) ; /* clear timer/counter */ TCNT1 = 0 ; OCR1A = 1999 ; OCR1B = 2500 ; /* Enable Compare match interruption */ TIMSK1 = (1 << OCIE1A) ; } /* initialize interrupt */ { bstate = 0 ; /* select falling edge */ EICRA = (1 << ISC01) ; /* Enable external interruption */ EIMSK = (1 << INT0) ; } /* duty ratio */ pcnt = 0 ; state = 0 ; *(duty+0) = 0 ; *(duty+1) = 0 ; *(dutyx+0) = 0 ; *(dutyx+1) = 0 ; *(direction+0) = 0 ; *(direction+1) = DIR_LEFT ; led_duty = 10 ; /* default direction */ dir = DIR_CENTER ; lane = LANE_NONE ; } /* INT0 interrupt */ ISR(INT0_vect) { AFLAG = ON ; } /* UART receive interrupt */ ISR(USART_RX_vect) { UBYTE ch ; /* get 1 charactoer */ ch = UDR0 ; /* store */ *(sbuf+sindex) = ch ; sindex++ ; /* judge */ if ( ch == '\r' ) { UFLAG = ON ; sindex = 0 ; } } /* TIMER0 interrupt */ ISR(TIMER0_COMPA_vect) { UBYTE bport ; UBYTE dport ; /* default */ bport = 0 ; dport = PORTD & ~0x20 ; /* judge */ if ( pcnt < *(dutyx+0) ) { if ( *(direction+0) == 1 ) { bport |= 0x01 ; } if ( *(direction+0) == 2 ) { bport |= 0x02 ; } } if ( pcnt < *(dutyx+1) ) { if ( *(direction+1) == 1 ) { bport |= 0x04 ; } if ( *(direction+1) == 2 ) { bport |= 0x08 ; } } if ( pcnt < led_duty ) { dport |= 0x20 ; } /* impress */ PORTB = bport ; PORTD = dport ; /* increment */ pcnt++ ; if ( pcnt == PMAX ) { pcnt = 0 ; *(dutyx+0) = *(duty+0); *(dutyx+1) = *(duty+1); } } /* TIMER1 interrupt */ ISR(TIMER1_COMPA_vect) { /* increment */ tickcount++ ; /* increment */ mcount++ ; /* judge */ if ( mcount == 10 ) { mcount = 0 ; WFLAG = ON ; } } 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 ( !(UCSR0A & (1 << UDRE0)) ) ; UDR0 = x ; } void crlf(void) { uart_putchar('\r'); uart_putchar('\n'); } void uart_puts(UBYTE *x) { while ( *x != '\0' ) { uart_putchar( *x ) ; x++ ; } crlf(); } void first_message(void) { char msg[20]; /* copy */ strcpy_P(msg,msg_first); /* show */ uart_puts((UBYTE *)msg); } void delay_ms(UWORD x) { ULONG target ; /* set counter */ target = tickcount + (ULONG)x ; /* wait */ while ( target > tickcount ) ; } void set_xck(UBYTE x) { /* impress signal */ if ( x ) { PORTC |= (1 << XCK) ; } else { PORTC &= ~(1 << XCK) ; } } void set_sin(UBYTE x) { if ( x ) { PORTC |= (1 << SIN) ; } else { PORTC &= ~(1 << SIN) ; } } void reset_cam(void) { /* impress XCK:L */ set_xck(OFF) ; /* impress RST:L */ PORTC &= ~(1 << RST) ; /* impress XCK:H */ set_xck(ON) ; /* impress RST:H */ PORTC |= (1 << RST) ; /* impress XCK:L */ set_xck(OFF) ; /* debugging */ if ( DFLAG ) { send_uart_msg(MSG_RESET) ; } } void send_cam(UWORD x) { UBYTE i ; UWORD tmp ; tmp = x ; /* impress XCK:L */ set_xck(OFF) ; /* send address */ for ( i = 0 ; i < 3 ; i++ ) { /* impress data bit */ set_sin(OFF); if ( tmp & 0x400 ) { set_sin(ON); } /* impress XCK:H */ set_xck(ON) ; /* shift */ tmp <<= 1 ; /* impress XCK:L */ set_xck(OFF) ; } /* send data */ PORTC &= ~(1 << LOAD); tmp = x ; for ( i = 0 ; i < 8 ; i++ ) { /* impress LOAD bit */ if ( i == 7 ) { PORTC |= (1 << LOAD); } /* impress data bit */ set_sin(OFF); if ( tmp & MASK80 ) { set_sin(ON); } /* impress XCK:H */ set_xck(ON) ; /* shift */ tmp <<= 1 ; /* impress XCK:L */ set_xck(OFF) ; } PORTC &= ~(1 << LOAD); set_sin(OFF); } void send_start(void) { /* impress XCK:L */ set_xck(OFF) ; /* impress STARST:H */ PORTD |= (1 << START); /* impress XCK:H */ set_xck(ON) ; /* impress RST:L */ PORTD &= ~(1 << START); /* impress XCK:L */ set_xck(OFF) ; } void get_img(UBYTE x) { UBYTE dh ; UBYTE dl ; UWORD result ; UWORD max ; UWORD min ; /* debug */ if ( DFLAG ) { send_uart_msg(MSG_ST) ; } /* send start */ send_start(); /* debug */ if ( DFLAG ) { send_uart_msg(MSG_GI) ; } /* READ data and show*/ img_cnt = 0 ; max = 0 ; min = 0 ; while ( img_cnt < MAX_SIZE ) { /* impress XCK:H */ set_xck(ON); /* impress XCK:L */ set_xck(OFF) ; /* show */ if ( PINC & 2 ) { /* start conversion */ start_adc() ; /* wait */ wai_adc() ; /* get data */ dl = ADCL ; dh = ADCH ; result = (dh << 8) + dl ; result >>= 2 ; /* show */ if ( x == 0 ) { show_value( (UBYTE)result ); /* new line */ if ( (img_cnt % 16) == 15 ) { crlf(); } } /* store */ if ( x == 1 ) { if ( is_center( img_cnt ) ) { max += result ; } if ( is_edge( img_cnt ) ) { min += result ; } } /* increment */ img_cnt++ ; } } /* debug */ if ( DFLAG ) { send_uart_msg(MSG_CP) ; } /* calculate */ if ( x == 1 ) { max >>= 2 ; min >>= 2 ; /* store */ threshold = (UBYTE)((max+min) >> 1); } } void send_default(void) { send_cam((0 << 8) | 0x80); /* exposure */ send_cam((1 << 8) | 0x03); /* exposure time change this to adjust picture light */ send_cam((2 << 8) | 0x00); send_cam((3 << 8) | 0x30); send_cam((4 << 8) | 0x01); send_cam((5 << 8) | 0x00); send_cam((6 << 8) | 0x01); send_cam((7 << 8) | 0x21); /* 0x80, 0x03, 0x00, 0x30, 0x01, 0x00, 0x01, 0x21 */ /* debugging */ if ( DFLAG ) { send_uart_msg(MSG_DEFAULT) ; } } void start_adc(void) { ADCSRA |= (1 << ADSC) ; } void wai_adc(void) { while ( (ADCSRA & (1 << ADSC)) ) ; } void show_value(UBYTE x) { UBYTE tmp ; UBYTE val[3] ; /* store */ tmp = x ; /* separate */ *(val+0) = tmp / 100 + '0' ; tmp %= 100 ; *(val+1) = tmp / 10 + '0' ; *(val+2) = tmp % 10 + '0' ; /* show */ uart_putchar( *(val+0) ); uart_putchar( *(val+1) ); uart_putchar( *(val+2) ); /* send space */ uart_putchar( ' ' ); } void send_uart_msg(UBYTE x) { char msg[20] ; /* set message */ switch (x) { case MSG_HELP : strcpy_P(msg,msg_h) ; break ; case MSG_RESET : strcpy_P(msg,msg_c) ; break ; case MSG_REGISTER : strcpy_P(msg,msg_r) ; break ; case MSG_IMAGE : strcpy_P(msg,msg_g) ; break ; case MSG_DEFAULT : strcpy_P(msg,msg_s) ; break ; case MSG_DEBUG : strcpy_P(msg,msg_d) ; break ; case MSG_PULSE : strcpy_P(msg,msg_p) ; break ; case MSG_ST : strcpy_P(msg,msg_st); break ; case MSG_GI : strcpy_P(msg,msg_gi); break ; case MSG_CP : strcpy_P(msg,msg_cp); break ; case MSG_DUTY : strcpy_P(msg,msg_sp); break ; } /* send */ uart_puts((UBYTE *)msg ); } void update_motor(PARAMP x) { /* front */ *(direction+0) = x.direction ; *(duty+0) = x.rlduty ; if ( *(direction+0) == DIR_CENTER ) { *(duty+0) = 0 ; } /* rear */ *(direction+1) = DIR_LEFT ; *(duty+1) = x.duty ; } void get_sensor(void) { UWORD result ; UBYTE index ; UBYTE res ; UBYTE i ; UBYTE sensor ; UBYTE avr ; UBYTE dh ; UBYTE dl ; /* send start */ send_start(); /* READ data and show*/ img_cnt = 0 ; index = 0 ; i = 0 ; while ( img_cnt < MAX_SIZE ) { /* impress XCK:H */ set_xck(ON); /* impress XCK:L */ set_xck(OFF) ; /* judge */ if ( PINC & 2 ) { /* start conversion */ start_adc() ; /* wait */ wai_adc() ; /* get data */ dl = ADCL ; dh = ADCH ; result = (dh << 8) + dl ; /* shift */ result >>= 2 ; /* judge */ if ( result > threshold ) { res++ ; } /* generate line code */ if ( (img_cnt % 16) == 15 ) { *(rdat+i) = res ; res = 0 ; i++ ; i %= 8 ; } /* generate sensor data */ if ( (img_cnt % 128) == 127 ) { /* average */ avr = 0 ; avr += *(rdat+0) ; avr += *(rdat+1) ; avr += *(rdat+2) ; avr += *(rdat+3) ; avr += *(rdat+4) ; avr += *(rdat+5) ; avr += *(rdat+6) ; avr += *(rdat+7) ; avr >>= 3 ; /* compare */ sensor = 0 ; if ( *(rdat+0) > avr ) { sensor |= 0x80 ; } if ( *(rdat+1) > avr ) { sensor |= 0x40 ; } if ( *(rdat+2) > avr ) { sensor |= 0x20 ; } if ( *(rdat+3) > avr ) { sensor |= 0x10 ; } if ( *(rdat+4) > avr ) { sensor |= 0x08 ; } if ( *(rdat+5) > avr ) { sensor |= 0x04 ; } if ( *(rdat+6) > avr ) { sensor |= 0x02 ; } if ( *(rdat+7) > avr ) { sensor |= 0x01 ; } /* store */ *(sdat+index) = sensor ; /* increment */ index++ ; } /* increment */ img_cnt++ ; } } } UBYTE is_center(UWORD x) { if ( x == 8127 || x == 8128 ) return ON ; /* 128*63+63 128*63+64 */ if ( x == 8255 || x == 8256 ) return ON ; /* 128*64+63 128*64+64 */ return OFF ; } UBYTE is_edge(UWORD x) { if ( x == 8064 || x == 8191 ) return ON ; /* 128*63 128*63+127 */ if ( x == 8192 || x == 8319 ) return ON ; /* 128*64 128*64+127 */ return OFF ; } /* system call */ void cre_tsk(UBYTE tid,void (*tsk)(void)) { tcb[tid].tsk = tsk; tcb[tid].wcount = 0; } void sta_tsk(UBYTE tid,UBYTE sta) { UWORD tmp ; tmp = (1 << tid); if ( sta == TTS_READY ) { ready |= tmp; } if ( sta == TTS_SUSPEND ) { suspend |= tmp; } if ( sta == TTS_WAIT ) { waitq |= tmp; } } void rsm_tsk(UBYTE tid) { UWORD tmp ; tmp = (1 << tid); ready |= tmp; suspend &= ~tmp; waitq &= ~tmp; } void sus_tsk(UBYTE tid) { UWORD tmp ; tmp = (1 << tid); ready &= ~tmp; suspend |= tmp; waitq &= ~tmp; } void slp_tsk(void) { sus_tsk(run_tsk); } void wai_tsk(UWORD x) { UWORD tmp ; tmp = (1 << run_tsk); ready &= ~tmp; suspend &= ~tmp; waitq |= tmp; tcb[run_tsk].wcount = x ; } void init_os(void) { ready = 0; suspend = 0; waitq = 0; } UBYTE is_tsk_ready(UBYTE tid) { return( (ready >> tid) & 1 ) ; } void tsk0_proc(void) { UBYTE cmd ; UBYTE chx ; UBYTE dir ; UBYTE val[2] ; UBYTE valx ; /* check */ if ( UFLAG == OFF ) { return ; } /* clear flag */ UFLAG = OFF ; /* interpreter */ /* get command character */ cmd = *(sbuf+0) ; /* reset camera */ if ( cmd == 'C' ) { reset_cam() ; } /* set register value */ if ( cmd == 'R' ) { /* get channel */ chx = get_hex( *(sbuf+3) ); /* get code */ *(val+0) = get_hex( *(sbuf+1) ); *(val+1) = get_hex( *(sbuf+2) ); /* send this value to camera */ valx = (val[0] << 4)+ val[1] ; send_cam( (chx << 8) | valx ); } /* set default value */ if ( cmd == 'S' ) { send_default() ; } /* set debug flag */ if ( cmd == 'D' ) { DFLAG = OFF ; if ( *(sbuf+1) == '1' ) { DFLAG = ON ; } } /* get picture */ if ( cmd == 'G' ) { crlf(); get_img(0) ; } /* set duty */ if ( cmd == 'P' ) { /* get channel */ chx = get_hex( *(sbuf+4) ); /* get direction */ dir = get_hex( *(sbuf+1) ); /* get code */ *(val+0) = get_hex( *(sbuf+2) ); *(val+1) = get_hex( *(sbuf+3) ); /* calculate */ valx = 10 * val[0] + val[1] ; /* store */ if ( chx == 2 ) { led_duty = valx ; } else { *(direction+chx) = dir ; *(duty+chx) = valx ; } } /* show duty */ if ( cmd == 'p' ) { for ( chx = 0 ; chx < 2 ; chx++ ) { /* direction */ uart_putchar( *(direction+chx) + '0' ); uart_putchar( ' ' ); /* duty */ *(val+0) = *(duty+chx) / 10 ; *(val+1) = *(duty+chx) % 10 ; uart_putchar( *(val+0) + '0' ); uart_putchar( *(val+1) + '0' ); crlf(); } /* LED duty */ *(val+0) = led_duty / 10 ; *(val+1) = led_duty % 10 ; uart_putchar( *(val+0) + '0' ); uart_putchar( *(val+1) + '0' ); crlf(); } /* help */ if ( cmd == '?' ) { send_uart_msg(MSG_HELP); send_uart_msg(MSG_RESET); send_uart_msg(MSG_REGISTER); send_uart_msg(MSG_IMAGE); send_uart_msg(MSG_DEFAULT); send_uart_msg(MSG_DEBUG); send_uart_msg(MSG_PULSE); send_uart_msg(MSG_DUTY); } /* new line */ crlf(); } void tsk1_proc(void) { /* judge */ if ( AFLAG == OFF ) { return ; } /* clear flag */ AFLAG = OFF ; /* increment */ bstate++ ; /* change */ if ( bstate & 1 ) { rsm_tsk(BLINDRUN); led_duty = 99 ; } else { sus_tsk(BLINDRUN); sus_tsk(MOVE); crank_move(0,0,0); led_duty = 10 ; } } void tsk2_proc(void) { /* reset camera */ reset_cam(); /* send paramaters */ send_default(); /* get threshold */ get_img(1); /* slow */ straight_move(10,1000); /* mid */ straight_move(20,1000); /* top */ straight_move(30,1000); /* wake up MOVE task */ rsm_tsk(MOVE); /* exit */ slp_tsk(); } void tsk3_proc(void) { UBYTE sensor_data ; /* get sensor data */ sensor_data = convert_code(*(sdat+63)); /* state machine */ switch ( state ) { case 0 : /* judge */ state = 0 ; if ( sensor_data == ALL_WHITE ) { state = 100 ; } if ( sensor_data == LEFT_WHITE ) { state = 200 ; lane = LANE_LEFT ; } if ( sensor_data == RIGHT_WHITE ) { state = 200 ; lane = LANE_RIGHT; } if ( sensor_data == CENTER ) { state = 10 ; } if ( sensor_data == LITTLE_LEFT ) { state = 20 ; } if ( sensor_data == LEFT ) { state = 30 ; } if ( sensor_data == BIG_LEFT ) { state = 40 ; } if ( sensor_data == LITTLE_RIGHT ) { state = 50 ; } if ( sensor_data == RIGHT ) { state = 60 ; } if ( sensor_data == BIG_RIGHT ) { state = 70 ; } break ; /* CENTER */ case 10 : state = 80 ; straight_move(20,0); break ; /* LITTLE_LEFT (move center) */ case 20 : state = 80 ; right_move( 5 ); break ; /* LEFT (move center) */ case 30 : state = 80 ; right_move( 10); break ; /* BIG_LEFT (move center) */ case 40 : state = 80 ; right_move( 15); break ; /* LITTLE_RIGHT (move center) */ case 50 : state = 80 ; left_move( 5 ); break ; /* RIGHT (move center) */ case 60 : state = 80 ; left_move( 10); break ; /* BIG_RIGHT (move center) */ case 70 : state = 80 ; left_move( 15); break ; /* delay */ case 80 : state = 90 ; delay_ms(1000) ; break ; /* return */ case 90 : state = 0 ; straight_move(20,0) ; break ; /* CRANK */ /* crank slow move */ case 100 : if ( sensor_data == CRANK_RIGHT ) { state = 110 ; dir = DIR_RIGHT ; } if ( sensor_data == CRANK_LEFT ) { state = 110 ; dir = DIR_LEFT ; } straight_move(10,1000); break ; /* crank rotate */ case 110 : state = 120 ; crank_move(dir,10,5); delay_ms(3000); break ; /* crank rotate right (bit by bit) */ case 120 : if ( is_crank_center(sensor_data) == ON ) { state = 130 ; } else { crank_move(dir,5,5); delay_ms(100); } break ; /* crank slow move */ case 130 : state = 140 ; straight_move(10,1000); break ; /* return */ case 140 : state = 0 ; straight_move(20,0); break ; /* LANE */ /* lane slow move */ case 200 : if ( sensor_data == ALL_BLACK ) { state = 210 ; dir = DIR_RIGHT ; if ( lane == LANE_LEFT ) { dir = DIR_LEFT ; } } else { straight_move(10,1000); } break ; /* lane change */ case 210 : state = 220 ; lane_move(dir,10,5); delay_ms(1000); break ; /* lane moving */ case 220 : if ( is_lane_edge(sensor_data) == ON ) { state = 230 ; } else { straight_move(10,1000); } break ; /* lane change completed */ case 230 : state = 240 ; if ( dir == DIR_RIGHT ) { dir = DIR_LEFT ; } else { dir = DIR_RIGHT ; } lane_move(dir,10,5); delay_ms(1000); break ; /* lane slow move */ case 240 : state = 250 ; straight_move(10,1000); break ; /* return */ case 250 : state = 0 ; straight_move(20,0); break ; } /* */ get_sensor() ; } void straight_move(UBYTE x,UWORD tx) { crank_move(DIR_CENTER,0,x); if ( tx ) { delay_ms(tx) ; } } void right_move(UBYTE x) { crank_move(DIR_RIGHT,x,10); } void left_move(UBYTE x) { crank_move(DIR_LEFT,x,10); } void crank_move(UBYTE xa,UBYTE xb,UBYTE xc) { param.direction = xa; param.rlduty = xb; param.duty = xc; update_motor( param ); } void lane_move(UBYTE xa,UBYTE xb,UBYTE xc) { crank_move(xa,xb,xc); } UBYTE is_crank_center(UBYTE x) { UBYTE result ; /* judge */ switch ( x ) { case CENTER : case LITTLE_LEFT : case LITTLE_RIGHT : result = ON ; break ; default : result = OFF; break ; } return result ; } UBYTE is_lane_edge(UBYTE x) { UBYTE result ; /* judge */ switch ( x ) { case CENTER : case LITTLE_LEFT : case LEFT : case BIG_LEFT : case LITTLE_RIGHT : case RIGHT : case BIG_RIGHT : result = ON ; break ; default : result = OFF; break ; } return result ; } UBYTE convert_code(UBYTE x) { UBYTE result ; /* default */ result = ILLEAGAL ; /* judge */ if ( x == 0x00 ) { result = ALL_BLACK ; } if ( x == 0xff ) { result = ALL_WHITE ; } if ( x == 0x38 || x == 0x18 || x == 0x1c ) { result = CENTER ; } if ( x == 0xf0 || x == 0xf8 ) { result = LEFT_WHITE ; } if ( x == 0x0f || x == 0x1f ) { result = RIGHT_WHITE ; } if ( x == 0x10 || x == 0x30 ) { result = LITTLE_LEFT ; } if ( x == 0x60 || x == 0x70 ) { result = LEFT ; } if ( x == 0xc0 || x == 0xe0 ) { result = BIG_LEFT ; } if ( x == 0x08 || x == 0x0c ) { result = LITTLE_RIGHT ; } if ( x == 0x06 || x == 0x0e ) { result = RIGHT ; } if ( x == 0x03 || x == 0x07 ) { result = BIG_RIGHT ; } if ( 100 <= state && state < 200 ) { if ( x == 0x0e || x == 0x0f || x == 0x1f || x == 0x3f ) { result = CRANK_RIGHT ; } if ( x == 0xe0 || x == 0xf0 || x == 0xf8 || x == 0xfc ) { result = CRANK_LEFT ; } } return result ; }  テストボードの回路は、以下です。
目次

inserted by FC2 system