勉強しないとな~blog

ちゃんと勉強せねば…な電気設計エンジニアです。

マイコンと加速度センサでタコメータを作る - 12. メータモード実装

早くRXタコメータを仕上げたい事情が出てきたので、まだ評価作業に微妙なところはありますが、タコメータとして動かせるように機能を実装したいと思います。

タコメータ機能

基本的には、現在の回転数[rpm]を液晶に数字で表示したいと思います。
本当に単純ですが、こんな感じ。

f:id:nokixa:20201205231627p:plain

f:id:nokixa:20201205232658j:plain:w400

  • 真ん中に大きく表示
  • 単位(rpm)も表示しておく
  • 緑色が目に優しいかと、背景は黒か

タコメータ実装

既にFFTグラフリアルタイム表示機能を実装していて、FFT動作周りは同じ処理になります。
回転数の推定(ピーク位置探索およびrpm計算)、LCD表示あたりが新しく実装しないといけないところです。

表示用フォント

GitHubリポジトリのリンクを再掲します。

GitHub - hubnoki/RXtacho: Designing tachometer using RX220

LCD表示について、今は1文字あたり5x8ドットサイズのデータを用意して、これで文字表示を行っています。(ソースコードfont.c,font.h)

このフォントデータは、以下のサイトからもらってきました。

libstock.mikroe.com

実際にLCDに表示してみた様子。

f:id:nokixa:20201206222145j:plain:w500

これを元に、数字とrpmの表示だけ大きなフォントを用意し、LCD表示を行いたいと思います。

typedef struct{
    unsigned char f[5];
}FONT_DATA;

