Vol.896 14.Jun.2024

フォントとは PICミニBB(6)_グラフィックLCD(VRam利用)

F FONTあれこれ(1)  〜フォントとは?

by fjk

 パソコンを使っているとフォントは身近な存在ですが、その使い方や中身はよく判らずに利用している。そこで、「(コンピュータで使われる)フォントとは?」と調べて見た。
 フォントとは、「本来、『同じサイズで、書体デザインの同じ活字のひとそろい』を意味するが、現在では画面に表示したり、書籍など紙面に印刷したりするためにコンピュータ上で利用できるようにした書体データを指す」(ウィキペディア)とある。

  1. 「書体」
     「書体」には、「セリフ体 (明朝体)」 と「サンセリフ体 (ゴシック体)」が代表的で、「楷書体」や「行書体」など多くの書体がある。セリフ(serif)とは曲げの部分に付けられる突起でヒゲとも呼ばれる。サン(sans)は無いの意味でサンセリフは「ヒゲのない」となる。
     
  2. 「ビットマップフォント」と「アウトラインフォント」
     ビットマップフォントは点(ドット)の集合で表現する方法で、拡大するとギザギザ(ジャギー)が目立つようになるが、BDF(Glyph Bitmap Distribution Format)ファイルと呼ばれ、ドットビットが1対1で対応しているので、CPUの負担が少なく、メモリが少ないコンピュータ向きである。。
     アウトライン(輪郭線)フォントはフォントの輪郭を計算し、曲線を利用して滑らかに描く方法で、拡大してもジャギーが目立たない。しかし、小さい文字にするとはっきりしなくなることがある。主なフォントとして「TrueTypeフォント」(TTF)、「OpenTypeフォント」(OTF)などがある。
     
  3. 「等倍フォント」と「プロポーショナルフォント」
     等倍フォントは全ての文字を同じ幅で表現するフォントで、プロポーショナルフォントは文字毎に最適な幅で表現されるフォント。
     
  4. 「カーニング」
     プロポーショナルフォントで文字間隔を調整する方法で、カーニング有り無しで微妙に調整される。
     
  5. 「ウェイト」
     ウェイトとは、文字の線の太さを指し、ウェイトによって「ライト」「ノーマル」「ボールド」などに分けられる。
     
  6. Widowsでフォントの確認と追加 (ここなど参照)
    @ 「コントロールパネル」
    A 「ディスクトップのカスタマイズ」
    B 「フォントのプレビュー、削除、表示または非表示」で、インストールされている全てのフォントが表示される。
     さらに、フォントを追加するには、
    C 追加したいフォントファイルを選択し、Bで開いているフォントエリアにドラッグ&ドロップ。
     
  7. BDFフォントファイルの構造
     アウトラインフォントはデータサイズが大きく、PIC等の小さなコンピュータシステムでは、メモリが少なくてすむビットマップフォント(BDFファイル)がよく利用される。
     BDFファイルの構造は、

    フォントファイルの構造

    東雲フォント(shnmk16.bdf)の一部

    【参考】
      ・FILEFORMAT
      ・BDFフォント仕様
      ・TTFフォントTrueType
     
     フォントを使用する場合、著作権があるものが多いので、注意が必要です。
     フリーで使えるフォントでは「東雲フォント」が有名で、その他にも、以下のページなどを参照、
     「フリーで使える!ビットマップフォント86種類のまとめ
     
  8. BDFフォントビュアー
     BDFフォントを見つけると、どんな書体か見たくなり、フリーのフォントエディッタ(ビュアー)探して、試してみたが、イマイチだったので、EXCELで簡単なフォントビュアー(fontviewer24.xlsx)を作ってみた。
    fontviewer24.xlsx の使い方】
    @ ビットパターンを見たいBDFファイル(テキストファイルです)を、秀丸エディッタ等で開く。
    A ビットマップデータ(BITMAPの次から下)をコピーし、EXCELのBDF以下にペーストする。
    ・ ドットサイズは24x24ドットまで対応(縦ドットが少ない場合は0で埋める)。
    ・ パターン表示部下部には、gLCD表示用として使えるよう縦方向のデータを16進数で表示している。
     
    ★黄セルに文字を入れ、青セルのコードをbdfファイル内で探し、BITMAPをBDF(黄緑)にコピー

        東雲16ドットフォント(shnmk16.bdf)より


