LCDモジュール ACM1602NI(I2C接続) を制御するライブラリ

Dependents:   scan2 BoxController

LcdAcm1602ni.cpp

Committer:
orivant
Date:
2016-12-19
Revision:
12:b5829a58bbaf
Parent:
11:e0849411adfa

File content as of revision 12:b5829a58bbaf:

/** LCDモジュール ACM1602NI を制御するクラスの定義
*/
#include "LcdAcm1602ni.h"

const uint8_t    LcdAcm1602ni::LINE_HEAD_ADDR_TBL[LINE_COUNT] = {0x00, 0x40};     //!< 行の先頭アドレス
    
/** コンストラクタ
*/
LcdAcm1602ni::LcdAcm1602ni(PinName pinSDA, PinName pinSCL)
    :m_pinSDA(pinSDA)
    ,m_pinSCL(pinSCL)
    ,m_i2c(pinSDA, pinSCL)
    ,m_isMyI2c(true)
    ,m_currentLineNo(0)
    ,m_currentCharaNo(0)
    ,m_displayVisible(true)
    ,m_cursorVisible(false)
    ,m_blinkEnable(false)
{
    m_i2c.frequency(I2C_MAX_FREQUENCY);
}
LcdAcm1602ni::LcdAcm1602ni(I2C& i2c)
    :m_pinSDA(NC)
    ,m_pinSCL(NC)
    ,m_i2c(i2c)
    ,m_isMyI2c(false)
    ,m_currentLineNo(0)
    ,m_currentCharaNo(0)
    ,m_displayVisible(true)
    ,m_cursorVisible(false)
    ,m_blinkEnable(false)
{
}
/** デストラクタ
*/
LcdAcm1602ni::~LcdAcm1602ni()
{
}


/** 初期化
*/
void LcdAcm1602ni::initialize()
{
    uint8_t command;

    // 画面クリア(00000001 = 0x01)
    writeCommand(0x01);
    wait_us(2160);
    
    // ファンクション設定(0011[8bitモード]1[2行モード]0[文字5x8表示モー]00 = 00111000 = 0x38)
    writeCommand(0x38);
    wait_us(53);
    
    // ディスプレイ表示
    command = calcDisplayControlByteData();
    writeCommand(command);
    wait_us(53);

    // データ書き込み後アドレス加算モード設定(0000011[インクリメント]0 = 00000110 = 0x06)
    writeCommand(0x06);
    wait_us(53);

}


/** 1文字描画
*/
void LcdAcm1602ni::putc(char c)
{
    // 1文字書き込み
    writeData(c);
    // カーソル位置管理処理
    bool ret = incCursorPos();
    if (ret) {
        // 復帰・改行が発生したのでカーソル位置変更
        uint8_t addr = calcCursorAddr(m_currentLineNo, m_currentCharaNo);
        writeCommand(0x80 | addr);
    }
}
/** 文字列描画
*/
void LcdAcm1602ni::puts(const char* pStr)
{
    uint8_t addr;
    bool ret;
    const char* pt = pStr;
    bool stayLocate = false;
    while (*pt) {
        const char &c = *pt;
        if (c == '\r') {
            // 復帰コードの場合、行の先頭にカーソルを移動する
            m_currentCharaNo = 0;
            // 実際の移動処理は後で行う
            stayLocate = true;
        }
        else if (c == '\n') {
            // 改行コードの場合、次の行にカーソルを移動する
            m_currentLineNo = (m_currentLineNo + 1) % LINE_COUNT;
            // 実際の移動処理は後で行う
            stayLocate = true;
        }
        else {
            // 通常の文字コードの場合
            if (stayLocate) {
                // 復帰・改行の予約がある場合は先に処理
                addr = calcCursorAddr(m_currentLineNo, m_currentCharaNo);
                writeCommand(0x80 | addr);
                stayLocate = false;
            }
            // 1文字書き込み
            writeData(c);
            // カーソル位置管理処理
            ret = incCursorPos();
            if (ret) {
                // 改行が発生したのでカーソル位置変更
                // 実際の移動処理は後で行う
                stayLocate = true;
            }
        }
        pt++;
    }
    if (stayLocate) {
        // 復帰・改行の予約が残っている場合は処理する
        addr = calcCursorAddr(m_currentLineNo, m_currentCharaNo);
        writeCommand(0x80 | addr);
    }
}
/** フォーマット指定描画
*/
void LcdAcm1602ni::printf(const char* pFormat, ...)
{
    va_list ap;
    va_start(ap, pFormat);
    char* allocatedBuffer;
    int size = vasprintf(&allocatedBuffer, pFormat, ap);
    va_end(ap);
    puts(allocatedBuffer);
    free(allocatedBuffer);
}


/** カーソル位置変更
*/
void LcdAcm1602ni::locate(uint8_t lineNo, uint8_t charaNo)
{
    if (lineNo >= LINE_COUNT) lineNo = LINE_COUNT - 1;
    if (charaNo >= LINE_CHARA_COUNT) charaNo = LINE_CHARA_COUNT - 1;
    m_currentLineNo = lineNo;
    m_currentCharaNo = charaNo;
    uint8_t addr = calcCursorAddr(m_currentLineNo, m_currentCharaNo);
    writeCommand(0x80 | addr);
}
/** カーソル位置取得:行番号
*/
uint8_t LcdAcm1602ni::getCurrentLineNo() const
{
    return m_currentLineNo;
}
/** カーソル位置取得:文字番号
*/
uint8_t LcdAcm1602ni::getCurrentCharaNo() const
{
    return m_currentCharaNo;
}


