目次

LCDモニタ

 知り合いがジャンク箱にある部品類を廃棄すると
 いうので、NokiaのLCDを貰ってきました。



 電源電圧3.3Vで、インタフェースがSPIです。
 内蔵メモリがフレームバッファになっていて
 84ドットx48ラインです。

 この類のLCDでは、標準タイプなのか、フレーム
 バッファは次のように画面に対応します。



 横をY方向とし、ライン方向はページという
 単位で扱っています。48ラインは6ページ
 分に相当します。

 マイクロコンピュータ内蔵SRAMにフレームバッファを
 確保します。そのフレームバッファにビットパターン
 をライト後、表示させてみます。

 内蔵SRAMで構成したフレームバッファへのデータライト
 は1バイト単位として、次のようにラスターで扱います。



 LCDに表示する場合、並べ替えてから、データ転送
 する仕様とします。

 一息で作れないので、パーソナルコンピュータから
 マイクロコンピュータにコマンドを与え、内蔵SRAM
 の中に用意した配列に、画像データを転送する部分
 から作成していきます。



 LCDは、3.3V動作なので、電源電圧3.3Vで直結できる
 マイコンとしてAnalogDevicesのADcU7026を使います。



 端末ソフトでマイコンとやりとりするため
 コマンドを決めます。

 マイコン内蔵SRAMに、画像データを書き込むため
 のコマンド'W'は、次の仕様で使います。

   W+カラム位置+ライン位置+データ{enter}

    カラム位置は、横方向が84ピクセルなので
   1バイト単位でデータを書き込むとして
   0から10です。10進数2桁で指定します。
   10のときは、
   8ビットx11になるので、4ビット分は意味
   がないことに。

    ライン位置は、縦方向が48ラインなので
   0から47です。10進数2桁で指定します。

   データは8ビット(=1バイト)で与えると
   して、16進数2桁で指定します。

 仕様から、シリアルインタフェースで利用する
 受信バッファは、8バイト用意します。
 さらに、画面1枚分は、配列に入れるとして
 11x48=728バイト確保します。

    typedef unsigned char UBYTE ;

    UBYTE lcd_buf[8];

    #define LCDBUFSIZE 528

    UBYTE lcd_buf[LCDBUFSIZE] ;

 マイコン内蔵SRAMに入っている画像データを
 表示するため、11バイトをリードして16進数
 で表示します。2進数で表示する方がよい
 ですが、端末ソフトの画面では見にくいので
 16進数表示とします。

   F{enter}

 で処理を開始します。

 マイコン内蔵SRAMから、LCDのSRAMに転送
 するコマンドは、次のように1文字とします。

   D{enter}

 フレームバッファの内容をクリアするために
 ひとつコマンドを用意します。

   C{enter}

 コマンドを決めたなら、コマンドインタプリタを
 作り、より下位の処理を定義します。

  while(ON) {
    /* command interrpreter */
    if ( uflag == ON ) {
      /* clear flag */
      uflag = OFF ;
      /* new line */
      crlf();
      /* judge */
      cmd = *(sbuf+0) ;
      /* help */
      if ( cmd == '?' ) { show_help(); }
      /* write bit pattern */
      if ( cmd == 'W' ) {
        /* get column byte number */
        ax = get_hex( *(sbuf+1) );
        ax *= 10 ;
        ax += get_hex( *(sbuf+2) );
        /* get line number */
        ay = get_hex( *(sbuf+3) );
        ay *= 10 ;
        ay += get_hex( *(sbuf+4) );
        /* get bit pattern */
        xdat = get_hex( *(sbuf+5) );
        xdat <<= 4 ;
        xdat += get_hex( *(sbuf+6) );
        /* judge */
        eflag = 0 ;
        if ( ax > 10 ) {
          rs_puts("column error !") ;
          crlf() ;
          eflag++ ; 
        }
        if ( ay > 47 ) {
          rs_puts("line error !") ;
          crlf() ;
          eflag++ ; 
        }
        /* store data */
        if ( eflag == 0 ) { *(lcd_buf+11*ay+ax) = xdat ; }
      }
      /* show frame buffer */
      if ( cmd == 'F' ) {
        for ( ay = 0 ; ay < 48 ; ay++ ) {
          /* line number */
          rs_putc( asc_hex[ay / 10] );
          rs_putc( asc_hex[ay % 10] );
          rs_putc(':');
          /* 1 line context */
          for ( ax = 0 ; ax < 11 ; ax++ ) {
            /* get data */
            xdat = *(lcd_buf+11*ay+ax) ;
            /* show */
            rs_putc( asc_hex[(xdat >> 4) & MASK0F] );
            if ( ax < 10 ) {
              rs_putc( asc_hex[xdat & MASK0F] );
              /* separator */
              rs_putc('_');
            }
          }
          /* new line */
          crlf();
        }
      }
      /* clear frame buffer */
      if ( cmd == 'C' ) {
        for ( ay = 0 ; ay < 48 ; ay++ ) {
          for ( ax = 0 ; ax < 11 ; ax++ ) {
            *(lcd_buf+11*ay+ax) = 0 ;
          }
        }
      }
      /* display LCD */
      if ( cmd == 'D' ) { lcd_show() ; }
    }
  }

 コマンドインタプリタの動作を確認しました。

 ヘルプコマンドテスト



 フレームバッファ関連テスト



 LCD表示テスト



 LCDの表示については、内蔵ドライバの
 データシートを参照しました。



 データシートからレジスタの機能と
 書込みシーケンスを理解しておきます。
  1. チップセレクトイネーブル
  2. コマンドでファンクション設定(0x21)
  3. コマンドでファンクション設定(0x90)
  4. コマンドでファンクション設定(0x10) 表示の初期設定
  5. コマンドでファンクション設定(0x0C) 表示制御
  6. SRAMのアドレス設定
  7. データ転送
  8. チップセレクトディセーブル
 シーケンスを眺めると、コマンドとデータの  書き込みが必要です。両者の区別は、ピンに  与える論理値で選らぶため、ピンアサインを  定義します。 #define SPI_SCE 20 /* 4 */ #define SPI_RST 19 /* 3 */ #define SPI_DC 18 /* 2 */ #define SPI_DAT 17 /* 1 */ #define SPI_CLK 16 /* 0 */  コマンドとデータ転送に関する関数を定義します。 void lcd_primitive(UBYTE which,UBYTE x) { UBYTE tmp ; UBYTE loop ; /* get data */ tmp = x ; /* enable CS */ GP3DAT &= ~(1 << SPI_SCE) ; /* select data or command */ GP3DAT &= ~(1 << SPI_DC); if ( which ) { GP3DAT |= (1 << SPI_DC); } /* loop */ for ( loop = 0 ; loop < 8 ; loop++ ) { /* impress 1 bit */ GP3DAT &= ~(1 << SPI_DAT); if ( tmp & MASK80 ) { GP3DAT |= (1 << SPI_DAT); } /* 1 -> CLK */ GP3DAT |= (1 << SPI_CLK); /* shift */ tmp <<= 1 ; /* 0 -> CLK */ GP3DAT &= ~(1 << SPI_CLK); } /* disable CS */ GP3DAT |= (1 << SPI_SCE) ; } void lcd_cmd(UBYTE x) { lcd_primitive(OFF,x); } void lcd_dat(UBYTE x) { lcd_primitive(ON,x); }  LCDのリセットを利用できるように  単独の関数を定義します。 void lcd_rst(void) { GP3DAT &= ~(1 << SPI_RST) ; delay_ms(1); GP3DAT |= (1 << SPI_RST) ; }  LCDの初期化をひとつの関数にまとめます。 void lcd_init(void) { UBYTE loop ; /* reset */ lcd_rst() ; /* store parameters */ lcd_cmd( 0x20 | 1 ); /* H = 1 */ lcd_cmd( 0x04 | 1 ); /* TC = 1 (0-3) */ lcd_cmd( 0x10 | 3 ); /* Bais = 3 (0-7) */ lcd_cmd( 0x80 | 68); /* Vop = 68 (0-127) コントラスト設定 */ lcd_cmd( 0x20 | 0 ); /* H = 0, Horizontal addressing */ lcd_cmd( 0x08 | 4 ); /* Display Mode Normal = 4 */ /* Set Y = 0 (0-5) */ /* Set X = 0 (0-83) */ lcd_locate(0,0) ; /* clear LCD */ for ( loop = 0 ; loop < 6 ; loop++ ) { lcd_locate(0,loop); lcd_clear(0,83) ; } }  LCDはブロックごとに内蔵SRAMにデータを  転送して表示します。そのための関数を  定義しました。 void lcd_locate(UBYTE x,UBYTE y) { lcd_cmd(CMD_YDIR | y) ; lcd_cmd(CMD_XDIR | x) ; } void lcd_clear(UBYTE sx,UBYTE dx) { UBYTE i ; UBYTE last ; /* calculate size */ last = dx - sx + 1 ; /* write */ for ( i = 0 ; i < last ; i++ ) { lcd_dat(0); } } void lcd_set_data(UBYTE *ptr,UBYTE sx,UBYTE dx) { UBYTE i ; UBYTE last ; /* calculate size */ last = dx - sx + 1 ; /* write */ for ( i = 0 ; i < last ; i++ ) { lcd_dat( *(ptr+i) ); } }  関数lcd_locateは、SRAMの書込み開始位置を指定します。  書込み開始位置を指定したなら、データを順次転送です。  データを1バイト書込む度に、アドレスを+1する  ので、次々とデータを書込んで表示させます。  今回はマイコン内部にフレームバッファを用意し  そこからデータを引き出して、ビットパターンを  再構成して対応します。再構成した内容をLCDに  転送するために、関数lcd_set_dataを定義しました。  フレームバッファからビットパターンを  再構成して表示する関数は、以下です。 void lcd_show(void) { UBYTE i ; UBYTE j ; UBYTE last ; UBYTE src[8] ; UBYTE dst[8] ; UWORD aidx ; /* line */ for ( ay = 0 ; ay < 6 ; ay++ ) { /* clear block buffer */ for ( i = 0 ; i < 84 ; i++ ) { *(lcd_block+i) = 0 ; } /* block */ for ( ax = 0 ; ax < 11 ; ax++ ) { /* get vertical data */ for ( i = 0 ; i < 8 ; i++ ) { aidx = ax+11*(7-i)+88*ay ; *(src+i) = *(lcd_buf+aidx) ; } /* arrange (vertical -> horizontal) */ for ( i = 0 ; i < 8 ; i++ ) { /* clear destination */ *(dst+i) = 0 ; /* rotate with right 90 degree */ for ( j = 0 ; j < 8 ; j++ ) { *(dst+i) |= ((*(src+j) & MASK80) >> j) ; } /* shift */ for ( j = 0 ; j < 8 ; j++ ) { *(src+j) <<= 1 ; } } /* calculate bit size */ last = 8 ; if ( ax == 10 ) { last >>= 1 ; } /* copy */ for ( i = 0 ; i < last ; i++ ) { aidx = (ax << 3) ; *(lcd_block+aidx+i) = *(dst+i) ; } } /* set address */ lcd_locate(0,ay); /* transfer data */ lcd_set_data(lcd_block,0,83) ; } }  動作は単純で、次のようにしています。  マイコン内部に用意したフレームバッファの  内容(84dotx48line)を一気にLCDに転送して  表示させます。  コマンドインタプリタを使いやすくして  ソースコードにまとめます。 #include <ADuC7026.h> #define OFF 0 #define ON OFF+1 /* data definitions */ typedef unsigned char UBYTE ; typedef signed char SBYTE ; typedef unsigned short UWORD ; typedef signed short SWORD ; typedef unsigned long ULONG ; typedef signed long SLONG ; void IRQ_Handler(void) __irq; void init_usr(void); #define MASKFF 0xFF #define MASK0F 0x0F #define MASKF0 0xF0 #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 MASK07 0x07 #define LCDBUFSIZE 528 #define CMD_YDIR 0x40 #define CMD_XDIR 0x80 /* LCD pin assignment */ #define SPI_SCE 20 #define SPI_RST 19 #define SPI_DC 18 #define SPI_DAT 17 #define SPI_CLK 16 void rs_putc(UBYTE x); void crlf(void); void rs_puts(UBYTE *x); UBYTE get_hex(UBYTE x); void show_help(void); void delay_ms(ULONG x); void lcd_primitive(UBYTE which,UBYTE x); void lcd_cmd(UBYTE x); void lcd_dat(UBYTE x); void lcd_rst(void); void lcd_init(void); void lcd_locate(UBYTE x,UBYTE y); void lcd_set_data(UBYTE *ptr,UBYTE sx,UBYTE dx); void lcd_clear(UBYTE sx,UBYTE dx); void lcd_show(void); /* global variables */ volatile ULONG timcnt ; volatile UBYTE uflag ; volatile UBYTE sbuf[8] ; volatile UBYTE sindex ; volatile UBYTE cmd ; volatile UBYTE asc_hex[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; volatile UBYTE lcd_buf[LCDBUFSIZE] ; volatile UBYTE lcd_block[84] ; volatile UBYTE ax ; volatile UBYTE ay ; int main(void) { UBYTE eflag ; UBYTE xdat ; /* initialize user */ init_usr(); /* show message */ rs_puts("Hello"); crlf(); lcd_init(); /* endless loop */ while(ON) { /* command interrpreter */ if ( uflag == ON ) { /* clear flag */ uflag = OFF ; /* new line */ crlf(); /* judge */ cmd = *(sbuf+0) ; /* help */ if ( cmd == '?' ) { show_help(); } /* write bit pattern */ if ( cmd == 'W' ) { /* get column byte number */ ax = get_hex( *(sbuf+1) ); ax *= 10 ; ax += get_hex( *(sbuf+2) ); /* get line number */ ay = get_hex( *(sbuf+3) ); ay *= 10 ; ay += get_hex( *(sbuf+4) ); /* get bit pattern */ xdat = get_hex( *(sbuf+5) ); xdat <<= 4 ; xdat += get_hex( *(sbuf+6) ); /* judge */ eflag = 0 ; if ( ax > 10 ) { rs_puts("column error !") ; crlf() ; eflag++ ; } if ( ay > 47 ) { rs_puts("line error !") ; crlf() ; eflag++ ; } /* store data */ if ( eflag == 0 ) { *(lcd_buf+11*ay+ax) = xdat ; } } /* show frame buffer */ if ( cmd == 'F' ) { for ( ay = 0 ; ay < 48 ; ay++ ) { /* line number */ rs_putc( asc_hex[ay / 10] ); rs_putc( asc_hex[ay % 10] ); rs_putc(':'); /* 1 line context */ for ( ax = 0 ; ax < 11 ; ax++ ) { /* get data */ xdat = *(lcd_buf+11*ay+ax) ; /* show */ rs_putc( asc_hex[(xdat >> 4) & MASK0F] ); if ( ax < 10 ) { rs_putc( asc_hex[xdat & MASK0F] ); /* separator */ rs_putc('_'); } } /* new line */ crlf(); } } /* clear frame buffer */ if ( cmd == 'C' ) { /* get pattern */ xdat = get_hex( *(sbuf+1) ); /* update LCD buffer */ for ( ay = 0 ; ay < 48 ; ay++ ) { for ( ax = 0 ; ax < 11 ; ax++ ) { *(lcd_buf+11*ay+ax) = 0 ; if ( xdat ) { *(lcd_buf+11*ay+ax) = MASKFF ; } } } /* show */ lcd_show() ; } /* display LCD */ if ( cmd == 'D' ) { lcd_show() ; } } } /* dummy return */ return (0); } void IRQ_Handler(void) __irq { volatile UBYTE ch ; /* judge UART receive interruption */ if ( (IRQSTA & UART_BIT) == UART_BIT ) { /* judge */ if ( COMSTA0 & 1 ) { /* clear flag */ ch = COMRX ; *(sbuf+sindex) = ch ; sindex++ ; if ( ch == '\r' ) { sindex = 0 ; uflag = ON ; } } } /* judge timer3 interruption (1ms) */ if ( (IRQSTA & WATCHDOG_TIMER_BIT) == WATCHDOG_TIMER_BIT ) { /* clear timer3 interrupt flag */ T3CLRI = 0xff ; /* increment timer counter */ timcnt++ ; /* blink */ if ( (timcnt & 0x1ff) == 500 ) { GP4DAT ^= (1 << 23); } } } void init_usr(void) { UWORD loop ; /* select clock 41.78MHz / initialized in start up routine */ PLLKEY1 = 0xaa ; PLLCON = 0x01 ; PLLKEY2 = 0x55 ; /* power control initialized in start up routine */ /* clear flag */ uflag = OFF ; /* clear counter */ timcnt = 0 ; sindex = 0 ; /* initialize UART */ { /* set baud rate 19200 bps CD = 1 DL = 0x22 */ COMCON0 = 0x80 ; /* select COMDIV1 and COMDIV0 */ COMDIV0 = 0x22 ; COMDIV1 = 0x00 ; /* set conditions */ COMCON0 = 0x03 ; /* select COMRX and COMTX , 8bit data , 1 stop bit , no parity */ /* enable interrupt */ COMIEN0 = 0x01 ; /* ERBFI */ } /* P0 */ { /* */ GP0DAT = 0xDF3C0000 ; } /* P1 */ { /* use UART */ GP1CON = 0x00000011 ; /* */ GP1DAT = 0xfe000000 ; } /* P2 */ { /* all bits inputs */ GP2DAT = 0x00000000 ; } /* P3 */ { /* all bits outputs */ GP3DAT = 0xff180000 ; } /* P4 */ { GP4DAT = 0xff000000 ; } /* initialize timer 3 (1s) */ { T3LD = 33 ; /* (32.768kHz / 32) = about 1 kHz */ T3CON = 0xc0 ; /* enable , cyclic , 1/1 */ } /* clear LCD buffer */ for ( loop = 0 ; loop < LCDBUFSIZE ; loop++ ) { *(lcd_buf+loop) = 0 ; } /* enable timer 3 interrupt and UART interrupt */ IRQEN = WATCHDOG_TIMER_BIT | UART_BIT ; } /* UART putchar */ void rs_putc(UBYTE x) { /* ? transmmit buffer empty */ while( (COMSTA0 & 0x40) == 0 ) ; /* set value */ COMTX = x ; } /* carriage return and line feed */ void crlf(void) { rs_putc('\r'); rs_putc('\n'); } /* UART puts */ void rs_puts(UBYTE *x) { while ( *x != '\0' ) { rs_putc( *x ) ; x++ ; } } /* convert ASCII to number */ UBYTE get_hex(UBYTE x) { UBYTE result ; /* default */ result = 0 ; /* judge */ 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 ; } /* show help */ void show_help(void) { rs_puts("? help") ; crlf(); rs_puts("W set data") ; crlf(); rs_puts(" column(10) line(10) data(16)") ; crlf(); rs_puts("F show frame buffer context") ; crlf(); rs_puts("C clear frame buffer context") ; crlf(); rs_puts("D display on LCD") ; crlf(); } void delay_ms(ULONG x) { ULONG last ; /* calculate */ last = timcnt + x ; /* wait */ while ( timcnt < last ) ; } void lcd_primitive(UBYTE which,UBYTE x) { UBYTE tmp ; UBYTE loop ; /* get data */ tmp = x ; /* enable CS */ GP3DAT &= ~(1 << SPI_SCE) ; /* select data or command */ GP3DAT &= ~(1 << SPI_DC); if ( which ) { GP3DAT |= (1 << SPI_DC); } /* loop */ for ( loop = 0 ; loop < 8 ; loop++ ) { /* impress 1 bit */ GP3DAT &= ~(1 << SPI_DAT); if ( tmp & MASK80 ) { GP3DAT |= (1 << SPI_DAT); } /* 1 -> CLK */ GP3DAT |= (1 << SPI_CLK); /* shift */ tmp <<= 1 ; /* 0 -> CLK */ GP3DAT &= ~(1 << SPI_CLK); } /* disable CS */ GP3DAT |= (1 << SPI_SCE) ; } void lcd_cmd(UBYTE x) { lcd_primitive(OFF,x); } void lcd_dat(UBYTE x) { lcd_primitive(ON,x); } void lcd_rst(void) { GP3DAT &= ~(1 << SPI_RST) ; delay_ms(1); GP3DAT |= (1 << SPI_RST) ; } void lcd_init(void) { UBYTE loop ; /* reset */ lcd_rst() ; /* store parameters */ lcd_cmd( 0x20 | 1 ); /* H = 1 */ lcd_cmd( 0x04 | 1 ); /* TC = 1 (0-3) */ lcd_cmd( 0x10 | 3 ); /* Bais = 3 (0-7) */ lcd_cmd( 0x80 | 68); /* Vop = 68 (0-127) コントラスト設定 */ lcd_cmd( 0x20 | 0 ); /* H = 0, Horizontal addressing */ lcd_cmd( 0x08 | 4 ); /* Display Mode Normal = 4 */ /* Set Y = 0 (0-5) */ /* Set X = 0 (0-83) */ lcd_locate(0,0) ; /* clear LCD */ for ( loop = 0 ; loop < 6 ; loop++ ) { lcd_locate(0,loop); lcd_clear(0,83) ; } } void lcd_locate(UBYTE x,UBYTE y) { lcd_cmd(CMD_YDIR | y) ; lcd_cmd(CMD_XDIR | x) ; } void lcd_set_data(UBYTE *ptr,UBYTE sx,UBYTE dx) { UBYTE i ; UBYTE last ; /* calculate size */ last = dx - sx + 1 ; /* write */ for ( i = 0 ; i < last ; i++ ) { lcd_dat( *(ptr+i) ); } } void lcd_clear(UBYTE sx,UBYTE dx) { UBYTE i ; UBYTE last ; /* calculate size */ last = dx - sx + 1 ; /* write */ for ( i = 0 ; i < last ; i++ ) { lcd_dat(0); } } void lcd_show(void) { UBYTE i ; UBYTE j ; UBYTE last ; UBYTE src[8] ; UBYTE dst[8] ; UWORD aidx ; /* line */ for ( ay = 0 ; ay < 6 ; ay++ ) { /* clear block buffer */ for ( i = 0 ; i < 84 ; i++ ) { *(lcd_block+i) = 0 ; } /* block */ for ( ax = 0 ; ax < 11 ; ax++ ) { /* get vertical data */ for ( i = 0 ; i < 8 ; i++ ) { aidx = ax+11*(7-i)+88*ay ; *(src+i) = *(lcd_buf+aidx) ; } /* arrange (vertical -> horizontal) */ for ( i = 0 ; i < 8 ; i++ ) { /* clear destination */ *(dst+i) = 0 ; /* rotate with right 90 degree */ for ( j = 0 ; j < 8 ; j++ ) { *(dst+i) |= ((*(src+j) & MASK80) >> j) ; } /* shift */ for ( j = 0 ; j < 8 ; j++ ) { *(src+j) <<= 1 ; } } /* calculate bit size */ last = 8 ; if ( ax == 10 ) { last >>= 1 ; } /* copy */ for ( i = 0 ; i < last ; i++ ) { aidx = (ax << 3) ; *(lcd_block+aidx+i) = *(dst+i) ; } } /* set address */ lcd_locate(0,ay); /* transfer data */ lcd_set_data(lcd_block,0,83) ; } }  端末ソフトから、複数のコマンドを組み合わせて  動作を確認しました。  地を黒に設定  地を白に設定  縦線を引く  横線を引く  斜線を引く  ビットパターン設定  同じような操作で128ドットx64ラインの  LCDを動かせるようにしました。  H8内部に用意したフレームバッファに  データパターンを書き込み、表示して  みます。  フレームバッファの内容に対応して  パターンが表示されることを、確認  できました。  H8/3052Fのソースコードは、以下です。 #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 ITU1_AREG 24999 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 TFLAG x_flags.BIT.B1 #define UFLAG x_flags.BIT.B2 #define STRG x_flags.BIT.B3 #define P1DDR P1.DDR #define P1DR P1.DR.BYTE #define P2DDR P2.DDR #define P2DR P2.DR.BYTE #define P3DDR P3.DDR #define P3DR P3.DR.BYTE #define P4DDR P4.DDR #define P4DR P4.DR.BYTE #define P5DDR P5.DDR #define P5DR P5.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 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 MAXCOUNT 60 #define MAXADR 512 #define MASK80 0x80 #define LCD_DAT 7 #define LCD_CLK 6 #define LCD_RST 5 #define LCD_CS2 4 #define LCD_CS1 3 #define LCD_RS 2 #define LCD_RW 1 #define LCD_E 0 #define LCD_RS_H 1 #define LCD_RS_L 0 #define SEL_LEFT 2 #define SEL_RIGHT 1 #define SEL_NONE 0 #define GMAX 512 #define YMAX 8 #define XMAX 64 void init_sci_1(TBaudRate x); void rs1_putchar(UBYTE x); void rs1_crlf(void); void rs1_puts(UBYTE *x); void show_help(void); UBYTE sindex ; UBYTE sbuf[16]; UBYTE cmd ; UBYTE asc_hex[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'} ; UBYTE glcdl[MAXADR]; UBYTE glcdr[MAXADR]; UBYTE lcd_page_buf[XMAX]; UBYTE src[8] ; UBYTE dst[8] ; /*--------------------------------*/ /* Insert user functions protoype */ /*--------------------------------*/ void user_initialize(void); void init_timer1(void); UBYTE get_hex(UBYTE x); void delay_ms(UWORD x); void binary_display(UBYTE x); void lcd_primitive(UBYTE which,UBYTE x); void lcd_dat(UBYTE x); void lcd_cmd(UBYTE x); void lcd_select_plane(UBYTE x); void lcd_display(UBYTE x); void lcd_show(void); void lcd_rst(void); void init_lcd(void); void lcd_set_start_line(UBYTE x); void lcd_set_address(UBYTE x); void lcd_set_page(UBYTE x); void lcd_locate(UBYTE pgx,UBYTE idx); void lcd_set_data(UBYTE *ptr,UBYTE sx,UBYTE lx) ; /*------*/ /* main */ /*------*/ int main(void) { UBYTE xx ; UBYTE yy ; UBYTE xdat ; UBYTE eflag ; /* disable interrupt */ DI ; /* initialize */ user_initialize(); /* enable interrupt */ EI ; /* opening message */ rs1_puts("Hello"); rs1_crlf(); /* 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() ; } /* show frame buffer context */ if ( cmd == 'F' ) { /* line */ for ( yy = 0 ; yy < 64 ; yy++ ) { /* line number */ rs1_putchar( asc_hex[(yy >> 4) & MASK0F] ); rs1_putchar( asc_hex[yy & MASK0F] ); rs1_putchar(':'); /* raster */ for ( xx = 0 ; xx < 16 ; xx++ ) { /* get 1 byte */ if ( xx < 8 ) { xdat = *(glcdl+xx+8*yy) ; } else { xdat = *(glcdr+(xx-8)+8*yy) ; } /* show 1 byte with hexadecimal format */ rs1_putchar( asc_hex[(xdat >> 4) & MASK0F] ); rs1_putchar( asc_hex[xdat & MASK0F] ); if ( xx < 15 ) { rs1_putchar('_'); } } /* new line */ rs1_crlf(); } /* new line */ rs1_crlf(); } /* set 1 byte to frame buffer */ if ( cmd == 'W' ) { /* get X axies */ xx = 10 * get_hex( *(sbuf+1) ) + get_hex( *(sbuf+2) ); /* get Y axies */ yy = 10 * get_hex( *(sbuf+3) ) + get_hex( *(sbuf+4) ); /* get data */ xdat = (get_hex( *(sbuf+5) ) << 4) | get_hex( *(sbuf+6) ); /* judge */ eflag = 0 ; if ( xx > 15 ) { rs1_puts("X location error !"); eflag++ ; rs1_crlf(); } if ( yy > 63 ) { rs1_puts("Y location error !"); eflag++ ; rs1_crlf(); } /* store */ if ( eflag == 0 ) { if ( xx < 8 ) { *(glcdl+xx+8*yy) = xdat ; } else { *(glcdr+(xx-8)+8*yy) = xdat ; } } } /* show */ if ( cmd == 'D' ) { lcd_show(); } /* clear */ if ( cmd == 'C' ) { /* get bit data */ eflag = get_hex( *(sbuf+1) ); xdat = 0 ; if ( eflag ) { xdat = MASKFF ; } /* set value to frame buffer */ for ( yy = 0 ; yy < 64 ; yy++ ) { for ( xx = 0 ; xx < 8 ; xx++ ) { *(glcdl+xx+8*yy) = xdat ; /* left */ *(glcdr+xx+8*yy) = xdat ; /* right */ } } /* transfer */ lcd_show(); } } } return 0 ; } /*-----------------------*/ /* Insert user functions */ /*-----------------------*/ void user_initialize(void) { /* PORT 1 */ P1DR = 0 ; P1DDR = MASKFF ; /* all outputs */ /* PORT 2 */ P2DR = 0 ; P2DDR = MASKFF ; /* all outputs */ /* PORT 3 */ P3DR = 0 ; P3DDR = MASKFF ; /* all outputs */ /* PORT 4 */ P4DR = 0 ; P4DDR = MASKFF ; /* all outputs */ /* PORT 8 */ P8DR = 0 ; P8DDR = MASKFF ; /* all outputs */ /* PORT A */ PADR = 0 ; PADDR = MASKFF ; /* all outputs */ /* PORT B */ PBDR = 0 ; PBDDR = 0xff ; /* all outputs */ /* initialize */ init_timer1(); /* clear flags */ x_flags.DR = 0 ; /* clear SCI buffer */ *(sbuf+0) = 0 ; sindex = 0 ; /* initialize */ timcnt = 0 ; /* SCI */ init_sci_1(br9600); } 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 ; } /*+++++++++++++++++++++++++++++++++++++*/ /* ITU1 interrupt with compare match A */ /* 1ms interval */ /*+++++++++++++++++++++++++++++++++++++*/ void int_imia1(void) { UBYTE dummy ; /* clear flag */ dummy = ITU1.TSR.BIT.IMFA ; ITU1.TSR.BIT.IMFA = OFF ; /* increment */ timcnt++ ; /* judge 10ms passed */ if ( timcnt & 10 ) { STRG = ON ; } /* judge 1000ms passed */ if ( timcnt & 100 ) { TFLAG = 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) { while ( *x ) { /* send 1 charactors */ rs1_putchar(*x); x++ ; } } /*++++++++++++*/ /* 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_crlf(); rs1_puts("W set data") ; rs1_crlf(); rs1_puts(" column(15) line(64) data(16)") ; rs1_crlf(); rs1_puts("F show frame buffer context") ; rs1_crlf(); rs1_puts("C clear frame buffer context") ; rs1_crlf(); rs1_puts("D display on LCD") ; rs1_crlf(); } void lcd_show(void) { UBYTE ax ; UBYTE ay ; UBYTE i ; UBYTE j ; UBYTE k ; UBYTE *xptr ; UWORD aidx ; for ( k = 0 ; k < 2 ; k++ ) { /* select plane */ lcd_select_plane(SEL_LEFT); xptr = glcdl ; if ( k ) { lcd_select_plane(SEL_RIGHT); xptr = glcdr ; } /* disable plane */ lcd_display(OFF); /* transfer data */ lcd_set_start_line(0) ; /* left plane */ for ( ay = 0 ; ay < 8 ; ay++ ) { /* clear page buffer */ for ( i = 0 ; i < 64 ; i++ ) { *(lcd_page_buf+i) = 0 ; } /* raster */ for ( ax = 0 ; ax < 8 ; ax++ ) { /* get vertical data */ for ( i = 0 ; i < 8 ; i++ ) { aidx = ax+8*(7-i)+64*ay ; *(src+i) = *(xptr+aidx) ; } /* arrange (vertical -> horizontal) */ for ( i = 0 ; i < 8 ; i++ ) { /* clear destination */ *(dst+i) = 0 ; /* rotate with right 90 degree */ for ( j = 0 ; j < 8 ; j++ ) { *(dst+i) |= ((*(src+j) & MASK80) >> j) ; } /* shift */ for ( j = 0 ; j < 8 ; j++ ) { *(src+j) <<= 1 ; } } /* copy */ for ( i = 0 ; i < 8 ; i++ ) { aidx = (ax << 3) ; *(lcd_page_buf+aidx+i) = *(dst+i) ; } } /* transfer page buffer */ { /* set address */ lcd_locate(ay,0); /* transfer data */ lcd_set_data(lcd_page_buf,0,63) ; } } /* enable plane */ lcd_display(ON); } /* */ lcd_select_plane(SEL_NONE); } 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 ) ; } void binary_display(UBYTE x) { UBYTE loop ; UBYTE bdat ; /* show */ for ( loop = 0 ; loop < 8 ; loop++ ) { bdat = '0' ; if ( x & MASK80 ) { bdat++ ; } rs1_putchar( bdat ); x <<= 1 ; } } void lcd_primitive(UBYTE which,UBYTE x) { UBYTE loop ; UBYTE tmp ; /* get data */ tmp = x ; /* Write mode */ PBDR &= ~(1 << LCD_RW); /* data transfer to 74HC164 */ for ( loop = 0 ; loop < 8 ; loop++ ) { /* set bit datum */ PBDR &= ~(1 << LCD_DAT) ; if ( tmp & MASK80 ) { PBDR |= (1 << LCD_DAT) ; } /* CLOCK : H */ PBDR |= (1 << LCD_CLK) ; /* shift */ tmp <<= 1 ; /* CLOCK : L */ PBDR &= ~(1 << LCD_CLK) ; } /* confirm RS */ PBDR &= ~(1 << LCD_RS) ; if ( which ) { PBDR |= (1 << LCD_RS) ; } /* latch */ PBDR |= (1 << LCD_E) ; PBDR &= ~(1 << LCD_DAT) ; /* dummy */ PBDR &= ~(1 << LCD_E) ; /* read mode */ PBDR |= (1 << LCD_RW); } void lcd_dat(UBYTE x) { lcd_primitive(ON,x) ; } void lcd_cmd(UBYTE x) { lcd_primitive(OFF,x) ; } void lcd_select_plane(UBYTE x) { /* CS1 = 0 , CS2 = 0 */ PBDR &= ~(1 << LCD_CS1); PBDR &= ~(1 << LCD_CS2); /* */ if ( x == SEL_LEFT ) { PBDR |= (1 << LCD_CS1); } if ( x == SEL_RIGHT ) { PBDR |= (1 << LCD_CS2); } } void lcd_display(UBYTE x) { lcd_cmd(0x3E | x); } void lcd_set_address(UBYTE x) { /* check */ if ( x >= XMAX ) return ; /* send address */ lcd_cmd(0x40 | x); } void lcd_set_page(UBYTE x) { /* check */ if ( x >= YMAX ) return ; /* send address */ lcd_cmd(0xb8 | x); } void lcd_set_start_line(UBYTE x) { /* check */ if ( x >= XMAX ) return ; /* send address */ lcd_cmd(0xC0 | x); } void lcd_locate(UBYTE pgx,UBYTE idx) { lcd_set_page(pgx); lcd_set_address(idx); } void lcd_set_data(UBYTE *ptr,UBYTE sx,UBYTE lx) { UBYTE loop ; UBYTE last ; /* calculate length */ last = lx - sx + 1 ; /* store */ for ( loop = 0 ; loop < last ; loop++ ) { lcd_dat( *(ptr+loop) ); } } void lcd_rst(void) { /* nRESET : L */ PBDR &= ~(1 << LCD_RST) ; /* wait 1ms */ delay_ms(1); /* nRESET : H */ PBDR |= (1 << LCD_RST) ; } void init_lcd(void) { /* reset */ lcd_rst() ; /* delay 30 ms */ delay_ms( 30 ) ; /* select first line */ lcd_cmd(0xC0); /* display on */ lcd_cmd(0x3f); }  回路図は、以下。
目次

inserted by FC2 system