/******************************************************** * SPI制御カラーグラフィックLCD用ライブラリ * 横表示で設定 * LCD_Initialize(); // 初期化 * Clear_LCD(); // 全画面消去 * SET_LCD_Cursor_Position(); // 座標指定 * lcd_Pixel(); // 1ドット表示 * lcd_Line(); // 直線描画 * lcd_Circle(); // 円描画 * lcd_Char_8x8(); // 8x8ANK文字表示 * lcd_Char_12x12(); // 12x12ANK文字表示 * lcd_Str_8x8(); // 8x8ANK文字列表示 * lcd_Str_12x12(); // 12x12ANK文字列表示 * * 液晶:1.77inch 128 x 160dot color LCD「TFT2P2037-E * コントローラIC:S6D0151 * * 2022/8/6 N.Ishii *********************************************************/ #include "p24FJ64GA002.h" #include "S6D0151.h" #include "ASCII_font.h" // ASCII 8x8ドット #include "ASCII12dot.h" // ASCII 12x12dot /******************************************************* * スタートバイト送信関数: 転送速度≒ 4MHz(250nS) * スタートバイト:ID+RS+RW * コマンド書込み時:id= 0x70・データ書込み時:id= 0x72 ********************************************************/ void SendStartByte(unsigned char id) { char Loop; SPI_CS = 0; for(Loop=0; Loop<8; Loop++){ SPI_DATA = 0; if ((id & 0x80) != 0){ SPI_DATA = 1; } SPI_CLK = 1; id <<= 1; SPI_CLK = 0; } } /******************************************************* * レジスタ番号送信関数 ********************************************************/ void SendRegNo(unsigned int reg_no) { char Loop; for(Loop=0; Loop<16; Loop++){ SPI_DATA = 0; if ((reg_no & 0x8000) != 0){ SPI_DATA = 1; } SPI_CLK = 1; reg_no <<= 1; SPI_CLK = 0; } SPI_CS = 1; } /******************************************************* * データ送信関数 ********************************************************/ void SendData(unsigned int data) { char Loop; for(Loop=0; Loop<16; Loop++){ SPI_DATA = 0; if ((data & 0x8000) != 0){ SPI_DATA = 1; } SPI_CLK = 1; data <<= 1; SPI_CLK = 0; } SPI_CS = 1; } /******************************************************* * SPIによるレジスタへの書込みデータ送信関数 * SPI転送速度:500k(2u) ********************************************************/ void S6D0151_SPI_write(unsigned int reg_no, unsigned int data) { SendStartByte(0x70); // スタートバイト(ID+RS+RW)送信:コマンド書込み SendRegNo(reg_no); // レジスタ番号送信 SendStartByte(0x72); // スタートバイト(ID+RS+RW)送信:データ書込み SendData(data); // レジスタに書込むデータ送信 } /**************************** * LCD初期化関数 *****************************/ void LCD_Initialize() { /// RESET負パルス出力 SPI_RST= 0; delay_ms(34); SPI_RST= 1; delay_ms(18); S6D0151_SPI_write(0x0007, 0x0020); // DISPLAY CONTOROL REG. NORMAL DRAIVE S6D0151_SPI_write(0x00B6, 0x013F); // Module Vendor POWER ON SEQUENCE CONTOROL OF SETUP CIRCUIT REG. S6D0151_SPI_write(0x00B4, 0x0010); // MTP CONTROL S6D0151_SPI_write(0x0012, 0x00B2); // POWER CONTROL 2 S6D0151_SPI_write(0x0013, 0x080E); // POWER CONTROL 3 S6D0151_SPI_write(0x0014, 0x5BCA); // POWER CONTROL 4 S6D0151_SPI_write(0x0061, 0x0018); // OSCILLATOR CONTROL S6D0151_SPI_write(0x0010, 0x190C); // POWER CONTROL 1 delay_ms(84); S6D0151_SPI_write(0x0013, 0x081E); // POWER CONTROL 3 delay_ms(34); S6D0151_SPI_write(0x0002, 0x0100); // LCD INVERSION CONTROL /// In case of Horizontal S6D0151_SPI_write(0x0001, 0x0114); // DRIVER OUTPUT CONTROL S6D0151_SPI_write(0x0003, 0x0028); // ENTRY MODE S6D0151_SPI_write(0x0008, 0x0202); // BLANK PERIOD CONTROL 1 S6D0151_SPI_write(0x000B, 0x0000); // FRAME CYCLE CONTROL S6D0151_SPI_write(0x000C, 0x0000); // EXTERNAL DISPLAY INTERFACE CONTROL S6D0151_SPI_write(0x0061, 0x0018); // OSCILLATOR CONTROL S6D0151_SPI_write(0x0069, 0x0000); // DC/DC CONVERT LOW POWER MODE SETTING S6D0151_SPI_write(0x0070, 0x0000); // SOURCE DRIVER PRE-DRIVING PERIOD SETTING S6D0151_SPI_write(0x0071, 0x0000); // GATE OUTPUT PERIOD CONTROL S6D0151_SPI_write(0x0011, 0x0000); // GAMMA CONTROL 1 S6D0151_SPI_write(0x0030, 0x0303); // GAMMA CONTROL 2 (R30h to R37h) S6D0151_SPI_write(0x0031, 0x0303); // GAMMA CONTROL 2 (R30h to R37h) S6D0151_SPI_write(0x0032, 0x0303); // GAMMA CONTROL 2 (R30h to R37h) S6D0151_SPI_write(0x0033, 0x0000); // GAMMA CONTROL 2 (R30h to R37h) S6D0151_SPI_write(0x0034, 0x0404); // GAMMA CONTROL 2 (R30h to R37h) S6D0151_SPI_write(0x0035, 0x0404); // GAMMA CONTROL 2 (R30h to R37h) S6D0151_SPI_write(0x0036, 0x0404); // GAMMA CONTROL 2 (R30h to R37h) S6D0151_SPI_write(0x0037, 0x0000); // GAMMA CONTROL 2 (R30h to R37h) S6D0151_SPI_write(0x0038, 0x0707); // GAMMA CONTROL 2 S6D0151_SPI_write(0x0040, 0x0000); // GATE SCAN POSITION S6D0151_SPI_write(0x0042, 0x9F00); // 1st SCREEN DRIVING POSITION S6D0151_SPI_write(0x0043, 0x0000); // 2nd SCREEN DRIVING POSITION S6D0151_SPI_write(0x0044, 0x7F00); // HORIZONTAL RAM ADDRESS POSITION S6D0151_SPI_write(0x0045, 0x9F00); // VERTICAL RAM ADDRESS POSITION S6D0151_SPI_write(0x0069, 0x0000); // DC/DC CONVERT LOW POWER MODE SETTING S6D0151_SPI_write(0x0070, 0x0000); // SOURCE DRIVER PRE-DRIVING PERIOD SETTING S6D0151_SPI_write(0x0071, 0x0000); // GATE OUTPUT PERIOD CONTROL S6D0151_SPI_write(0x0073, 0x0000); // TEST_KEY S6D0151_SPI_write(0x00B3, 0x0000); // PUMPING CLOCK SOURCE SELECTION S6D0151_SPI_write(0x00BD, 0x0000); // MTP DATA READ S6D0151_SPI_write(0x00BE, 0x0000); // INTERFACE MODE SELECTION S6D0151_SPI_write(0x0021, 0x0000); // GRAM ADDRESS SET delay_ms(34); S6D0151_SPI_write(0x0007, 0x0020); // DISPLAY CONTROL delay_ms(34); S6D0151_SPI_write(0x0007, 0x0021); // DISPLAY CONTROL S6D0151_SPI_write(0x0007, 0x0027); // DISPLAY CONTROL delay_ms(66); S6D0151_SPI_write(0x0007, 0x0037); // DISPLAY CONTROL } /*************************** * 画面消去関数 * 消去用色指定あり ****************************/ void Clear_LCD(unsigned int color) { int Loop; SET_LCD_Cursor_Position(0, 0); // 原点セット SendStartByte(0x70); // スタートバイト(ID+RS+RW)送信:コマンド書込み SendRegNo(0x0022); // レジスタ番号送信:Write data to GRAM REG. //// GRAM全エリア(20480ワード= 128 x 160)を、0x0000で埋める for(Loop=0; Loop<20480; Loop++){ SendStartByte(0x72); // スタートバイト(ID+RS+RW)送信:データ書込み SendData(color); // レジスタに書込むデータ送信:GRAMクリアデータ } } /**************************** * 座標指定関数 *****************************/ void SET_LCD_Cursor_Position(unsigned int Xpos, unsigned int Ypos) { unsigned int data= ((Xpos << 8) | Ypos); // 座標シリアルデータ生成:xxyyh SendStartByte(0x70); // スタートバイト(ID+RS+RW)送信:コマンド書込み SendRegNo(0x0021); // レジスタ番号送信:RAM ADDRESS REG. SendStartByte(0x72); // スタートバイト(ID+RS+RW)送信:データ書込み SendData(data); // レジスタに書込むデータ送信:座標シリアルデータ } /*********************************** * 1ピクセル表示関数 * 座標は(0,0)-(159,127) ***********************************/ void lcd_Pixel(unsigned int Xpos, unsigned int Ypos, unsigned int color) { SET_LCD_Cursor_Position(Xpos, Ypos); // ドット描画座標セット if((Xpos0) ? (a) : -(a)) void lcd_Line(int x0, int y0, int x1, int y1, unsigned int color) { int steep, t; int deltax, deltay, error; int x, y; int ystep; y0=ENDROW-y0 -1; // Y座標反転 y1=ENDROW-y1 -1; /// 差分の大きいほうを求める steep = (abs(y1 - y0) > abs(x1 - x0)); /// x、yの入れ替え if(steep){ t = x0; x0 = y0; y0 = t; t = x1; x1 = y1; y1 = t; } if(x0 > x1) { t = x0; x0 = x1; x1 = t; t = y0; y0 = y1; y1 = t; } deltax = x1 - x0; // 傾き計算 deltay = abs(y1 - y0); error = 0; y = y0; /// 傾きでステップの正負を切り替え if(y0 < y1) ystep = 1; else ystep = -1; /// 直線を点で描画 for(x=x0; x<=x1; x++) { if(steep) lcd_Pixel(y,x,color); else lcd_Pixel(x,y,color); error += deltay; if((error << 1) >= deltax) { y += ystep; error -= deltax; } } } /************************************* * 円を描く関数 * 中心点と半径を指定 * (Fussyさんのアルゴリズムを使用) **************************************/ void lcd_Circle(int x0, int y0, int r, unsigned int color) { int x = r; int y = 0; int F = -2 * r + 3; while(x >= y){ lcd_Pixel(x0+x, y0+y, color); lcd_Pixel(x0-x, y0+y, color); lcd_Pixel(x0+x, y0-y, color); lcd_Pixel(x0-x, y0-y, color); lcd_Pixel(x0+y, y0+x, color); lcd_Pixel(x0-y, y0+x, color); lcd_Pixel(x0+y, y0-x, color); lcd_Pixel(x0-y, y0-x, color); if(F >= 0){ x--; F -= 4 * x; } y++; F += 4 * y + 2; } } /***************************************** * ANK文字表示関数 8x8ドット * 160/8=20文字/行 128/8=16行 * (0, 0) - (19, 15)の範囲 ******************************************/ void lcd_Char_8x8(char colum, char line, unsigned char letter, unsigned int color1, unsigned int color2){ unsigned char j, i, Mask; if((colum < 20) && (line < 16)){ // 範囲チェック for(j=0; j<5; j++){ // 横5ドット Mask = 0x80; // 上位ビットから表示 for(i=0; i<8; i++){ // 縦1ライン分表示 if((chrom[letter-0x20][j] & Mask) != 0) lcd_Pixel(colum*8+j+3, (line+1)*8-i, color1); else lcd_Pixel( colum*8+j+3, (line+1)*8-i, color2); //背景色 Mask = Mask >> 1; } } /// フォントは、5dot幅、残りの、3dot*8dotスペースを背景色で塗りつぶす。 for(j=5; j<8; j++){ for(i=0; i<8; i++){ lcd_Pixel(colum*8+j+3, (line+1)*8-i, color2); //背景色 } } } } /***************************************** * ANK文字表示関数 12x12ドット * 160/12= 13文字/行 128/14= 9文字/列 * (0, 0) - (12, 8)の範囲 ******************************************/ void lcd_Char_12x12(char colum, char line, unsigned char letter, unsigned int color1, unsigned int color2){ unsigned char j, i, Mask; if((colum < XChar_12x12) && (line < YLine_12x12)){ // 範囲チェック // ANK表示出力 3バイトの2ラインずつを6回繰り返す for(j=0; j<6; j++){ // 8ドット連続部の表示 Mask = 0x80; for(i=0; i<8; i++){ // 1ライン目前半8ドット表示 if((ANKFont[letter][j*3] & Mask) != 0) lcd_Pixel(colum*12+i+4, line*14+j*2+2, color1); else lcd_Pixel(colum*12+i+4, line*14+j*2+2, color2); //背景色 // 2ライン目後半8ドット表示 if((ANKFont[letter][j*3+2] & Mask) != 0) lcd_Pixel(colum*12+i+8, line*14+j*2+3, color1); else lcd_Pixel(colum*12+i+8, line*14+j*2+3, color2); //背景色 Mask = Mask >> 1; } // 分割部4ドットずつ表示 Mask = 0x80; // 1ライン目後半4ドット表示 for(i=0; i<4; i++){ if((ANKFont[letter][j*3+1] & Mask) != 0) lcd_Pixel(colum*12+i+12, line*14+j*2+2, color1); else lcd_Pixel(colum*12+i+12, line*14+j*2+2, color2); //背景色 Mask = Mask >> 1; } // 2ライン目前半4ドット表示 for(i=4; i<8; i++){ if((ANKFont[letter][j*3+1] & Mask) != 0) lcd_Pixel(colum*12+i, line*14+j*2+3, color1); else lcd_Pixel(colum*12+i, line*14+j*2+3, color2); //背景色 Mask = Mask >> 1; } } } } /**************************************** * 文字列描画関数_1 * 8x8dot Font用:20文字x16行で指定 *****************************************/ void lcd_Str_8x8(char colum, char line, char *s, unsigned int color1, unsigned int color2) { while (*s){ lcd_Char_8x8(colum++, line, *s++, color1, color2); if(colum >= XChar_8x8){ line++; colum = 0; if(line >= YLine_8x8) line = 0; } } } /**************************************** * 文字列描画関数_2 * 12x12dot Font用:13文字/行x9列で指定 *****************************************/ void lcd_Str_12x12(char colum, char line, char *s, unsigned int color1, unsigned int color2) { while (*s){ lcd_Char_12x12(colum++, line, *s++, color1, color2); if(colum >= XChar_12x12){ line++; colum = 0; if(line >= YLine_12x12) line = 0; } } } //////// usec単位ディレイ関数 void delay_us(int usec){ usec = (int)(CLOCK*usec)/ 10; while(usec) { asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); usec--; } } /////// msec単位ディレイ関数 void delay_ms(int msec){ int i; for(i=0; i< msec; i++) delay_us(1000); }