リアルタイムふうOS キャラクタ表示LCDドライバ

RTF-OS LCD driver

LCD初期化タスクとドライバタスクの初期化

Flow chart

#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初期化タスク

Flow chart

#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;
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です