Vol.906 8.Nov.2024

JoySTick付きリモコン ご当地ナンバープレート PICミニBB(16)_市販漢字フォントROM

M はじめてのM5StickC_Plus(15) 〜JoyStick

by fjk

 abc883でM5StickC_Plusを使った赤外線リモコンを作ったが、チャンネルの移動などでスイッチを何度も押さなければならず使いづらかった。
 そこで、I2C接続のUnit-JoyStickを入手し、操作性の改善を図った。

【JoyStickの動作テスト】 joystick-test.m5f(zip)
 M5StickC-plusにJoyStickユニットを接続し、JoyStickの動作を確認した。XY軸とも中点付近では130(±5程度の誤差あり)で、ステックを動かすと0〜255の値を得ることができるが、斜め方向ではこの検出幅は狭くなる。中央の値に誤差があり、ボタンを押すと少しずれるので、90〜170まではStickデータが有効でない範囲とした。また、Stickの動作の判断は、リアルタイムでは早く反応しすぎるので、500mS毎に行うことにした。
 また、ボタンを押し込むと数値が0から1に変化する。ただし、JoyStickのボタンはかなり強く押さないと反応しない。

センター位置

ボタンを押すと

JoyStickテスト用UIFLOW画面
【JoyStick付きIOdataリモコン】 IOremote-Joy.m5f+sendNEC.m5b+myblock.m5b(zip)
 abc883のスケッチをベースに、JoyStickのスケッチを追加した。M5StickCのボタンとJoyStickが共通で使えるパートを関数化した。
 JoyStick付きのIOデータリモコンができたが、Stickを大きく動かすとStickがロックされるので注意!。しかし、ロック状態にするとカーソルが連続で移動するので、この機能を利用することもできる。
 もちろん、今までのボタン操作も同時に使用可能である。

JoyStick付きリモコン

JoyStick付きIOリモコンのUIFLOW画面(sendNEC.m5bとmyblock.m5bも必要)


N ご当地ナンバープレート  〜地方版図柄入りナンバー

by fjk

 地方版図柄入りナンバープレートは、”走る広告塔”として、地域の風景や観光資源を図柄とすることにより、地域の魅力を全国に発信することを目的に提供を開始し、平成30年10月1日から入手可能である。(詳細は、国土交通省のHPを参照)。

 キャンピングカーのシュピーレンを、4から8ナンバーへの変更にともない、地方図版入りナンバーを取得することにした。
 その手続きと手順は、図柄入りナンバープレートお申し込み方法(pdf)や、富山県図柄入りナンバープレートの交付についてを参照。

【大まかな流れ】
@ 希望番号・図柄ナンバープレート申込みサービスからweb申込み(窓口でも申請できます)
 ・番号をそのままの場合と、変える場合が選べる(希望番号がある場合は新規として申し込む)
A 交付手数料・寄付金を支払う
B 入金確認メールの受信。交付申請書のダウンロード・印刷(交付申請書の有効期限は1ヶ月)
 −−−ここからは窓口−−−(富山県の場合:富山市新庄町馬場)
C 交換申請 【富山県自動車税センター・税務課】
D 登録申請・届け出 【国交省・北陸信越運輸支局・登録部門】
E (旧ナンバーの取り外し・)ナンバープレートの交付 【富山県自動車税センター・税務課】

※ 「地方版図柄入りナンバープレート」の他に、全国統一デザインの「全国版図柄入りナンバープレート」(期間限定)もあります。


P PICミニBBシリーズ(16)  〜市販漢字フォントROM(GT20L16J1Y)

by fjk

 abc905でEEPROMにフォントデータを書込、そのROMを使ってグラフィックLCDに漢字などの表示ができるようになったが、ROMに書き込むのが面倒な場合、第2水準までの漢字フォントが既に書き込まれたROMが売られている。今回、そのようなspi接続ROMであるGT20L16J1Y(@308)を使ってみた。
 GT20L16J1Yの入手・詳細はスイッチサイエンスなど。[ GT20L16J1Yの全フォントと格納アドレス(zip)]

