目次
前
次
LCDモニタ
知り合いがジャンク箱にある部品類を廃棄すると
いうので、NokiaのLCDを貰ってきました。
電源電圧3.3Vで、インタフェースがSPIです。
内蔵メモリがフレームバッファになっていて
84ドットx48ラインです。
この類のLCDでは、標準タイプなのか、フレーム
バッファは次のように画面に対応します。
横をY方向とし、ライン方向はページという
単位で扱っています。48ラインは6ページ
分に相当します。
マイクロコンピュータ内蔵SRAMにフレームバッファを
確保します。そのフレームバッファにビットパターン
をライト後、表示させてみます。
内蔵SRAMで構成したフレームバッファへのデータライト
は1バイト単位として、次のようにラスターで扱います。
LCDに表示する場合、並べ替えてから、データ転送
する仕様とします。
一息で作れないので、パーソナルコンピュータから
マイクロコンピュータにコマンドを与え、内蔵SRAM
の中に用意した配列に、画像データを転送する部分
から作成していきます。
LCDは、3.3V動作なので、電源電圧3.3Vで直結できる
マイコンとしてAnalogDevicesのADcU7026を使います。
端末ソフトでマイコンとやりとりするため
コマンドを決めます。
- ? help
- W set data
- F show frame buffer context
- C clear frame buffer context
- D display on LCD
マイコン内蔵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の表示については、内蔵ドライバの
データシートを参照しました。
データシートからレジスタの機能と
書込みシーケンスを理解しておきます。
- チップセレクトイネーブル
- コマンドでファンクション設定(0x21)
- コマンドでファンクション設定(0x90)
- コマンドでファンクション設定(0x10) 表示の初期設定
- コマンドでファンクション設定(0x0C) 表示制御
- SRAMのアドレス設定
- データ転送
- チップセレクトディセーブル
シーケンスを眺めると、コマンドとデータの
書き込みが必要です。両者の区別は、ピンに
与える論理値で選らぶため、ピンアサインを
定義します。
#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);
}
回路図は、以下。
目次
前
次