温度表示をOLEDからe-Paperへ刷新

2月25日
  • 要旨

    温度計の表示をe-Paperにしてみました。
     

     

  • 経緯

    ・我が家では、屋外(窓の外)と室内(廊下)の2か所で温度を観測しています。  
    ・温度計はバッテリー駆動のため、低消費電力モード(5μA)で動作させています。屋外設置のため、通信方式は無線(Bluetooth)を採用しています。

    ・温度計の情報を受信し、Macへ送信する中継器を用意していましたが、この部分を改良することにしました。  
     
     <温度の記録>

     

  • 課題

    1. マイコンに接続している液晶基板(OLED)が白黒表示のみで、明るさの調整不可
    2. 焼き付きを防ぐために文字を10秒単位で移動させても、焼き付きが発生してしまう。
    3. 画面が小さく、老眼には見づらい。
        

     

  • 改良点

    4. 画面を大きく(2.9インチ)する。
    5. 紙のように見えるe-Paperでの表示を試す。


     

  • トライの経過

    ・2月8日
     AliExpressから部品が届き、情報収集を開始。

    ・2月17日  
     メーカーから対象(白黒版)の資料を入手し、デモソフトで動作確認。

    ・2月18日  
     ビットバンギングでシリアル通信を実現し、ポート設定の自由度を向上。

    ・2月20日  
     等幅フォントをプロポーショナルフォント風に改良。

    ・2月22日  
     複数ファイルを扱うため、開発環境をArduino IDEからVisual Studio Codeへ変更。  
     Gitでソース履歴の管理を開始。

    ・2月23日  
     デモソフトから必要部分のみソースコードを抽出し、中継器へ移植しています

 

  • 最後に

    今回は開発環境を変更したため、不慣れな操作が続き、
    少し大変でしたが、とりあえずe-Paperに表示できました。

    もう少し試行を重ねて内容がまとまりましたら、投稿します。  


    ここまで読んでいただき、ありがとうございます。

 

 

 

 

 

 

 

 

諦めていたレタスの小さな芽

2月24日 諦めていたレタスの小さな芽
  • 昨日の最低気温は14.2度と、異常なほど暖かかったです。
    今朝の最低気温も8.2度と、少し暖かく感じます。

    さて、1月18日に種まきしたレタスですが、
    あまりの寒さに発芽しないものと諦めていました。

    苗ドーム越しではよく見えなかったのですが、発芽していました。


    ただ、この芽がレタスなのか雑草なのかは判別できませんので、
    しばらく水やりをしながら観察していきます。

 
1月18日 5月収穫を目指してサニーレタス播種
  • 朝の最低気温は5.3℃と、比較的暖かかったです。  
    さて、1月16日に裏庭に放置していたオクラの鉢を撤去し、
    空いた鉢にサニーレタスを播いてみました。  

    収穫時期は5月ごろになるようです。
    うまくいくか分かりませんが、楽しみが一つ増えました。

 

4月末のような朝と、少しの収穫

2月23日 4月末のような朝と、少しの収穫
  • 朝の最低気温は14.2度と、まるで4月末ごろの陽気ですね。

    今日は、少し無謀かと思いながらも、KODAK Charmeraで記録してみました。

    昨日、苗ドームを外したチンゲンサイと春菊ですが、少しだけ収穫しました。

     

2月22日 三寒四温の朝、苗ドームを外す
  • 朝の最低気温は7.5度と、比較的暖かかったですね。
    三寒四温とよく言われますが、今年は2月ごろからその傾向が見られます。

    さて、チンゲンサイと春菊の鉢ですが、
    苗ドームの中で窮屈そうにしていたため、ドームを外しました。

    また寒さが戻るころには、収穫しようかと思っています。今回はCyber-shotで撮影。

 

三寒四温の朝、苗ドームを外す

2月22日
  • 朝の最低気温は7.5度と、比較的暖かかったですね。
    三寒四温とよく言われますが、今年は2月ごろからその傾向が見られます。

    さて、チンゲンサイと春菊の鉢ですが、
    苗ドームの中で窮屈そうにしていたため、ドームを外しました。

    また寒さが戻るころには、収穫しようかと思っています。

  • 今回の撮影は、Cyber-shotで撮影

 

 

 

 <2月15日 記載内容の抜粋>

 

