Vol.895 31.May.2024

コンプレッサーの選び方 PICミニBB(5)_SPI接続グラフィックLCDユニット

C コンプレッサーの選び方

by fjk

 タイヤ交換時にコンプレッサーを利用しているが、購入からかなり時間がたっており、少しエアーが漏れているようなのでそろそろ交換時期かなと思い、購入時に確認すべき仕様について纏めてみた。

  1. ポンプ方式・騒音
    オイルフリー ○:クリーンエアー、オイル交換不要
    ×:耐久性・連続使用時間に制限
    給油式 ○:連続使用、低騒音・低振動
    ×:オイルミスト、オイル交換
  2. 吐出空気圧(出力)と用途
      3馬力以上は家庭用コンセントの電気容量を超えるので、2馬力までが選択子。
       
  3. タンク容量
    容 量主な用途
    〜8Lエアブラシ(細かな塗装)
    8L〜タイヤの空気入れ、短時間の埃飛ばし、エアタッカー、釘打ち機 
    30L〜タイヤ交換、エアダスター、スプレーガン、サンドブラスト
    50L〜連続使用エア工具
  4. タンク内圧力
     0.8〜4.5Mpaのものがあるが、家庭用では0.8または1.0Mpaがほとんど。

 すなわち、家庭用では1馬力、タンク容量が30Lを選択しておくと無難。
 騒音を気にするなら、給油(オイル)式の静音タイプが選択子。


P PICミニBBシリーズ(5)  〜SPI接続グラフィックLCDユニット

by fjk

 秋月電子で売られているSPI接続の「超小型グラフィックLCD」(AQM1248A、ピッチ変換キット、秋月#107007、800円)にPICで文字を表示してみた。なお、AQM1248Aは3.3Vで動作するため、PICを5Vで使う場合、SPI信号レベルの変換を行う必要が有り、このレベル変換用として「4ビット双方向ロジックレベル変換モジュール」(AE-LCNV4、秋月#113837、200円)と3.3Vの3端子レギュレータ(LM2950G-3.3、秋月#116990、160円)を用いた。
 マスターとなるPIC-BASIC-spiはPIC16F18325(秋月#110890、220円)を用い、gLCDユニットとは10ピンのコネクタを使用した(abc894等と配線が少し異なる)。なお、グラフィックBB側の未使用のコネクタピンは、BB上で信号がぶつからないよう、ラジオペンチで抜いている


SPI接続グラフィックLCD回路図

グラフィックLCDボード配線図

MCCのpinmodule設定

MCCのsystem設定

MCCのSPI設定

 今回、プログラムを簡単にするため、文字表示位置のX(水平)方向は任意の位置に指定可能だが、Y(垂直)方向は8ドット(LCDのバイト)単位の位置とした(Y座標の8ドット未満は無視)。
 文字フォントはグラフィック表示できるので「はじめてのPIC2」さんの5x7ドットプロポーショナルフォントを利用させていただいた。
 さて、MMCでGenerateし、プログラムを書き込んで、実行(run)してみるが・・、何故かSPIが動作していない。オシロで確認すると、クロックが出ていない!!。
 そこで、ネットで調べて見ると、「ENGピカ」さんのページに、その問題と解決策が紹介されていた。その内容は、

MCCで生成されたSPI1_Initialize()関数が初期化時にコールされますが、SPIが許可されないため、別途レジスタを操作してSPIをスタートする必要があります。そこで、system初期化後に以下を記述を追加:
    SSP1CON1bits.SSPEN = 1;

 この問題は、MCCのMSSP1で、RegstersのSSP1CON1のSSPENをenableに変更し、Generateしても、SPI1_Initialize()関数の最後で「SSP1CON1bits.SSPEN = 0;」とされているので、MCC設定とうりには反映されない(MCCのバグ?、ここで変更しても良い)。

 ということで、上記の記述を追加すると、無事SPIが動作し、AQM1248AグラフィックLCDに文字などを表示することができた。
 今回、SPIの通信クロックとして、I2C(100kHz)よりも早い2MHzを使用したが、正常に通信することができた。
 なお、5V電源としても使用しているUSBによるパソコンとのターミナル通信はデバッグ(動作確認)用で、動作モニターとして使用しないのであればEUSARTの設定(およびputs)は不要。(EUSARTの設定はabc889を参照)


AQM1248Aにデモ表示中

AQM1248A画面の拡大

【参考とした・・】
*1)「逆引きPIC電子工作やりたいこと事典」(後閑哲也、技術評論社)
*2)「はじめてのPIC-2」さん
*3)「畑から」さん

