2015年12月13日日曜日

メモリ液晶ブレークアウト(サンプルプログラム)


メモリ液晶ブレークアウト基板 サンプルプログラム(Arduino用)

最初にヘッダ部分です。

#include <avr/pgmspace.h>
#include <SPI.h>

// GND  GND
// SCK  13
// MOSI 11
// MISO 12
#define CSR 10
#define CSL  9
// 5V   5V

#define SCREEN0 0
#define SCREEN1 1
#define LINE_LENGTH 50
#define RAMLINE_LENGTH 52
// mode
#define BYTE_MODE 0x00
#define SEQUENTIAL_MODE 0x40
// command
#define READ 0x03
#define WRITE 0x02
#define READ_STATUS 0x05  // called RDSR in datasheet
#define WRITE_STATUS 0x01 // called WRSR in datasheet
// BASE_ADDR
#define SCREEN0_BASE 0x0000
#define SCREEN1_BASE 0x4000
int _comflag;
int _modeflag;
int _clearflag;
byte lcd_line[] = {
 0x00,
 0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,0x08,
 0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,0x04,
 0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,0x0C,
 0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,0x02,
 0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,0x0A,
 0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,0x06,
 0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,0x0E,
 0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,0x01,
 0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,0x09,
 0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,0x05,
 0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,0x0D,
 0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,0x03,
 0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,0x0B,
 0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,0x07,
 0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,0x0F,
};


「#include <avr/pgmspace.h>」と「#include <SPI.h>」は、もともとArduinoに準備されているライブラリです。
 #これらを使用しているので「#include」して下さい。
「// GND  GND」と「// SCK  13」と「// MOSI 11」と「// MISO 12」と「// 5V   5V」は、Arduinoに接続する場所が固定です。
 #指定の場所に繋いでください
「#define CSR 10」と「#define CSL  9」は任意の場所に変更可能です。
 #変更したピンと接続してください
それ以外の部分は「オマジナイ」だと思って下さい。
#今回は説明を割愛させていただきます

そして初期化部分です。
void setup() {
  AkiSpiLcd();
  delay(1);
  cls();
  cls_ram(SCREEN0);
}
「AkiSpiLcd」これはメモリ液晶ブレークアウト基板を使う為の初期化命令です。
「cls」これはメモリ液晶の全画面消去命令です。
「cls_ram(SCREEN0)」これはSRAM上の画面バッファ(0ページ目)の消去命令です。


次にメイン部分です。
void loop() {
  drawDot(random(0,399),random(0,239));
  ram2lcd(SCREEN0);
}
「drawDot」これは任意の横縦座標にドットを書くプログラムです。
 #今回、横座標は乱数で0~399の間に、縦座標は乱数で0~239の間にドットを書きます。
「ram2lcd」これはSRAM(0ページ目)内に作った画面イメージをメモリ液晶に転送する命令です。


「drawDot」命令です。
void drawDot(int posX, int posY) {
  int address = (posX / 8) + (posY * RAMLINE_LENGTH) + 2;
  byte data = ram_read(address);
  data |= 0x80 >> (posX % 8);
  ram_write(address, data);
}
「int address」このaddressにドットを書きたいSRAMの座標が入ります。
「ram_read」これはSRAMの任意の場所のデータを読み込む命令です。
 #これで「data」に現状のドット情報を読み込みます
「data |= 0x80 >> (posX % 8);」これは「現状のドット状況」に「新しく書くドット」を重ね合わせています。
「ram_write」これはSRAMへの書き込み命令です。
 #完成した「data」を書き込みます。

最後は「みんなのラボで準備したプログラム」で、メモリ液晶ブレークアウト基板用のプログラムです。