【ハードウェア】
レベル変換後の回路をコンパクトにするため、連結可能なミニブレッドボード2枚を連結して使用した。PICは16F18325でabc905のBase14のRC2とRC3の配線を変更したものを用いた(配線写真参照)。
3.3Vの電源は三端子DC/DCレギュレータVX07803-500(秋月電子#115148、@350)、RAMはspi接続で512kbit(64kbyte)の23LC512(秋月電子#114062、@220)を準備した

ブレッドボードの配線状況(BSS138利用)

第2水準漢字の"齋"、小文字'o'も表示

GT20L16J1Y利用グラフィック表示回路図
 ◆レベル変換ICとLCDの相性問題?
フォントROMやグラフィックLCDの電源は3.3Vとなっているので、8ビットレベル変換キット(秋月電子#117062、@250)を利用した。ところが、何故かグラフィックLCDに何も表示されなかった。そこで、オシロスコープで調べて見ると、CS端子の入力信号のGNDレベルが1V程度と高くなっていた(他の信号はちゃんとGNG = 0V)。配線を何度も確かめてみるが間違いは無く、グラフィックLCDを外すと正常。−>この原因は今のところ不明。
そこで、このCS信号を別回路でレベル変換を行うことにした。レベル変換の方法にはいくつかの方法があるが、BSS138を利用した4ビットレベル変換回路では、グラフィックLCDが正常に動作しているので、BSS138(秋月電子#104232、100/25個)を使うことにし、BSS138をブレッドボードで使いたいのでSOT-23-3DIP化基板(秋月電子#114298、¥80/5枚、ピンは3ピンのみ使用)も準備した。

gLCDのCS入力信号(GNDレベルが変)

BSS138を利用し改良後(ノイズも無し)

【ソフトウェア】
基本的にはabc905と(コマンドも)ほぼ同じだが、フォントROMアドレスはdefine文で宣言し、ROMが変わっても、フォントの参照アドレスの変更を容易に行えるようにした(第2水準漢字にも対応)。
KコマンドはROMアドレスを指定してフォントパターンを読み出し、画面に8か16文字を表示するが、コマンドの最後に”.”(ピリオド)を付けると、1文字のみを(端末にパターン数値データも)表示する。(LコマンドはJISコードで指定)
GT20L16J1Yにはデータの書き込みができないので、ユーザーフォントは(電源がOFFになると消えるが)RAM(23LC512)に記憶することにした。ユーザマップは8BC00Hから、データは8C000Hから。
なお、漢字ROMにはバグ(全角小文字'o'が大文字で表示される)があり(プログラムで対応済み)、その詳細はスイッチサイエンス参照。
また、収録されている全文字の表示には対応していないので、必要であれば表示できるように修正して下さい。
 
 ●ROMのデレータイム
データシートでは、ROMアクセスサイクル間に100nSが必要とあり、EEPROMではROMステータスを利用したが、GT20L16J1Yではステータスの読出しができないので、__delay_ms()関数を使うことにした。しかし、今回は読出しのみなのでデレータイムを無しにした。もし連続読み込み時などでエラーが出る場合、ROMアクセス時のデレータイムを有効にすること。

 
【abc906-18325.cファイル】 abc906-18325.c + myProject.h(zip)

/*******************************(abc906-18325)*********
 * SPI接続メモリ(GT20L16J1Y/23LC512) with AQM1248A  
 ******************************************************/

#include "myProject.h"

char     RBuf[BFSIZE];             // シリアル受信バッファ
uint8_t  SFlg;                     // シリアル受信フラグ

uint16_t KARY[] = {'漢','字',0x828F, 'O',0};
char     KSTR[] = "齋藤デす。◆o5";

//---- ターミナルにプロンプト文字表示
void prtPrompt(uint8_t m){
    if(m)  putch('#');	           //printf("# "); // 連続書込モード中
    else   putch('$');             //printf("$ "); // 通常書込モード
    putch(' ');
}

/*-----------------------------------
 *        Main application
 ------------------------------------*/
void main(void){
    uint8_t cmd;

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

    gLCD_int();
    gLCD_clr(0);                    // 黒ベタは0xFF
    
    puts("Ready\r");                // 動作確認用
    gLCD_strX(0,0,"Ready");

    spiMem_cmd_R("R");              // メモリ動作確認用
   
    #ifndef VBA
        prtPrompt(spiMem_SqMode());
    #endif 
        
    while (1){
        if(SFlg){
            gLCD_clr(0);            // グラフィック画面消去
            gLCD_strX(0,0,RBuf);    // LCDにコマンド表示
            cmd = RBuf[0];          // コマンドは第1文字
            #ifndef VBA
                printf("\n\r");
            #endif
            switch(cmd) {           // 各コマンドの実行
                case 'W': spiMem_cmd_W(RBuf);  break;
                case 'R': spiMem_cmd_R(RBuf);  break;
                case 'Q': spiMem_cmd_Q(RBuf);  break;
                case 'U': spiMem_cmd_U(RBuf);  break;
                case 'S': spiMem_cmd_W(RBuf);  break;
                case 'P': spiMem_cmd_P(RBuf);  break;
                case 'K': spiMem_cmd_K(RBuf);  break;
                case 'L': spiMem_cmd_L(RBuf);  break;
                case 'Y': gLCD_ZstrX(0,32,(char *)KSTR,1); break;
                case 'Z': gLCD_ZstrX(0,32,(char *)KARY,0); break;
                                    // 有効なコマンドがなく
                default:  if(spiMem_SqMode()){
                            spiMem_cmd_WSQ(RBuf);
                          }         // 連続書込モード中なら
                          break;    // 書込シーケンスを実行
            }
            SFlg = 0;
            #ifndef VBA
                prtPrompt(spiMem_SqMode());
            #endif
        }
        IO_RA4_Toggle();
        __delay_ms(500);
    }
}
/**===  End of File  ===*/
【myProject.hファイル】

/**************************(myProject.h)***
 *   プロジェクト個別条件指定ファイル     *
 *   (main.cと同じフォルダーに作成)     *
 ******************************************/

#include "mcc_generated_files/mcc.h"
//#include "myStdlib.h"
//#include "i2cLCD_ST7032i.h"
//#include "AQM1248A.h"
#include "AQM1248A_v5.h"
//#include "ADT7410.h"
//#include "DS1307.h"
//#include "PC_EEPROM.h"
#include "spi_Mem5.h"

#define  ON    1
#define  OFF   0

#define VBA                         // Excel VBA 使用?
#define FONT_ROM                    // フォントROM有り?

#define MBFSIZE	256                 // メモリ操作用バッファーサイズ

/***** PIC電源電圧 ***********************/
//--- VCC宣言無しは5V(VCC=50と同じ)
#define VCC   50                    // 電源電圧は5V
//#define VCC   33                  // 電源電圧は3.3V

/***** EUSARTモジュール *******************/
//#include "../myXC8lib/myEusart.h"
#define BFSIZE  120                 // 80 から増やした
//--- ECHO宣言無しはエコー有り(ECHO ONと同じ)
#define ECHO  ON                    // エコー有り
//#define ECHO  OFF                 // エコー無し

/***** MSSPモジュール *********************/
#define MASTER 1
#define SRAVE  2
//#define I2CMODE MASTER            // マスターとして使用
//#define I2CMODE SRAVE             // スレーブとして使用
//--- MSSPが一つしか無い場合は I2C宣言無し
//#define I2C  1                    // I2C1を使用
//#define I2C  2                    // I2C2を使用

#if I2CMODE == MASTER
    #if I2C == 1
        #include "mcc_generated_files/examples/i2c1_master_example.h"
    #elif I2C == 2
        #include "mcc_generated_files/examples/i2c2_master_example.h"
    #else
        #include "mcc_generated_files/examples/i2c_master_example.h"
    #endif
 #endif

//--- SPIが一つしか無い場合は宣言しない
#define SPIMODE MASTER              // マスターとして使用
//#define SPIMODE SRAVE             // スレーブとして使用

#define SPI  1                      // SPI1を使用
//#define SPI  2                    // SPI2を使用

/*********** End of File ******************/

 
【spi_Mem5.hファイル】 spi_Mem5.c/h(zip)

/******************************(spi_Mem5.h)***************
 *	SPI接続メモリ(GT20L16J1Y/23LC512)ヘッダーファイル
 ********************************************************/

#include "ctype.h"                  // isxdigit()
#include "stdio.h"                  // puts(),..
#include "stdlib.h"                 // atoi()...
#include "string.h"                 // strtok()...

#define SPIMEM_WRITEcmd 0x02        // WRITE
#define SPIMEM_READcmd  0x03        // READ

#define SPIROM_WR_STATS 0x01        // WRSR
#define SPIROM_WRITEcmd 0x02        // WRITE
#define SPIROM_READcmd  0x03        // READ
#define SPIROM_RD_STATS 0x05        // RDSR
#define SPIROM_WR_ENABL 0x06        // WREN
#define SPIROM_PG_ERASE 0x42        // PE: Page Erase
#define SPIROM_CP_ERASE 0xC7        // CE: Chip Erase
#define SPIROM_SC_ERASE 0xD8        // SE: Sector Erase

/***  SPI 汎用サブルーチン *****/
//-----  アドレスadrから、1バイトを読み出す
uint8_t SPI_Mem_Read(uint32_t adr);

//-----  アドレスadrに、1バイトdtを書き込む
uint8_t SPI_Mem_Write(uint32_t adr, uint8_t dat);

//-----  アドレスadrからnバイトをary[]に読み出す
void SPI_Mem_NRead(uint32_t adr,uint8_t *ary,uint16_t cnt);

//-----  アドレスadrからary[]のnバイトを書き込む
void SPI_Mem_NWrite(uint32_t adr,uint8_t *ary,uint16_t cnt);

//----  シーケンスモードの確認
uint8_t spiMem_SqMode();

//--- SPI-ROMのステータスの取得
uint8_t SPI_Rom_RdStat();

/****  ターミナルコマンド  *****/
//----- Wコマンド   W[aaaa][,[d0,・・[,]]]
uint16_t spiMem_cmd_W(char *str);

//---- Rコマンド  R[aaaa][,n]
uint16_t spiMem_cmd_R(char *str);

//---- WSQ (連続書込モード)
uint16_t spiMem_cmd_WSQ(char *str);

//---- Qコマンド(連続書込モードの解除)   Q
void spiMem_cmd_Q(char *str);

//---- U(dump)コマンド    U[aaaa]
//         (64バイトのデータをDBuf[]に読み出す)
int spiMem_cmd_U(char *str);

//---- P(Page)コマンド    P[W/R][aaaa]
//          (DBuf[]の64バイトの表示と、読み書き)
int spiMem_cmd_P(char *str);

//---- Kコマンド(漢字表示コマンド)   K[H][n][.]
int spiMem_cmd_K(char *str);

//---- L(文字)表示コマンド  L[n] 
void spiMem_cmd_L(char *str);

/*******end of file  *****/
【spi_Mem5.cファイル】

/******************************(spi_Mem5.c)***************
 *  SPI接続メモリ(GT20L16J1Y/23LC512)読み書きライブラリ
 ***********************************************************/

#include <stdlib.h>
#include <stdio.h>
#include "myProject.h"

#define ROM_DELAY   1               // ROM用デレータイム(uS)

//=== グローバル変数 ============
char     Dlm[] = ",";               // 文字列区切りデリミタ
char     SBuf[20];                  // 文字列処理用バッファー

//--- SPIメモリー用
static uint32_t CrtAdr = 0;         // カレントアドレス
static uint8_t  DBuf[MBFSIZE];      // ページメモリ用バッファー
static uint8_t  SqMode = 0;         // シーケンスモードフラグ
static char     lstCmd;             // 最終コマンド
static uint8_t  spiRom = 1;         // spiRomかどうか
static uint16_t lstChr = 0;         // 最終表示文字
static uint8_t  fntPtn[32];         // フォントパターン用

/*************************************
 *  SPIC EEPROM function
 **************************************/
 
//---- ROMステータスの読み出し・・・GT20L16J1Yでは無効です
uint8_t SPI_Rom_RdStat(){           // EEPROMのみ使用
    uint8_t stat;
    CS0_SetLow();
    SPI1_ExchangeByte(SPIROM_RD_STATS);
    stat = SPI1_ExchangeByte(0xAA); // 0xAAはダミー
    CS0_SetHigh();
    return stat;
}

//---- コマンドと24ビットアドレスを送信 
void sendAdr(uint8_t cmd, uint32_t adr){
    if(spiRom) CS0_SetLow();        // spiRom(25LC1024)選択
    else       CS1_SetLow();        // spiRam(23LCV1024)選択
    SPI1_ExchangeByte(cmd);         // send Command
    SPI1_ExchangeByte((uint8_t)(adr>>16));
    SPI1_ExchangeByte((uint8_t)(adr>>8));
    SPI1_ExchangeByte((uint8_t)adr);
} 

//-----  アドレスadrから、1バイトを読み出す
uint8_t SPI_Mem_Read(uint32_t adr){
    uint8_t dat;
    if(adr < 0x80000) spiRom = 1;   // spiRom(25LC1024)指定
    else              spiRom = 0;   // spiRam(23LCV1024)指定
    sendAdr(SPIMEM_READcmd,adr);    // send Read_CMD & Address
    dat = SPI1_ExchangeByte(0xAA);
    if(spiRom) CS0_SetHigh();       // spiRomの場合
    else       CS1_SetHigh();       // spiRamの場合
	return dat;
}

//-----  アドレスadrに、1バイトdtを書き込む
uint8_t SPI_Mem_Write(uint32_t adr, uint8_t dat){
    if(adr < 0x80000){
        spiRom = 1;                 // spiRom指定
        CS0_SetLow();
        SPI1_ExchangeByte(SPIROM_WR_ENABL); // Set Write Enable Bit
        CS0_SetHigh();
    }else{
        spiRom = 0;                 // spiRam指定
    }
    sendAdr(SPIMEM_WRITEcmd,adr);   // send Write_CMD & Address
    SPI1_ExchangeByte(dat);
    if(spiRom){                     // spiRomの場合
        CS0_SetHigh();
        __delay_ms(6);
    }else{                          // spiRamの場合
        CS1_SetHigh();
    }
    return dat;
}

//-----  アドレスadrからnバイトをary[]に読み出す
void SPI_Mem_NRead(uint32_t adr,uint8_t *ary,uint16_t cnt){
    if(adr < 0x80000) spiRom = 1;   // spiRom指定
    else              spiRom = 0;   // spiRam指定
    sendAdr(SPIMEM_READcmd,adr);    // send Read_CMD & Address
    SPI1_ReadBlock(ary,cnt);        // block read
    if(spiRom){
        CS0_SetHigh();
//        while(SPI_Rom_RdStat() & 1);
//        __delay_us(ROM_DELAY);
    }else{
        CS1_SetHigh();
    }    
}

//-----  アドレスadrからary[]のnバイトを書き込む
void SPI_Mem_NWrite(uint32_t adr,uint8_t *ary,uint16_t cnt){
    if(adr < 0x80000){
        spiRom = 1;                 // spiRom指定
        CS0_SetLow();
        SPI1_ExchangeByte(SPIROM_WR_ENABL); // Set Write Enable Bit
        CS0_SetHigh();
    }else{
        spiRom = 0;                 // spiRam指定
    }
    sendAdr(SPIMEM_WRITEcmd,adr);   // send Write_CMD & Address
    SPI1_WriteBlock(ary,cnt);       //  block write
    if(spiRom){
        CS0_SetHigh();
//        while(SPI_Rom_RdStat() & 1);
//        __delay_us(ROM_DELAY);
    }else{
        CS1_SetHigh();
    }
}

/****** 汎用サブルーチン ********************/
//   16進数文字変換  uint16 -> str(Hex)
uint8_t my_utoa2(uint16_t n){
    n &= 0x0F;
    if(n < 10)  return '0'+ (uint8_t)n;
    else        return 'A'+ ((uint8_t)n - 10);
}

void my_utoa(uint8_t *str, uint16_t wd, uint8_t dg){
    if(dg > 3)  *str++ = my_utoa2(wd >> 12);
    if(dg > 2)  *str++ = my_utoa2(wd >> 8);
    if(dg > 1)  *str++ = my_utoa2(wd >> 4);
    *str++ = my_utoa2(wd);
    *str = '\0';
}

//---- 16進文字列を10進数に変換
uint32_t my_xtoi(char *str){
    uint32_t dec;
    dec = strtoul(str,NULL,16);
    return (uint32_t)dec;
}

//---  文字列出力関数(標準出力へ)
void my_puts(char *str){            // 文字列のみ出力
    while(*str) putch(*str++);
}

void my_putsLf(char *str){          // 次行に移動(LF)付き
    my_puts(str);
    putch('\r');
}

//---- ページバッファープリント
//void prt_PBf(){
void prt_PBf(uint8_t *cBf, uint16_t n){
    uint16_t i;
//    for(i = 0; i < MBFSIZE; i++){   // 16文字×8行表示
    for(i = 0; i < n; i++){
        if(i % 16 == 0) putch('\r');
//        my_utoa((uint8_t *)SBuf,DBuf[i],2);
        my_utoa((uint8_t *)SBuf,cBf[i],2);
        putch(SBuf[0]); putch(SBuf[1]); putch(' ');
//        printf(" %02X",DBuf[i]);
    }
    puts("\r");
}

//---- 20ビットアドレスと8ビットデータを16進数で文字列に格納
void sPrt_AdrDt(char *strP,uint32_t adr, uint8_t dt, char ch){
    uint16_t a16;
    uint8_t  h;
    h = (uint8_t)((adr>>16) & 0x0F);
    *strP++ = my_utoa2(h);
    a16 = (uint16_t)(adr & 0x0FFFF);
    my_utoa((uint8_t *)strP,a16,4);
    strP += 4;
    *strP++ = ' '; *strP++ = ch; *strP++ =' ';
    my_utoa((uint8_t *)strP,(uint16_t)dt,2);
    strP += 2;
    *strP = '\0';
}

//---- 20ビットアドレス1と20ビットアドレス2を16進数で文字列に格納
void sPrt_AdrAdr(char *strP,uint32_t adr1, uint32_t adr2, char ch){
    uint16_t a16;
    uint8_t  h;
    h = (uint8_t)((adr1>>16) & 0x0F);
    *strP++ = my_utoa2(h);
    a16 = (uint16_t)(adr1 & 0x0FFFF);
    my_utoa((uint8_t *)strP,a16,4);
    strP += 4;
    *strP++ = ' '; *strP++ = ch; *strP++ =' ';
    h = (uint8_t)((adr2>>16) & 0x0F);
    *strP++ = my_utoa2(h);
    a16 = (uint16_t)(adr2 & 0x0FFFF);
    my_utoa((uint8_t *)strP,a16,4);
    strP += 4; 
    *strP = '\0';
}

/************************************
 * 	コマンドアクション
 ************************************/
//----- Wコマンド   W[aaaa][,[d0,・・[,]]]
uint16_t spiMem_cmd_W(char *str){
    char     *pt;                       // 文字列操作用ポインタ
    uint8_t  last;                      // 文字列の最後の位置
    uint32_t res = 0;                   // Hex文字数値変換結果
    uint8_t  dt = 0;                    // 書き込むバイトデータ
    uint16_t cnt = 0;                   // 実際に書き込んだバイト数

    lstCmd = str[0];
    if(strlen(str)==1){                 // 'W'のみなら
        SqMode = 1;                     // 連続書込モードにセット
        #ifndef VBA
            puts("SqMode ON\n\r");
        #endif
        return 0;                       // データは書き込まない
    }
    last = (uint8_t)strlen(str)-1;      // 文字列の行末位置を取得
    if(str[last] == ','){               // 行末がコンマなら
        SqMode = 1;                     // 連続書込モードにセット
        #ifndef VBA
            puts("SqMode ON\n\r");
        #endif
        str[last]='\0';                 // 行末のコンマを消す
    }
    if(str[1]!=','){                    // 第2文字がコンマか?
        pt = strtok(str+1,Dlm);         // コマンドの次文字から
        if(pt != NULL){                 // アドレスデータがある
            res = my_xtoi(pt);
            CrtAdr = res;
        }
        pt = strtok(NULL,Dlm);          // 次文字列取込
    }else{
        pt = strtok(str+1,Dlm);         // 文字列取込
    } 
    do{
        if(pt != NULL){                 // データがあるか?
            res = my_xtoi(pt);
            dt = (uint8_t)res;
            if(lstCmd=='W'){
                SPI_Mem_Write(CrtAdr,dt); // データを書き込む
            }else if(lstCmd == 'S'){
                DBuf[CrtAdr & 0x7F]= dt;  
            }
            sPrt_AdrDt(SBuf,CrtAdr,dt,'<');
//            sprintf(SBuf,"%05lX < %02X",CrtAdr,dt);
            my_putsLf(SBuf);
//            printf("%s\r",SBuf);
            prtHstr_LnClr(0,16,SBuf);
            CrtAdr++; cnt++;          
            pt = strtok(NULL,Dlm);      // 次文字へ
        }
    }while(pt != NULL);                 // データがあるだけ繰り返す
    return cnt;                         // 書き込んだ文字数を返す
}

//---- Rコマンド  R[aaaa][,n]
uint16_t spiMem_cmd_R(char *str){
    char *pt;                           // 文字列操作用ポインタ
    uint16_t n = 1;                     // 指定された読込バイト数
    uint32_t res = 0;                   // Hex文字数値変換結果
    uint8_t  dt;                        // 読み込んだバイトデータ
    uint16_t cnt = 0;                   // 実際に読み出されたバイト数
    uint16_t i;                         // ループ変数
    
    lstCmd = str[0];
    if(strlen(str) > 1){
        if(str[1]==','){
            pt = strtok(str+2,Dlm);
            if(pt != NULL){             // データ無し?
                res = my_xtoi(pt);
                n = (uint16_t)res;
            }
        }else{
            pt = strtok(str+1,Dlm);
            if(pt != NULL){             // addressがある?
                res = my_xtoi(pt);
                CrtAdr = res;
            }
            pt = strtok(NULL,Dlm);      // 次文字へ
            if(pt != NULL){             // データ無し?
                res = my_xtoi(pt);
                n = (uint16_t)res;
            }
        }
    }

    for(i = 0; i < n; i++ ){
        dt = SPI_Mem_Read(CrtAdr);      // データを読み出す
        sPrt_AdrDt(SBuf,CrtAdr,dt,'<');
//        sprintf(SBuf,"%05lX > %02X",CrtAdr,dt);
        my_putsLf(SBuf);
//        printf("%s\r",SBuf);
        gLCD_strX(64,0,SBuf);
        prtHstr_LnClr(0,16,SBuf);
        CrtAdr++; cnt++;
    }
    SqMode = 0;
    return cnt;                         // 読み込んだデータ数を返す
}

//---- WSQ (連続書込モード)
uint16_t spiMem_cmd_WSQ(char *str){
    char     *pt;                       // 文字列操作用ポインタ
    uint8_t  dt;                        // 書き込むバイトデータ
    uint32_t res;                       // Hex文字数値変換結果
    uint16_t cnt = 0;                   // 実際に読み出されたバイト数

    pt = strtok(str,Dlm);
    while(pt != NULL){                  // データがあるだけ繰り返す
        res = my_xtoi(pt);
        dt = (uint8_t)res;
        if(lstCmd == 'W'){
            SPI_Mem_Write(CrtAdr,dt);   // データを書き込む
        }else if(lstCmd=='S'){
            DBuf[CrtAdr & 0x7F]= dt;  
        }
        sPrt_AdrDt(SBuf,CrtAdr,dt,'<');
//        sprintf(SBuf,"%05lX < %02X",CrtAdr,dt);
        my_putsLf(SBuf);
//     	  printf("%s\r",SBuf);
        prtHstr_LnClr(0,16,SBuf);
        CrtAdr++; cnt++;
        pt = strtok(NULL,Dlm);          // 次文字列へ
    }
    return cnt;                         // 書き込んだデータ数を返す
}

//---- Qコマンド(連続書込モードの解除)   Q
void spiMem_cmd_Q(char *str){
    lstCmd = str[0];
    SqMode = 0;
    #ifndef VBA
        puts("SqMode OFF\r");
    #endif
}

//---- U(dump)コマンド    U[aaaa]
//         (64バイトのデータをDBuf[]に読み出す)
int spiMem_cmd_U(char *str){
    char    *pt;                        // 文字列操作用ポインタ
    uint32_t res;                       // Hex文字数値変換結果
    uint32_t ad;                        // 指定アドレス

    lstCmd = str[0];
    pt = strtok(str+1,Dlm);
    if(pt != NULL){                     // アドレス有り?
        res = my_xtoi(pt);
        CrtAdr = res;
    }
    ad = CrtAdr & 0xFFFF80;               // 128バイト単位に 
    SPI_Mem_NRead(ad, DBuf, MBFSIZE);     // MBFSIZE8バイトをDBuf[]に読出し
    sPrt_AdrAdr(SBuf,ad,ad + MBFSIZE - 1,'-');
//    sprintf(SBuf,"%05lX - %05lX", ad, ad+127);
    my_puts(SBuf);
//    printf("%s",SBuf);
    prtHstr_LnClr(0,16,SBuf);
//    prt_PBf();
    prt_PBf(DBuf,MBFSIZE);
    SqMode = 0;
    return 0;
}
//..  fntPtn[]を使ってフォントパターンデータの表示
int spiMem_cmd_u(char *str){
    char    *pt;                        // 文字列操作用ポインタ
    uint32_t res;                       // Hex文字数値変換結果
    uint32_t ad;                        // 指定アドレス

    pt = strtok(str+1,Dlm);
    if(pt != NULL){                     // アドレス有り?
        res = my_xtoi(pt);
        CrtAdr = res;
    }
    ad = CrtAdr & 0xFFFFF0;             // 16バイト単位に 
    if(lstCmd == 'H'){                  // 第2文字がHか?
        SPI_Mem_NRead(ad, fntPtn, 16);  // 16バイトをfntPtn[]に読出し
        gLCD_nk16X(0,32,(char *)fntPtn,8);
        prt_PBf(fntPtn,16);
    }else{
        SPI_Mem_NRead(ad, fntPtn, 32);  // 32バイトをfntPtn[]に読出し
        gLCD_nk16X(0,32,(char *)fntPtn,16);
        prt_PBf(fntPtn,32);
    }
    SqMode = 0;
    return 0;
}

//---- P(Page)コマンド    PW[aaaa]
//          (DBuf[]の64バイトをメモリに書き込む)
int spiMem_cmd_P(char *str){
    char     *pt;                       // 文字列操作用ポインタ
    uint32_t res;                       // Hex文字数値変換結果
    uint32_t ad;                        // 指定アドレス

    lstCmd = str[0];
    if(strlen(str)==1){
        puts("PageBuffer");
//        printf("PageBuffer");
//        prt_PBf();
        prt_PBf(DBuf,MBFSIZE);
        return 0;
    }
    if(str[1]=='R'){
        spiMem_cmd_U(str+1);
        return 0;
    }
    if(str[1] != 'W') return -1;        // 第2文字がW?
    pt = strtok(str+2,Dlm);
    if(pt != NULL){                     // アドレス有り?
        res = my_xtoi(pt);
        CrtAdr = res;
    }
    ad = CrtAdr & 0xFFFF80;              // 128バイト単位に
    SPI_Mem_NWrite(ad,DBuf,MBFSIZE);     // DBuf[]のMBFSIZEバイト書込
    sPrt_AdrAdr(SBuf,ad,ad + MBFSIZE - 1,'-');
//    sprintf(SBuf,"PW:%05lX - %05lX",ad,ad+127);
    my_putsLf(SBuf);
//     	printf("%s\r",SBuf);
    prtHstr_LnClr(0,16,SBuf);
    SqMode = 0;    
    return 0;
}

//----  シーケンスモードの確認
uint8_t spiMem_SqMode(){
    return SqMode;
}

//---- K(漢字)表示コマンド  K[H][n][.] 
int spiMem_cmd_K(char *str){
    char     *kp;                       // 文字列操作用ポインタ
    uint8_t  last;                      // 文字列の最後の位置
    uint8_t  sgChr = 0;                 // 1:単文字、0:複数文字
    uint8_t  i;
    lstCmd = str[0];
    kp = (char *)DBuf;
    last = (uint8_t)strlen(str)-1;      // 文字列の行末位置を取得
    if(str[last] == '.'){               // 行末がピリオドなら
        sgChr = 1;                      // 単文字モードに
        str[last]='\0';                 // 行末のコンマを消す
    }
    if(str[1] == 'H'){                  // 第2文字がHか?
        lstCmd = str[1];                // 最終コマンドは'H'
        if(strlen(str)>2){              // アドレスデータ有り
            if(sgChr) spiMem_cmd_u(str+1); // fntPtnに読み込み一文字表示
            else      spiMem_cmd_U(str+1); // データをDBufに読み込み
        }
        if(sgChr==0){                   // 単文字表示モードでないなら
            for(i = 0; i < 16; i++){
                gLCD_nk16X(8*i,32,kp+16*i,8);
            }
        }
    }else{                              // 全角文字の場合
        if(strlen(str)>1){              // アドレスデータ有り
            if(sgChr) spiMem_cmd_u(str); // fntPtnに読み込み一文字表示
            else      spiMem_cmd_U(str); // データをDBufに読み込み
        }
        if(sgChr==0){                   // 単文字表示モードでないなら
            for(i = 0;i < 8; i++){
                gLCD_nk16X(16*i,32,kp+32*i,16);
            }
        }
    }
    SqMode = 0;
    return i;
}

//---- L(文字)表示コマンド  L[n] (文字コード)
void spiMem_cmd_L(char *str){
    char     *pt;                       // 文字列操作用ポインタ
    uint32_t res;                       // Hex文字数値変換結果
    uint16_t ftCd = 0;                  // フォントコード
    
    lstCmd = str[0];
    if(strlen(str)==1){                 // アドレス無し	
        ftCd = lstChr + 1;              // 次文字
    }else{
        pt = strtok(str+1,Dlm);
        if(pt != NULL){                 // アドレス有り?
            res = my_xtoi(pt);
            if(res>0)   ftCd = (uint16_t)res;
        }
    }
    if(ftCd<256)  gLCD_HchrX(0,32,(uint8_t)ftCd);
    else          gLCD_ZchrX(0,32,ftCd,2);
    lstChr = ftCd;
    my_utoa((uint8_t *)SBuf,lstChr,4); my_putsLf(SBuf);
    SqMode = 0;
}

/******* End of File ********/

 
【AQM1248A_v5.c/hファイル】 AQM1248A_v5.c/h + Font_5x7.h(zip)

/******************************(AQM1248A_v5.h)************
 *   Grafic LCD  AQM1248A_m.h 用ライブラリ(FONT別)
 **********************************************************/

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

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

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

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

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

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

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

/*--- バイト単位で16ドットパターン(漢字など)の表示
 *	  表示位置(xpos, ypos)、データ配列(k)
 *    フォントアドレス(*pKj)、 横ドット数(cdt) 
 *  ・戻り: 次表示X文字位置 */
uint8_t gLCD_nk16X(uint8_t xpos, uint8_t ypos, char *pKj, uint8_t cdt);

//---- バイtト単位で半角(8x16)文字表示(次xpos位置を返す)
/*	  表示位置(xpos, ypos)、半角文字コード(chCode)
 *  ・戻り: 次表示X文字位置 */
uint8_t gLCD_HchrX(uint8_t xpos, uint8_t ypos, uint8_t chCode);

//---- バイト単位で半角文字列表示(次xpos位置を返す)-----
/*	  表示位置(xpos, ypos)、半角文字列(*str)
 *  ・戻り: 次表示X文字位置 */
uint8_t gLCD_HstrX(uint8_t xpos, uint8_t ypos, char *str);

//---- バイト単位で行をクリアして半角文字列表示(次xpos位置を返す)
/*	  表示位置(xpos, ypos)、半角文字列(*str)
 *  ・戻り: 次表示X文字位置 */
uint8_t prtHstr_LnClr(uint8_t xpos, uint8_t ypos, char* str);

//---- 漢字フォントアドレス取得
/*      文字コード(JIS) :kCode
 *  ・戻り: フォントアドレス  */
uint32_t KfntAdr(uint16_t kCode);

//---- バイト単位位置で全角(漢字)文字を表示
/*      表示位置(xpos,ypos)、文字コード:kCd(S-JIS)
 *      エンディアン:ed (0:ビッグ、1:リトル)
 *  ・戻り、次表文字位置 */
uint8_t gLCD_ZchrX(uint8_t xpos, uint8_t ypos, uint16_t kCd,uint8_t ed);

//---- バイト単位位置で全角(漢字)文字列を表示
/*      表示位置(xpos,ypos)、文字列:*str (S-JIS)、
 *      エンディアン:ed (0:配列文字、1:文字列)
 *  ・戻り、次表文字位置 */
uint8_t gLCD_ZstrX(uint8_t xpos, uint8_t ypos, char *str,uint8_t ed);

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

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

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

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

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

/*---  ドット単位で16ドットパターン(漢字など)の表示
 *    表示位置(xpos, ypos)、データ配列(k)
 *    データ要素番号(kj)、 横ドット数(cln)
 *    表示色(col、0:白/1:黒/8:反転)
 *  ・戻り: 次表示X文字位置 */
uint8_t Put_nK16(uint8_t xpos, uint8_t ypos, char *k, uint8_t cln, uint8_t col);

//----  ドット単位で半角文字表示(次xpos位置を返す)
/*    表示位置(xpos, ypos)、半角文字コード(chCode)
 *    表示色(col、0:白/1:黒/8:反転)
 *  ・戻り: 次表示X文字位置 */
uint8_t Put_HchrX(uint8_t xpos, uint8_t ypos, uint8_t chCode,uint8_t col);

//----  ドット単位で半角文字列を表示(次xpos位置を返す)
/*    表示位置(xpos, ypos)、半角文字列(*str)
 *    表示色(col、0:白/1:黒/8:反転)
 *  ・戻り: 次表示X文字位置 */
uint8_t Put_HstrX(uint8_t xpos, uint8_t ypos, char *str, uint8_t col);

//----  ドット単位で全角文字表示(次xpos位置を返す)
/*    表示位置(xpos, ypos)、全角文字コード(kCd)、エンディアン(ed)
 *    表示色(col、0:白/1:黒/8:反転)
 *  ・戻り: 次表示X文字位置 */
uint8_t Put_ZchrX(uint8_t xpos, uint8_t ypos, uint16_t kCd, uint8_t ed, uint8_t col);

//----  ドット単位で全角文字列を表示(次xpos位置を返す)
/*    表示位置(xpos, ypos)、半角文字列(*str)、エンディアン(ed)
 *    表示色(col、0:白/1:黒/8:反転)
 *  ・戻り: 次表示X文字位置 */
uint8_t Put_ZstrX(uint8_t xpos, uint8_t ypos, char *str, uint8_t ed, uint8_t col);
【AQM1248A_v5.cファイル】

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

#include "myProject.h"
#include "Font_5x7.h"

#define VRAM_ADR    0x80000
#define LCG_C_SIZE  128

//---  フォントデータアドレス(GT20L16J1Y)  (EEPROM)
#define F_HALF  0x3E7E0     // 半角         0x00200
#define F_SYM   0x00000     // 記号         0x01000
#define F_SYM2  0x00BC0     // 記号2        0x01C00
#define F_NUM   0x01960     // 数字         0x01E00
#define F_ASC   0x01B80     // ASC(大)     0x02000
#define F_ASC2  0x01F80     // ASC2(小)    0x02400
#define F_HIRA  0x02340     // ひらかな     0x02800
#define F_KATA  0x02F00     // カタカナ     0x03260
#define F_KAN1  0x0AA40     // 漢字1水準   0x04000
#define F_KAN2  0x21CE0     // 漢字2水準   -------
#define U_MAP   0x8BC00     // usrFontMap   0x00C00
#define U_FONT  0x8C000     // usrFontDat   0x1C000

#define H_BLANK     0x007F0

static uint8_t vBf[32];     // フォントパターン用バッファー
static uint8_t uMap[128];

const char Z_Small_o[]=     // フォントスモール'o'
            {0x00,0x00,0x00,0x00,0x00,0xC0,0x20,0x10,
             0x10,0x20,0xC0,0x00,0x00,0x00,0x00,0x00,
             0x00,0x00,0x00,0x00,0x00,0x03,0x04,0x08,
             0x08,0x04,0x03,0x00,0x00,0x00,0x00,0x00 };

//--- SPI-vRam アクセス関数
uint8_t vRam_read(uint8_t xpos, uint8_t ypos){
    uint32_t adr;
    adr = VRAM_ADR + (uint32_t)ypos * LCG_C_SIZE + xpos;
    return SPI_Mem_Read(adr);
}

void vRam_write(uint8_t xpos, uint8_t ypos, uint8_t dat){
    uint32_t adr;
    adr = VRAM_ADR + (uint32_t)ypos * LCG_C_SIZE + xpos;
    SPI_Mem_Write(adr, dat);
}

void vRam_Nread(uint8_t xpos,uint8_t ypos,char *ptn,uint8_t n){
    uint32_t adr;
    adr = VRAM_ADR + (uint32_t)ypos * LCG_C_SIZE + xpos;
    SPI_Mem_NRead(adr,(uint8_t *)ptn,n);
}

void vRam_Nwrite(uint8_t xpos,uint8_t ypos,char *ptn,uint8_t n){
    uint32_t adr;
    adr = VRAM_ADR + (uint32_t)ypos * LCG_C_SIZE + xpos;
    SPI_Mem_NWrite(adr,(uint8_t *)ptn,n);
}

//-------- G-LCDを初期化 ------------------------------------
void gLCD_int(void){
    gCS_SetLow();                   // gLCDセレクト有効
    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();                  // gLCDセレクト無効
}

//-------- G-LCDのデータを全消去(指定データで埋める)---
void gLCD_clr(char dat){			
    uint8_t x, y;
    gCS_SetLow();                   // gLCDセレクト有効
    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++){
            SPI1_ExchangeByte(dat);
        }
    }
    gCS_SetHigh();                  // gLCDセレクト無効
    for(y = 0; y < 6; y++){
        for(x = 0; x < 128; x++){
            vRam_write(x,y,dat);    // vRamクリア
        }
    }
}

//-------- カーソル位置指定 -----------------------------------
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, sx, yAdr, ptn;
    chr -= 0x20;                    //配列アドレスを計算
    gLCD_posXY(xpos, ypos);         //表示位置を指定
    sx = xpos;                      // posxを保存
    yAdr = ypos >> 3;
    gCS_SetLow();                   // チップセレクト有効
    gRS_SetHigh();                  // 表示データ指定
    for(i = 0; i < 5; i++) {        //データを順に取得
        ptn = Font[chr][i];
        if(ptn == 0xFF)  break;     //幅狭文字なら抜ける
        vBf[i] = ptn;
        SPI1_ExchangeByte(ptn);
        xpos++;
    }
    vBf[i] = 0;
    SPI1_ExchangeByte(0);           //文字間隔を空ける
    xpos++;
    gCS_SetHigh();                  // チップセレクト無効
    vRam_Nwrite(sx,ypos,(char *)vBf, i);  // vRamに書き込む 
    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++){
         SPI1_ExchangeByte(*(ptn + i));
    }
    gCS_SetHigh();                  // チップセレクト無効
    vRam_Nwrite(xpos,ypos,ptn,n);
    return xpos + n;                // 次表示位置を返す
}