extern const FONT_DATA font[];
const FONT_DATA font[]=
{
     {{0x00, 0x00, 0x00, 0x00, 0x00}} // 20
    ,{{0x00, 0x00, 0x5f, 0x00, 0x00}} // 21 !
    ,{{0x00, 0x07, 0x00, 0x07, 0x00}} // 22 "
    ,{{0x14, 0x7f, 0x14, 0x7f, 0x14}} // 23 #
    ,{{0x24, 0x2a, 0x7f, 0x2a, 0x12}} // 24 $
    ,{{0x23, 0x13, 0x08, 0x64, 0x62}} // 25 %
    ,{{0x36, 0x49, 0x55, 0x22, 0x50}} // 26 &
    ,{{0x00, 0x05, 0x03, 0x00, 0x00}} // 27 '
    ,{{0x00, 0x1c, 0x22, 0x41, 0x00}} // 28 (
    ,{{0x00, 0x41, 0x22, 0x1c, 0x00}} // 29 )
    ,{{0x14, 0x08, 0x3e, 0x08, 0x14}} // 2a *
    ,{{0x08, 0x08, 0x3e, 0x08, 0x08}} // 2b +
    ,{{0x00, 0x50, 0x30, 0x00, 0x00}} // 2c ,
    ,{{0x08, 0x08, 0x08, 0x08, 0x08}} // 2d -
    ,{{0x00, 0x60, 0x60, 0x00, 0x00}} // 2e .
    ,{{0x20, 0x10, 0x08, 0x04, 0x02}} // 2f /
    ,{{0x3e, 0x51, 0x49, 0x45, 0x3e}} // 30 0
    ,{{0x00, 0x42, 0x7f, 0x40, 0x00}} // 31 1
    ,{{0x42, 0x61, 0x51, 0x49, 0x46}} // 32 2
    ,{{0x21, 0x41, 0x45, 0x4b, 0x31}} // 33 3
    ...

unsigned char型の5個の配列で、5x8ドットの文字を表しています。

LCD自体は160x128の解像度ですが、1文字20x32ドット(元の4倍)くらいにすれば数字4桁+rpm は表示されそうなので、そうしてみます。

4倍フォント

以下のように4倍フォントを用意しました。

  • font.hで、FONT_DATA_X4型を用意 (unsigned int型を20個で1文字)
  • FONT_DATA_X4型の配列font_x4[]
#define W_FONT_X4 20

typedef struct{
    unsigned int f[W_FONT_X4];
}FONT_DATA_X4;

extern const FONT_DATA_X4 font_x4[];
  • font.cで、元のフォントデータ(font[])を元に、4倍フォント(font_x4[])を作成
    • 今回使っているRX220のRAM(16KB)にはとても入りませんが、ROM(256KB)には十分入るので、定数となるようにして、ROMに入れてもらうことを期待します。
  • まず、8bitデータを32bitデータに拡張するマクロを用意
#define BYTE_X4(d) \
( ((((unsigned int)d) >> 7) & 0x1) << 31 ) \
( ((((unsigned int)d) >> 7) & 0x1) << 30 ) \
( ((((unsigned int)d) >> 7) & 0x1) << 29 ) \
( ((((unsigned int)d) >> 7) & 0x1) << 28 ) \
( ((((unsigned int)d) >> 6) & 0x1) << 27 ) \
( ((((unsigned int)d) >> 6) & 0x1) << 26 ) \
( ((((unsigned int)d) >> 6) & 0x1) << 25 ) \
( ((((unsigned int)d) >> 6) & 0x1) << 24 ) \
( ((((unsigned int)d) >> 5) & 0x1) << 23 ) \
( ((((unsigned int)d) >> 5) & 0x1) << 22 ) \
( ((((unsigned int)d) >> 5) & 0x1) << 21 ) \
( ((((unsigned int)d) >> 5) & 0x1) << 20 ) \
( ((((unsigned int)d) >> 4) & 0x1) << 19 ) \
( ((((unsigned int)d) >> 4) & 0x1) << 18 ) \
( ((((unsigned int)d) >> 4) & 0x1) << 17 ) \
( ((((unsigned int)d) >> 4) & 0x1) << 16 ) \
( ((((unsigned int)d) >> 3) & 0x1) << 15 ) \
( ((((unsigned int)d) >> 3) & 0x1) << 14 ) \
( ((((unsigned int)d) >> 3) & 0x1) << 13 ) \
( ((((unsigned int)d) >> 3) & 0x1) << 12 ) \
( ((((unsigned int)d) >> 2) & 0x1) << 11 ) \
( ((((unsigned int)d) >> 2) & 0x1) << 10 ) \
( ((((unsigned int)d) >> 2) & 0x1) << 9 ) \
( ((((unsigned int)d) >> 2) & 0x1) << 8 ) \
( ((((unsigned int)d) >> 1) & 0x1) << 7 ) \
( ((((unsigned int)d) >> 1) & 0x1) << 6 ) \
( ((((unsigned int)d) >> 1) & 0x1) << 5 ) \
( ((((unsigned int)d) >> 1) & 0x1) << 4 ) \
( ((((unsigned int)d) >> 0) & 0x1) << 3 ) \
( ((((unsigned int)d) >> 0) & 0x1) << 2 ) \
( ((((unsigned int)d) >> 0) & 0x1) << 1 ) \
( ((((unsigned int)d) >> 0) & 0x1) << 0 )
  • 元のフォントデータを、垂直方向にBYTE_X4マクロで4倍に、水平方向にデータを繰り返すことで4倍にします。エディタの力を借りてゴリゴリ書きます。
const FONT_DATA_X4 font_x4[] = 
{

     {{
        BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),
        BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),
        BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),
        BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),
        BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00)
    }} // 20
    ,{{
        BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),
        BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),
        BYTE_X4(0x5f),BYTE_X4(0x5f),BYTE_X4(0x5f),BYTE_X4(0x5f),
        BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),
        BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00)
    }} // 21 !
    ,{{
        BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),
        BYTE_X4(0x07),BYTE_X4(0x07),BYTE_X4(0x07),BYTE_X4(0x07),
        BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),
        BYTE_X4(0x07),BYTE_X4(0x07),BYTE_X4(0x07),BYTE_X4(0x07),
        BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00),BYTE_X4(0x00)
    }} // 22 "
    , ...

LCD表示

上記の4倍フォントをLCD上に表示できるようにします。