開発環境移行の朝と、ベランダのチンゲンサイ収穫

2月21日 
  • 今日の最低気温は3.6度で、昨日より2.5度ほど暖かくなりました。とはいえ、寒がりの身にはあまり実感できません。

    朝4時に起きて、Arduinoの開発環境をArduino IDEからVisual Studioへ移行していたため、菜園の観察はお昼になってしまいました。

    2階ベランダのプランターで育てていたチンゲンサイを収穫し、夕飯の鍋に入れようと思っています。

日陰で育てたソロモンホウレンソウを初収穫

2月20日 日陰で育てたソロモンホウレンソウを初収穫
  • 二十四節気の雨水を過ぎたというのに、
    今日の最低気温は1.1度。まるで真冬に逆戻りしたかのようです。  

    昨年10月ごろ、玄関横の一日中日陰になる菜園に
    直播きしたソロモンホウレンソウを、ようやく初収穫しました。
    お昼のサラダにしておいしくいただきました。

 

2月1日 立春間近でも続く寒さ、野菜は耐寒中
  • 今日から2月ですね。大寒から12日が過ぎました。
    あと4日ほどで立春ですが、まだまだ寒さが続きます。

    さて、  
    朝の屋外最低気温は0.9度まで下がりました。昼過ぎには6.9度まで上がったため、
    2階ベランダ、1階廊下、1階玄関横の野菜に水やりをしました。

    写真は玄関横の様子で、不織布を開け、鉢は苗ドームを外しています。

    この時期、ほとんどの野菜は生長が止まり、寒さに耐えている状態です。



     

1月8日 成長はゆっくり、それでもがんばるホウレンソウ
  • 朝から曇り空で、最低気温は2.3度でした。少し風も出てきました。
    さて、
    玄関横にある、一日中日が差さない小さな菜園の不織布の中を観察してみました。
    直まきしたソロモン(ほうれん草)は、成長しているようには見えませんが、枯れもせず健気にがんばっています

e-Paperの等幅フォントをプロポーショナルフォント風に

経緯

e-Paperプログラムに付属していた等幅フォント(モノスペースフォント)ですが、見栄えがあまり良くなかったため、プロポーショナルフォント風に改良してみました。

手順

1.構造体 sFONTに文字幅を指定するための lengthOffset を定義しました。8行目 