P PICミニBBシリーズ(6)  〜グラフィックLCD(VRam利用)

by fjk

 前報(abc895)ではバイト単位位置にしか文字を表示できなかったが、ドット単位位置で表示できるようにすることにした。ところが、LCDにはバイト単位毎にしか書き込めず、ドットをずらしてデータを書き込むと、以前に書かれたデータを消してしまう。本来はLCD画像データを一度読み込んで、書き込みたいデータと組み合わせて、再度書き込めば良いのだが、AQM1248Aの画像メモリは読み出せない。
 そこで、PICのメモリ上に画像メモリと同じ容量のvRamエリアを準備し、vRam上でデータを作成後、LCDに書き込むことにした。なお、vRamに必要なメモリは以下のように768バイトとなる。
   ( 48 dot÷ 8 bit ) ×128 dot =768 byte
 RAM=1KbyteのPIC16F18325でも良さそうだが、念のためRAM=2KbyteのIC16F18326を使った。また、LCDはバックライト付きに変更した。その他のハード・MCCの設定はabc895と同じ。
 「バックライト付きグラフィックLCD(秋月#110048、500円)」は「ピッチ変換基板(秋月#107006、450円)」と組み合わせ、バックライト用の端子に100Ω(1/6W)の抵抗を介して、3.3Vを供給した


準備したパーツ
(ライト端子は2mm高に切断)

LCDの配線
(Gnd、抵抗はVccに接続)

 新ライブラリは、前報(abc895)のAQM1248Aライブラリをベースとしたが、vRamにアクセスするための座標データが必要なので、gLCD_chr()とgLCD_str()関数は削除した。代わりにgLCD_chrX()、gLCD_strX()関数を使う必要がある。新しいライブラリ名はAQM1248A_m。
 また、関数の引数の並び順を、xpos、ypos、data、・・に変更し、位置指定関数名もgLCD_posXY()とした。(詳細はAQM1248A_m.hファイル参照)
 上記の関数は、LCDのバイト単位位置で描画(上書き)するが、さらに、ドット単位位置で描画する以下の関数を追加した。新たに追加した関数は、点の消去(col=0)、点の描画(col=1)、点反転(col=8)をcolで指定することができる。

//-------ドット単位位置で点を描く----------------------
void gLCD_PSet(uint8_t xpos, uint8_t ypos, uint8_t col)
//-------ドット単位位置で文字を描く(次xpos位置を返す)-------
uint8_t gLCD_PutChr(uint8_t xpos, uint8_t ypos, char ch, uint8_t col)
//-------ドット単位位置で文字列を描く(次xpos位置を返す)---
uint8_t gLCD_PutStr(uint8_t xpos, uint8_t ypos, char * str, uint8_t col)
//-------ドット単位位置でパターンを描く(次xpos位置を返す)---
uint8_t gLCD_PutPtn(uint8_t xpos, uint8_t ypos, char * ptn, uint8_t n, uint8_t col)
//-------ドット単位位置で直線を描く-------------------
void gLCD_Line(uint8_t x0, uint8_t y0, int8_t x1, uint8_t y1, uint8_t col)

【デモ・テスト】  使用メモリ( ROM:3,490 byte、RAM:982 byte )
・ 水平ラインから上はバイト単位位置で描画、水平ラインから下はドット単位位置で描画している。
・ クロスのラインは2秒ごとにcol=8(点反転、XOR)で描画し、表示/非表示を繰り返す。
・ サイン曲線の描画は、近似データの配列変数をパターンで、およびXY指定ドットでプロットした。
・ 16x16ドットの漢字表示も試した。漢字パターンデータの作成には、上記 fontviewer24.xlsx を利用した。
・ 画面消去をgLCD_clr(0xFF)に変更すると全画面が黒となり、col=0として白文字のテストができる


デモ・テスト実行中
(abc895をバックライト付きLCDに交換)

LCD表示拡大
(クロスライン表示中)

【プログラム】 abc896-18326.c(zip) EUSARTについてはabc889を参照

/*******************************(abc896-18326)******
 *   Graphic LCD (AQM1248A_m) test  
 ***************************************************/

#include "mcc_generated_files/mcc.h"
#include "AQM1248A_m.h"

// #define  BFSIZE 20                     // eusart.hで宣言
char     sBf[BFSIZE];                   // 文字列作業エリア
char     rBuf[BFSIZE];                  // シリアル受信バッファ
uint8_t  sFlg;                          // シリアル受信フラグ

char msg1[] = "-- AQM1248A_m --\n\r";

char gptn[] = { 0x01,0x02,0x04,0x10,
                0x20,0x40,0x80,0x80,
                0x80,0x40,0x20,0x10,
                0x08,0x04,0x02,0x01 };

uint8_t sinP[] = {4,6,7,8,7,6,4,2,1,0,1,2,
                  4,6,7,8,7,6,4,2,1,0,1,2,4};  // Sin Wave

const char k[4][16]={
    {0x00,0x10,0x60,0x01,0x06,0x04,0xE4,0x24,
     0x2F,0x24,0xE4,0x24,0x2F,0x24,0xE4,0x04},
    {0x00,0xC0,0x30,0x0C,0x03,0x90,0x95,0x55,
     0x55,0x35,0x1F,0x35,0x55,0x55,0x91,0x90},  // 漢
    {0x00,0x1C,0x04,0x04,0x24,0x24,0x24,0x24,
     0xA7,0xA4,0x64,0x24,0x04,0x04,0x1C,0x00},
    {0x00,0x02,0x02,0x02,0x02,0x02,0x02,0x82,
     0xFF,0x02,0x02,0x02,0x02,0x02,0x02,0x02}   // 字
    };

uint8_t gLCD_k16X(uint8_t xpos, uint8_t ypos, uint16_t kj){
    uint16_t kk;
    kk = kj * 2; gLCD_ptnX(xpos, ypos, (char *)k[kk],16); 
    kk = kk+1; xpos=gLCD_ptnX(xpos, ypos+8, (char *)k[kk],16);
    return xpos;
}

uint8_t Put_K16(uint8_t xpos, uint8_t ypos, uint16_t kj, uint8_t col){
    gLCD_PutPtn(xpos, ypos, (char *)k[kj*2], 16,col); 
    xpos = gLCD_PutPtn(xpos, ypos+8, (char *)k[kj*2+1],16,col);
    return xpos;
}

/*----------------------------------------
 *        Main application
 -----------------------------------------*/
void main(void){
    char ch, i;
    uint8_t xpos, ypos, col;
    uint16_t kj;

    SYSTEM_Initialize();
    SSP1CON1bits.SSPEN = 1;                 //SPI1を有効に
    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();

    gLCD_int();
    gLCD_clr(0);                            // 黒ベタは0xFF
    col = 1;                                // col=0/1/8
    
    puts(msg1);                             // 動作確認用
    
  // --- バイト単位位置で描画
    gLCD_strX(0,0,msg1);
    xpos = 0;
    for(i = 0; i < 3; i++){
        xpos = gLCD_ptnX(xpos,8,gptn,16);
    }
    xpos = 90;
    for(kj = 0; kj < 2; kj++){
        xpos = gLCD_k16X(xpos,0,kj);
    }
    
  // --- ドット単位位置で描画
    gLCD_Line(0,20,127,20,col);
    xpos = 5;
    for(ch = 0x31; ch < 0x3A; ch++){
        xpos = gLCD_PutChr(xpos,23,ch,col);
    }
    gLCD_PutPtn(67,25,gptn,16,col);
    gLCD_PutStr(3,35,"Sin Wave",col);
    for(xpos = 0; xpos < 25; xpos++){
        ypos = sinP[xpos];
        gLCD_PSet(xpos+55, ypos+36,col);
    }
    xpos = 91; ypos = 27;
    for(kj = 0; kj < 2; kj++){
            xpos = Put_K16(xpos,ypos,kj,col); 
    }    
    
    while (1){
        // Cross Line Draw
        gLCD_Line(0, 0,127,47,8);
        gLCD_Line(0,47,127, 0,8);
        __delay_ms(2000);
    }
}

【AQM1248A_mライブラリ】
 abc895で紹介したAQM1248Aライブラリーから、引数の位置や変数名を変更しているので注意!!

AQM1248A_m.c/h(zip)

/***********************************(AQM1248A_m.c)******
 *     AQM1248A グラフィックライブラリ(vRam付き)
 **********************************************************/

#include "mcc_generated_files/mcc.h"
#include "AQM1248A_m.h"

static uint8_t vRam[6][128];            // LCD表示バッファーメモリ

//-------- G-LCDを初期化 ------------------------------------
void gLCD_int (void){
    gCS_SetLow();                       // チップセレクト有効
    gRS_SetLow();                       // コマンドデータ指定
    SPI1_ExchangeByte(0xAE);            // Display = OFF
    SPI1_ExchangeByte(0xA0);            // ADC = normal
    SPI1_ExchangeByte(0xC8);            // C.output = revers
    SPI1_ExchangeByte(0xA3);            // bias = 1/7
    SPI1_ExchangeByte(0x2C);            // power control 1
    __delay_ms(2);                      // 2mS遅延
    SPI1_ExchangeByte(0x2E);            // power control 2
    __delay_ms(2);                      // 2mS遅延
    SPI1_ExchangeByte(0x2F);            // power control 3
    SPI1_ExchangeByte(0x23);            // Vo ratio set
    SPI1_ExchangeByte(0x81);            // E-volume mode
    SPI1_ExchangeByte(0x1C);            // E-volume value
    SPI1_ExchangeByte(0xA4);            // 全点灯しない
    SPI1_ExchangeByte(0x40);            // start line = 0
    SPI1_ExchangeByte(0xA6);            // 白黒反転しない
    SPI1_ExchangeByte(0xAF);            // Display = ON
    gCS_SetHigh();                      // チップセレクト無効
}

//-------- G-LCDのデータを全消去(指定データで埋める)---
void gLCD_clr (char dat){			
    uint8_t x, y;
    gCS_SetLow();                       // チップセレクト有効
    for(y = 0; y < 6; y++){
        gRS_SetLow();                   // コマンド指定
        SPI1_ExchangeByte(0xB0 + y);
        SPI1_ExchangeByte(0x10);
        SPI1_ExchangeByte(0x00);
        gRS_SetHigh();                  // 表示データ指定
        for(x = 0; x < 128; x++){
            vRam[y][x] = dat;           // vRamクリア
            SPI1_ExchangeByte(vRam[y][x]);
        }			
    }
    gCS_SetHigh();                      // チップセレクト無効
}

//-------- カーソル位置指定 -----------------------------------
void gLCD_posXY(uint8_t xpos, uint8_t ypos){
    gCS_SetLow();                       // チップセレクト有効
    gRS_SetLow();                       // コマンド指定
    SPI1_ExchangeByte(0xB0 | (ypos >> 3));
    SPI1_ExchangeByte(0x10 | (xpos >> 4));
    SPI1_ExchangeByte(xpos & 0x0F);
    gCS_SetHigh();                      // チップセレクト無効
}

//-------- バイト単位で文字表示(次xpos位置を返す) ---------
uint8_t gLCD_chrX(uint8_t xpos, uint8_t ypos, char chr){
    uint8_t i, yAdr, ptn;
    //有効フォントデータでないなら何もしない
    if((ch < 0x20)||(ch > 0x7f)) return xpos;
    chr -= 0x20;                        //配列アドレスを計算
    gLCD_posXY(xpos, ypos);             //表示位置を指定
    yAdr = ypos >> 3;
    gCS_SetLow();                       // チップセレクト有効
    gRS_SetHigh();                      // 表示データ指定
    for(i = 0; i < 5; i++) {            //データを順に取得
        ptn = Font[chr][i];
        if(ptn == 0xFF)  break;         //幅狭文字なら抜ける
        vRam[yAdr][xpos] = ptn;
        SPI1_ExchangeByte(vRam[yAdr][xpos++]);
    }
    vRam[yAdr][xpos] = 0;
    SPI1_ExchangeByte(vRam[yAdr][xpos++]);  //文字間隔を空ける
    gCS_SetHigh();                      // チップセレクト無効
    return xpos;                        //次表示位置を返す
}

//-------- バイト単位で文字列表示(次xpos位置を返す)-----
uint8_t gLCD_strX(uint8_t xpos, uint8_t ypos, char *str){
    while(*str)  xpos = gLCD_chrX(xpos, ypos, *str++);
    return xpos;                        //次表示位置を返す
}

//-------- バイト単位でパターンを表示(次xpos位置を返す)-
uint8_t gLCD_ptnX(uint8_t xpos, uint8_t ypos, char *ptn, uint8_t n){
    uint8_t i, yAdr;
    gLCD_posXY(xpos, ypos);             // 表示位置を指定
    gCS_SetLow();                       // チップセレクト有効
    gRS_SetHigh();                      // 表示データ指定
    yAdr = ypos >> 3;
    for(i = 0; i < n; i++){
         vRam[yAdr][xpos + i] = *ptn++ ;	
         SPI1_ExchangeByte(vRam[yAdr][xpos + i]);
    }
    gCS_SetHigh();                      // チップセレクト無効
    return xpos + n;                    // 次表示位置を返す
}

//---- バイト単位でn個の指定データで埋める(次xpos位置を返す)
uint8_t gLCD_clrX(uint8_t xpos, uint8_t ypos, char dat, uint8_t n){
    uint8_t i, yAdr;
    gLCD_posXY(xpos,ypos);              // 表示位置を指定
    gCS_SetLow();                       // チップセレクト有効
    gRS_SetHigh();                      // 表示データ指定
    yAdr = ypos >> 3;
    for(i = 0; i < n; i++) {
        vRam[yAdr][xpos] = dat;		
        SPI1_ExchangeByte(vRam[yAdr][xpos]);
    }
    gCS_SetHigh();                      // チップセレクト無効
    return xpos+n;                      // 次開始位置を返す
}


/*==============================
 * ドット単位位置で描画         
 *==============================*/

//----------ドット単位で点を描く----------------------
void gLCD_PSet(uint8_t xpos, uint8_t ypos, uint8_t col){
    uint8_t yAdr, yBit;                 // yアドレス、ビット位置
    uint8_t ptn = 0x01;                 // ビットパターン
    if((xpos > 127) || (ypos > 47))  return;
    yAdr = ypos >> 3; yBit = ypos & 0x07;
    ptn <<= yBit;
    switch(col){
        case 0:	vRam[yAdr][xpos] &= (~ptn); break;
        case 1:	vRam[yAdr][xpos] |= ptn;    break;
        case 8:	vRam[yAdr][xpos] ^= ptn;    break;
    }
    gLCD_posXY(xpos,ypos);  
    gCS_SetLow();                       // チップセレクト有効
    gRS_SetHigh();                      // 表示データ指定
    SPI1_ExchangeByte(vRam[yAdr][xpos]);
    gCS_SetHigh();                      // チップセレクト無効
}

//-------ドット単位で文字を描く(次xpos位置を返す)-------
uint8_t gLCD_PutChr(uint8_t xpos, uint8_t ypos, char ch, uint8_t col){
    uint8_t i, j, ptn, msk;
    //有効フォントデータでないなら何もしない
    if((ch < 0x20)||(ch > 0x7f)) return xpos;
    ch -= 0x20;                         //配列アドレスを計算
    for(i = 0; i < 5; i++){
        msk = 0x01;                     //ビットマスクデータ
        ptn = (uint8_t)Font[ch][i];
        if(ptn == 0xFF) break;          //幅狭文字なら抜ける
        for(j = 0; j < 8; j++){
            if(ptn & msk)    gLCD_PSet(xpos + i,ypos + j,col);
            msk <<= 1;
        }
    } 
    return xpos + i + 1;
}

//-------ドット単位で文字列を描く(次xpos位置を返す)---
uint8_t gLCD_PutStr(uint8_t xpos, uint8_t ypos, char * str, uint8_t col){
    while(*str)                         //文字列終端まで継続
        xpos = gLCD_PutChr(xpos,ypos,*str++,col);
    return xpos;                        //次表示位置を返す
}

//-------ドット単位でパターンを描く(次xpos位置を返す)-------
uint8_t gLCD_PutPtn(uint8_t xpos, uint8_t ypos, char *ptn, uint8_t n, uint8_t col){
    uint8_t i, j, msk; 
    for(i = 0; i < n; i++){
        msk = 0x01;                     //ビットマスクデータ
        for(j = 0; j < 8; j++){
            if(*ptn & msk)    gLCD_PSet(xpos+i,ypos+j,col);
            msk <<= 1;
        }
        ptn++;
    }
    return xpos + i;
}

// --- ABS、SWAP関数定義

#define ABS(a)    (((a)>0) ? (a) : -(a))
//#define SWAP(type,a,b) ({type tmp = (a); (a) = (b); (b) = tmp;})

void swap_u8(uint8_t *a, uint8_t *b){
	uint8_t tmp; tmp = *a; *a = *b; *b = tmp;
}

//----------ドット単位で直線を描く-------------------
void gLCD_Line(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t col){
    uint8_t steep, x, y, tmp;
    int   ystep, deltax, deltay, error;
    steep = (ABS(y1 - y0) > ABS(x1 - x0));
    if(steep){   swap_u8(&x0,&y0); swap_u8(&x1,&y1); }
    if(x0 > x1){ swap_u8(&x0,&x1); swap_u8(&y0,&y1); }
    deltax = x1 - x0;                       //  傾き計算
    deltay = abs(y1 - y0);
    error = 0;
    y = y0;
    if(y0 < y1) ystep = 1; else ystep = -1;
    for(x = x0; x < x1 + 1; x++){
        if(steep) gLCD_PSet(y,x,col); 
        else      gLCD_PSet(x,y,col);
        error += deltay;
        if((error << 1) >= deltax){
            y += ystep;
            error -= deltax;
        }
    }
}

/******************************(AQM1248A_m.h)************
 *   Grafic LCD  AQM1248A_m.h 用ライブラリ
 *   (5x7dotのプロポーショナル文字パターン付き)
 **********************************************************/

/*---  G_LCDを初期化する
 *	gLCD_int(void); */
void gLCD_int(void);

/*---  G_LCDのRAMの書込みアドレスを指定する
 *	gLCD_posyx(xpos,ypos);
 *	  表示文字位置(xpos,ypos) */
void gLCD_posXY(uint8_t, uint8_t );

/*---  G_LCDのRAMを全消去(指定データで埋める)
 *	gLCD_clr(dat);
 *	  埋めたい1バイトデータ(dat) */
void gLCD_clr(char );

/*---  G_LCDにchrコードの文字パターンを表示
 *	gLCD_chrX(xpos, ypos, ch);
 *	  表示位置(ypos,xpos)、表示文字(ch)  */
uint8_t gLCD_chrX(uint8_t , uint8_t , char);

/*---  文字列strをG_LCDに表示する
 *	gLCD_strX(xpos, ypos, *str);
 *	  表示位置(xpos,ypos)、表示文字列(str) */
uint8_t gLCD_strX(uint8_t , uint8_t , char *);

/*---  ビットパターンをG_LCDに表示する
 *	gLCD_ptnX(xpos, ypos, *ptn, n);
 *	  表示位置(xpos, ypos)、パターン(*ptn)・・バイト単位
 *    転送数(n)  */
uint8_t gLCD_ptnX(uint8_t , uint8_t , char *, uint8_t );

/*---  指定したdatで指定数nだけ表示
 *	gLCD_clrX(xpos, ypos, dat, n);
 *	  表示位置(xpos, ypos)、データ(dat)・・1バイト
 *    転送数(n) */
uint8_t gLCD_clrX(char , uint8_t , uint8_t , uint8_t );

/*---  ドット単位で点を描く
 *  gLCD_PSet(xpos, ypos, col);
 *    表示位置(xpos, ypos)、表示色(col、0:白/1:黒/8:反転)*/
 void gLCD_PSet(uint8_t , uint8_t , uint8_t );

/*---  ドット単位で文字を描く(次xpos位置を返す)
 *  gLCD_PutChr(xpos, ypos, ch, col);
 *    表示位置(xpos, ypos)、表示文字コード(ch)
 *    表示色(col、0:白/1:黒/8:反転)*/
 uint8_t gLCD_PutChr(uint8_t , uint8_t, char, uint8_t );

/*---  ドット単位で文字列を描く(次xpos位置を返す)
 *  gLCD_PutChr(xpos, ypos, *str, col);
 *    表示位置(xpos, ypos)、表示文字列(*str)
 *    表示色(col、0:白/1:黒/8:反転)*/
 uint8_t gLCD_PutStr(uint8_t , uint8_t, char *, uint8_t );

/*-------ドット単位でパターンを描く(次xpos位置を返す)
 *  gLCD_PutPtn(xpos, ypos, *ptn, n, col);
 *    表示位置(xpos, ypos)、表示パターン(*ptn)・・バイト単位
 *    転送数(n)、表示色(col、0:白/1:黒/8:反転)*/
 uint8_t gLCD_PutStr(uint8_t, uint8_t, char *, uint8_t , uint8_t );

/*----------ドット単位で直線を描く
 *  gLCD_Line(x0, y0, x1, y1, col);
 *    開始位置(x0,y0)、終了位置(x1,y1)、
 *    表示色(col、0:白/1:黒/8:反転)*/
 void gLCD_Line(uint8_t , uint8_t ,uint8_t , uint8_t , uint8_t);


/*********************************************************
 * キャラクタデータ (ASCII 0x20-0x7F) 
**********************************************************
 [フォントデータの記載は省略(詳細はabc895参照)]

【おまけ】

変数データを入れ替える必要が有り、swap()関数を作った。しかし、type毎にswap関数が必要となる。
void swap_u8(uint8_t *a, uint8_t *b){
  uint8_t tmp; tmp = *a; *a = *b; *b = tmp;
}
// 使用例: swap_u8(&a, &b);
 
そこで、SWAP()をマクロで記述できないか調べてみた。このマクロはどんなデータ(タイプ)でも使用できるが、typeをいちいち指定しなければならず、どちらが良いか・・。(c90では使用できない)
#define SWAP(type,a,b) ({type tmp = (a); (a) = (b); (b) = tmp;})
// 使用例: SWAP(uint8_t, a, b)


※プログラムのリストをハイライト無しのスタイルで見る場合はここをクリック


※ 本レポートの参考・利用は、あくまでも自己責任でお願いします。


フォントとは PICミニBB(6)_グラフィックLCD(VRam利用)