LCD制御の処理はlcdc_ST7735S.c(.h)に作ってあり、現状、文字表示の関数として以下を用意しています。

void lcdc_putchar(char c, _UWORD color, _UWORD x0, _UWORD y0);
void lcdc_puts(char *s, _UWORD color, _UWORD x0, _UWORD y0);

基準位置と表示したい文字(列)を指定する形です。
これらの4倍フォントを使用するバージョンを用意します。

void lcdc_putchar_x4(char c, _UWORD color, _UWORD x0, _UWORD y0);
void lcdc_puts_x4(char *s, _UWORD color, _UWORD x0, _UWORD y0);

関数名を変えただけです。
これらの関数の実装は、元のものから少しいじって用意します。

//-------------------------------------------------
// 4x font functions
//-------------------------------------------------

// bit_ptn[j].bit(b) : (j)th y, (b)th x
// display area : rectangle of (x0, y0), (x0 + 31, y0 + dy - 1)
static void lcdc_draw_32x(const unsigned int *bit_ptn, _UWORD color, _UWORD x0, _UWORD y0, _UWORD dy)
{
    int i, j;
    unsigned int tmp;


    lcdc_set_area(x0, x0 + 31, y0, y0 + dy-1);

    write_command(0x2C);

    DEVICE_RS_SET();
    DEVICE_CS_CLEAR();

    for(j = 0; j < dy; j++){          // Row loop

        tmp = bit_ptn[j];

        for(i = 0; i < 32; i++){ // Column loop

            if( tmp & 0x01 ){
                DEVICE_SPI_TX_BUFW( (_UBYTE)(color >> 8) );
                DEVICE_SPI_TX_BUFW( (_UBYTE)color );
            }
            else{
                DEVICE_SPI_TX_BUFW(0x0);
                DEVICE_SPI_TX_BUFW(0x0);
            }

            tmp >>= 1;
        }
    }

    while(!DEVICE_SPI_TX_END)
        ;
    DEVICE_CS_SET();

}


void lcdc_putchar_x4(char c, _UWORD color, _UWORD x0, _UWORD y0)
{
    int i, j;
    unsigned char index;
    
    if( (c < 0x20) || (c > 0x7F) )
        index = 0x20;
    else
        index = c - 0x20;
        
    lcdc_row_col_exchange();

    lcdc_draw_32x(font_x4[index].f, color, y0, x0, W_FONT_X4);

    lcdc_row_col_exchange();
}

void lcdc_puts_x4(char *s, _UWORD color, _UWORD x0, _UWORD y0)
{
    _UWORD x_tmp, y_tmp;
    char *p;

    p = s;

    x_tmp = x0;
    y_tmp = y0;

    while(*p != '\0'){
        if(x_tmp > LCDC_X_WIDTH - W_FONT_X4){
            // If there is not enough space for x direction,
            // rewind x position, and increment y position.
            x_tmp = x0;
            y_tmp += 32 + VERTICAL_PITCH;
            if(y_tmp >= LCDC_Y_WIDTH)
                break;
        }
        else{
            lcdc_putchar_x4(*p, color, x_tmp, y_tmp);
            p++;
            x_tmp += (W_FONT_X4 + HORIZONTAL_PITCH);
        }
    }

}

4倍フォント表示確認

詳細は省略しますが、UARTからのコマンド入力で機能テストができるようにしているので、ここに4倍フォント表示テストコマンドを追加して動かしてみたいと思います。

TeratermでCOMポートに接続し、以下のように入力します。

**** program start ****
Built on e2studio version 6.2.0
RX UART > lcd_area 0 9F 0 7F

RX UART > lcd_fill 0 0 0
color:0
Elapsed time : 79ms

RX UART > lcd_puts_x4
string to display :
1234rpm

RX UART >

f:id:nokixa:20201206221544p:plain:w400

LCD表示はこうなりました。

f:id:nokixa:20201206230316j:plain:w500

いい感じ。
ぎざぎざですが。

ひとまずここまで

タコメータ用の文字表示ができるようになりました。
どんどんタコメータ機能の実装を進めていきます。