MAX7219の使い方8×8LCD無ライブラリー(9)ESP32編

この4日~5日の間,頭をさんざん悩ませていました。何のことはない,数字のを上から落ちてくるようにし
たくて,あれこれなやんでしました。特に,この二日間は,散歩しながらも,うまくいかない原因を考えては
,手直しを考える。散歩が終わってからは実際に修正してみる,の繰り返しをしてました。今日,やっと思っ
た動作ができるよいうになりました。スケッチのアルゴリズム(手順)は,ほぼ間違いなかったのですが,
順番を間違っていました。本来ならば,

  保持しているメモリの移動→→新しい書き込み

の順でしなければならないのに,

  書き込み→メモリーの移動

の順にしてました。完成したときは,思わず,やった,と叫びそうになりました。

動画のような動作になりますが,一秒の表示のところが,時々,数字が飛びます。これは,処理の関係で仕方
ないのかなと思います。スケッチは,ほとんどが,bit の操作で,今回は,備え付けの関数を使わないで,
or と and で処理しました。冗長なスケッチですが,次のものが,数字をセットする部分のスケッ
チです。

/**************************************************************
*number_set_V_T(int y,int x,string num)
*
***************************************************************/
void number_set_V_T(int y,int x,char ch){
 
  int num;
  unsigned char buff;
  unsigned char buff_suji;


  if(ch=='0'){num=0;}
  if(ch=='1'){num=1;}
  if(ch=='2'){num=2;}
  if(ch=='3'){num=3;}
  if(ch=='4'){num=4;}
  if(ch=='5'){num=5;}
  if(ch=='6'){num=6;}
  if(ch=='7'){num=7;}
  if(ch=='8'){num=8;}
  if(ch=='9'){num=9;}
  if(ch=='A'){num=10;}


  int u_num=(x-1)/8+1;
  if((x % 8)==0){
     x=8;
  }
  else{
     x=x % 8;
  }


  switch (x){    
      case 8:
        for(int n=7;n>=0;n--){
          v_shift_T(u_num,x);


          buff_suji=suuji[num][n];
          buff_suji=buff_suji<<2;//数字を2ビットシフト
          dot_hoji[u_num][1]=dot_hoji[u_num][1] & 0b00011111;
          dot_hoji[u_num][1]=dot_hoji[u_num][1] | buff_suji;
          dummy[8-n]=dot_hoji[u_num][1];


          dot_hyouji(u_num);
          delay(TM);
         
        }
        break;
      case 7:
        for(int n=7;n>=0;n--){
           v_shift_T(u_num,x);


          buff_suji=suuji[num][n];
          buff_suji=buff_suji<<1;//数字を2ビットシフト
          dot_hoji[u_num][1]=dot_hoji[u_num][1] & 0b10001111;
          dot_hoji[u_num][1]=dot_hoji[u_num][1] | buff_suji;
         
          dot_hyouji(u_num);
          delay(TM);
         
        }
        break;      
      case 6:
        for(int n=7;n>=0;n--){
           v_shift_T(u_num,x);


          buff_suji=suuji[num][n];
          dot_hoji[u_num][1]=dot_hoji[u_num][1] & 0b11000111;
          dot_hoji[u_num][1]=dot_hoji[u_num][1] | buff_suji;
         
          dot_hyouji(u_num);
          delay(TM);
        }
        break;
      case 5:
       for(int n=7;n>=0;n--){
          v_shift_T(u_num,x);


          buff_suji=suuji[num][n];
          buff_suji=buff_suji>>1;//数字を右に1ビットシフト
          dot_hoji[u_num][1]=dot_hoji[u_num][1] & 0b11100011;
          dot_hoji[u_num][1]=dot_hoji[u_num][1] | buff_suji;
         
          dot_hyouji(u_num);
          delay(TM);
        }
        break;      
      case 4:
        for(int n=7;n>=0;n--){
          v_shift_T(u_num,x);


          buff_suji=suuji[num][n];
          buff_suji=buff_suji>>2;//数字を右に2ビットシフト
          dot_hoji[u_num][1]=dot_hoji[u_num][1] & 0b11110000;
          dot_hoji[u_num][1]=dot_hoji[u_num][1] | buff_suji;


          dot_hyouji(u_num);
          delay(TM);
        }
        break;  
      case 3:
        for(int n=7;n>=0;n--){
          v_shift_T(u_num,x);


          buff_suji=suuji[num][n];
          buff_suji=buff_suji>>3;//数字を右に3ビットシフト
          dot_hoji[u_num][1]=dot_hoji[u_num][1] & 0b11111000;
          dot_hoji[u_num][1]=dot_hoji[u_num][1] | buff_suji;
         
          dot_hyouji(u_num);
          delay(TM);
        }
        break;
      case 2:
        if(u_num>1){
          for(int n=7;n>=0;n--){
            v_shift_T(u_num,x);


            buff_suji=suuji[num][n];
            buff_suji=buff_suji>>4;
            dot_hoji[u_num][1]=dot_hoji[u_num][1] & 0b11111100;
            dot_hoji[u_num][1]=dot_hoji[u_num][1] | buff_suji;
           
            buff_suji=suuji[num][n];
            buff_suji=buff_suji<<4;
            dot_hoji[u_num-1][1]=dot_hoji[u_num-1][1] & 0b01111111;
            dot_hoji[u_num-1][1]=dot_hoji[u_num-1][1] | buff_suji;


            dot_hyouji(u_num);
            delay(TM);
          }
        }
        else{
          for(int n=7;n>=0;n--){
            v_shift_T(u_num,x);


            buff_suji=suuji[num][n];


            buff_suji=buff_suji>>4;
            dot_hoji[u_num][1]=dot_hoji[u_num][1] & 0b11111100;
            dot_hoji[u_num][1]=dot_hoji[u_num][1] | buff_suji;
            buff_suji=suuji[num][n];


            dot_hyouji(u_num);
            delay(TM);
          }
        }
        break;
      case 1:
        if(u_num>1){
          for(int n=7;n>=0;n--){
            v_shift_T(u_num,x);


            buff_suji=suuji[num][n];
           
            buff_suji=buff_suji>>5;
            dot_hoji[u_num][1]=dot_hoji[u_num][1] & 0b11111110;
            dot_hoji[u_num][1]=dot_hoji[u_num][1] | buff_suji;
           
            buff_suji=suuji[num][n];
            buff_suji=buff_suji<<3;
            dot_hoji[u_num-1][1]=dot_hoji[u_num-1][1] & 0b00111111;
            dot_hoji[u_num-1][1]=dot_hoji[u_num-1][1] | buff_suji;


            dot_hyouji(u_num);
            delay(TM);
          }
        }
        else{
          for(int n=7;n>=0;n--){
             v_shift_T(u_num,x);


            buff_suji=suuji[num][n];
            buff_suji=buff_suji>>5;
            dot_hoji[u_num][1]=dot_hoji[u_num][1] & 0b11111110;
            dot_hoji[u_num][1]=dot_hoji[u_num][1] | buff_suji;
           
            dot_hyouji(u_num);
            delay(TM);
          }
        }
        break;      
  }
}

