シフトレジスタ実験

概要

Arduino互換機Japaninoで8x8LEDマトリクス(A3880EG)を制御…するために
シフトレジスタ74HC595を使ってみる。

2010/07/02

2個つないでLEDマトリクスのROW側8ビットCOL側8ビットづつ制御する作戦で作ってみた。
LED1画素ずつの制御はOKなんだが、ダイナミック点灯させると、チラつく。
ShiftOut命令遅い?
2個直列で16ビット送信ではなく、2個を独立制御して8ビットずつ送ってみるとか実験しよう。
あー、そういえばコンデンサも入れてなかった。買ってきていれてみよう。

2010/07/04

コンデンサも入れてやってみたのだが、やっぱり16ビット送信すると間に合わない。
1個ずつ個別に点灯させることは出来るのだが、ダイナミック点灯させるとチラつく。
仕方が無いので信号線を6本出して、74HC595をひとつずつ別に制御してみる。
COL選択のためのShiftOutはROW選択のShiftOut8回につきにつき1回でいい。
72回のShiftOutで1画面出来上がり。チラつかないのだが、点灯時間の待ちをdelayMicroseconds(200)とするとチラつく。delayを一切入れないでOKだった。
やっぱりShiftOut命令が遅いんだろうなぁ。
今はLEDの赤しか結線してないので、今後緑を入れたときにやっぱり16ビット送ることになるので、今回と同じような問題が発生する。
さて、どうしたものか。2つのポートに同時に信号を送るShiftOutを自作するか。

2010/07/10

Japaninoの作品集にLEDマトリクスでハノイの塔やっている人がいたのを忘れていた。記事を見なおしてみる。
ATMega168(8Mhz)では常時点灯が厳しい。ShiftOutではなくdigitalWriteが遅いのだとか。
で、その記事では「ポートに直接書き込むというあまり好ましくない」方法をとっている模様。
いいじゃない、好ましくない方法大好きです(笑)
Arduino日本語リファレンスにはポート操作というのがあるので試してみよう。
こんな操作、機械語でゲームボーイとかスーパーファミコンとか触ってたとき以来だ。わくわくするぜ(笑)

2010/07/23

久しぶりにいじってみた。なんだかいろいろ忘れてる。
で、ポート直叩き実験をやってみた。とりあえず順調。

2010/07/24

どうやら出来たっぽい。1画素ずつ点灯消灯できて、
なおかつ1画素あたりのdelayを300Microsecondsにしてもチラつかない。
かなりの高速化が出来たと考えて良い?
つぎのステップは16ビット送信、24ビット送信だ。


2012/07/14

ソースコードの提供依頼があったので掲載
当時の書きかけテストコードそのままです。
2012/08/02
コメントなどいろいろ加筆。

٤Ƴ٤Ĥ
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
-
|
|
!
-
|
|
|
|
|
|
!
 
 
 
 
 
 
 
-
|
!
-
|
|
|
|
|
|
|
|
!
 
 
-
-
!
!
 
 
-
|
-
|
|
|
-
|
-
|
!
|
-
|
!
|
|
!
|
-
!
-
!
-
|
|
-
|
!
|
-
|
!
|
-
|
!
-
!
|
|
!
|
|
!
|
|
|
-
|
|
|
!
|
!
!
|
-
 
 
!
//74HC595を2つ使用する。
//1つ目の74HC595はマトリクスLEDのROW側のピン8つと接続。2つ目はCOL側に接続。
//以降1番、2番と呼称する。
 
//配線は以下のとおり。これは適宜変更すること。
//arduinoのデジタルピン2 -> 1番のSH_CP
//arduinoのデジタルピン3 -> 1番のST_CP
//arduinoのデジタルピン4 -> 1番のDS
//arduinoのデジタルピン5 -> 2番のSH_CP
//arduinoのデジタルピン6 -> 2番のST_CP
//arduinoのデジタルピン7 -> 2番のDS
 
const int CLOCKPIN1 = 2;
const int LATCHPIN1 = 3;
const int DATAPIN1 = 4;
const int CLOCKPIN2 = 5;
const int LATCHPIN2 = 6;
const int DATAPIN2 = 7;
 