// LCD ----------------------------------------
void AkiSpiLcd() {
  pinMode(CSR,OUTPUT);
  pinMode(CSL,OUTPUT);
  _ram_deselect();
  _lcd_deselect();
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV2);
  SPI.setDataMode(SPI_MODE0);
  _comflag = _modeflag = _clearflag = 0;
}
void cls() {
  _modeflag = 0;
  _clearflag = 1;
  _lcd_select();
  SPI.transfer((_modeflag << 7) | (_comflag << 6) | (_clearflag << 5));
  SPI.transfer(0x00);
  _lcd_deselect();
  cominvert();
}
void cls_ram(int screen) {
  switch(screen) {
    case 0:
      _cls_ram(SCREEN0_BASE);
      break;
    case 1:
      _cls_ram(SCREEN1_BASE);
      break;
  }
}
void directUpdateSingle(int line, byte *data) {
  _modeflag = 1;
  _clearflag = 0;
  _lcd_select();
  SPI.transfer((_modeflag << 7) | (_comflag << 6) | (_clearflag << 5));
  SPI.transfer(lcd_line[line]);
  for(int x = 0;x < LINE_LENGTH;x++) {
    SPI.transfer(*(data + x));
  }
  SPI.transfer(0);
  SPI.transfer(0);
  _lcd_deselect();
  cominvert();
}
void directUpdateMulti(int line, int length, byte *data) {
  _modeflag = 1;
  _clearflag = 0;
  _lcd_select();
  for (int y = 1;y < length;y++) {
    SPI.transfer((_modeflag << 7) | (_comflag << 6) | (_clearflag << 5));
    SPI.transfer(lcd_line[line]);
    for(int x = 0;x < LINE_LENGTH;x++) {
      SPI.transfer(*(data + y * LINE_LENGTH + x));
    }
    line++;
  }
  SPI.transfer(0);
  SPI.transfer(0);
  _lcd_deselect();
  cominvert();
}
void cominvert() {
  _modeflag = 0;
  _clearflag = 0;
  _lcd_select();
  SPI.transfer((_modeflag << 7) | (_comflag << 6) | (_clearflag << 5));
  SPI.transfer(0x00);
  _lcd_deselect();
  if (_comflag == 0) {
    _comflag = 1;
  } else {
    _comflag = 0;
  }
}
void ramReadSingleLine(int line, byte *buffer, int screen) {
  switch(screen) {
    case 0:
      screen = SCREEN0_BASE;
      break;
    case 1:
      screen = SCREEN1_BASE;
      break;
  }
  line = line * RAMLINE_LENGTH;
  int address = screen + line;
  ram_read2(address, buffer, RAMLINE_LENGTH);
}  
void ramReadMultiLine(int line, int length, byte *buffer, int screen) {
  switch(screen) {
    case 0:
      screen = SCREEN0_BASE;
      break;
    case 1:
      screen = SCREEN1_BASE;
      break;
  }
  line = line * RAMLINE_LENGTH;
  int address = screen + line;
  ram_read2(address, buffer, RAMLINE_LENGTH * length);
}
void ramWriteSingleLine(int line, byte *data, int screen) {
  switch(screen) {
    case 0:
      screen = SCREEN0_BASE;
      break;
    case 1:
      screen = SCREEN1_BASE;
      break;
  }
  line--;
  line = line * RAMLINE_LENGTH;
  int address = screen + line;
  ram_write2(address, data, LINE_LENGTH);  
}
void ramWriteMultiLine(int line, int length, byte *data, int screen) {
  _modeflag=1;
  _clearflag=0;
  switch(screen) {
    case 0:
      screen = SCREEN0_BASE;
      break;
    case 1:
      screen = SCREEN1_BASE;
      break;
  }
  int address = screen + line;
  _ram_writeStatus(SEQUENTIAL_MODE);
  _ram_prepareCommand(WRITE, address);
  for (int y = 0;y < length;y++) {
    SPI.transfer((_modeflag << 7) | (_comflag << 6) | (_clearflag << 5));
    SPI.transfer(lcd_line[line] );
    for (int x = 0;x < LINE_LENGTH;x++) {
      SPI.transfer(*data);
      data++;
    }
    line++;
  }
  _ram_deselect();
  _ram_writeStatus(BYTE_MODE);
}
void _lcd_select() {
  digitalWrite(CSL,HIGH);
  delayMicroseconds(5);
}
void _lcd_deselect() {
  delayMicroseconds(5);
  digitalWrite(CSL,LOW);
}
// SRAM ----------------------------------------
void ram2lcd(int screen) {
  byte linebuffer[RAMLINE_LENGTH];
  for (int y = 0;y < 240;y++) {
    ram_read2(y * RAMLINE_LENGTH + 2,linebuffer,RAMLINE_LENGTH);
    directUpdateSingle(y + 1,linebuffer);
  }
}
byte ram_read(int address) {
  _ram_prepareCommand(READ, address);
  byte result = SPI.transfer(0);
  _ram_deselect();
  return result;
}
void ram_read2(int address, byte *buffer,int count) {
  _ram_writeStatus(SEQUENTIAL_MODE);
  _ram_prepareCommand(READ, address);
  for (int i = 0;i< count;i++) {
    buffer[i] = SPI.transfer(0);
  }
  _ram_deselect();
  _ram_writeStatus(BYTE_MODE);
}
void ram_write(int address, byte data) {
  _ram_prepareCommand(WRITE, address);
  SPI.transfer(data);
  _ram_deselect();
}
void ram_write2(int address, byte *buffer, int count) {
  _ram_writeStatus(SEQUENTIAL_MODE);
  _ram_prepareCommand(WRITE, address);
  for (int i = 0;i < count;i++) {
    SPI.transfer(buffer[i]);
  }
  _ram_deselect();
  _ram_writeStatus(BYTE_MODE);
}
byte _ram_readStatus() {
  _ram_select();
  SPI.transfer(READ_STATUS);
  byte result = SPI.transfer(0);
  _ram_deselect();
  return result;
}
void _ram_writeStatus(byte status) {
  _ram_select();
  SPI.transfer(WRITE_STATUS);
  SPI.transfer(status);
  _ram_deselect();
}
void _ram_prepareCommand(byte command, int address) {
  _ram_select();
  SPI.transfer(command);
  SPI.transfer((address >> 8) & 0xff);
  SPI.transfer(address & 0xff);
}
void _ram_select() {
  digitalWrite(CSR,LOW);
}
void _ram_deselect() {
  digitalWrite(CSR,HIGH);
}
void _cls_ram(int address) {
  _modeflag = 1;
  _clearflag = 0;
  _ram_writeStatus(SEQUENTIAL_MODE);
  _ram_prepareCommand(WRITE, address);
  for (int y = 1;y <= 240;y++) {
    SPI.transfer((_modeflag << 7) | (_comflag << 6) | (_clearflag << 5));
    SPI.transfer(lcd_line[y]);
    for (int x = 0;x < LINE_LENGTH;x++) {
      SPI.transfer(0x00);
    }
  }
  _ram_deselect();
  _ram_writeStatus(BYTE_MODE);
}
これはチョット複雑かつ長いプログラムなので、今は説明を割愛させていただきます。