//---- バイト単位でn個の指定データで埋める(次xpos位置を返す)
uint8_t LCD_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++) {
        SPI1_ExchangeByte(dat);
    }
    gCS_SetHigh();                  // チップセレクト無効
    for(i=0;i<// 次開始位置を返す
}

//---- バイト単位で(縦)16ドットパターン(漢字など)の表示
/*  xpos: X位置、   ypos: Y位置
 *  *pKj: 漢字パターンデータポインタ、 cdt: 漢字横ドット数
 *---------------------------------------------------- */
uint8_t gLCD_nk16X(uint8_t xpos, uint8_t ypos, char *pKj, uint8_t cdt){
    gLCD_ptnX(xpos, ypos,(char *)pKj, cdt); 
    xpos = gLCD_ptnX(xpos, ypos+8, (char *)(pKj + cdt),cdt);
    return xpos;
}

//---- 半角(8x16)文字表示(次xpos位置を返す)-----
uint8_t gLCD_HchrX(uint8_t xpos, uint8_t ypos, uint8_t chCode){

    uint32_t adr;
    if((chCode >= 0x20) & (chCode < 0x7F)){
        adr = (chCode - 0x20) * 16 + F_HALF;
    }else{
        adr = H_BLANK;              // 半角ブランク表示
    }
    SPI_Mem_NRead(adr,(uint8_t *)vBf,16);
    xpos = gLCD_nk16X(xpos, ypos, (char *)vBf, 8);        
    return xpos;
}

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