diff --git a/fonts.h b/fonts.h
index 3015167..164f8ca 100644
--- a/fonts.h
+++ b/fonts.h
@@ -48,6 +48,7 @@
 #include <stdint.h>

 struct sFONT {
+  const uint8_t *lengthOffset; //等幅送りを少しだけ戻します
   const uint8_t *table;
   uint16_t Width;
   uint16_t Height

2.等幅フォントでは、次の文字の書き出し位置 refcolumn にフォント幅 font->Width を加算します。15行目

3.幅の狭い文字(例:i、l、I など)の場合は、送りを調整するため、refcolumn から定数 lengthOffsetの値を差し引きます。16行目

4.17〜19行目 幅の狭い文字(例:i、l、I など)が連続する場合は、送りをさらに戻して調整します。17〜19行目

diff --git a/epdpaint.cpp b/epdpaint.cpp
index 859b964..64e51a5 100644
--- a/epdpaint.cpp
+++ b/epdpaint.cpp
@@ -169,13 +169,13 @@ void Paint::DrawStringAt(int x, int y, const char* text, sFONT* font, int colore
     const char* p_text = text;
     unsigned int counter = 0;
     int refcolumn = x;
-
     /* Send the string character by character on EPD */
     while (*p_text != 0) {
         /* Display one character on EPD */
         DrawCharAt(refcolumn, y, *p_text, font, colored);
         /* Decrement the column position by 16 */
         refcolumn += font->Width;               //等幅送り
+        refcolumn -= font->lengthOffset[ *p_text - ' ' ]; //送りを戻す定数
+     if(*p_text == 'l' && *(p_text+1) == 'l') refcolumn -= 3;
+     if(*p_text == 'i' && *(p_text+1) == 'i') refcolumn -= 3;
+     if(*p_text == 'I' && *(p_text+1) == 'I') refcolumn -= 2;
         /* Point on the next character */
         p_text++;
         counter++;

5.文字幅指定用の lengthOffset は、ASCIIコード 0x20〜0x7F の範囲で定義しています。11〜17行目

6.sFONT 構造体の Font20 に、文字幅テーブル Font20_Length を追加しました。25行目

diff --git a/font20.cpp b/font20.cpp
index 70a220f..fd51c93 100644
--- a/font20.cpp
+++ b/font20.cpp
@@ -40,6 +40,18 @@
 #include <avr/pgmspace.h>

 // Character bitmaps for Courier New 15pt
+
+const uint8_t Font20_Length[] PROGMEM =
+{
+//0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f
+  1,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1, //2
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, //3
+  1,2,3,1,2,1,2,1,3,3,1,1,1,1,3,3, //4
+  2,1,1,1,1,1,1,0,2,2,2,1,1,1,1,1, //5
+  1,2,3,2,2,4,3,2,3,5,4,4,3,2,2,2, //6
+  2,2,4,3,4,2,2,2,2,3,2,1,1,1,1,1  //7
+};
+
 const uint8_t Font20_Table[] PROGMEM =
 {
        // @0 ' ' (14 pixels wide)
@@ -2135,6 +2147,7 @@ const uint8_t Font20_Table[] PROGMEM =


 sFONT Font20 = {
+  Font20_Length,
   Font20_Table,
   14, /* Width */
   20, /* Height */

7.font24``font16``font12``font8も同様の構造にしました

以上です。最後まで読んでいただき、ありがとうございました。

逆光を避けたモクレン撮影と手動フォーカス

2月19日 逆光を避けたモクレン撮影と手動フォーカス
  • 今日の最低気温は2.6度で、真冬に戻ったような寒さでした。

    さて、モクレンの撮影時間についてですが、
    朝は逆光になるため、花が真っ黒に写ってしまいます。

    そのため、午後2時半ごろに撮影しています。
    ただし、これ以上遅くなると隣家の影に入ってしまいます。

    iPhoneの標準カメラアプリでは、被写体の面積が小さいため、
    自動ではピントを合わせることができませんでした。

    そこで、「Halide Mark II」アプリを使い、手動でピント合わせを行いました。

2月2日 昼過ぎのモクレン撮影と明度調整の試行錯誤
  • 朝からTideプログラムを見直しているうちに昼過ぎになってしまい、
    慌ててモクレンの様子を投稿しようと、裏庭で撮影してみました。

    今年の花芽を決めて撮影しましたが、写真は真っ黒にしか写りません。

    そこで撮影位置を変えてみましたが、それでもまだ暗かったため、
    Pixelmator Proを使い中間明度をほんの少しだけ明るく調整してみました。



1月27 目測でピントを目合わせ
  • iPhoneで手動ピント合わせができる「Halide Mark II」のサブスクリプションを始めましたが、一つ問題が出てきました。  

    なるべく高い位置から撮影しようと腕を伸ばすと、画面が目から離れてしまい、老眼ではよく見えません。

    そこで試しに、手動モードで表示される距離の数値に合わせて撮影してみたところ、ばっちりピントが合いました。  


    45年前の夜間スナップ写真も、こんなふうに目測でピント合わせをしていたな、という記憶がよみがえりました。

1月17日 対象の花芽決め
  • 今日の最低気温は3.3℃でした。
    これからさらに寒くなるようで、電気代が気になる季節ですね。  

    さて、iPhoneでの撮影ではピンボケになることが多く、困っていました。
    そこで、手動でピント合わせができるアプリを購入したので、
    初夏まで試してみることにしました。

1月4日 モクレン撮影のピンボケ対策に「Halide Mark II」を試す
  • 12月12日、モクレンの記録でピンボケ対策として 
    「Final Cut Camera」のフォーカスピーキング機能を使いました。  
    ただしこの方法は、撮影後に動画から静止画を切り出す必要があり、少し手間がかかります。

    そこで、手動でピント合わせができるカメラアプリを探したところ、
    いくつか候補が見つかりました。
    その中から「Halide Mark II - Pro Camera」を選びました。

     

  • 使い方は、以下の記事を参考にしました。  

  • 手動ピント合わせの補助機能としては
    • フォーカスピーキング

    • 画面中央を拡大表示できるルーペ

  • 実際に撮影してみました

  • さまざまな機能があるようですが、特にルーペ拡大はとてもありがたいです。
    これで、iPhoneとデジカメの2台持ちをしなくて済みそうです。

    ただし残念な点として、年間3,000円のサブスクリプション費用がかかります。
    みなさまは、どのようにされているでしょうか。

 

ビットバンギングによるSPI通信の実装(XIAO Seeed RP2040)

背景

ビットバンギング手法を用いて、ソフトウェアから直接GPIOを操作し、SPI通信をエミュレートします。
(Emulate SPI communication by directly manipulating GPIO in software using bit-banging techniques.)

2月17日に、e-Paperをマイコン(XIAO Seeed RP2040)で動作させました。
その際、SPI通信には専用ピン(MOSIピンとSCKピン)を使用していました。

今回、これらの機能を任意のデジタルピンに割り当てられるようにするため、ビットバンギング手法を用いて実装してみました。

ソース変更

今回のメイン変更点  SPI通信でのビットバンギング手法による、通信

void EpdIf::BitBangingSpiTransfer(unsigned char data){
  for (int i = 7; i >= 0; i--) {
    // Set MOSI to the current bit
    if (data & (1 << i))
        digitalWrite(MOSI_PIN, HIGH);
    else
        digitalWrite(MOSI_PIN, LOW);
    
    // Toggle SCK (rising edge)
    digitalWrite(SCK_PIN, HIGH);
    // Toggle SCK (Falling edge)
    // delay(1);       // Hold clock high
    digitalWrite(SCK_PIN, LOW);
    // delay(1);       // Hold clock low
  }
}

epd2in9_V2.cpp

diff --git a/epd2in9_V2.cpp b/epd2in9_V2.cpp
index 04ba86b..b20b188 100644
--- a/epd2in9_V2.cpp
+++ b/epd2in9_V2.cpp
@@ -244,7 +244,8 @@ int Epd::Init_4Gray() {
 void Epd::SendCommand(unsigned char command) {
     DigitalWrite(dc_pin, LOW);
     DigitalWrite(cs_pin, LOW);
-    Spi.Transfer(command);
+    //for bit banging
+    Spi2Transfer(command);
     DigitalWrite(cs_pin, HIGH);
 }

@@ -254,7 +255,8 @@ void Epd::SendCommand(unsigned char command) {
 void Epd::SendData(unsigned char data) {
     DigitalWrite(dc_pin, HIGH);
     DigitalWrite(cs_pin, LOW);
-    Spi.Transfer(data);
+     //for bit banging
+    Spi2Transfer(data);^M
     DigitalWrite(cs_pin, HIGH);
 }

epd2in9_V2.ino

diff --git a/epd2in9_V2.ino b/epd2in9_V2.ino
index afe2b02..8622e4d 100644
--- a/epd2in9_V2.ino
+++ b/epd2in9_V2.ino
@@ -24,7 +24,8 @@
  * THE SOFTWARE.
  */

-#include <SPI.h>
+//for bit banging
+// #include <SPI.h>
 #include "epd2in9_V2.h"
 #include "epdpaint.h"
 #include "imagedata.h"
@@ -82,40 +83,40 @@ void setup() {
   paint.Clear(UNCOLORED);

   Serial.print("paint.DrawStringAt \n\r");
  paint.DrawStringAt(0, 40, "Hello world!", &Font20, COLORED);

   epd.SetFrameMemory(paint.GetImage(), 0, 10, paint.GetWidth(), paint.GetHeight
());

   Serial.print("epd.DisplayFrame \n\r");
   epd.DisplayFrame();

epdif.cpp

diff --git a/epdif.cpp b/epdif.cpp
index b1f89c9..8956563 100644
--- a/epdif.cpp
+++ b/epdif.cpp
@@ -26,8 +26,8 @@
  */

 #include "epdif.h"
-#include <SPI.h>
-
+//for bit banging
+// #include <SPI.h>
 EpdIf::EpdIf() {
 };

@@ -46,23 +46,48 @@ void EpdIf::DelayMs(unsigned int delaytime) {
     delay(delaytime);
 }

-void EpdIf::SpiTransfer(unsigned char data) {
+//for bit banging
+void EpdIf::Spi2Transfer(unsigned char data) {
     digitalWrite(CS_PIN, LOW);
-    SPI.transfer(data);
+    BitBangingSpiTransfer(data);
     digitalWrite(CS_PIN, HIGH);
 }

+//for bit banging
+void EpdIf::BitBangingSpiTransfer(unsigned char data){
+  for (int i = 7; i >= 0; i--) {
+    // Set MOSI to the current bit
+    if (data & (1 << i))
+        digitalWrite(MOSI_PIN, HIGH);
+    else
+        digitalWrite(MOSI_PIN, LOW);
+
+    // Toggle SCK (rising edge)
+    digitalWrite(SCK_PIN, HIGH);
+    // Toggle SCK (Falling edge)
+    // delay(1);       // Hold clock high
+    digitalWrite(SCK_PIN, LOW);
+    // delay(1);       // Hold clock low
+  }
+}
+
+
 int EpdIf::IfInit(void) {
     pinMode(CS_PIN, OUTPUT);
     pinMode(RST_PIN, OUTPUT);
     pinMode(DC_PIN, OUTPUT);
-    pinMode(BUSY_PIN, INPUT);
+    pinMode(BUSY_PIN, INPUT);
+
+    //for bit banging
+    pinMode(SCK_PIN, OUTPUT);
+    pinMode(MOSI_PIN, OUTPUT);

     pinMode(PWR_PIN, OUTPUT);
     DigitalWrite(PWR_PIN, 1);

-    SPI.begin();
-    SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
+    //for bit banging
+    // SPI.begin();
+    // SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
     return 0;
 }

epdif.h

diff --git a/epdif.h b/epdif.h
index 1679bed..094eae1 100644
--- a/epdif.h
+++ b/epdif.h
@@ -36,12 +36,18 @@
 // #define CS_PIN          10
 // #define BUSY_PIN        7
 // #define PWR_PIN         6
+
+// RP-2040
 #define RST_PIN         D2
 #define DC_PIN          D3
 #define CS_PIN          D4
 #define BUSY_PIN        D5
 #define PWR_PIN         D6

+//for bit banging
+#define MOSI_PIN        D10
+#define SCK_PIN         D8
+
 class EpdIf {
 public:
     EpdIf(void);
@@ -51,7 +57,10 @@ public:
     static void DigitalWrite(int pin, int value);
     static int  DigitalRead(int pin);
     static void DelayMs(unsigned int delaytime);
-    static void SpiTransfer(unsigned char data);
+    //for bit banging
+    // static void SpiTransfer(unsigned char data);
+    static void Spi2Transfer(unsigned char data);
+    static void BitBangingSpiTransfer(unsigned char data);
 };

 #endif
 
 ```

夏野菜の準備開始、キャベツをベランダへ移動

2月18日 夏野菜の準備開始、キャベツをベランダへ移動
  • 昨日から寒くなり、今日の最低気温は3.9度でした。  
    とはいえ、まもなく3月ですので、夏野菜の準備を始めます。

    そこで、種まきスペースを作るため、パソコン横に置いてあったキャベツを2階のベランダへ移しました。急に屋外へ出すことになりましたが、以前からベランダに置いてあるキャベツは立派に育っていますので、大丈夫だろうと思っています。

 

1月24日 気温5度を超えてからの水やり
  • 朝5時ごろ、外気の最低気温が更新され、0.3度となりました。  
    室内はエアコンを18度に設定していましたが、
    廊下との間を半分開けていたため、室温は13度まで下がっていました。

    さて、
    太陽が当たり気温が5度を超えたので、2階ベランダのキャベツに水やりをしました。

     

  • 12月22日 苗ドームを外し
    • 2階ベランダのキャベツですが、12月19日に観察したところ、
      苗ドームの中に空間がなくなり、窮屈そうにしていました。  

      これから一段と寒くなりますが、思い切って苗ドームを外しました。
      心配なので、しばらくは毎日観察するつもりです。

プライバシーポリシー |ページトップへ

`