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(*,*)

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

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

あれこれやっていましたが,やっとまた1つ理解が進みました。これも,分かってる方からすればな
んでもないことなのでしょうが,改めて理解できたというところです。
単体(1つだけ)の書き込みをしてる分にはいいのですが,for等で繰り返し処理をすると2回目以降
の書き込みで,1番目にLED書き込んたデータが2番目,3番目,4番目と順次表示されます。書き込
みは1番目のLEDなのに2番目以降のLEDに表示されるが理解できませんでした。これもやっと理解でき
ました。

 一度書き込まれたデータの後に書き込みを行うと,
 先に書き込まれたデータに上書きされるのではなく,
 先に書き込まれたデータは,次以降のLEDに順送りにされる。

このことが分からなくて,思った動作をさせられず,もがきました。

 for(int i=1;i<9;i++){
    maxTransfer(i,1);
    digitalWrite(CS_PIN, HIGH);
    delay(500);
  }

この繰り返しのスケッチは,一番左に1つドットを描き,それを一番下まで繰り返すスケッチです。このまま
だと動画のようになります。

それと, digitalWrite(CS_PIN, HIGH); の命令は,本来 maxTransfer( ,); のサブ関数内で一括処理して
た、ものです,データをかきこんだらそれをレジスタにその都度アップロード・ラッチを行う処理でした。
データの書き込み--アップロード(ラッチ)と一連の流れで処理してしまうと,別な命令の書き込み
ができないので,諸兄スケッチから変更しました。こうすることで、下記のスケッチのように、何もしない
命令( maxTransfer(0,0))を2番目、3番目、4番目のLEDに先送りにし、一度にデータをアップロード
ラッチすることで、余分な表示を防げます。

for(int i=1;i<9;i++){
    maxTransfer(0,0);
    maxTransfer(0,0);
    maxTransfer(0,0);
    maxTransfer(i,1);
    digitalWrite(CS_PIN, HIGH);
    delay(500);
  }

2番目,3番目,4番目に先に送られたno-opコードのため余分な表示がされなくなります。

一度表示されると,消去するまで,表示されますので,次のように一度表示したものを消去すると移動するよ
うに見えます。

For(int i=1;i<9;i++){
    maxTransfer(0,0);
    maxTransfer(0,0);
    maxTransfer(0,0);
    maxTransfer(i,1);
    digitalWrite(CS_PIN, HIGH);
    delay(500);
    maxTransfer(0,0);
    maxTransfer(0,0);
    maxTransfer(0,0);
    maxTransfer(i,0);
    digitalWrite(CS_PIN, HIGH);
  }

ここまでたどり着くのに結構時間がかかりました。ライブラリーを作成している先達は,いち早くこういうこ
とが理解できたのでしょうね。凡人はとてつもなく時間がかかります。

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

あれこれやってますが,どのHPを見ても,二個目,三個目,四個目のMAX7219に指令を出す方々が書いてあ
りませんでした。これまでかと思い,取説を確認してみるとありました。ありました。きちんと表記があるじゃないですか。

  ===二つ目以降のチップを操作する===

 4つのMAX7219をカスケード接続する場合,4番目のチップに書き込みを行うには,希望する
 16ビットワードの後に,3つのno-noコード(16進の0xXX0X表2)送信します。
 LOAD/CSがハイになった時点で,すべてのデバイスにデータがラッチられます。最初の3つのチップ
 は,no-noコマンドを受け取り,4番目のチップが目的のデータを受け取ります。

とありました。これで,もうちょっと先に進めそうです。

また,諸兄のHPを参考にarduino風に書き換えていた,SPIのデータ書き込みのスケッチも動きました。

#define CLK 13
#define DIN 11
#define CS  10

void setup(){
  Serial.begin( 9600 );     // シリアル通信を初期化する。通信速度は9600bps
    pinMode(CLK, OUTPUT );
    pinMode(DIN, OUTPUT );
    pinMode(CS, OUTPUT );
}

void wait(int i){
  volatile int j,k;
  for(j=0;j<i;j++){
    for(k=0;k<55;k++);
  }
}