//--- 行をクリアして半角文字列表示(次xpos位置を返す)
uint8_t prtHstr_LnClr(uint8_t xpos, uint8_t ypos,char* str){
    gLCD_clrX(0,ypos  ,0,LCG_C_SIZE);
    #ifdef FONT_ROM
        gLCD_clrX(0,ypos+8,0,LCG_C_SIZE);
        return gLCD_HstrX(xpos,ypos,str);
    #else
        return  gLCD_strX(xpos,ypos,str);
    #endif
}

//--- ユーザー漢字マップ読出し
void read_UsrMap(uint8_t p){
    uint32_t ad;
    ad = U_MAP + p * 128;
    SPI_Mem_NRead(ad,uMap,128);
}

//--- ユーザー文字格納アドレス取得
uint32_t get_UFntAdr(uint16_t kCode){
    uint8_t pg,i;
    uint16_t *usrP;
    usrP = (uint16_t*)uMap;
    for(pg = 0; pg < 8; pg++){
        read_UsrMap(pg);
        for(i = 0; i < 64; i++){
            if(*usrP == 0xFFFF) return 0;
            if(*usrP == kCode)  return U_FONT + pg * 2048 + i * 32;
            usrP++;
        }
    }
    return 0;
}

/*--- JISー>シフトJIS変換
uint16_t Jis2SJis(uint16_t jCd){
    uint8_t hi,lo;
    hi = jCd >> 8;
    lo = (uint8_t)jCd;
    if(hi && 1){
        if(lo < 0x60)   lo = lo + 0x1F;
        else            lo = lo + 0x20;
    }else{              lo = lo + 0x7E;
    }
    if(hi < 0x5F)       hi = (hi + 0xE1) >> 1;
    else                hi = (hi + 0x161) >> 1;
    return (hi * 256 + lo);
}
*/
//---- シフトJISー>JIS変換
uint16_t SJis2Jis(uint16_t sCd){
    uint8_t hi,lo;
    hi = sCd >> 8;
    lo = (uint8_t)sCd;
    if(hi <= 0x9F){
        if(lo < 0x9F)   hi = hi * 2 - 0xE1;
        else            hi = hi * 2 - 0xE0;
    }else{
        if(lo < 0x9F)   hi = (hi - 0xB0) * 2 - 1;
        else            hi = (hi - 0xB0) * 2;
    }
    if(lo < 0x7F)       lo = lo - 0x1F;
    else{
        if(lo < 0x9F)   lo = lo - 0x20;
        else            lo = lo - 0x7E;
    }
    return (hi * 256 + lo);
}