次が,メモリーをシフトする部分のスケッチです。

/**************************************************************
*void v_shift_T(int u_num,x)
*
****************************************************************/
void v_shift_T(int u_num,int x){
  unsigned char buff=0;
  unsigned char buff1=0;
 
 switch (x){
    case 8:
       for(int n=8;n>1;n--){
        buff=dot_hoji[u_num][n-1] & 0b11100000;
        buff1=dot_hoji[u_num][n] & 0b00011111;
        dot_hoji[u_num][n]=buff | buff1;
      }
      break;
    case 7:
      for(int n=8;n>1;n--){
        buff=dot_hoji[u_num][n-1] & 0b01110000;
        buff1=dot_hoji[u_num][n] & 0b10001111;
        dot_hoji[u_num][n]=buff | buff1;
      }
      break;    
    case 6:
      for(int n=8;n>1;n--){
        buff=dot_hoji[u_num][n-1] & 0b00111000;
        buff1=dot_hoji[u_num][n] & 0b11000111;
        dot_hoji[u_num][n]=buff | buff1;
      }
      break;
    case 5:
      for(int n=8;n>1;n--){
        buff=dot_hoji[u_num][n-1] & 0b00011100;
        buff1=dot_hoji[u_num][n] & 0b11100011;
        dot_hoji[u_num][n]=buff | buff1;
      }
      break;
    case 4:
      for(int n=8;n>1;n--){
        buff=dot_hoji[u_num][n-1] & 0b00001110;
        buff1=dot_hoji[u_num][n] & 0b11110001;
        dot_hoji[u_num][n]=buff | buff1;
      }
      break;
    case 3:
        for(int n=8;n>1;n--){
          buff=dot_hoji[u_num][n-1] & 0b00000111;
          buff1=dot_hoji[u_num][n] & 0b11111000;
          dot_hoji[u_num][n]=buff | buff1;
        }
        break;
    case 2:
        if(u_num>1){


          for(int n=8;n>1;n--){
            buff=dot_hoji[u_num][n-1] & 0b00000011;
            buff1=dot_hoji[u_num][n] & 0b11111100;
            dot_hoji[u_num][n]=buff | buff1;


            buff=0;
            buff1=0;


            buff=dot_hoji[u_num-1][n-1] & 0b10000000;          
            buff1=dot_hoji[u_num-1][n] & 0b01111111;
            dot_hoji[u_num-1][n]=buff | buff1;
          }
        }
        else{
          for(int n=8;n>1;n--){
            buff=dot_hoji[u_num][n-1] & 0b00000011;
            buff1=dot_hoji[u_num][n] & 0b11111100;
            dot_hoji[u_num][n]=buff | buff1;
          }
        }
        break;
    case 1:
      if(u_num>1){
          for(int n=8;n>1;n--){
            buff=dot_hoji[u_num][n-1] & 0b00000001;
            buff1=dot_hoji[u_num][n] & 0b11111110;
            dot_hoji[u_num][n]=buff | buff1;


            buff=dot_hoji[u_num-1][n-1] & 0b11000000;          
            buff1=dot_hoji[u_num-1][n] & 0b00111111;
            dot_hoji[u_num-1][n]=buff | buff1;
          }
        }
        else{
          for(int n=8;n>1;n--){
            buff=dot_hoji[u_num][n-1] & 0b00000001;
            buff1=dot_hoji[u_num][n] & 0b11111110;
            dot_hoji[u_num][n]=buff | buff1;
          }
        }
      break;            
  }
}