//****************************************************************
//arduino自作関数
//データ書き込み
//****************************************************************
void LED_MAT_SEND(unsigned char SELECT, unsigned char DATA){
  digitalWrite( CS, HIGH );// Load ON
  wait(2);void 
  digitalWrite( CS, LOW );// Load OF

  for(int i=0;i<8;i++){               // Send Register data
        digitalWrite( CLK, LOW );//CLK OFF
        if(((SELECT << i) & 0b10000000)==0){
          digitalWrite( DIN, LOW );
          Serial.print( '-' );
        }
        else{
          digitalWrite( DIN, HIGH );
          Serial.print( '+' );
        }
      wait(1);
      digitalWrite( CLK, HIGH );//CLK ON
      wait(1);
  }

  for(int i=0;i<8;i++){               // Send LED DATA
      digitalWrite( CLK, LOW );//CLK OFF


      if(((DATA << i) & 0b10000000)==0){
        digitalWrite( DIN, LOW );
        Serial.print( '-' );
      }
      else{
        digitalWrite( DIN, HIGH );
        Serial.print( '+' );
      }
      wait(1);
      digitalWrite( CLK, HIGH );//CLK ON
      wait(1);
    }
    digitalWrite( CS, HIGH );// Load ON
    wait(2);
    digitalWrite( CS, LOW );// Load OFF
    Serial.print( "******" );
}

デバッグ用のSerial.printは残してあります。また,この, digitalWrite( CLK, HIGH );は結構クロックをつかうようなので,一括処理のものに後で変更しようと思います。このスケッチもSPIライブラリーを使うと,別な諸兄の書かれた下記のように6行程度ですんでしまいます。

void maxTransferCMD(uint8_t address, uint8_t value) {
  digitalWrite(CS_PIN, LOW);
  SPI.transfer(address); // Send address.
  SPI.transfer(value); // Send the value.
  digitalWrite(CS_PIN, HIGH); // Finish transfer.
}

今日,取説で見つけた記述をもとに,2個目3個目のMAX7219に書き込めるスケッチも考えてみたいと思います。

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

何年か前に、8×8の小さ目のLCDマトリックスで、PICを使って流れるサインボードのおもちゃを作成しまし
た。ネットサーフィンをしていると、ちょっと大きめの8×8LCDマトリックスがめにとまりましたので、
思わず、いくつかポチってしまいました。

この一つのものと、4連のもの合計3つをアリでぽちりました。

4連のものは、赤と青を購入しました。

この、LCDは、MAX7219というコントロールIC(ドライバー)が使われていて、比較的たやすく、コント
ロールができるようで、arduinoだと、専用のライプラリーもいくつかあるようです。また、このLCDの
面白いのは、横に連結して使えることです。どのくらい連結できるのかわかりませんが、arduinoの設定
の項目には11個の記載がありましたので、もしかして、電源のこと考えないなら、11個ぐらい連結で
きるのかもしれません。

ライブラリーを使えばいいのでしょうが、MAX7219を直接コントロールしたくて、あれこれしらべました。
幸い詳しく書かれている諸兄のHPが見つかりましたので、ここを参考にいろいろやってみます。

いままで、いろんなもののコントロールに、SPI(シリアル通信)を使う記事も見かけましたが、実際は
どんなふうにするのかいまいち理解がおよびませんでしたが、なんとなく理解することができました。
諸兄のHPによれば、下記のようになるそうです。SPIは3本の線でやり取りします。CLK,Cs,DOUTの3本の
線で下記のようにやり取りをします。

 ・Load端子をLowにセット

  -・CLK端子をLowにセット
  +・15ビット目の値をDINにセット
  +・CLK端子をHighにセット ここでシフトレジスタの0ビット目に①の値がセットされます
  +    つまり 00000000 0000000 がMAX7219のシフトレジスタに入ってま
  +・CLK端子をLowにセット
  +・14ビット目の値をDINにセット
  +・CLK端子をHighにセット ここでシフトレジスタがシフトし②が0ビット目に入ります
  -  つまり 00000000 000000①② が入ってます
      これを繰り返して 16ビットすべて送信したら

  LoadをHighにセットします

  この瞬間シフトレジスタの値が 指定されてたレジスタに反映されます。

この流れを、プログラムに組んでやれば、基本的なデータの送信ができます。この送信の手順は、

のデータシートに記載のあるタイミング図をみればいいみたいですが、いままで、この意味がよく分かり
ませんでした。今となって、やっとその意味が分かりました。

このデータ送信も、arduinoだとSPI(シリアル通信)のライブラリーがあるので、簡単にできてしまうよう
なので、ちょっと、びっくりですね。

Arduino PWM 再び (2)

割り込みを使ったPWMのLチカをやりましたが,機能として備わっているPWMもやってみることにしました。
でもがっかりしました。簡単過ぎるのです。

analogWrite(PIN番号,DUTY)

これだけで,できてしまうのです。ただ,analogWriteでは,周波数とかの細かい設定はできないようです。
DUTYは最高が0~255まで,指定できるようです。PICだと,設定値をビット演算して,レジスターに書き
込むのでちょっと面倒です。周波数とかの細かい設定をするには,やはりレジスタをいじるようです。