//--- 全角(漢字)フォントアドレス取得)
uint32_t KfntAdr(uint16_t kCode){
    uint8_t msb, lsb;
    uint32_t lmsb, llsb;
    msb = kCode >> 8;
    lsb = (uint8_t)kCode & 0x000FF;
    lmsb = (uint32_t)msb;
    llsb = (uint32_t)lsb;
    if(msb>=0x21 & msb<0x30){
        if(msb==0x21){                      // 記号1
            if(lsb>=0x21 & lsb<=0x7E) return F_SYM + (lsb-0x21)*32;
            else                      return get_UFntAdr(kCode);
        }else if(msb==0x22){                // 記号2
            if(lsb>=0x21 & lsb<=0x2E) return F_SYM2 + (lsb-0x21)*32;
            else                      return get_UFntAdr(kCode);
        }else if(msb==0x23){                // ASCII
            if(lsb>=0x30 & lsb<=0x39) return F_NUM + (lsb-0x30)*32;
            if(lsb>=0x41 & lsb<=0x5A) return F_ASC + (lsb-0x41)*32;
            if(lsb>=0x61 & lsb<=0x7A) return F_ASC2 + (lsb-0x61)*32;
            else                      return get_UFntAdr(kCode);
        }else if(msb==0x24){                // ひらかな
            if(lsb>=0x21 & lsb<=0x73) return F_HIRA + (lsb-0x21)*32;
            else                      return get_UFntAdr(kCode);
        }else if(msb==0x25){                // カタカナ
            if(lsb>=0x21 & lsb<=0x76) return F_KATA + (lsb-0x21)*32;
            else                      return get_UFntAdr(kCode);
        }
    }else if(msb<0x50){                     // 漢字(第1水準)
        if(lsb>=0x21 & lsb<=0x7E) return F_KAN1 + (lmsb-0x30)*3008+(llsb-0x21)*32;
        else                      return get_UFntAdr(kCode);
    }else if(msb<0x75){                     // 漢字(第2水準)GT20L16J1Y使用時のみ
        if(lsb>=0x21 & lsb<=0x7E) return F_KAN2 + (lmsb-0x50)*3008+(llsb-0x21)*32;
        else                      return get_UFntAdr(kCode);
    }
	return get_UFntAdr(kCode);
}