かなり頭を悩ませましたが,やっとできて,ほっとしてます。こうやって,ああでもないこうでもないとあれ
これ考えることはとってもいいぼけ防止になってるるかなと思います。

我が家のブルーベリーの木

昨年,沢山の実をつけた我が家のブルベリーですが,思い切って剪定し,今年は実はならないかなと思って
いましたが,結構花が咲きました。

ところが,この少ない花目当てに鳥がついばみにきました。これは,やばい,ということで,さっそっく網
を書けることにしました。

昨年は,実が付いてから網をかけましたが,今年は,咲いた花が少ないので,花の段階からです。家の者と
1時間程度かけて,網をかけました。

昨年と違う種類の網にしましたが,今回の網は,それほど手こずらすにかけることができました。

ESP32で秋月ACM1602NIを使う (3)

ACM162NIの命令について調べていましたが,何となく理解できましたが,カーソルの移動について,いま
いちでしたが,またまた諸兄のHPにて理解が進みました。ACM1602NIの制御では,

COMMMANDを送るときは,0X00 を送信して,
data を送るときは,0x80を送信します。

マニュアルを読んでいるとDDRAMのアドレスを送ればいいとありましたが,その方法がわかりませんでした。

それぞれアドレスが表示位置をあらわしていますので,1行目の3文字めにカーソルを移動するには,

   0x80+0x02

を送ってやればいいようです。このことを諸兄のHPのサブルーチンを見ていてやっと理解できました。
スケッチでは,orをとって実現すればいいようです。諸兄のHPにはサブルーチンが下記のようにありました。

void setCursor(byte col, byte row)
{
    byte row_offsets[] = { 0x00, 0x40 };
 
    if ( row > 1 ) {
        row = 1;
    }
    writeCmd( 0x80 | (col + row_offsets[row]) );
}

ACM1602NIの制御を理解するのに,熊谷研修室というHPが役にたちました。

ESP32で秋月ACM1602NIを使う (2)

早とちりしてました。何回かのトライで,昇天させたかと思っていましたが,しばらく,PICへの書き込みをし
ていなかったのでうまくデータを読み込めていなかったようです。その後何度か書き込みにトライしてみた
ら,見事成功しました。久しぶりにPICKIT3を使ったのですが,調子悪いものがあり,結局,中華製の安いも
のでの成功でした。書き込みに使ったPCも今使っているものの前に使っててもので,このPCはUSBポートの調
子がいまいちでしたが,何カ所かあるポートのうちの一カ所が調子いいようで,やっとそこで成功いたしまし
た。

I2Cの通信速度を落とさなくても,I2Cスキャナーでも確認できましたし,

 Wire.begin(21,22)