昨日作った割り込みのPWMと備え付け機能のPWMを使い,LEDをだんだん明るくして,だんだん暗くする
というスケッチを書いて動かしてみました。

include<avr/io.h>
#include <avr/interrupt.h>


int k=0;
int BLUE_LED_PIN = 11;  // PWM出力させるピン番号を指定
int RED_LED_PIN = 13;   //11は備え付け,13は割り込みj
int DUTY = 0;


void setup() {
  pinMode(RED_LED_PIN, OUTPUT);
  pinMode(BLUE_LED_PIN, OUTPUT);


  TCCR1A  = 0;
  TCCR1B  = 0;
  TCCR1B = bit(WGM12) | bit(CS11) | bit(CS10); // CTCモードで分周率64
  TIMSK1 = bit(OCIE1A); // 割り込みをタイマー1に設定
  //TCCR1B |= (1 << WGM12) | (1 << CS12);  //CTCmode //prescaler to 256
  OCR1A   = 6-1;
  //TIMSK1 |= (1 << OCIE1A);
}


ISR (TIMER1_COMPA_vect) {
 if(k<255){
    k=k+1;
  }
  else{
    k=0;
  }
  if(k==0){
    digitalWrite(RED_LED_PIN, HIGH);
  }
  if(k==DUTY){
    digitalWrite(RED_LED_PIN, LOW);
  }
}


void loop() {
   while(DUTY<255){//だんだん明るくする
    analogWrite(BLUE_LED_PIN, DUTY);
    DUTY=DUTY+1;
    delay(25);
  }
  delay(500);
   while(DUTY>1){//だんだん暗くする
    analogWrite(BLUE_LED_PIN, DUTY);
    DUTY=DUTY-1;
    delay(25);
  }
  delay(500);
}

ほぼ同じような動作をしますが,割り込みを使った方は,あるタイミングでちらつきます。どのタイミングで
ちらつくのか分かりませんが,多分,カウント等余分な動作をしているからかなと推測します。

赤のLEDが割り込みでの点滅で,青のLEDが備え付け機能を使った点滅です。

Arduino PWM 再び

このところ,Arduinoをいじってます。PICに比べると遙かにわかりやすいです。ただ,PICに比べると,細か
な設定等が難しいのが欠点であるといえば欠点ですが。

今回は,ArduinoにもPWMの機能が備わっていますが,この機能を使わずに割り込みで,PWMを簡易的に実現してみました。PWMを実現するには,単純に,端子をLOWとHIGHTに切り替えることができればいいので,通常は,

   端子をHIGHT
   delay(50)
   端子をLOW

みたいにすれば,たやすく実現できます。ただ,このdelay(50)がちょっと気に入らないので,使わないで
実現できないかと考えた訳です。構想としては,TIMER割り込みの回数を数えて,

   0回目の割り込み→→端子をHIGHT
   n回目の割り込み→→端子をLOW
   規定の回数の割り込みで,また,0から数えるLOW

組み込みのPWMでも,レジスターレベルでカウントして,考え方としては,上記のものと同じ考えでやってる
ようです。

arduinoで,やってみました。LEDがだんだん明るくなると次は次第に暗くなるというスケッチを描いてみまし
た。

#include<avr/io.h>
#include <avr/interrupt.h>
int k=0;
int n=0;
void setup() {
  pinMode(13, OUTPUT);


  TCCR1A  = 0;
  TCCR1B  = 0;
  TCCR1B = bit(WGM12) | bit(CS11) | bit(CS10); // CTCモードで分周率64
  TIMSK1 = bit(OCIE1A); // 割り込みをタイマー1に設定
  //TCCR1B |= (1 << WGM12) | (1 << CS12);  //CTCmode //prescaler to 256
  OCR1A   = 11-1;
  //TIMSK1 |= (1 << OCIE1A);
}


ISR (TIMER1_COMPA_vect) {
 if(k<100){
    k=k+1;
  }
  else{
    k=0;
    digitalWrite( 13, HIGH);
  }
  if(k==n){
    digitalWrite( 13, LOW);
  }
}


void loop() {
   while(n<100){//だんだん明るくする
    n=n+1;
    delay(25);
  }
   while(n>1){//だんだん暗くする
    n=n-1;
    delay(25);
  }
 
}

動作している様子です。時々,ちらつきがあります。LEDで動かしていますが,もしかして,これで,モー
ターを制御するとばたついたりするかもしれません。