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利用)