前回は、結局電子ペーパーを使わず、大きなフォントを作ったところで終わりました。
alasixosaka.hatenablog.com
今回は、そのフォントを表示させてみます。
といってもあまり大きな変更点はありません。
フォントのデータが大きいのでちょっと長いですが、スケッチの全文です。実際の時計を動かす段になったらもっとデータは大きくなってしまうのですが。
#include <SPI.h> #define COLORED 0 #define UNCOLORED 1 #define RST_PIN 8 #define DC_PIN 9 #define CS_PIN 10 #define BUSY_PIN 7 #define EPD_WIDTH 128 #define EPD_HEIGHT 296 #define ROTATE_0 0 #define ROTATE_90 1 #define ROTATE_180 2 #define ROTATE_270 3 #define IF_INVERT_COLOR 1 //unsigned char* image; int width; int height; int rotate; unsigned long time_start_ms; unsigned char image[1024]; unsigned char WS_20_30[159] = { 0x80, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x10, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x80, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x10, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x8, 0x0, 0x0, 0x0, 0x0, 0x1, 0xA, 0xA, 0x0, 0xA, 0xA, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x8, 0x0, 0x1, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x0, 0x0, 0x0, 0x22, 0x17, 0x41, 0x0, 0x32, 0x36 }; unsigned char _WF_PARTIAL_2IN9[159] = { 0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x80,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x40,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0A,0x0,0x0,0x0,0x0,0x0,0x2, 0x1,0x0,0x0,0x0,0x0,0x0,0x0, 0x1,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0, 0x22,0x17,0x41,0xB0,0x32,0x36, }; unsigned char zero[96] ={ // @192 '0' (7 pixels wide) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 7, 255, 254, 0, 0, 255, 252, 0, 0, 63, 240, 127, 248, 31, 241, 255, 255, 31, 227, 255, 255, 143, 231, 255, 255, 207, 231, 255, 255, 207, 231, 255, 255, 207, 227, 255, 255, 143, 241, 255, 255, 31, 240, 63, 252, 31, 248, 0, 0, 63, 254, 0, 0, 255, 255, 192, 7, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }; unsigned char one[96] = { // @204 '1' (7 pixels wide) 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 243, 255, 254, 127, 243, 255, 255, 63, 243, 255, 255, 191, 243, 255, 255, 159, 241, 255, 255, 159, 240, 0, 0, 15, 240, 0, 0, 7, 240, 0, 0, 7, 241, 255, 255, 255, 243, 255, 255, 255, 243, 255, 255, 255, 243, 255, 255, 255, 243, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }; unsigned char two[96] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 243, 255, 255, 255, 240, 255, 254, 31, 240, 127, 254, 15, 240, 31, 255, 15, 241, 143, 255, 207, 241, 199, 255, 231, 241, 227, 255, 231, 241, 241, 255, 231, 241, 252, 127, 231, 241, 254, 63, 199, 241, 255, 15, 135, 240, 255, 128, 15, 240, 127, 192, 31, 240, 127, 240, 63, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }; unsigned char tre[96] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 248, 127, 254, 31, 248, 127, 254, 31, 248, 255, 255, 15, 241, 255, 63, 207, 243, 255, 63, 231, 243, 255, 63, 231, 243, 255, 31, 231, 243, 255, 31, 231, 243, 254, 31, 231, 249, 254, 79, 199, 248, 248, 103, 135, 252, 0, 96, 15, 254, 0, 240, 31, 255, 3, 252, 63, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }; unsigned char fou[96] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 243, 255, 255, 255, 240, 255, 255, 255, 240, 127, 255, 255, 242, 31, 255, 255, 243, 143, 255, 255, 243, 195, 255, 255, 243, 241, 255, 255, 243, 248, 127, 247, 243, 254, 63, 243, 243, 255, 15, 240, 0, 0, 7, 240, 0, 0, 7, 240, 0, 0, 7, 243, 243, 255, 255, 247, 243, 255, 255, 255, 243, 255, 255, 255, 241, 255, 255, 255, 240, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }; unsigned char fiv[96] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 248, 127, 255, 255, 248, 127, 128, 7, 240, 255, 0, 7, 241, 255, 191, 199, 243, 255, 159, 199, 243, 255, 159, 199, 243, 255, 159, 199, 243, 255, 159, 199, 243, 255, 159, 199, 249, 255, 31, 199, 248, 124, 63, 199, 252, 0, 63, 199, 254, 0, 127, 195, 255, 129, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }; unsigned char six[96] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 63, 255, 254, 0, 7, 255, 252, 0, 1, 255, 248, 126, 64, 255, 249, 255, 56, 127, 241, 255, 62, 63, 243, 255, 159, 31, 243, 255, 159, 159, 243, 255, 159, 207, 243, 255, 159, 207, 241, 255, 159, 199, 249, 255, 31, 231, 248, 126, 63, 231, 252, 0, 63, 231, 254, 0, 127, 255, 255, 129, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }; unsigned char sev[96] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 7, 255, 255, 254, 7, 255, 255, 255, 135, 243, 255, 255, 199, 240, 127, 255, 199, 240, 31, 255, 199, 248, 7, 255, 199, 255, 0, 255, 199, 255, 224, 63, 199, 255, 248, 7, 199, 255, 255, 1, 199, 255, 255, 224, 71, 255, 255, 248, 7, 255, 255, 255, 7, 255, 255, 255, 231, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }; unsigned char eig[96] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 3, 240, 127, 252, 1, 224, 31, 252, 0, 192, 31, 248, 124, 143, 143, 241, 254, 31, 207, 241, 255, 63, 231, 243, 255, 63, 231, 243, 255, 63, 231, 243, 255, 63, 231, 243, 255, 63, 231, 243, 254, 63, 231, 249, 254, 31, 199, 248, 248, 79, 143, 252, 0, 192, 15, 254, 1, 224, 31, 255, 3, 240, 63, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }; unsigned char nin[96] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 255, 255, 0, 63, 255, 254, 0, 31, 255, 252, 63, 15, 243, 252, 127, 207, 243, 252, 255, 231, 243, 252, 255, 231, 249, 252, 255, 231, 248, 252, 255, 231, 252, 126, 255, 231, 252, 62, 127, 199, 254, 3, 63, 15, 255, 128, 0, 31, 255, 224, 0, 63, 255, 252, 1, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }; void setup() { // put your setup code here, to run once: Serial.begin(115200); pinMode(CS_PIN, OUTPUT); pinMode(RST_PIN, OUTPUT); pinMode(DC_PIN, OUTPUT); pinMode(BUSY_PIN, INPUT); SPI.begin(); SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0)); Init(); //ClearFrameMemory(0xFF); //DisplayFrame(); //SetRotate(ROTATE_0); int rotate = 0; //SetWidth(128); int width = 128; //SetHeight(24); int height = 24; //Clear(COLORED, width, height); //Clear(UNCOLORED, width, height); //Serial.println("Clear"); //delay(2000); Serial.println("Image"); SetFrameMemory_Base(width, 296); DisplayFrame(); time_start_ms = millis(); } void loop() { // put your main code here, to run repeatedly: //time_now_s = (millis() - time_start_ms) / 1000; width = 32; height = 24; rotate = 1; //Clear(UNCOLORED, width, height); //char j[] = {'0','\0'}; boolean i = false; while(1){ //j[0] = i + '0'; //DrawStringAt(0, 4, j, &Font12, COLORED); //SetFrameMemory_Partial(paint.GetImage(), 60, 72, width, height); for (int i=0; i<60; i++){ int sec1 = i / 10; int sec2 = i % 10; SetFrameMemory_Partial_pre(); //Serial.println(sec1); switch (sec1){ case 1: SetFrameMemory_Partial(one, 16, 200, width, height); break; case 2: SetFrameMemory_Partial(two, 16, 200, width, height); break; case 3: SetFrameMemory_Partial(tre, 16, 200, width, height); break; case 4: SetFrameMemory_Partial(fou, 16, 200, width, height); break; case 5: SetFrameMemory_Partial(fiv, 16, 200, width, height); break; case 6: SetFrameMemory_Partial(six, 16, 200, width, height); break; case 7: SetFrameMemory_Partial(sev, 16, 200, width, height); break; case 8: SetFrameMemory_Partial(eig, 16, 200, width, height); break; case 9: SetFrameMemory_Partial(nin, 16, 200, width, height); break; default: SetFrameMemory_Partial(zero, 16, 200, width, height); } switch (sec2){ case 1: SetFrameMemory_Partial(one, 16, 224, width, height); break; case 2: SetFrameMemory_Partial(two, 16, 224, width, height); break; case 3: SetFrameMemory_Partial(tre, 16, 224, width, height); break; case 4: SetFrameMemory_Partial(fou, 16, 224, width, height); break; case 5: SetFrameMemory_Partial(fiv, 16, 224, width, height); break; case 6: SetFrameMemory_Partial(six, 16, 224, width, height); break; case 7: SetFrameMemory_Partial(sev, 16, 224, width, height); break; case 8: SetFrameMemory_Partial(eig, 16, 224, width, height); break; case 9: SetFrameMemory_Partial(nin, 16, 224, width, height); break; default: SetFrameMemory_Partial(zero, 16, 224, width, height); } DisplayFrame_Partial(); //Clear(UNCOLORED, width, height); //i = !i; Serial.println(millis()); } } } void Init(){ Reset(); WaitUntilIdle(); SendCommand(0x12); WaitUntilIdle(); SendCommand(0x01);//Driver output control SendData(0x27); SendData(0x01); SendData(0x00); SendCommand(0x11); //data entry mode SendData(0x03); SetMemoryArea(0, 0, EPD_WIDTH-1, EPD_HEIGHT-1); SendCommand(0x21); // Display update control SendData(0x00); SendData(0x80); SetMemoryPointer(0, 0); WaitUntilIdle(); SetLut_by_host(WS_20_30); } void Reset(){ digitalWrite(RST_PIN, HIGH); delay(20); digitalWrite(RST_PIN, LOW); delay(5); digitalWrite(RST_PIN, HIGH); delay(20); } void WaitUntilIdle(){ while(1){ if(digitalRead(BUSY_PIN)==LOW) break; delay(5); } delay(5); } void SendCommand(unsigned char command){ digitalWrite(DC_PIN, LOW); digitalWrite(CS_PIN, LOW); SpiTransfer(command); digitalWrite(CS_PIN, HIGH); } void SendData(unsigned char data){ digitalWrite(DC_PIN, HIGH); digitalWrite(CS_PIN, LOW); SpiTransfer(data); digitalWrite(CS_PIN, LOW); } void SetMemoryArea(int x_start, int y_start, int x_end, int y_end){ SendCommand(0x44); /* x point must be the multiple of 8 or the last 3 bits will be ignored */ SendData((x_start >> 3) & 0xFF); SendData((x_end >> 3) & 0xFF); SendCommand(0x45); SendData(y_start & 0xFF); SendData((y_start >> 8) & 0xFF); SendData(y_end & 0xFF); SendData((y_end >> 8) & 0xFF); } void SetMemoryPointer(int x, int y){ SendCommand(0x4E); /* x point must be the multiple of 8 or the last 3 bits will be ignored */ SendData((x >> 3) & 0xFF); SendCommand(0x4F); SendData(y & 0xFF); SendData((y >> 8) & 0xFF); WaitUntilIdle(); } void SetLut_by_host(unsigned char *lut){ SetLut((unsigned char *)lut); SendCommand(0x3f); SendData(*(lut+153)); SendCommand(0x03); // gate voltage SendData(*(lut+154)); SendCommand(0x04); // source voltage SendData(*(lut+155)); // VSH SendData(*(lut+156)); // VSH2 SendData(*(lut+157)); // VSL SendCommand(0x2c); // VCOM SendData(*(lut+158)); } void SetLut(unsigned char *lut){ unsigned char count; SendCommand(0x32); for(count=0; count<153; count++) SendData(lut[count]); WaitUntilIdle(); } void SpiTransfer(unsigned char data){ digitalWrite(CS_PIN, LOW); SPI.transfer(data); digitalWrite(CS_PIN, HIGH); } void DisplayFrame(){ SendCommand(0x22); SendData(0xc7); SendCommand(0x20); WaitUntilIdle(); } void SetFrameMemory_Base(int width, int height) { Serial.println(width); Serial.println(height); SetMemoryArea(0, 0, width - 1, height - 1); SetMemoryPointer(0, 0); SendCommand(0x24); /* send the image data */ for (int i = 0; i < width / 8 * height; i++) { //SendData(pgm_read_byte(&image_buffer[i])); SendData(0xFF); } SendCommand(0x26); /* send the image data */ for (int i = 0; i < width / 8 * height; i++) { //SendData(pgm_read_byte(&image_buffer[i])); SendData(0xFF); } } void SetFrameMemory_Partial( const unsigned char* image_buffer, int x, int y, int image_width, int image_height ) { int x_end; int y_end; if ( image_buffer == NULL || x < 0 || image_width < 0 || y < 0 || image_height < 0 ) { return; } /* x point must be the multiple of 8 or the last 3 bits will be ignored */ x &= 0xF8; image_width &= 0xF8; //if (x + image_width >= this->width) { // x_end = this->width - 1; //} else { x_end = x + image_width - 1; //} //if (y + image_height >= this->height) { // y_end = this->height - 1; //} else { y_end = y + image_height - 1; //} SetMemoryArea(x, y, x_end, y_end); SetMemoryPointer(x, y); SendCommand(0x24); /* send the image data */ for (int j = 0; j < y_end - y + 1; j++) { for (int i = 0; i < (x_end - x + 1) / 8; i++) { SendData(image_buffer[i + j * (image_width / 8)]); } } } void SetFrameMemory_Partial_pre(void){ digitalWrite(RST_PIN, LOW); delay(2); digitalWrite(RST_PIN, HIGH); delay(2); SetLut(_WF_PARTIAL_2IN9); SendCommand(0x37); SendData(0x00); SendData(0x00); SendData(0x00); SendData(0x00); SendData(0x00); SendData(0x40); SendData(0x00); SendData(0x00); SendData(0x00); SendData(0x00); SendCommand(0x3C); //BorderWavefrom SendData(0x80); SendCommand(0x22); SendData(0xC0); SendCommand(0x20); WaitUntilIdle(); } void DisplayFrame_Partial(void) { SendCommand(0x22); SendData(0x0F); SendCommand(0x20); WaitUntilIdle(); }
主な変更点だけ記載します。
まず、メモリを大量に消費していたWaveShareのロゴのデータを削除しました。その代わり、全部白くなるように(要するにクリアと同じ)0xFFを書き込むようにしました。これでクリアができるので、Setupから、ClearFrameMemory関数を呼び出すところをコメントアウト、また、画面クリアのコマンドClear(COLORED, width, height); と Clear(UNCOLORED, width, height); もコメントアウトして動作しないようにしてあります。これらのコマンドで呼び出している関数も不要なので削除しています。また、前回のスケッチで使っていないDrawAbsolutePixelという関数が記載されていました。これも削除しています。
loop関数の中のWhile(1)から始まる無限ループの中身ですが、カウンタ変数をiとして0から59まで変化させ、その数値を電子ペーパーに表示させています。
for (int i=0; i<60; i++){ int sec1 = i / 10; int sec2 = i % 10; SetFrameMemory_Partial_pre(); //Serial.println(sec1); switch (sec1){ case 1: SetFrameMemory_Partial(one, 16, 200, width, height); break; ~省略~ default: SetFrameMemory_Partial(zero, 16, 200, width, height); } switch (sec2){ case 1: SetFrameMemory_Partial(one, 16, 224, width, height); break; ~省略~ default: SetFrameMemory_Partial(zero, 16, 224, width, height); } DisplayFrame_Partial();
変数sec1がiの10の位、sec2が1の位です。
そして、SetFrameMemory_Partial_pre(); という関数を新しく作って呼び出しています。これは、前回のスケッチのSetFrameMemory_Partial関数の前半部分、メモリーに書き込む前までを切り出したものです。数字を2桁分書き込みますので、書き込みが2回に分けて行われるのでメモリに書き込む前までの処理を1回行い、10の位を書き込み、1の位を書き込み、表示させるという処理の流れになっています。書き込むところが、それぞれswitch(sec1)とswitch(sec2)の部分で、数値に応じてそれぞれのデータを書き込んでいます。ポインタを使ったり、配列を使ったりして、SetFrameMemory_Partial関数を呼び出す部分をもう少しスマートにかけると思いますが、とりあえず動けばOKという感じでswitch文を使いました。一応数字はきれいに表示できました。
しかし、問題はいろいろ山積です。
まず、ウェイトを何も入れていないのですが、書き換えにほぼ1秒かかっています。スペックシートでは部分書き換えの処理時間は0.5秒となっていましたがそんなに短くできそうにありません。処理時間のうち大半は書き換えを待っている時間(つまりマイコンは何もせず待機している)と思われますので、果報は寝て待てということでWaitUntilBusyを実行する前にマイコンはスリープしてやってもいいとは思います。これでマイコンの消費電力は下げることができますが、電子ペーパーがずっと動きっぱなしということになるので、果たしでどのくらい電流を消費するのか? 電子ペーパーの方もうスリープをかけてやらないと電池駆動は難しいのではないかと考えています。
まあ、とりあえず、Arduinoでできそうなことはここまでのような感じですので、次回からPICを使って動かそうと思います。