2022年9月11日日曜日

aitendoの7セグ液晶をArduinoで使ってみた。

 先日解析した、aitendoのSVM343-1っていう7セグ液晶なんだけど、Arduinoで扱いやすい様にスケッチを作ってみた。ライブラリ化するともっと使いやすいかもしれないけどあんまり大きくないのでそのままスケッチに取り込んで使ってもいいかなとか思ったり。

ベースはこの前の解析用スケッチで、HT1621にソフトウェアSPIでデータを送るんだけど、各桁に表示しやすいようにした感じ。桁をまたぐようにレジスタが設定されているのでちょっと面倒だったけど、バッファに一旦orで書き込んで一気に転送する形にしてみた。LCD側から読み出すこともできそうだけど面倒だったので…

#define CLOCK 12
#define DATA 13
#define CS 11

#define COMMAND_MODE 0b10000000
#define WRITE_MODE 0b10100000

#define SYS_EN 0b00000010   //LCDバイアス発生機と発振器有効化
#define LCD_OFF 0b00000100  //LCDバイアス発生機無効化
#define LCD_ON 0b00000110   //LCDバイアス発生機有効化
#define RC256K 0b00110000   //内蔵RC発振器使用 (256kHz)

//7セグ表示用リスト
const uint8_t numArray[11] = {
  0b00111111,  //0
  0b00000110,  //1
  0b01011011,  //2
  0b01001111,  //3
  0b01100110,  //4
  0b01101101,  //5
  0b01111101,  //6
  0b00000111,  //7
  0b01111111,  //8
  0b01101111,  //9
  0b01000000   //マイナス
};

void writeBits(uint8_t data, uint8_t cnt) {
  for (uint8_t i = 0; i < cnt; i++, data <<= 1) {
    digitalWrite(CLOCK, LOW);
    digitalWrite(DATA, data & 0x80 ? HIGH : LOW);
    digitalWrite(CLOCK, HIGH);
  }
}

void write(uint8_t address, uint8_t data) {
  digitalWrite(CS, LOW);
  writeBits(WRITE_MODE, 3);
  writeBits(address << 3, 6);
  writeBits(data, 8);
  digitalWrite(CS, HIGH);
}

void cmd(uint8_t data) {
  digitalWrite(CS, LOW);
  writeBits(COMMAND_MODE, 4);
  writeBits(data, 8);
  digitalWrite(CS, HIGH);
}

void setSegments(uint8_t segData[4], uint8_t dotData) {
  uint8_t lcdBuffer[16] = {};
  for (uint8_t i = 0; i < 4; i++) {
    if (i <= 1) {
      lcdBuffer[14 - 2 * i] |= (segData[i] & 0b00000001) << 3;  //a
      lcdBuffer[14 - 2 * i] |= (segData[i] & 0b00000010) << 6;  //b
      lcdBuffer[15 - 2 * i] |= (segData[i] & 0b00100000) << 2;  //f
      lcdBuffer[15 - 2 * i] |= (segData[i] & 0b01000000) >> 3;  //g
    } else {
      lcdBuffer[14 - 2 * i] |= (segData[i] & 0b00000001) << 7;  //a
      lcdBuffer[13 - 2 * i] |= (segData[i] & 0b00000010) << 2;  //b
      lcdBuffer[14 - 2 * i] |= (segData[i] & 0b00100000) >> 2;  //f
      lcdBuffer[15 - 2 * i] |= (segData[i] & 0b01000000) << 1;  //g
    }
    lcdBuffer[1 + 2 * i] |= (segData[i] & 0b00000100) << 5;  //c
    lcdBuffer[2 * i] |= (segData[i] & 0b00001000);           //d
    lcdBuffer[2 * i] |= (segData[i] & 0b00010000) << 3;      //e
  }
  lcdBuffer[5] |= (dotData & 0b00000001) << 3;  //2桁目のドット
  lcdBuffer[3] |= (dotData & 0b00000010) << 2;  //3桁目のドット
  lcdBuffer[1] |= (dotData & 0b00000100) << 1;  //4桁目のドット
  lcdBuffer[11] |= (dotData & 0b00001000);      //コロン
  for (uint8_t i = 0; i < 16; i++) {
    write(i, lcdBuffer[i]);
  }
}

void displayInt(int intData, uint8_t dotPos) {
  uint8_t data[4] = {};
  uint8_t digit = 1;
  data[3] = numArray[abs(intData) % 10];
  if (abs(intData) > 9) {
    data[2] = numArray[abs(intData) / 10 % 10];
    ++digit;
  }
  if (abs(intData) > 99) {
    data[1] = numArray[abs(intData) / 100 % 10];
    ++digit;
  }
  if (abs(intData) > 999) {
    data[0] = numArray[abs(intData) / 1000 % 10];
    ++digit;
  }
  if (intData < 0) {
    data[3 - digit] = numArray[10];
  }
  setSegments(data, dotPos);
}

void setup() {
  pinMode(CLOCK, OUTPUT);
  pinMode(DATA, OUTPUT);
  pinMode(CS, OUTPUT);
  digitalWrite(CS, HIGH);

  cmd(RC256K);
  cmd(0b01010010);  // 1/3バイアス 1/4デューティー
  cmd(SYS_EN);
  cmd(LCD_ON);

  for (uint8_t i = 0; i < 16; i++) {
    write(i, 0);
  }
}

void loop() {
  static int i = 0;
  displayInt(i, 0b00000000);
  i--;
  delay(100);
}

こんな感じでとりあえずはintに対応で小数点の位置は手動で入力するタイプにしてみた。液晶の仕様上-999から9999までしか正常に表示できない。範囲外はテキトーに表示されるので注意かも。

センサのデータとかを表示したい場合はfloatのほうが使いそうなのでfloatにも対応してみたい。

0 件のコメント:

コメントを投稿