RTF-OS LCD driver
LCD初期化タスクとドライバタスクの初期化
#define N_LCD_MSG 32 /* LCDコマンドバッファのバイト数 */
flag_type *flag_lcd_init; /* 初期化完了フラグ */
tcb_type *tcb_lcd_main; /* 初期化タスクTCB */
tcb_type *tcb_lcd_driver; /* ドライバタスクTCB */
mbx_type *mbx_lcd; /* ドライバとAPIで通信するメールボックス */
uint8 lcd_msg[ N_LCD_MSG ]; /* LCDコマンドをバッファ */
void init_lcd( void )
{
tcb_lcd_main = create_tcb( lcd_main );
tcb_lcd_driver = create_tcb( lcd_driver );
mbx_lcd = create_mbx( lcd_msg, N_LCD_MSG );
flag_lcd_init = create_flag();
start_task( tcb_lcd_main ); /* LCD初期化タスクの起床 */
}
LCD初期化タスク
#define INIT_WAIT_TIME 100 /* LCDリセット待ち時間 */
#define CMD_WAIT_TIME 2 /* LCD コマンド実行時間 */
void lcd_main( uint8 state )
{
static const uint8 init_cmd[][2] = { /* LCD初期化コマンドリスト */
{ LCD_CMD, 0x28 },
{ LCD_CMD, 0x08 },
{ LCD_CMD, 0x01 },
{ LCD_CMD, 0x06 },
{ LCD_CMD, 0x0f } /* 0c:カーソルなし 0f:カーソル&ブリンク */
};
static uint8 i;
tcb_type *tcb;
uint8 result;
tcb = tcb_lcd_main;
switch( state ) {
case 0:
clr_RW(); /* RW=0 */
clr_E(); /* E=0 */
clr_RS(); /* RS=0 */
i = 0;
delay_task( tcb, INIT_WAIT_TIME );
break;
case 1:
if( i++ >= 3 ) {
set_E(); /* E=1 */
set_DATA( 0x2 ); /* LCDデータバスに出力 */
clr_E(); /* E=0 */
delay_task( tcb, 10 );
} else {
set_E(); /* E=1 */
set_DATA( 0x3 ); /* LCDデータバスに出力 */
clr_E(); /* E=0 */
set_next_state( tcb, 1 );
delay_task( tcb, 10 );
}
break;
case 2:
i = 0;
start_task( tcb_lcd_driver ); /* ドライバタスクを起床 */
slice_task( tcb );
break;
case 3:
if( i >= 5 ) {
slice_task( tcb );
} else {
result = send_msg((uint8 *)&init_cmd[ i ][0], 2, mbx_lcd ); /* コマンド送信 */
set_next_state( tcb, 3 );
if( result ) {
i++;
slice_task( tcb );
} else {
delay_task( tcb, 10 ); /* 失敗なら10ms後に再トライ */
}
}
break;
case 4:
set_flag( flag_lcd_init ); /* 初期化完了フラグをセット */
break;
default:
break;
}
}
#define DATA_PORT (PORTA) /* DATA のポート */
#define DATA_LSB (0) /* DATA のbit4の位置 */
void set_DATA( uint8 data )
{
uint8 temp;
temp = DATA_PORT;
temp &= ~( 0x0f << DATA_LSB );
temp |= (uint8)( data << DATA_LSB );
DATA_PORT = temp;
}
LCDドライバタスク
他タスクからのLCDコマンドを受け取り実行する
#define DATA_PORT (PORTA) /* DATA のポート */
#define DATA_DDR (DDRA) /* DATA の入出力設定レジスタ */
#define DATA_PIN (PINA) /* DATA の入力ポート */
#define DATA_LSB (0) /* DATA のbit4の位置 */
#define BUSY_MASK (0x80) /* BFフラグチェック用bitマスク */
void lcd_driver( uint8 state )
{
static uint8 data, len, *msg;
static uint8 busy;
tcb_type *tcb;
mbx_type *mbx;
mbx = mbx_lcd;
tcb = tcb_lcd_driver;
switch( state ) {
case 0: /* コマンド待ち */
wait_msg( mbx, tcb );
break;
case 1: /* busyチェック */
disable_int();
DATA_DDR = (uint8)(DATA_DDR & (0xf0 << DATA_LSB)); /* set input */
clr_RS();
set_RW();
set_E();
busy = (uint8)((DATA_PIN << (4 - DATA_LSB)) & 0xf0); /* high 4 bit */
clr_E();
clr_E();
set_E();
busy |= (uint8)((DATA_PIN >> DATA_LSB) & 0x0f); /* low 4 bit */
clr_E();
clr_RW();
DATA_DDR = (uint8)(DATA_DDR | (0x0f << DATA_LSB)); /* set output */
enable_int();
if( busy & BUSY_MASK ) {
/* LCD is busy */
set_next_state( tcb, state );
delay_task( tcb, CMD_WAIT_TIME );
} else {
slice_task( tcb );
}
break;
case 2: /* コマンド実行 */
msg = get_msg( mbx );
switch( *msg++ ) {
case LCD_CMD:
data = *msg;
clear_msg( mbx );
clr_RS();
slice_task( tcb );
break;
case LCD_DATA:
data = *msg;
clear_msg( mbx );
set_RS();
slice_task( tcb );
break;
case LCD_PRINT:
len = (uint8)( get_msglen( mbx ) - 1 );
set_RS();
set_next_state( tcb, 4 );
slice_task( tcb );
break;
default:
clear_msg( mbx );
set_next_state( tcb, 0 );
slice_task( tcb );
break;
}
break;
case 3: /* 1バイトコマンド:LCD_CMD LCD_DATA */
disable_int();
set_E();
set_DATA((uint8)( data >> 4 ));
clr_E();
clr_E();
set_E();
set_DATA((uint8)( data & 0x0f ));
clr_E();
enable_int();
set_next_state( tcb, 0 );
slice_task( tcb );
break;
case 4: /* 文字列表示コマンド:LCD_PRINT */
if( len-- ) {
data = *msg++;
disable_int();
set_E();
set_DATA((uint8)( data >> 4 ));
clr_E();
clr_E();
set_E();
set_DATA((uint8)( data & 0x0f ));
clr_E();
enable_int();
slice_task( tcb );
} else {
clear_msg( mbx );
set_next_state( tcb, 0 );
slice_task( tcb );
}
break;
case 5: /* 文字列表示コマンド:LCD_PRINT check busy */
disable_int();
DATA_DDR = (uint8)(DATA_DDR & (0xf0 << DATA_LSB)); /* set input */
clr_RS();
set_RW();
set_E();
busy = (uint8)((DATA_PIN << (4 - DATA_LSB)) & 0xf0); /* high 4 bit */
clr_E();
clr_E();
set_E();
busy |= (uint8)((DATA_PIN >> DATA_LSB) & 0x0f); /* low 4 bit */
clr_E();
clr_RW();
DATA_DDR = (uint8)(DATA_DDR | (0x0f << DATA_LSB)); /* set output */
enable_int();
if( busy & BUSY_MASK ) {
/* LCD is busy */
set_next_state( tcb, state );
delay_task( tcb, CMD_WAIT_TIME );
} else {
set_RS();
set_next_state( tcb, 4 );
slice_task( tcb );
}
break;
default:
break;
}
}
static void set_DATA( uint8 data )
{
uint8 temp;
temp = DATA_PORT;
temp &= ~( 0x0f << DATA_LSB );
temp |= (uint8)( data << DATA_LSB );
DATA_PORT = temp;
}