【プログラム】 abc895-18325.c(zip)
※ライブラリにバグがあったのと、全関数をテストするためのプログラムに修正しました。(6/2)

/*******************************(abc895-18325)******
 *   Graphic LCD (AQM1248A) test  
 ***************************************************/

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

char     sBf[BFSIZE];       // 文字列作業エリア
char     rBuf[BFSIZE];      // シリアル受信バッファ
uint8_t  sFlg;              // シリアル受信フラグ

char gptn[] = { 0x01,0x03,0x07,0x0F,
                0x1F,0x3F,0x7F,0xFF,
                0xFE,0xFC,0xF8,0xF0,
                0xE0,0xC0,0x80,0x00 };

/*-----------------------------------
 *        Main application
 ------------------------------------*/
void main(void){
    char ch;
    uint8_t xpos;

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

    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();

    gLCD_int();
    gLCD_clr(0);

    puts("-- Hellow AQM1248A ! --\n")  // 動作確認用

    while (1){
        gLCD_posyx(0,0);
        gLCD_str("-- Hellow AQM1248A ! --");
        gLCD_chr(0x22);
        gLCD_posyx(8,0);
        for(ch = 0x23; ch < 0x3A; ch++){
            gLCD_chr(ch);
        }
        gLCD_posyx(16,0);
        for(ch = 0x40; ch < 0x50; ch++){
            gLCD_chr(ch);
        }
        gLCD_posyx(24,0);
        gLCD_str("PQRSTUVWXYZ");
        gLCD_clrX(0xCA,24,100,20);     
        xpos = 0;
        for(ch = 0x60; ch < 0x70; ch++){
            xpos = gLCD_chrX(ch,32,xpos);
        }
        gLCD_strX("pqrstuvwxyz",40,0);
        xpos = gLCD_ptnX(gptn,40,100,16);
        xpos = gLCD_ptnX(gptn,40,xpos,16);   
    }
}

【AQM1248Aライブラリ】
 SPI通信でAQM1248Aにコマンドやデータを送信するには、SPI1_ExchangeByte()関数を用いた。
 送信手順は、AQM1248AのCSをLowにし、続いてRSをLowにしてコマンド送り、それからRSをHighに指定しデータを送る。送信終了後は、他のデバイスとぶつからないよう、CSをHighに戻しておく。
 データのブロック通信用としてSPI1_ExchangBlock()関数があるが、blockにパターンデータを指定したところ、何故か全て0xFFデータとして表示されたので、SPI1_ExchangeByte()関数を繰り返し使用した(今後の課題)。なお、gLCD_clrX()関数は任意のエリアを消去(塗りつぶす)ことができる。

AQM1248A.c/h(zip)

/***********************************(AQM1248A.c)********
 *     RC3  gRS     0:コマンド  1:データ
 *     RA2  gCS     0:有効      1:無効
 *     RC2  spiSDO
 *     RC0  spiSCK     idle時:Hi   SCKの立下でデータ変更
 **********************************************************/

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

//-------- 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
                               //--内部レギュレータをON
    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_chr (char dat){
    char i,ptn;
    dat -= 0x20;                    //配列アドレスを計算
    gCS_SetLow();
    gRS_SetHigh();
    for(i=0; i<5; i++) {
        ptn = Font[dat][i];
        if(ptn == 0xFF) break;      //幅狭文字なら抜ける
        SPI1_ExchangeByte(ptn);
    }
    SPI1_ExchangeByte(0);
    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++){
            SPI1_ExchangeByte(dat);
        }			
    }
    gCS_SetHigh();                  // チップセレクト無効
}