「ヘッダ部分」と「初期化部分」と「メイン部分」と「drawDot命令」と「みんなのラボで準備したプログラム」を1つのプログラムに合体すれば、画面上の任意の場所(ランダム)でドットを書くDEMOプログラムの完成です!

drawDotを元にdrawLineやdrawArc等を作ると良いでしょう。
画面外にドットを書かないようにクリッピング等の処理も作ると良いでしょう。


mbed用ライブラリも「みんなのラボで準備したプログラム」は全く同じ作りになっています。

メモリ液晶ブレークアウトについて(前書き)



「メモリ液晶ブレークアウト基板」について


前書き

 LS027B4DH01(メモリ液晶本体)は「400×240ドット」の「白黒二値」表示が可能です。
 「1バイト=8ビット」なので、実際には「400÷8×240バイト」の空間があります。

 LS027B4DH01からは「薄く」「細かく」「壊れやすい」ケーブルが出ています。
 このケーブルを受ける専用コネクタが、当商品(メモリ液晶ブレークアウト基板)には搭載されています。
 これにより、お客様にはLS027B4DH01を当製品のコネクタに差し込むだけで使用が可能とりなります。
 当商品とマイコンボード(Arduinoやmbedほか)の接続には、当製品基板上に2.54ピッチの接続穴が開いておりますので、ピンヘッダなどをハンダ付けしてご利用いただく形となります。

 LS027B4DH01はドットを書く事はできますが、どこにドットがあるかの読み込みができません。
 画像を表示するような場合は問題ないかもしれませんが、任意の場所に点を書いたり、線を引いたり、グラフを書くような場合には問題があります。
 そこで当製品では256KbitのSRAMを搭載いたしました。
 一度SRAM上に画面のイメージを作り、完成したデータを画像としてメモリ液晶に転送する事を考えております。

 当製品にLS027B4DH01を張り付けてご利用いただけるよう「印」も印刷されております。
 これは、薄くて強度の弱い液晶を保護する目的です。
 それ以外にもフロントパネルやArduinoを固定できるネジ穴の開いたバックパネル、フロントパネルやバックパネルを固定するネジやナット、スペーサーも同梱されております。
 #Arduino固定用のネジは付属していません(Arduino専用品ではないため)



※メモリ液晶に直接ドットを書く事もできますし、SRAMも画面バッファとしてではなく自由に使う事ができます。

2015年3月25日水曜日

アクリル製リール台(中に入っているもの)

商品に入っているもののイメージ画です。






底板





--------------------------------------------------






左板
右板





#右板と左板は同じものです

--------------------------------------------------



1穴板


2穴板



 #1穴板と2穴板は、どちらか片方だけ使います

--------------------------------------------------



クロスバー


同じものが2本入っています。
#2本を組み合わせて使います

--------------------------------------------------

プラネジ 6本
 普通のプラスチックネジ(画像はありません)

--------------------------------------------------

プラナット 6個
 普通のプラスチックナット(画像はありません)

アクリル製リール台(作り方)

中に入っている部品はコチラに画像が掲載されています。
#画像を確認しながら作れば、とても簡単です!

1.底板に右板を装着してネジ止めします。
 #ネジ2ヶ所


 














2.右板に1穴板(または2穴板)を装着してネジ止めします。
 #ネジ1ヶ所


3.底板と1穴板(または2穴板)に左板を装着してネジ止めします。
 #ネジ3ヶ所


4.クロスバーをクロスします。
 #ネジ無し(差し込むだけです)


これで完成です。

※注意点
 1穴板(2穴板)の端は細くなっています、組み立て時に無理な力をかけて割らないように気を付けて下さい。
 プラネジのネジ山は壊れやすいです、無理に回して山が削れないように気を付けて下さい。