eepooのアイコン画像
eepoo 2021年02月21日作成 (2021年03月13日更新)
製作品 製作品 閲覧数 1448
eepoo 2021年02月21日作成 (2021年03月13日更新) 製作品 製作品 閲覧数 1448

32x64フルスクラッチライブラリによる内外温湿度表示時計

32x64フルスクラッチライブラリによる内外温湿度表示時計

LED Matrix PanelのESP32用ライブラリをフルスクラッチで作り、室内用と室外用にATH10を二つ接続。RTC(DS3231)をつないで室内外温湿度表示付き時計を作りました。
時計の操作(時刻合わせなど)はロータリスイッチを使い、暗くなったら表示も暗くするためにCdSを使っています。
フルカラーであることを示すために趣味の悪い色使いになっていますが、実際には落ち着いた色にしています。
キャプションを入力できます

AHT10はI2Cのカスケード接続です。ケーブルが短い室内はOKでしたが、1m程になる室外はエラーが出て安定しませんでした。フラットケーブルを使って、SDAとSCLの間にGND線を置くようにしたら安定しました。
I2CはRTCとも共有しています。
基板はKiCADで描いて作った自作基板です。基本的にHUB75への接続とRTCの接続でほとんどの使えるピンが埋まってしまうのでボタンをつけることができず、ロータリエンコーダで時刻設定などを行うことにしました。

ソースコードを全て載せると、ソースコードだらけになってしまうので、ポイントのところを抜粋して載せます。
 YanelsオブジェクトはMatrix panelの幅x高さ の int16_t バッファint16_t buf[]を持ちます。
ドットの描画は B0RRRRGGGGGBBBBB と各色5bitずつで定義した int16_t を設定します。
バッファプレーンに点を描画する部分です。

void YPanels::drawDot(int16_t x, int16_t y, int16_t color, bool wraproll, bool alpha) { if (x < 0) { if (wraproll) { x = x + PANEL_WIDTH; } else return; } else { if (x >= PANEL_WIDTH) { if (wraproll) { x = x - PANEL_WIDTH; } else return; } else { if (y < 0) { if (wraproll) { y = y + PANEL_HEIGHT; } else return; } else { if (y >= PANEL_HEIGHT) { if (wraproll) { y = y - PANEL_HEIGHT; } else return; } } } if (alpha) { buf[y * PANEL_WIDTH + x] = buf[y * PANEL_WIDTH + x] | color; } else { buf[y * PANEL_WIDTH + x] = color; } } }

Matrix Panelにバッファプレーンを転送する描画のキモになる部分、輝度bit毎に上から下までスキャンする。

int ganma[5] = {1, 16, 30, 60, 127}; //輝度bit 各諧調ページの光る時間を定義している //bufの内容を書き出す currRowはスキャンごとの行、 pageは輝度bit void writeColors() { for (byte col = 0; col < PANEL_WIDTH; col++) { bool rr1 = buf[currRow * PANEL_WIDTH + col] & (1 << page + 10); bool rr2 = buf[(currRow + SCAN_COUNT) * PANEL_WIDTH + col] & (1 << page + 10); bool gg1 = buf[currRow * PANEL_WIDTH + col] & (1 << page + 5); bool gg2 = buf[(currRow + SCAN_COUNT) * PANEL_WIDTH + col] & (1 << page + 5); bool bb1 = buf[currRow * PANEL_WIDTH + col] & (1 << page); bool bb2 = buf[(currRow + SCAN_COUNT) * PANEL_WIDTH + col] & (1 << page); //CLKをLOWにする digitalWrite(CLK, LOW); // PB7=CLK digitalWrite(R1, rr1); digitalWrite(R2, rr2); digitalWrite(G1, gg1); digitalWrite(G2, gg2); digitalWrite(B1, bb1); digitalWrite(B2, bb2); digitalWrite(CLK, HIGH); // PB7=CLK } } //page と currRowを順次進める pageは輝度bit 0~4 currRowはスキャン 0~16 void nextSection() { currRow++; if (currRow == SCAN_COUNT) { currRow = 0; page++; if (page == 5) { page = 0; } } } //currRowに従ってABCDをセットする void setScan(byte row) { digitalWrite(AA, row & B00000001); digitalWrite(BB, row & B00000010); digitalWrite(CC, row & B00000100); digitalWrite(DD, row & B00001000); } //page(輝度ビット)毎に光らせて消して次のスキャンを行う void IRAM_ATTR onTimer() { portENTER_CRITICAL_ISR(&timerMux); // Increment the counter and set the time of ISR portEXIT_CRITICAL_ISR(&timerMux); xSemaphoreGiveFromISR(timerSemaphore, NULL); timerAlarmDisable(timer); digitalWrite(OE, HIGH); //出力を消す nextSection(); setScan(currRow); digitalWrite(LAT, LOW); writeColors(); digitalWrite(LAT, HIGH); digitalWrite(OE, LOW); timerAlarmWrite(timer, ganma[page], true); timerAlarmEnable(timer); }

インスタンス生成後にタイマーをactivateする部分

void YPanels::begin() //タイマー初期化をコンストラクタに入れるとうまくいかない { timerSemaphore = xSemaphoreCreateBinary(); // Create semaphore to inform us when the timer has fired timer = timerBegin(0, OE_PSCALE, true); // Use 1st timer of 4 (counted from zero). Set 80 divider for prescaler (see ESP32 Technical Reference Manual for more info). timerAttachInterrupt(timer, &onTimer, true); // Attach onTimer function to our timer. timerAlarmWrite(timer, ganma[page], true); // Set alarm to call onTimer function every second (value in microseconds).Repeat the alarm (third parameter) timerAlarmEnable(timer); }

ちなみに、ピンアサインは以下の通り

define R1 25 #define G1 26 #define B1 27 #define R2 21 #define G2 22 #define B2 23 #define AA 12 #define BB 16 #define CC 17 #define DD 18 #define CLK 15 #define LAT 32 #define OE 33
eepooのアイコン画像
プログラミング大好きな本業メカ屋 arduinoからマイコンに手を出し、BluePillやESP32などでいろいろ作っています。 HUB75のLED Matrix Panelのライブラリを作ったりもしています。
ログインしてコメントを投稿する