//-------- カーソル位置指定 -----------------------------------
void gLCD_posyx(uint8_t ypos, uint8_t xpos){
    gCS_SetLow();                   // チップセレクト有効
    gRS_SetLow();                   // コマンド指定
                                // ページを指定
    SPI1_ExchangeByte(0xB0 | (ypos >> 3));
                                    // ページ内RAMアドレスを分割指定
    SPI1_ExchangeByte(0x10 | (xpos >> 4));
    SPI1_ExchangeByte(xpos & 0xF);
    gCS_SetHigh();                  // チップセレクト無効
}

//-------- 文字列出力 ------------------------------------------
void gLCD_str(char *str){			
    while(*str)                     //文字列終端まで継続
        gLCD_chr(*str++);           //文字出力
}

//-------- 指定位置に文字表示(次xpos位置を返す) ---------
uint8_t gLCD_chrX(char dat, uint8_t ypos, uint8_t xpos){
    uint8_t i,ptn;					
    dat -= 0x20;                    //配列アドレスを計算
    gLCD_posyx( ypos, xpos);        //表示位置を指定
    gCS_SetLow();                   // チップセレクト有効
    gRS_SetHigh();                  // 表示データ指定
    for(i = 0; i < 5; i++) {        //データを順に取得
        ptn = Font[dat][i];
        if(ptn == 0xFF)  break;     //幅狭文字なら抜ける
        SPI1_ExchangeByte(ptn);
    }                 
    SPI1_ExchangeByte(0);           //文字間隔を空ける
    gCS_SetHigh();                  // チップセレクト無効
    return i + 1 + xpos;            //次表示位置を返す
}

//-------- 指定位置から文字列表示(次xpos位置を返す)-----
uint8_t gLCD_strX(char *str, uint8_t ypos, uint8_t xpos){
    while(*str)                     //文字列終端まで継続
        xpos = gLCD_chrX(*str++, ypos, xpos);
    return xpos;                    //次表示位置を返す
}

//-------- 指定位置からパターンを表示(次xpos位置を返す)----
uint8_t gLCD_ptnX(char *ptn, uint8_t ypos, uint8_t xpos, uint8_t n){
    uint8_t i;
    gLCD_posyx(ypos, xpos);         // 表示位置を指定
    gCS_SetLow();                   // チップセレクト有効
    gRS_SetHigh();                  // 表示データ指定
    for(i=0; i < n;i++){
         SPI1_ExchangeByte(ptn[i]);
    }
//    SPI1_ExchangeBlock(ptn, n);   // ブロックデータ送信
    gCS_SetHigh();                  // チップセレクト無効
    return xpos + n;                // 次表示位置を返す
}

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

/******************************(AQN1248A.h)***************
 *   Grafic LCD  AQM1248A.h 用ライブラリ
 *   (5x7dotのプロポーショナル文字パターン付き)
 **********************************************************/
/*  G_LCDを初期化する
 *	gLCD_int(void); */
void gLCD_int(void);

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

/*  G_LCDにchコードの文字パターンを表示
 *	gLCD_chr(ch);
 *	  表示文字コード(ch) */
void gLCD_chr(char );

/*  文字列strをG_LCDに表示する
 *	gLCD_str(*str);
 *	  表示文字列(*str) */
void gLCD_str(char *);

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

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

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

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

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

