/******************************************************************************** * 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 * * <更新履歴:N.Ishii> * 220813 * 7セグLED風表示の実験をする為に、以下の3つの関数を追加しました。(原典:京谷氏) * LCD_PaintBox(); // 指定色でBOXを塗りつぶす関数 * Draw7seg_(); // 1桁の7segパターンを描画 * Draw7seg(); // 最大5桁の7segパターンを描画(ゼロブランク対応) * ライブラリ名を更新しました。S6D0151→ S6D0151_v2 ***********************************************************************************/ #include "p24FJ64GA002.h" #include "S6D0151_v2.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; } } } /****************************************************************** * 指定色でBOXを塗りつぶす関数 * 上から下の垂直線を描画終了座標(右下)まで描画して塗りつぶす。 * * 引数: * (X1,Y1)→ 描画開始座標(左上) * (X2,Y2)→ 描画終了座標(右下) * color→  塗りつぶし色 ******************************************************************/ void LCD_PaintBox(int X1, int Y1, int X2, int Y2, unsigned int color) { int tx,ty; for( ty = Y1 ; ty <= Y2 ; ty++ ){ for( tx = X1 ; tx <= X2 ; tx++){ lcd_Pixel(tx, ty, color); } } } /********************************************************************* * 1桁の7segパターンを描画する関数 * * 引数: * (X,Y)→ 原点のX,Y座標(7segの左上座標) * cPat→ 表示パターン * bit0:a * bit1:b * bit2:c * bit3:d * bit4:e * bit5:f * bit6:g * col→ 表示色 * coloff→ 消灯色 **********************************************************************/ void Draw7seg_(int X, int Y, unsigned char cPat, unsigned int col, unsigned int coloff) { unsigned int color; //// デコードパターン(引数:cPat)の各ビットを調べ、 //// '0'だったら、offし、'1'だったら、ペイントbox+両サイドの頂点(2か所)描画して7セグらしく描画 /* a */ if(cPat & 0x01) color = col; else color = coloff; LCD_PaintBox(X+4, Y, X+11, Y+2, color); lcd_Pixel(X+ 3, Y+1, color); lcd_Pixel(X+12, Y+1, color); /* b */ if(cPat & 0x02) color = col; else color = coloff; LCD_PaintBox(X+12, Y+4, X+14, Y+9, color); lcd_Pixel(X+13, Y+ 3, color); lcd_Pixel(X+13, Y+10, color); /* c */ if(cPat & 0x04) color = col; else color = coloff; LCD_PaintBox(X+11, Y+13, X+13, Y+18, color); lcd_Pixel(X+12, Y+12, color); lcd_Pixel(X+12, Y+19, color); /* d */ if(cPat & 0x08) color = col; else color = coloff; LCD_PaintBox(X+3, Y+20, X+10, Y+22, color); lcd_Pixel(X+ 2, Y+21, color); lcd_Pixel(X+11, Y+21, color); /* e */ if(cPat & 0x10) color = col; else color = coloff; LCD_PaintBox(X+0, Y+13, X+2, Y+18, color); lcd_Pixel(X+1, Y+12, color); lcd_Pixel(X+1, Y+19, color); /* f */ if(cPat & 0x20) color = col; else color = coloff; LCD_PaintBox(X+1, Y+4, X+3, Y+9, color); lcd_Pixel(X+2, Y+ 3, color); lcd_Pixel(X+2, Y+10, color); /* g */ if(cPat & 0x40) color = col; else color = coloff; LCD_PaintBox(X+4, Y+10, X+10, Y+12, color); lcd_Pixel(X+ 3, Y+11, color); lcd_Pixel(X+11, Y+11, color); } /************************************************************************************ * 最大5桁の7segパターンを描画する関数 * * 必ず数値桁数以上の最大5桁の表示桁数を指定すること。 * ゼロブランク対応 * * 引数: * (X,Y)→ 原点のX,Y座標(7segの左上座標) * Value→ 7セグに表示したい数値を、10進で指定 * cColum→ 表示桁数 最大5桁まで * col→  表示色 * coloff→ 非表示色:通常は背景色と同じ黒を指定 ***************************************************************************************/ const unsigned char font7seg[16] = { 0x3f, // 0 0x06, // 1 0x5b, // 2 0x4f, // 3 0x66, // 4 0x6d, // 5 0x7d, // 6 0x07, // 7 0x7f, // 8 0x6f, // 9 0x77, // A 0x7c, // b 0x39, // c 0x5e, // d 0x79, // E 0x71 // F }; #define PITCH7SEG 18 void Draw7seg(int X, int Y, unsigned int Value, unsigned char cColum, unsigned int col, unsigned int coloff) { unsigned int DispStartX; unsigned int CheckData, Data; char digit= 0; unsigned int col_5; // 5桁目の表示色 unsigned int col_4; // 4桁目の表示色 unsigned int col_3; // 3桁目の表示色 unsigned int col_2; // 2桁目の表示色 /// 最初に数値の桁数をチェック(数値=0の場合は、digit=0になる) CheckData = Value; while(CheckData != 0) { CheckData = CheckData/10; ++ digit; } /// あらかじめゼロブランクする桁を判断して、表示色を非表示色にするか、表示色にするか決める。 /// cColum == digit→ ブランクしない→ col_5,4,3,2= col /// cColum > digitの時だけ、ブランク if(cColum != digit) { if(cColum == 5) { if(digit == 4) { col_5= coloff; // _**** col_4= col_3= col_2= col; } if(digit == 3) { col_5= col_4= coloff; // __*** col_3= col_2= col; } if(digit == 2) { col_5= col_4= col_3= coloff; // ___** col_2= col; } if(digit <= 1) col_5= col_4= col_3= col_2= coloff; // ____*(____0も含む) } if(cColum == 4) { if(digit == 3) { col_4= coloff; // _*** col_3= col_2= col; } if(digit == 2) { col_4= col_3= coloff; // __** col_2= col; } if(digit <= 1) col_4= col_3= col_2= coloff; // ___*(___0も含む) } if(cColum == 3) { if(digit == 2) { col_3= coloff; // _** col_2= col; } if(digit <= 1) col_3= col_2= coloff; // __*(__0も含む) } if(cColum == 2) { if(digit <= 1) col_2= coloff; // _*(_0も含む) } } else col_5= col_4= col_3= col_2= col; ///// 7セグに表示したい数値に対応した、7セグデコードを行い、下請け関数の引数:cPatに渡す DispStartX = X - (5-cColum)*PITCH7SEG; // 書き始めの位置を計算 /// 5桁目が有る時は、数値を計算し表示 Data = Value; if(cColum >= 5) Draw7seg_(DispStartX, Y, font7seg[Data/10000], col_5, coloff); /// 4桁目が有る時は、数値を計算し表示 Data = Data%10000; DispStartX+=PITCH7SEG; if(cColum >= 4) Draw7seg_(DispStartX, Y, font7seg[Data/1000], col_4, coloff); /// 3桁目が有る時は、数値を計算し表示 Data = Data%1000; DispStartX+=PITCH7SEG; if(cColum >= 3) Draw7seg_(DispStartX, Y, font7seg[Data/100], col_3, coloff); /// 2桁目が有る時は、数値を計算し表示 Data = Data%100; DispStartX+=PITCH7SEG; if(cColum >= 2) Draw7seg_(DispStartX, Y, font7seg[Data/10], col_2, coloff); /// 1桁目は必ず数値を計算し表示 Data = Data%10; DispStartX+=PITCH7SEG; Draw7seg_(DispStartX,Y, font7seg[Data], col, coloff); } //////// 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); }