//---- バイト一単位で全角(漢字)文字表示
uint8_t gLCD_ZchrX(uint8_t xpos, uint8_t ypos, uint16_t kCd,uint8_t ed){
    uint32_t adr;
    uint16_t kk;
    uint8_t h,l;
    if(ed & 0x01){
        h = (uint8_t)(kCd>>8);
        l = (uint8_t)kCd;
        kCd = l*256+h;
    }
//    if(kCd == 0x828F) return gLCD_nk16X(xpos,ypos,(char *)Z_Small_o,16);
    if(ed < 2)  kk = SJis2Jis(kCd);
    else        kk = kCd;
    if(kk == 0x236F) return gLCD_nk16X(xpos,ypos,(char *)Z_Small_o,16);
    adr = KfntAdr(kk);
//    printf(" %X %lX\r",kk,adr);
    SPI_Mem_NRead(adr,(uint8_t *)vBf,32);
    if(adr)	return gLCD_nk16X(xpos,ypos,(char *)vBf,16);
    return xpos;
}

//---- バイト単位位置で全角(漢字)文字列表示
uint8_t LCD_ZstrX(uint8_t xpos, uint8_t ypos, char *str,uint8_t ed){
    uint16_t cd, *kjP;
    kjP = (uint16_t *)str;
    while(*kjP & 0xFF){
        xpos = gLCD_ZchrX(xpos,ypos,*kjP,ed);
        kjP++;
    }
    return xpos;
}		

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