/*********************************************************
 * キャラクタデータ (ASCII 0x20-0x7F) 
 *      5dotない幅の狭いフォント(!など)は0xFFで終端
**********************************************************/
const char Font[96][5]={
        {0x00,0x00,0xFF,0x00,0x00},     // 0x20, Space
        {0x5F,0xFF               },     // 0x21, ! x
        {0x00,0x07,0x00,0x07,0x00},     // 0x22, " x
        {0x14,0x7F,0x14,0x7F,0x14},     // 0x23, #
        {0x24,0x2A,0x7F,0x2A,0x12},     // 0x24, $
        {0x27,0x15,0x6B,0x54,0x72},     // 0x25, %
        {0x36,0x49,0x56,0x20,0x50},     // 0x26, &
        {0x0B,0x07,0x00,0xFF     },     // 0x27, ' x
        {0x1C,0x22,0x41,0xFF     },     // 0x28, ( x
        {0x41,0x22,0x1C,0xFF     },     // 0x29, ) x
        {0x2A,0x1C,0x7F,0x1C,0x2A},     // 0x2a, *
        {0x08,0x08,0x3E,0x08,0x08},     // 0x2b, + x
        {0x58,0x38,0xFF          },     // 0x2c, , x
        {0x08,0x08,0x08,0x08,0x08},     // 0x2d, -
        {0x60,0x60,0xFF          },     // 0x2e, . x
        {0x20,0x10,0x08,0x04,0x02},     // 0x2f, /
        {0x3E,0x51,0x49,0x45,0x3E},     // 0x30, 0
        {0x42,0x7F,0x40,0xFF     },     // 0x31, 1 x
        {0x72,0x49,0x49,0x49,0x46},     // 0x32, 2
        {0x22,0x41,0x49,0x49,0x36},     // 0x33, 3
        {0x18,0x14,0x12,0x7F,0x10},     // 0x34, 4
        {0x27,0x45,0x45,0x45,0x39},     // 0x35, 5
        {0x3C,0x4A,0x49,0x49,0x30},     // 0x36, 6
        {0x01,0x71,0x09,0x05,0x03},     // 0x37, 7
        {0x36,0x49,0x49,0x49,0x36},     // 0x38, 8
        {0x06,0x49,0x49,0x29,0x1E},     // 0x39, 9
        {0x36,0x36,0xFF,0x00     },     // 0x3a, : x
        {0x5B,0x3B,0xFF,0x00     },     // 0x3b, ; x
        {0x08,0x14,0x22,0x41,0xFF},     // 0x3c, < x
        {0x14,0x14,0x14,0x14,0x14},     // 0x3d, =
        {0x41,0x22,0x14,0x08,0xFF},     // 0x3e, > x
        {0x02,0x01,0x51,0x09,0x06},     // 0x3f, ?
        {0x32,0x49,0x79,0x41,0x3E},     // 0x40, @
        {0x7C,0x12,0x11,0x12,0x7C},     // 0x41, A 
        {0x41,0x7F,0x49,0x49,0x36},     // 0x42, B 
        {0x3E,0x41,0x41,0x41,0x22},     // 0x43, C 
        {0x41,0x7F,0x41,0x41,0x3E},     // 0x44, D 
        {0x7F,0x49,0x49,0x41,0x41},     // 0x45, E 
        {0x7F,0x09,0x09,0x01,0x01},     // 0x46, F 
        {0x3E,0x41,0x49,0x49,0x3A},     // 0x37, G 
        {0x7F,0x08,0x08,0x08,0x7F},     // 0x48, H 
        {0x41,0x7F,0x41,0xFF     },     // 0x49, I
        {0x20,0x40,0x41,0x3F,0x01},     // 0x4a, J 
        {0x7F,0x08,0x14,0x22,0x41},     // 0x4b, K 
        {0x7F,0x40,0x40,0x40,0x40},     // 0x4c, L 
        {0x7F,0x02,0x0C,0x02,0x7F},     // 0x4d, M 
        {0x7F,0x02,0x04,0x08,0x7F},     // 0x4e, N 
        {0x3E,0x41,0x41,0x41,0x3E},     // 0x4f, O 
        {0x7F,0x09,0x09,0x09,0x06},     // 0x50, P 
        {0x3E,0x41,0x51,0x21,0x5E},     // 0x51, Q
        {0x7F,0x09,0x19,0x29,0x46},     // 0x52, R 
        {0x26,0x49,0x49,0x49,0x32},     // 0x53, S 
        {0x01,0x01,0x7F,0x01,0x01},     // 0x54, T 
        {0x3F,0x40,0x40,0x40,0x3F},     // 0x55, U 
        {0x07,0x18,0x60,0x18,0x07},     // 0x56, V 
        {0x7F,0x20,0x18,0x20,0x7F},     // 0x57, W 
        {0x63,0x14,0x08,0x14,0x63},     // 0x58, X 
        {0x03,0x04,0x78,0x04,0x03},     // 0x59, Y 
        {0x61,0x51,0x49,0x45,0x43},     // 0x5a, Z 
        {0x00,0x7F,0x41,0x41,0xFF},     // 0x5b, [ x
        {0x02,0x04,0x08,0x10,0x20},     // 0x5c,  
        {0x41,0x41,0x7F,0x00,0xFF},     // 0x5d, ] x
        {0x04,0x02,0x01,0x02,0x04},     // 0x5e, ^ 
        {0x40,0x40,0x40,0x40,0x40},      // 0x5f, _
        {0x00,0x03,0x04,0xFF,0xFF},     // 0x60, ` x
        {0x20,0x54,0x54,0x54,0x38},     // 0x61, a
        {0x7F,0x28,0x44,0x44,0x38},     // 0x62, b
        {0x38,0x44,0x44,0x44,0xFF},     // 0x63, c x
        {0x38,0x44,0x44,0x28,0x7F},     // 0x64, d
        {0x38,0x54,0x54,0x54,0x18},     // 0x65, e
        {0x08,0x3F,0x09,0x09,0x02},     // 0x66, f
//        {0x08,0x54,0x54,0x54,0x3C},   // 0x67, g
        {0x18,0xA4,0xA4,0x9C,0x78},     // 0x67, g
        {0x7F,0x08,0x04,0x04,0x78},     // 0x68, h
        {0x44,0x7D,0x40,0xFF     },     // 0x69, i x
        {0x20,0x40,0x44,0x3D,0xFF},     // 0x6a, j x
        {0x7F,0x10,0x28,0x44,0xFF},     // 0x6b, k x
        {0x41,0x7F,0x40,0xFF     },     // 0x6c, l x
        {0x7C,0x04,0x78,0x04,0x78},     // 0x6d, m
        {0x7C,0x08,0x04,0x04,0x78},     // 0x6e, n
        {0x38,0x44,0x44,0x44,0x38},     // 0x6f, o
//        {0x7C,0x14,0x14,0x14,0x08},   // 0x70, p
        {0xFC,0x18,0x24,0x24,0x18},     // 0x70, p
//        {0x08,0x14,0x14,0x14,0x7C},   // 0x71, q
        {0x18,0x24,0x24,0x18,0xFC},     // 0x71, q
        {0x7C,0x08,0x04,0x04,0x08},     // 0x72, r
        {0x48,0x54,0x54,0x54,0x24},     // 0x73, s
        {0x04,0x3F,0x44,0x44,0xFF},     // 0x74, t x
        {0x3C,0x40,0x40,0x20,0x7C},     // 0x75, u
        {0x1C,0x20,0x40,0x20,0x1C},     // 0x76, v
        {0x3C,0x40,0x30,0x40,0x3C},     // 0x77, w
        {0x44,0x28,0x10,0x28,0x44},     // 0x78, x
        {0x0C,0x90,0x90,0x90,0x7C},     // 0x79, y
        {0x24,0x64,0x54,0x4C,0x24},     // 0x7a, z
        {0x08,0x36,0x41     ,0xFF},     // 0x7b, x
        {0x00,0x7F,0x00     ,0xFF},     // 0x7c, | x
        {0x41,0x36,0x08     ,0xFF},     // 0x7d, } x
        {0x02,0x01,0x02,0x04,0x02},     // 0x7e, ~ x
        {0x7F,0x7F,0x7F,0x7F,0x7F},     // 0x7f, DELx
    };


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


コンプレッサーの選び方 PICミニBB(5)_SPI接続グラフィックLCDユニット