のデフォルトの設定で,テストプログラムも動きました。LCDを壊さなくてよかったです。それに,あきらめ
なくて良かったです。今日は,ぐっすりねむれるかなあ。

それにしても,先達はすごいですねえ。今回,参考にさせていただいたHPの大本は,以前,ローコストシリア
ル通信モニターを作成したときのHPの方のHPでした。

今回I2CのLCDをあれこやったのは,複数のI2Cの機器や,SPIとI2Cの機器を混在させて使ってみようかなと考
えたからです。これで,秋月のLCDも回路に組み込むことができます。

**********追記**********
その後あれこれやりましたが,オリジナルのファームウエアーでは,下記の設定の 70000 が限界のようで

   Wire.begin(21,22,70000)

した。それを過ぎると認識(I2C通信不可になる)されなくなるようでした。ファームウエアの書き換え
できないようなら,通信速度を落として使うか,ACM1602NI以外のLCD使うようでしょうね。

ESP32で秋月ACM1602NIを使う (1)

あれこれやっているうちに,ESP32でも,手元にあった秋月のACM1602NIというLCDを使ってみることにし
ました。ACM1602NIは,バックライトの半固定抵抗,プルアップ用の抵抗,5Vで使う抵抗,等の外部の
配線がいるので,ブレッドボード用に小さな基板でアダプター?を作成しました。

いざサンプルのスケッチを書き込んで動作確認。ところが,うんともすんともいいません。配線が間違
ったのかと思いなんども確認しました。間違いがないようなので,I2Cスキャナーというスケッチで接続
を確認しても確認できません。別なI2CのLCDを接続してみると,そのLCDは接続が確認できて,I2Cのアド
レスも表示されます。ただ,時々,秋月のLCDを接続して,I2Cスキャナーを動かすと瞬間認識されること
もありました。さんざん頭をなやまして,あれこれ,くぐりましたがその原因にやっと行き着くことがで
きました。やはり先達は,すごい。なんと,ACM1602NIは,I2Cの標準通信速度の要件をみたしていなかっ
たのです。解決には,通信速度を下げるか,ACM1602NIのフォームウエア-を書き換えるかの2択だとあり
ましたので,とりあえず通信速度を落としてみました。Wire.h のライブラリーをつかいますが,このラ
イブラリーで,Wire.bigin()の初期設定をしますが,この設定で,SCL,SDA端子の設定,通信速度の設定を
するようです。通常は,通信速度は,省略するすとデフォルトの100000 が選択されるようですが,ここ
で, 50000 に落としてみました。

   Wire.bigin(21,22,50000); //(SCL端子,SDA端子,周波数)

に変更してみると,I2Cスキャナー も サンプルスケッチもあっけなく動きました。

下記のスケッチは,あるHPからお借りした,I2Cスキャナーのものです。このスケッチで,I2Cの個別のア
ドレスを取得することができます。通常は,ソフトで,I2Cのアドレスを変更できるみたいですが,秋月の
のものは,ソフトでは,変更できないようで,RX と表示のあるピンをGNDに落とすことで,0x3d に変更で
きるようです。(フォームウエア書き換え後みたいでした。)

// --------------------------------------
// i2c_scanner
//
// Version 1
//    This program (or code that looks like it)
//    can be found in many places.
//    For example on the Arduino.cc forum.
//    The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
//     Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26  2013
//    V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
//    by Arduino.cc user Krodal.
//    Changes by louarnold removed.
//    Scanning addresses changed from 0...127 to 1...119,
//    according to the i2c scanner by Nick Gammon
//    http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
//    As version 4, but address scans now to 127.
//    A sensor seems to use address 120.
// Version 6, November 27, 2015.
//    Added waiting for the Leonardo serial communication.
//
// branch out for ESP32 2018/05/25
//
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//
#include <Wire.h>

void setup()
{
  Wire.begin(21,22,50000);  //ここを書き換えた
  Serial.begin(115200);        
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\nI2C Scanner");
}

void loop()
{
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");
      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknown error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
  delay(5000);           // wait 5 seconds for next scan
}

幸い,手元には,ACM1602NI のフォームウエア-を書き換える部材は,そろっていますので,後日,
ACM1602NIのフォームウエア-を書き換えて,標準の通信速度で動くか確認してみようかなと思います。

arduino では,問題なく動いたのに,ESP32 で動かないのは,arduino の動作速度が,ESP32 に比
べるとその分,遅いのでしょうかね。

***********後日談************
諸先輩のHPを参考に,ACM1602NIに搭載されている16F689の書き換えを行ったが,見事に失敗。問題なく
動いていたACM1602NIは昇天してしまいました。