//-------ドット単位で文字を描く(次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関数定義

void swap_uint8_t(uint8_t *a, uint8_t *b){
    uint8_t tmp; tmp = *a; *a = *b; *b = tmp;
}
#define ABS(a)    (((a)>0) ? (a) : -(a))

//----------ドット単位で直線を描く-------------------
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_uint8_t(&x0,&y0); swap_uint8_t(&x1,&y1); }
    if(x0 > x1){  swap_uint8_t(&x0,&x1); swap_uint8_t(&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;
        }
    }
}

//---- ドット単位で(縦)16ドットパターン(漢字など)の表示(次xpos位置を返す)
/*  xpos: X位置、   ypos: Y位置,        col: 表示モード
 *  *pKj: 漢字パターンデータポインタ、  cdt: 漢字横ドット数
 *---------------------------------------------------- */
uint8_t Put_nK16(uint8_t xpos, uint8_t ypos, char *pKj, uint8_t cdt, uint8_t col){
    gLCD_PutPtn(xpos, ypos, (char *)pKj, cdt, col); 
    xpos = gLCD_PutPtn(xpos, ypos+8, (char *)(pKj + cdt),cdt, col);
    return xpos;
}

//---- ドット単位で半角文字表示(次xpos位置を返す)
uint8_t Put_HchrX(uint8_t xpos, uint8_t ypos, uint8_t chCode,uint8_t col){
    uint32_t adr;
    if((chCode >= 0x20) & (chCode < 0x7F)){
        adr = (chCode - 0x20) * 16 + F_HALF;
    }else{
        adr = H_BLANK;                  // 半角ブランク
    }
    SPI_Mem_NRead(adr,(uint8_t *)vBf,16);
    xpos = Put_nK16(xpos, ypos, (char *)vBf, 8, col);
    return xpos;
}