//1が点灯0が消灯 
//点灯時間により変化をつけるのならintの配列に変更。
bool data[8][8] =
{
  {1,1,1,1,0,1,1,1,},
  {0,1,1,1,0,1,1,1,},
  {0,1,1,1,0,1,1,1,},
  {1,0,0,0,0,1,1,1,},
  {1,1,1,1,0,1,1,1,},
  {1,1,1,1,0,0,0,0,},
  {1,1,1,1,0,1,1,1,},
  {0,0,0,1,0,1,0,0,},
};
 
void setup()
{
//より安全な方法: RXとTX(ピン0と1)は変更せず、2~7を出力に設定
  DDRD = DDRD | B11111100;
}
 
void loop()
{
  for(int y = 0; y < 8; ++y)    //ROW側のループ
  {
    PORTD &= ~(1 << LATCHPIN1);    //1番のLATCHPINを落とす→送信中はGNDにしなくてはいけない。
 
    for(int p = 0; p < 8; ++p)
    {
      if((y == p))                    //pが処理対象のROWならば
      {
        PORTD |= (1 << DATAPIN1);    //1番のDATAPINを上げる。対象のROWのみ点灯させるため。
      }
      else                            //そうでなければ
      {
        PORTD &= ~(1 << DATAPIN1);    //1番のデータピンを落とす。対象のROW以外は消灯するため。
      }
      PORTD |= (1 << CLOCKPIN1);    //1番のCLOCKPINを上げてシフトする。
      PORTD &= ~(1 << CLOCKPIN1);    //CLOCKPINを下げてシフト完了。
    }
    PORTD |= (1 << LATCHPIN1);    //1番のLATCHPINを上げる→送信完了
    //ROW yの設定完了
 
    //COLの設定
       for(int x = 0; x < 8; ++x)        //COL側のループ
    {
      PORTD &= ~(1 << LATCHPIN2);    //2番のLATCHPINを落とす→送信中はGNDにしなくてはいけない。
      for(int p = 0; p < 16; ++p)        //なぜ16にしているのかがイマイチ記憶が曖昧。
                                        //パフォーマンステストを行うため2倍の量を転送したような気がする。
                                        //8にして動作テストをしてみて欲しい。
      {
        if((x == (p%8)) && (data[y][7-x] == 1))    //該当する点灯データを取得して点灯なら
        {//この(p%8)はパフォーマンステストのためのコードなので気にしない。
          PORTD &= ~(1 << DATAPIN2);    //2番のDATAPINを落とす
        }
        else                            //そうでなければ
        {
          PORTD |= (1 << DATAPIN2);        //2番のDATAPINを上げる。
        }
        //上げ下げが逆になっているのは使っているマトリックスLEDの特性か、回路の都合なので正しい。必要に応じて修正。
 
        PORTD |= (1 << CLOCKPIN2);    //2番のCLOCKPINを上げてシフトする。
        PORTD &= ~(1 << CLOCKPIN2);    //CLOCKPINを下げてシフト完了。
      }                                //1行の8つのCOLに対して設定を完了。
      PORTD |= (1 << LATCHPIN2);    //2番のLATCHPINを上げる→送信完了
      delayMicroseconds(200);        //表示待ち200Microseconds
    }                                //ROW-yに対するCOL-xの設定完了
 
    PORTD &= ~(1 << LATCHPIN2);        //同様の手順で全消灯
    for(int p = 0; p < 16; ++p)
    {
      PORTD |= (1 << DATAPIN2);
      PORTD |= (1 << CLOCKPIN2);
      PORTD &= ~(1 << CLOCKPIN2);     
    }
    PORTD |= (1 << LATCHPIN2);
  }                                    //すべてのROWの処理完了
}
 
//正直、このプログラムが最適なのかどうかはもう一度回路を組み上げて検証してみないと自信がない。
//表示待ちのタイミングはここで良いのか、xのループの外のような気もしてくる。
//参考程度のものだと考えてこのプログラムをベースにして作り上げて欲しい。
 

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2012-08-02 (木) 02:33:30 (2576d)