MAX7219の使い方8×8LCD無ライブラリー(8)ESP32編

iphonアプリの時計と比べてみましたが,約2秒ほどの遅れがあるようです。ネットから取得,処理,表
示と結構いろんなことをやってますので,タイムラグがあるんでしょうね。

ネット接続関係や,時刻の取得については,諸兄がいろいろ掲載していますので,そちらが参考になるかと思
います。

MAX7219の使い方8×8LCD無ライブラリー(7)ESP32編

何年か前に,ワイヤレスのテパを作るのに,Xbee とPICであれこれやりました。当時は,ESP32については
知りませんでしたのでもし存在が分かってたら間違いなくESP32の方を使ったと思います。ということで,
今回は,ESP32を使って, arduino で走らせていた 8×8 表示のLEDの表示をあれこれやってみようと
思います。幸い,arduino と ESP32 は かなりの互換性があるようで,それほどてを加えないで,同じ
ことができます。さらにいいことには,標準で,wify と bluetooth が搭載されていますので,そのま
まで,wify に接続 できますし,bluetooth 経由のシリアル通信もできてしまいます。メモリーもかな
多くて,

     ESP32  フラッシュメモリー 4MB(プログラム可能領域 約1.3MB)
     arduino フラッシュメモリー 32KB 

ですから,よほど大きなスケッチ(プログラム)を組まない限り,余裕だと思います。設定をかえることで
プログラム可能領域は,3MB程度まで,増やせるようです。

流れで,写真のような,ブレッドボードで,インターネット時計を表示させるべく,あれこれやりまし
た。ESP32に直接MAX7219を接続されている方もいるようですが,一応,レベラ-を間にいれて,3.3V→5vに
してあります。