/** 画面クリア
*/
void LcdAcm1602ni::clearDisplay()
{
    writeCommand(0x01);
    wait_us(2160);
    locate(0, 0);
}
/** 行クリア
*/
void LcdAcm1602ni::clearLine(uint8_t lineNo)
{
    if (lineNo >= LINE_COUNT) return;
    
    // クリアする行の先頭に移動
    uint8_t addr = calcCursorAddr(lineNo, 0);
    writeCommand(0x80 | addr);
    // 1行全体に' '書き込み
    for (uint8_t i = 0; i < LINE_CHARA_COUNT; i++) {
        writeData(' ');
    }
    // カーソル位置をクリアした行の先頭に移動
    m_currentLineNo = lineNo;
    m_currentCharaNo = 0;
    addr = calcCursorAddr(m_currentLineNo, m_currentCharaNo);
    writeCommand(0x80 | addr);
}
/** 範囲クリア
*/
void LcdAcm1602ni::clearRange(uint8_t startLineNo, uint8_t startCharaNo, uint8_t endLineNo, uint8_t endCharaNo)
{
    if (startLineNo >= LINE_COUNT) return;
    if (startCharaNo >= LINE_CHARA_COUNT) return;
    if (startLineNo > endLineNo) return;
    if (startCharaNo > endCharaNo) return;
    if (endLineNo >= LINE_COUNT) endLineNo = LINE_COUNT - 1;
    if (endCharaNo >= LINE_CHARA_COUNT) endCharaNo = LINE_CHARA_COUNT - 1;

    uint8_t addr;
    for (uint8_t lineNo = startLineNo; lineNo <= endLineNo; lineNo++) {
        // 対象行の削除開始位置にカーソル移動
        addr = calcCursorAddr(lineNo, startCharaNo);
        writeCommand(0x80 | addr);
        // 消す範囲に' 'を書き込み
        for (uint8_t charaNo = startCharaNo; charaNo <= endCharaNo; charaNo++) {
            writeData(' ');
        }
    }
    // クリアした範囲の開始位置にカーソルを移動
    m_currentLineNo = startLineNo;
    m_currentCharaNo = startCharaNo;
    addr = calcCursorAddr(m_currentLineNo, m_currentCharaNo);
    writeCommand(0x80 | addr);
}


/** 画面の表示設定
*/
void LcdAcm1602ni::setDisplayVisible(bool visible)
{
    if (m_displayVisible == visible) return;
    m_displayVisible = visible;
    uint8_t command = calcDisplayControlByteData();
    writeCommand(command);
}
/** 画面の表示設定取得
*/
bool LcdAcm1602ni::getDisplayVisible() const
{
    return m_displayVisible;
}
/** カーソルの表示設定
*/
void LcdAcm1602ni::setCursorVisible(bool visible)
{
    if (m_cursorVisible == visible) return;
    m_cursorVisible = visible;
    uint8_t command = calcDisplayControlByteData();
    writeCommand(command);
}
/** カーソルの表示設定取得
*/
bool LcdAcm1602ni::getCursorVisible() const
{
    return m_cursorVisible;
}
/** カーソルの点滅設定
*/
void LcdAcm1602ni::setBlinkEnable(bool enable)
{
    if (m_blinkEnable == enable) return;
    m_blinkEnable = enable;
    uint8_t command = calcDisplayControlByteData();
    writeCommand(command);
}
/** カーソルの点滅設定取得
*/
bool LcdAcm1602ni::getBlinkEnable() const
{
    return m_blinkEnable;
}


/** LCDコマンド書き込み
*/
void LcdAcm1602ni::writeCommand(uint8_t commandByte)
{
    m_i2c.start();
    m_i2c.write(ADDR_BYTE_WRITE);
    m_i2c.write(CTRL_BYTE_COMMAND);
    m_i2c.write(commandByte);
    m_i2c.stop();
}
/** LCDデータ書き込み
*/
void LcdAcm1602ni::writeData(uint8_t  dataByte)
{
    m_i2c.start();
    m_i2c.write(ADDR_BYTE_WRITE);
    m_i2c.write(CTRL_BYTE_DATA);
    m_i2c.write(dataByte);
    m_i2c.stop();
}


/** ディスプレイ制御コマンド指定バイトデータの生成
*/
uint8_t LcdAcm1602ni::calcDisplayControlByteData(bool displayVisible, bool cursorVisible, bool blinkEnable) const
{
    uint8_t byteData = 0x08;
    if (displayVisible) byteData |= 0x04;
    if (cursorVisible)  byteData |= 0x02;
    if (blinkEnable)    byteData |= 0x01;
    return byteData;
}


/** カーソル位置移動管理
*/
bool LcdAcm1602ni::incCursorPos()
{
    m_currentCharaNo++;
    if (m_currentCharaNo >= LINE_CHARA_COUNT) {
        m_currentCharaNo = 0;
        m_currentLineNo = (m_currentLineNo + 1) % LINE_COUNT;
        return true;
    }
    return false;
}


/** カーソル位置のアドレス計算
*/
uint8_t LcdAcm1602ni::calcCursorAddr(uint8_t lineNo, uint8_t charaNo)
{
    uint8_t addr = LINE_HEAD_ADDR_TBL[lineNo] + charaNo;
    return addr;
}