//---- ドット単位で半角文字列を表示(次xpos位置を返す)
uint8_t Put_HstrX(uint8_t xpos, uint8_t ypos, char *str, uint8_t col){
    while(*str)  xpos = Put_HchrX(xpos, ypos, *str++, col);
    return xpos;                        //次表示位置を返す
}

//---- ドット単位で全角(漢字)文字表示
uint8_t Put_ZchrX(uint8_t xpos, uint8_t ypos, uint16_t kCd, uint8_t ed, uint8_t col){
    uint32_t adr;
    uint16_t kk;
    uint8_t h,l;
    if(ed & 0x01){
        h = (uint8_t)(kCd>>8);
        l = (uint8_t)kCd;
        kCd = l*256+h;
    }
    if(ed < 2)  kk = SJis2Jis(kCd);
    else        kk = kCd;
    if(kk == 0x236F)
		return Put_nK16(xpos,ypos,(char *)Z_Small_o,16, col);
    adr = KfntAdr(kk);
    SPI_Mem_NRead(adr,(uint8_t *)vBf,32);
    if(adr)	return Put_nK16(xpos,ypos,(char *)vBf,16, col);
    return xpos;
}

//---- ドット単位で全角(漢字)文字列表示
uint8_t Put_ZstrX(uint8_t xpos, uint8_t ypos, char *str, uint8_t ed, uint8_t col){
    uint16_t cd, *kjP;
    kjP = (uint16_t *)str;
    while(*kjP & 0xFF){
        xpos = Put_ZchrX(xpos,ypos,*kjP,ed,col);
        kjP++;
    }
    return xpos;
}

/*****  End of File   *****/

【EUSART】   EUSARTの設定 (abc900)
USBシリアル通信の設定
【PICライブラリ】 ライブラリの使い方 (abc840)
使用するライブラリの追加など
【MCCの設定】  MCC設定例 (abc895)
MCCでSPIを使う場合(一部のピン設定は変更すること)


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


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


JoySTick付きリモコン ご当地ナンバープレート PICミニBB(16)_市販漢字フォントROM