スケッチ(プログラム)の作成では,表示の部分で,その9割ぐらいの労力をさきました。SPIのライブラリー
は使いましたが,後は,自前で準備です。今回,はまったのは,switch case 文で,

     String ch;
     switch(ch){
       case ”今日”:
       case ”明日”:

のような表現ができなかったことです。arduino では,switchの括弧の中で使えるのは,int 型の数値だけ
のようで,最初分からず手間取りました。表示に必要な情報は,2進数で表現するため,あれやこれやで,
ビットの操作を今までになくやりました。

下記のスケッチは,作成に結構時間のかかった,数字の表示のサブルーチンです。キャラクターも適当に作り
ましたので,諸兄のような,かっこいい物ではありません。後日,動いている様子もUPします。

/**********************************************************
*数字セット
*
***********************************************************/
uint8_t suuji[12][8]={{0x0,0x38,0x28,0x28,0x28,0x28,0x38,0x0},//0
                {0x0,0x10,0x10,0x10,0x10,0x10,0x10,0x0},//1
                {0x0,0x38,0x8,0x38,0x20,0x20,0x38,0x0},//2
                {0x0,0x38,0x8,0x38,0x8,0x8,0x38,0x0},//3
                {0x0,0x28,0x28,0x38,0x8,0x8,0x8,0x0},//4
                {0x0,0x38,0x20,0x38,0x8,0x8,0x38,0x0},//5
                {0x0,0x38,0x20,0x38,0x28,0x28,0x38,0x0},//6
                {0x0,0x38,0x28,0x8,0x8,0x8,0x8,0x0},//7
                {0x0,0x38,0x28,0x38,0x28,0x28,0x38,0x0},//8
                {0x0,0x38,0x28,0x38,0x8,0x8,0x38,0x0},//9
                {0x0,0x0,0x10,0x0,0x0,0x10,0x0,0x0},//:
                {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}};//""
/***************************************************************
*number_set(int y,int x,string num)
*
***************************************************************/
void number_set(int y,int x,String ch){
  int num;
  if(ch=="0"){num=0;}
  if(ch=="1"){num=1;}
  if(ch=="2"){num=2;}
  if(ch=="3"){num=3;}
  if(ch=="4"){num=4;}
  if(ch=="5"){num=5;}
  if(ch=="6"){num=6;}
  if(ch=="7"){num=7;}
  if(ch=="8"){num=8;}
  if(ch=="9"){num=9;}
  if(ch=="10"){num=10;}

 int u_num=(x-1)/8+1;
  if((x % 8)==0){
    x=8;
  }
  else{
    x=x % 8;
  }
 
  switch (x){    
      case 8:
      case 7:
      case 6:
      case 5:
      case 4:      
      case 3:
        for(int i=1;i<9;i++){
          if(bitRead(suuji[num][i-1],5)){
            bitSet(dot_hoji[u_num][i],x-1);
          }
          else{
            bitClear(dot_hoji[u_num][i],x-1);
          }
          if(bitRead(suuji[num][i-1],4)){
            bitSet(dot_hoji[u_num][i],x-2);
          }
          else{
            bitClear(dot_hoji[u_num][i],x-2);
          }
          if(bitRead(suuji[num][i-1],3)){
            bitSet(dot_hoji[u_num][i],x-3);
          }
          else{
            bitClear(dot_hoji[u_num][i],x-3);
          }
        }
        break;
      case 2:
        for(int i=1;i<9;i++){  
          if(bitRead(suuji[num][i-1],5)){
            bitSet(dot_hoji[u_num][i],x-1);
          }
          else{
            bitClear(dot_hoji[u_num][i],x-1);
          }
          if(bitRead(suuji[num][i-1],4)){
            bitSet(dot_hoji[u_num][i],x-2);
          }
          else{
            bitClear(dot_hoji[u_num][i],x-2);
          }
          if(u_num>1){
            if(bitRead(suuji[num][i-1],3)){
              bitSet(dot_hoji[u_num-1][i],7);
            }
            else{
              bitClear(dot_hoji[u_num-1][i],7);
            }  
          }
        }
        break;
      case 1:
        for(int i=1;i<9;i++){  
            if(bitRead(suuji[num][i-1],5)){
              bitSet(dot_hoji[u_num][i],x-1);
            }
            else{
              bitClear(dot_hoji[u_num][i],x-1);
            }
            if(u_num>1){
              if(bitRead(suuji[num][i-1],4)){
                bitSet(dot_hoji[u_num-1][i],7);
              }
              else{
                bitClear(dot_hoji[u_num-1][i],7);
              }
              if(bitRead(suuji[num][i-1],3)){
                bitSet(dot_hoji[u_num-1][i],6);
              }
              else{
                bitClear(dot_hoji[u_num-1][i],6);
              }
            }
        }
      break;
      }
for(int i=1;i<9;i++){ 
    switch (u_num){
      case 1:
          maxTransfer(0,0);
          maxTransfer(0,0);
          maxTransfer(0,0);
          maxTransfer(i,dot_hoji[1][i]);
          digitalWrite(CS_PIN, HIGH);        
          break;
      case 2:
          maxTransfer(0,0);
          maxTransfer(0,0);
          maxTransfer(i,dot_hoji[2][i]);
          maxTransfer(i,dot_hoji[1][i]);
          digitalWrite(CS_PIN, HIGH);
          break;
      case 3:
          maxTransfer(0,0);
          maxTransfer(i,dot_hoji[3][i]);
          maxTransfer(i,dot_hoji[2][i]);
          maxTransfer(0,0);
          digitalWrite(CS_PIN, HIGH);
          break;  
      case 4:
          maxTransfer(i,dot_hoji[4][i]);
          maxTransfer(i,dot_hoji[3][i]);
          maxTransfer(0,0);
          maxTransfer(0,0);
          digitalWrite(CS_PIN, HIGH);
   }
}

また,数値の表示を呼び出すサブルーチンの引数は,数字を保存してある配列を呼び出すのに都合がよかった
のでint型にしていますが,時刻の表示を string の変数か呼び出すので,急遽 string 型にしましたが,
ここでも変換の備え付けの関数をつかいましたがうまくいかなかったので,サブルーチンの中で,
if 文で string から int に変換しました。

MAX7219の使い方 8×8LCD 無ライブラリー (6)

今日は,エクセルで,キャラクターやフォントを作るための簡単なVBAをプロシャージャを作り,画像のよう
なシートを作成しました。上のますに,0か1をいれるとイメージの画像が作成でき,あわせてそのデータが
16進数で表示されます。

下のますの,16進数入力のセルに16進数のデータをいれるとそれに応じて画像が表示されます。

このシートの作成にあたって,条件付き書式設定をし,関数を2つ作りました。上下のますの表示形式を文字
にしました。

作った関数は,0と1の入力から,二進数を作る関数です。それぞれセルを文字列として結合してるだけです。

Public Function moji_ketugou(Hani As Range) As String
  Dim moji As String
  Dim Buff As Range
  moji = ""
  For Each Buff In Hani
    moji = moji & Buff.Value
  Next Buff
  moji_ketugou = moji
End Function

次の関数は,二進数の特定のビットを取り出す関数で,二つ目のますのセルに埋め込んであります。
C10          C11           C12          C13
= bit_toridasi($B11,1)・= bit_toridasi($B11,5)・= bit_toridasi($B11,7)・= bit_toridasi($B11
,7)・・・・・・・・・

Public Function bit_toridasi(moji As Range, keta As Integer) As String

   bit_toridasi = MidB(moji.Value, keta, 1)

End Function

 

MAX7219の使い方 8×8LCD 無ライブラリー (5)

これといった目標もないのですが,今日は,画面をスクロールするスケッチを作ってみました。いろいろな方
法があるかとは思いますが,保持しているデータを全部,1ビットだけ左にシフトする操作を保持しているメ
モリーにほどこして,画面全体を表示しています。

スクロールさせる図形は,昨日までに作った,set_dot(*,*,*,*); の関数で表示してます。

set_dot(1,1,1,1);
set_dot(1,5,1,1);
set_dot(2,2,1,1);
set_dot(2,6,1,1);
set_dot(3,3,1,1);
set_dot(3,7,1,1);
set_dot(4,4,1,1);
set_dot(4,8,1,1);
set_dot(5,4,1,1);
set_dot(5,8,1,1);
set_dot(6,3,1,1);
set_dot(6,7,1,1);
set_dot(7,2,1,1);
set_dot(7,6,1,1);
set_dot(8,1,1,1);
set_dot(8,5,1,1);

下記がスクロールさせるスケッチです。セットした画像をエンドレスで表示するようにしてあります。

void men_Shift(){
  boolean buff=false;
  for(int y=1;y<9;y++){
    if(bitRead(dot_hoji[4][y],7)){//4ユニット目表示メモリーの最上位を保持
      buff=true;
    }
    else{
      buff=false;
    }
    dot_hoji[4][y]=dot_hoji[4][y]<<1;
      if(bitRead(dot_hoji[3][y],7)){
        bitSet(dot_hoji[4][y],0);
      }
    dot_hoji[3][y]=dot_hoji[3][y]<<1;
      if(bitRead(dot_hoji[2][y],7)){
        bitSet(dot_hoji[3][y],0);
      }
    dot_hoji[2][y]=dot_hoji[2][y]<<1;
      if(bitRead(dot_hoji[1][y],7)){
        bitSet(dot_hoji[2][y],0);
      }
    dot_hoji[1][y]=dot_hoji[1][y]<<1;
      if(buff){//4ユニット目表示メモリーの最上位をセット
        bitSet(dot_hoji[1][y],0);
      }
    maxTransfer(y, dot_hoji[4][y]);
    maxTransfer(y, dot_hoji[3][y]);
    maxTransfer(y, dot_hoji[2][y]);
    maxTransfer(y, dot_hoji[1][y]);
    digitalWrite(CS_PIN, HIGH);//一括アップロードラッチ 
  }
}

今回も,ビット演算子を使わないで,準備されているビット操作の関数を使いました。

この8×8LEDユニットとESP32というWi-Fiとブルートースを搭載したチップで,
時計をお作りになっている諸兄もいらっいます。

このチップは開発ボードと呼ばれているもので,簡単に書き込みのできるものです。余分なものを省いたチ
ップだけの販売もあります。このチップだけの物は,書き込み等の回路を自作か購入しなければなりません
が組み込みでなにかを作るには小型化できるメリットがあります。コスパもいいかなあ。

ちなみに開発ボードは,〇zonだと,700円前後。チップだけのものは,3個で800円なんてのもあります。
〇mazonからのものもそうですが,無線関係の機器は,技適マークの関連もあるので,難しいところですね。
ちなみに,少し前に,〇mazonから,二個セットのESP32を購入しましたが,2つのうち1つには,技適マーク
がついていませんでした。

MAX7219の使い方 8×8LCD 無ライブラリー (4)

思った位置のドットを点灯する関数を作ってみました。



Void set_dot(int x,int y,int u_num){
  switch (u_num){
    case 1:
        maxTransfer(0,0);
        maxTransfer(0,0);
        maxTransfer(0,0);
        maxTransfer(x,1<<(y-1));
        digitalWrite(CS_PIN, HIGH);
        break;
    case 2:
        maxTransfer(0,0);
        maxTransfer(0,0);
        maxTransfer(x,1<<(y-1));
        maxTransfer(0,0);
        digitalWrite(CS_PIN, HIGH);
        break;
    case 3:
        maxTransfer(0,0);
        maxTransfer(x,1<<(y-1));
        maxTransfer(0,0);
        maxTransfer(0,0);
        digitalWrite(CS_PIN, HIGH);
        break;  
    case 4:
        maxTransfer(x,1<<(y-1));
        maxTransfer(0,0);
        maxTransfer(0,0);
        maxTransfer(0,0);
        digitalWrite(CS_PIN, HIGH);
  }
}

この関数を使って,縦に順次点灯し,終わったら次の行を同じように点灯するスケッチを動かしてみました。

void loop() {
   Clear_Matrix();
  for(int u=1;u<5;u++){
    for(int y=1;y<9;y++){
      for(int x=1;x<9;x++){
        set_dot(x,y,u);
        delay(500);
      }
    }
  }
}}

このスケッチは次の動画のような動作をします。消すためのスケッチはいれてないのですが,縦の列のドット
は保持できるのですが,隣の行に書き込むと前の行のドットは消えてしまいます。これは意識して消している
のではなく,結果として消えてます。
横一列の表示は,8ビットのデータを書き込むこと0で行います。00000001 のデータを書き込むと一番右を
点灯させることができます。2番目を点灯させるために,1 を左に一個だけシフトさせて,00000010 の
データを作り,書き込んでいます。結果,一番右のドットは消灯することになります。

これは意図した動作ではないので,どうした物か考えましたが,結果,操作したドットの状態を記憶し
ないとだめだろうというこで,配列を準備して,操作したドットの情報を保持すれば,することにしま
した。次のスケッチが,メモリーの保持をいれて,ドットの点灯・消灯の選択をできるようにしたもの
です。

uint8_t dot_hoji[5][9];//保持用配列
void set_dot(int y,int x,int u_num,boolean on_off){
  switch (u_num){
    case 1:
        if(on_off){
          bitSet(dot_hoji[1][y],x-1);
        }
        else{
          bitClear(dot_hoji[1][y],x-1);
        }        
        maxTransfer(0,0);
        maxTransfer(0,0);
        maxTransfer(0,0);
        maxTransfer(y,dot_hoji[1][y]);
        digitalWrite(CS_PIN, HIGH);        
        break;
    case 2:
        if(on_off){
          bitSet(dot_hoji[2][y],x-1);
        }
        else{
          bitClear(dot_hoji[2][y],x-1);
        }
        maxTransfer(0,0);
        maxTransfer(0,0);
        maxTransfer(y,dot_hoji[2][y]);
        maxTransfer(0,0);
        digitalWrite(CS_PIN, HIGH);
        break;
    case 3:
        if(on_off){
          bitSet(dot_hoji[3][y],x-1);
        }
        else{
          bitClear(dot_hoji[3][y],x-1);
        }
        maxTransfer(0,0);
        maxTransfer(y,dot_hoji[3][y]);
        maxTransfer(0,0);
        maxTransfer(0,0);
        digitalWrite(CS_PIN, HIGH);
        break;  
    case 4:
        if(on_off){
          bitSet(dot_hoji[4][y],x-1);
        }
        else{
          bitClear(dot_hoji[4][y],x-1);
        }
        maxTransfer(y,dot_hoji[4][y]);
        maxTransfer(0,0);
        maxTransfer(0,0);
        maxTransfer(0,0);
        digitalWrite(CS_PIN, HIGH);
  }


}

このスケッチで,順番に点灯して,最後まで点灯したら,順番に消灯する,スケッチを動かしました。

画像を動かしているスケッチです。

void loop() {
  Clear_Matrix();
  for(int u=1;u<5;u++){
    for(int y=1;y<9;y++){
      for(int x=1;x<9;x++){
        set_dot(x,y,u,1);
        delay(100);
      }
    }
  }
   for(int u=4;u>0;u--){
    for(int y=8;y>0;y--){
      for(int x=8;x>0;x--){
        set_dot(x,y,u,0);
        delay(100);
      }
    }
  }
}

この変更をしているなかで,ちょっとはまりました。正しい記述を忘れていたようで,
二次元配列を次のように記述すると思いこんでました。

    ***[a,b]

正しくは,下記のように

    ***[a][b]

記述するようで,はまりました。頭の衰えが始まってるのかな(笑)と思います。
また,arduino は至れり尽くせりで,ビットのセットもクリアーも

  bitSet(*,*)
  bitClear(*,*)

という命令が準備されています。通常ですと,ビット演算をして,やるところです。