/************************************************************************************************** * Adafruit_1.5INCH_RGBOLED駆動用ライブラリーファイル * OLEDパネル:UG2828GDEDF11+キャリーボード * 制御IC:SSD1351 * * 原典:Adafruit HP/「mgo-tec電子工作」さん * * 2018.1.27 N.Ishii **************************************************************************************************/ #include // PIC32 peripheral library #include "SSD1351_OLEDlibPIC32MX.h" #include "ASCII_font.h" // ANK文字 8x8ドット #include "KanjiFont12b.h" // 漢字文字フォント 12x12ドット #include "imagedata.h" // 狛犬 //#include "imagedata_2.h" // 百合の花 /**************************************************************************** * Data/Command を指定して、OLEDに1バイトを送信 *---------------------------------------------------------------------------- * 入力: unsigned char d,char dc * 出力: 無し *---------------------------------------------------------------------------- * 備考: dc = 0 : Command, dc = 1 : Data *****************************************************************************/ void SPI_tx_byte(unsigned char d, char dc) { char Loop; if (dc) { SPI_DC = 1; } else { SPI_DC = 0; } SPI_OLED_CS = 0; // DCを確定してから、CSを落とすように修正した。180123 /// CLKを立下げてから、データ更新に修正した。 180123 SPI_CLK = 1; for (Loop=0;Loop<8;Loop++){ SPI_CLK = 0; SPI_OLED_DATA = 0; if ((d & (unsigned char)0x80) != 0){ SPI_OLED_DATA = 1; } // Nop(); // セットアップ時間を稼ぐ時は、ここに挿入だが、無くても動いた。(スペック=50nS) SPI_CLK = 1; // このタイミングで書込む。 d <<= 1; // 次のデータ・ビットのレベル判断のため、1ビット左へシフトして入れ替える。 // Nop(); // ホールド時間を稼ぐ時は、ここに挿入だが、無くても動いた。(スペック=50nS) } SPI_OLED_CS = 1; } /**************************************************************************** * OLEDモジュール制御IC SSD1351を 初期設定をする *****************************************************************************/ void OLEDInit(void) { //// OLED初期設定 delay_ms(2); // スペック=VDD_IO立上げから、1mSmin待つ SPI_OLED_CS = 0; // OLED チップイネーブル初期レベル(SPI_SD_CSも、別に存在) SPI_RES = 1; // OLED リセットレベル初期化 delay_ms(500); /// OLEDリセット・負パルス出力 SPI_RES = 0; delay_ms(500); SPI_RES = 1; // ここで既に、VCC ONしている。 delay_ms(500); // 500mS後に、OLED初期化開始 /// コマンド・データセット→  ここで既に、SEG/COM電源は、ONしている。 SPI_tx_byte(0xFD, 0); // Set Command Lock SPI_tx_byte(0x12, 1); // Unlock OLED driver IC MCU interface from entering command SPI_tx_byte(0xFD, 0); // Set Command Lock SPI_tx_byte(0xB1, 1); // Command A2,B1,B3,BB,BE,C1 accessible if in unlock state SPI_tx_byte(0xAE, 0); // Sleep mode On (Display OFF) SPI_tx_byte(0xB3, 0); // Front Clock Divider SPI_tx_byte(0xF1, 0); // 7:4 = Oscillator Frequency, 3:0 = CLK Div Ratio (A[3:0]+1 = 1..16) SPI_tx_byte(0xCA, 0); // Set MUX Ratio SPI_tx_byte(127, 1); SPI_tx_byte(0xA0, 0); // Set Re-map SPI_tx_byte(0b01110100, 1); // A[7:6] Set Color Depth= 65k color(16bitカラー) SPI_tx_byte(0x15, 0); // Set Column SPI_tx_byte(0, 1); // start SPI_tx_byte(127, 1); // end SPI_tx_byte(0x75, 0); // Set Row SPI_tx_byte(0, 1); // start SPI_tx_byte(127, 1); // end SPI_tx_byte(0xA1, 0); // Set Display Start Line SPI_tx_byte(0, 1); SPI_tx_byte(0xA2, 0); // Set Display Offset SPI_tx_byte(0, 1); SPI_tx_byte(0xB5, 0); // Set GPIO SPI_tx_byte(0, 1); SPI_tx_byte(0xAB, 0); // Function Selection SPI_tx_byte(0x01, 1); // Enable internal Vdd /8-bit parallel(コントローラ内部のMCUのバスを8bit設定) /// データシートの、ダブル・バイト・コマンドという表現は、コマンド+データで、1セットと理解し、修正(Adafruitコードは誤記?) SPI_tx_byte(0xB1, 0); // Set Reset(Phase 1) /Pre-charge(Phase 2) SPI_tx_byte(0b01110100, 1); // 9 DCLKs / 7 DCLKs /// データシートの、ダブル・バイト・コマンドという表現は、コマンド+データで、1セットと理解し、修正(Adafruitコードは誤記?) SPI_tx_byte(0xBE, 0); // Set VCOMH Voltage SPI_tx_byte(0x05, 1); // 0.82 x VCC [reset] SPI_tx_byte(0xA6, 0); // Reset to normal display SPI_tx_byte(0xC1, 0); // Set Contrast SPI_tx_byte(0xC8, 1); // Red contrast (reset=0x8A) SPI_tx_byte(0x80, 1); // Green contrast (reset=0x51) SPI_tx_byte(0xC8, 1); // Blue contrast (reset=0x8A) SPI_tx_byte(0xC7, 0); // Master Contrast Current Control SPI_tx_byte(0x0F, 1); // 0-15 SPI_tx_byte(0xB4, 0); // Set Segment Low Voltage(VSL) SPI_tx_byte(0xA0, 1); SPI_tx_byte(0xB5, 1); SPI_tx_byte(0x55, 1); SPI_tx_byte(0xB6, 0); // Set Second Precharge Period SPI_tx_byte(0x01, 1); // 1 DCLKS SPI_tx_byte(0x9E, 0); // Scroll Stop Moving SPI_tx_byte(0xAF, 0); // Sleep mode On (Display ON) } /*************************** * 画面消去関数 * 消去用色指定あり ****************************/ void OLED_Clear(unsigned short color){ short i; /// 描画エリア設定 SPI_tx_byte(0x15, 0); // Set Column SPI_tx_byte(0x00, 1); // start SPI_tx_byte(ENDCOL-1, 1); // end SPI_tx_byte(0x75, 0); // Set Row SPI_tx_byte(0x00, 1); // start SPI_tx_byte(ENDROW-1, 1); // end /// 全エリアを指定色で埋める。 SPI_tx_byte(0x5C, 0); // Write RAM // 16bit color mode for(i=0; i<(ENDCOL)*(ENDROW); i++){ SPI_tx_byte((unsigned char)(color >> 8), 1); SPI_tx_byte((unsigned char)color, 1); } } /*********************************** * 1ピクセル表示関数 * 座標は(0,0)-(127,127) ***********************************/ void OLED_Pixel(short Xpos, short Ypos, unsigned short color){ /* if raw>128 or colum >128 then do nothing */ if((Xpos<=ENDCOL-1) && (Ypos<=ENDROW-1)){ SPI_tx_byte(0x15, 0); // Set Column SPI_tx_byte(Xpos, 1); // start SPI_tx_byte(Xpos, 1); // end SPI_tx_byte(0x75, 0); // Set Row SPI_tx_byte(Ypos, 1); // start SPI_tx_byte(Ypos, 1); // end SPI_tx_byte(0x5C, 0); // Write RAM SPI_tx_byte((unsigned char)(color >> 8), 1); SPI_tx_byte((unsigned char)color, 1); } } /*************************** * 直線描画関数 ***************************/ #define abs(a) (((a)>0) ? (a) : -(a)) void OLED_Line(short x0, short y0, short x1, short y1, unsigned short color) { short steep, t; short deltax, deltay, error; short x, y; short 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) OLED_Pixel(y,x,color); else OLED_Pixel(x,y,color); error += deltay; if((error << 1) >= deltax) { y += ystep; error -= deltax; } } } /************************************* * 円を描く関数 * 中心点と半径を指定 * (Fussyさんのアルゴリズムを使用) **************************************/ void OLED_Circle(int x0, int y0, int r, unsigned short color){ int x = r; int y = 0; int F = -2 * r + 3; while(x >= y){ OLED_Pixel(x0+x, y0+y, color); OLED_Pixel(x0-x, y0+y, color); OLED_Pixel(x0+x, y0-y, color); OLED_Pixel(x0-x, y0-y, color); OLED_Pixel(x0+y, y0+x, color); OLED_Pixel(x0-y, y0+x, color); OLED_Pixel(x0+y, y0-x, color); OLED_Pixel(x0-y, y0-x, color); if(F >= 0){ x--; F -= 4 * x; } y++; F += 4 * y + 2; } } /******************************************************** * 16bitBMPカラーイメージ表示関数 * 128x128dot対応 *********************************************************/ void OLED_Image(void){ short Xpos, Ypos; short ptr; // PIC32MXの場合、int= 32bit/short= 16bit /// BMPフォーマットのデータは、左下から右上に向かって配列されているので /// この順で描画すると、上下逆様の画像表示になってしまう。 /// 右上の画素(ptr=(32906/2)-1)=16452, Xpos= 127, Ypos= 0)から下に向かって描画する必要がある。 ptr= 16452; for(Ypos=0; Ypos < ENDROW; Ypos++){ for(Xpos=ENDCOL-1; Xpos > -1; Xpos--){ OLED_Pixel(Xpos, Ypos, ImageData[ptr--]); } } } /***************************************** * ANK文字表示関数 8x8ドット * 128/8=16文字/行 128/8=16行 * (0, 0) - (15, 15)の範囲 ******************************************/ void OLED_Char(char colum, char line, unsigned char letter, unsigned short color1, unsigned short color2){ unsigned char j, i, Mask; if((colum < 16) && (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) OLED_Pixel(colum*8+j+3, (line+1)*8-i, color1); else OLED_Pixel( colum*8+j+3, (line+1)*8-i, color2); //背景色 Mask = Mask >> 1; } } /// フォントは、5bot幅、残りの、3dot*8dotスペースを背景色で塗りつぶす。 for(j=5; j<8; j++){ for(i=0; i<8; i++){ OLED_Pixel(colum*8+j+3, (line+1)*8-i, color2); //背景色 } } } } /******************************************* * 文字列描画関数 * 8x8dot Fontの場合:16文字x16行で指定 ********************************************/ void OLED_Str(char colum, char line, char *s, unsigned short color1, unsigned short color2){ while (*s){ OLED_Char(colum++, line, *s++, color1, color2); if(colum >= XChar){ line++; colum = 0; if(line >= YLine) line = 0; } } } /************************************************** * 漢字文字表示関数 *  フォントは12x12 * 漢字コードの範囲をチェックし異常なら-1を返す *  戻り値:0= 漢字フォント 1= 半角フォント ***************************************************/ short OLED_Kanji(char line, char colum, unsigned char *ptr, unsigned short color1, unsigned short color2) { short low, high; high = *ptr++; low = *ptr; // 漢字範囲チェックと表示 if(((high > 0x80) && (high < 0xA0)) || ((high > 0xDF) && (high < 0xEB))) { if((low > 0x3F) && (low < 0xFD) && (low != 0x7F)) { KanjiCode(line, colum, high, low, color1, color2); // 漢字表示制御 return(0); // 正常戻り } else return(-1); // エラー戻り } else return(-1); } /************************************* * 漢字表示 コード指定で表示 *  2バイトコードで指定 * 表示位置は9文字/9行で指定 **************************************/ void KanjiCode(char line, char colum, short upcode, short lowcode, unsigned short color1, unsigned short color2) { short upper, lower, i, j, pos; unsigned char Mask; if((line < 9) && (colum < 9)){ // 画面内か? line 10→9修正 180127 // 漢字コードから配列インデックス計算 upper = (upcode -0x81)*188; // xxFC-xx40+1-1(7F分) if(lowcode < 0x7F) // コード7Fはスキップ lower = (lowcode - 0x40); else lower = (lowcode - 0x41); // 7Fコードの1文字分を引く // 漢字表示出力 3バイトの2ラインずつを6回繰り返す for(j=0; j<6; j++){ // 8ドット連続部の表示 Mask = 0x80; for(i=0; i<8; i++){ // 1ライン目前半8ドット表示 if((KanjiFont12b[upper+lower][j*3] & Mask) != 0) OLED_Pixel(colum*13+i+3, line*13+j*2, color1); else OLED_Pixel(colum*13+i+3, line*13+j*2, color2); //背景色 // 2ライン目後半8ドット表示 if((KanjiFont12b[upper+lower][j*3+2] & Mask) != 0) OLED_Pixel(colum*13+i+7, line*13+j*2+1, color1); else OLED_Pixel(colum*13+i+7, line*13+j*2+1, color2); //背景色 Mask = Mask >> 1; } // 分割部4ドットずつ表示 Mask = 0x80; // 1ライン目後半4ドット表示 for(i=0; i<4; i++){ if((KanjiFont12b[upper+lower][j*3+1] & Mask) != 0) OLED_Pixel(colum*13+i+11, line*13+j*2, color1); else OLED_Pixel(colum*13+i+11, line*13+j*2, color2); //背景色 Mask = Mask >> 1; } // 2ライン目前半4ドット表示 for(i=4; i<8; i++){ if((KanjiFont12b[upper+lower][j*3+1] & Mask) != 0) OLED_Pixel(colum*13+i-1, line*13+j*2+1, color1); else OLED_Pixel(colum*13+i-1, line*13+j*2+1, color2); //背景色 Mask = Mask >> 1; } } } } /********************************************************* * 漢字文字列表示 * 9文字×9行で指定 *********************************************************/ void Kanji_Str(char line, char colum, const short* ptr, unsigned short color1, unsigned short color2) { while(*ptr){ if((line < 9) && (colum < 9)){ // 画面内か? KanjiCode(line, colum++, (short)*ptr++, (short)*ptr++, color1, color2); if(colum > 8){ line++; colum = 0; if(line > 8) line = 0; } } } } /********************************** * ループ遅延関数 msec単位 **********************************/ void delay_us(unsigned short usec) { unsigned short i, Max; Max = usec * Fosc/10; for(i=0; i