前回は、パタパタ表示機の製作過程を簡単にまとめました。
今回は、その制御・駆動回路と Arduino のスケッチを記録しておきます。
制御・駆動回路
ブロックごとの回路図です。
12 キーボードを使った入力回路
3 列 4 行のスイッチマトリクスです。
列側をプルアップし、行側を順次 LOW にすることで、押しボタンスイッチの状態を検出しています。
7 セグメント LED 表示回路
この部分は、パタパタ表示機の制御に関係はありません。Arduino からの出力データの確認のためにつけてあるだけなので、必要なければ外してかまいません。
7 セグメント LED の制御は、LED ドライバ IC TM1630 を利用しています。これを利用することで、I/O ピンは 3 個ですみますし、一度制御データを送ればずっと表示しつづけてくれますので、Arduino の負担も少なくなります。
ステッピングモータ駆動回路
ステッピングモータはユニポーラ駆動です。
モータに流れる電流を検出し、電流値が一定以上になったら給電を止めるチョッパ駆動になっています。モータ電圧は 12V 、電流は 0.25A としました。
駆動トランジスタは MOSFET 2SK4017 (60V 5A) 。ゲート回路はプッシュプルとしています。
Arduino の左にある Q13 は、原点位置検出用のフォトインタラプタです。ジャンク品なので仕様ははっきりしませんが、5V 回路で利用していたことだけわかっています。
発光側の順方向電圧は 1.2V ほどなので、電流は 5.6mA になっています。このとき、受光側はプルアップ抵抗 10KΩ できれいに ON-OFF してくれました。
出力は、通常時 LOW 、原点時に遮光され HIGH になります。
スケッチ
いつものように、備忘録的解説です。
- // Patapata Display Driver 2022.05.23 by meyon
- // 12-KeyScan Definition
- const byte Row0 = 2;
- const byte Row1 = 3;
- const byte Row2 = 4;
- const byte Row3 = 5;
- const byte Column0 = A3;
- const byte Column1 = A4;
- const byte Column2 = A5;
- // Stepper Definition
- const byte A_1 = 9;
- const byte A_3 = 10;
- const byte B_1 = 11;
- const byte B_3 = 12;
- const byte positionSensor = A2;
- byte sequence[] = {B0101, B0110, B1010, B1001};
- byte numberOfPhase = sizeof(sequence) / sizeof(sequence[0]);
- // 7-SD Driver TM1630 Definition
- #define DISPLAY_MODE 0x00
- #define WRITE_REG_AUTO_ADDR 0x40
- #define WRITE_REG_FIXED_ADDR 0x44
- #define READ_KEY_SCAN 0x42
- #define SET_DISPLAY_ADDR 0xC0
- #define DISPLAY_OFF 0x80
- #define DISPLAY_ON 0x88 | 0x84
- #define STB_ENABLE LOW
- #define STB_DISABLE HIGH
- #define DOT_POSITION -1
- const byte dioPin = 6;
- const byte clkPin = 7;
- const byte stbPin = 8;
- const byte numberOfDigits = DISPLAY_MODE & 1 ? 5 : 4;
- byte gridData[numberOfDigits] = {0};
- const byte digit[] = {
- 0b01111110, // 0
- 0b00001100, // 1
- 0b10110110, // 2
- 0b10011110, // 3
- 0b11001100, // 4
- 0b11011010, // 5
- 0b11111010, // 6
- 0b01001110, // 7
- 0b11111110, // 8
- 0b11011110, // 9
- 0b00000000, // 10:blank
- 0b00100000, // 11:dot
- };
- const byte blank = 10;
- const byte dot = 11;
I/O ピンとかコマンドとか表示データとかの定義です。
19 行目が 2-2 相励磁方式での各コイルの励磁パターン定義です。TM1630 のコマンド定義も、これまでと変更はありません。
- void setup() {
- // 12-KeyScan Setup
- pinMode(Row0, OUTPUT);
- pinMode(Row1, OUTPUT);
- pinMode(Row2, OUTPUT);
- pinMode(Row3, OUTPUT);
- pinMode(Column0, INPUT);
- pinMode(Column1, INPUT);
- pinMode(Column2, INPUT);
- digitalWrite(Row0, HIGH);
- digitalWrite(Row1, HIGH);
- digitalWrite(Row2, HIGH);
- digitalWrite(Row3, HIGH);
- // Stepper Setup
- pinMode(A_1, OUTPUT);
- pinMode(A_3, OUTPUT);
- pinMode(B_1, OUTPUT);
- pinMode(B_3, OUTPUT);
- pinMode(positionSensor, INPUT);
- goHome();
- // 7-SD Driver TM1630 Setup
- pinMode(dioPin, OUTPUT);
- pinMode(clkPin, OUTPUT);
- pinMode(stbPin, OUTPUT);
- }
各 I/O ピンのモード設定です。
81 行目は、起動時にパタパタ表示機を原点位置に送る制御です。
- // 12-Keyboard Scan
- unsigned int keyscan() {
- unsigned int ks = 0xC000;
- digitalWrite(Row0, LOW);
- ks |= (!digitalRead(Column0)<<0 | !digitalRead(Column1)<<1 | !digitalRead(Column2)<<2);
- digitalWrite(Row0, HIGH);
- digitalWrite(Row1, LOW);
- ks |= (!digitalRead(Column0)<<3 | !digitalRead(Column1)<<4 | !digitalRead(Column2)<<5);
- digitalWrite(Row1, HIGH);
- digitalWrite(Row2, LOW);
- ks |= (!digitalRead(Column0)<<6 | !digitalRead(Column1)<<7 | !digitalRead(Column2)<<8);
- digitalWrite(Row2, HIGH);
- digitalWrite(Row3, LOW);
- ks |= (!digitalRead(Column0)<<9 | !digitalRead(Column1)<<10 | !digitalRead(Column2)<<11);
- digitalWrite(Row3, HIGH);
- return ks;
- }
12 キーボードの状態を返す関数です。
キーの状態は 16 ビットのビット列です。上位 4 ビットは 1100 、続く 12 ビットは、各キーが押されているときに、対応したビットが 1 になります。
- // Setpper Feed
- void feed(byte s) {
- static byte phase = 0;
- static int period = 50;
- for(byte i = 0; i < s; i++) {
- digitalWrite(A_1, sequence[phase]>>3&1 ? HIGH : LOW);
- digitalWrite(A_3, sequence[phase]>>2&1 ? HIGH : LOW);
- digitalWrite(B_1, sequence[phase]>>1&1 ? HIGH : LOW);
- digitalWrite(B_3, sequence[phase]>>0&1 ? HIGH : LOW);
- phase++;
- if((numberOfPhase - 1) < phase) phase = 0;
- delay(period);
- }
- digitalWrite(A_1, LOW);
- digitalWrite(A_3, LOW);
- digitalWrite(B_1, LOW);
- digitalWrite(B_3, LOW);
- }
ステッピングモータを、引数のステップ数だけ回転させる関数です。
115 行目が回転速度です。
回転中は他の操作を受け付けません。引数分ステップを送ったら、給電を切ります。
- // Detect Home position
- void goHome() {
- feed(12);
- while(LOW == digitalRead(positionSensor)) {
- feed(1);
- }
- }
ステッピングモータを原点位置へ送る関数です。
電源投入時は回転が不安定になるので、いったん 12 ステップ送ってから、原点センサが HIGH になるまで 1 ステップずつ送ります。
- // 7-Segment Display Drive
- void displayNumbers(int n) {
- for(byte i = 0; i < numberOfDigits; i++) {
- int exponentialInDecimal = pow(10, i) + 0.5;
- bool zeroSuppression = (0 != i) && (DOT_POSITION < i) && (exponentialInDecimal > n);
- gridData[i] = zeroSuppression ? blank : n / exponentialInDecimal % 10 ;
- }
- digitalWrite(stbPin, STB_ENABLE);
- shiftOut(dioPin, clkPin, LSBFIRST, DISPLAY_MODE);
- digitalWrite(stbPin, STB_DISABLE);
- digitalWrite(stbPin, STB_ENABLE);
- shiftOut(dioPin, clkPin, LSBFIRST, WRITE_REG_AUTO_ADDR);
- digitalWrite(stbPin, STB_DISABLE);
- digitalWrite(stbPin,STB_ENABLE);
- shiftOut(dioPin, clkPin, LSBFIRST, SET_DISPLAY_ADDR | 0x00);
- for(byte i = 0; i < numberOfDigits; i++) {
- shiftOut(dioPin, clkPin, LSBFIRST, digit[gridData[i]]);
- shiftOut(dioPin, clkPin, LSBFIRST, DOT_POSITION == i ? digit[dot] : 0);
- }
- digitalWrite(stbPin, STB_DISABLE);
- digitalWrite(stbPin, STB_ENABLE);
- shiftOut(dioPin, clkPin, LSBFIRST, DISPLAY_ON);
- digitalWrite(stbPin, STB_DISABLE);
- }
TM1630 により 7 セグメント LED 表示器へ数値を表示させる関数です。引数に表示したい数値を渡します。
これも、これまでと変更はありません。
- void loop() {
- static byte keyData = 1;
- static byte currentKeyData = keyData;
- unsigned int keyStatus = keyscan();
- switch(keyStatus) {
- case 0xC001: keyData = 1; break;
- case 0xC002: keyData = 2; break;
- case 0xC004: keyData = 3; break;
- case 0xC008: keyData = 4; break;
- case 0xC010: keyData = 5; break;
- case 0xC020: keyData = 6; break;
- case 0xC040: keyData = 7; break;
- case 0xC080: keyData = 8; break;
- case 0xC100: keyData = 9; break;
- case 0xC200: keyData = 10; break;
- case 0xC400: keyData = 11; break;
- case 0xC800: keyData = 12;
- }
- displayNumbers(keyData);
- if(keyData >= currentKeyData) {
- feed(4 * (keyData - currentKeyData));
- currentKeyData = keyData;
- } else if(keyData < currentKeyData) {
- feed(4 * (12 + keyData - currentKeyData));
- currentKeyData = keyData;
- }
- }
176〜191 行で、キーの状態のビット列に応じて、表示する数値を分岐しています。複数のキーを押した場合の規定はありませんので、無視されます。
193 行目で、7 セグメント LED に数値を表示します。
195〜201 行で、ステッピングモータを送るステップ数を算出しています。
パタパタ表示機の数値を 1 進めるとき、ステッピングモータは 4 ステップ送ります。
表示する数値が大きくなるときは、現在値との差分だけ進めます。数値が小さくなる場合、逆回転はできませんから、差分に 12 を足した数を進めることになります。
作ってみての、感想など
表示部分の構造は、もっと試行錯誤してみないといけないようです。最も気になるところは、フラップの上下の位置が揃わないこと。フラップの取り付け穴と爪の位置関係がビミョーです。
製作途中の表示部を見つけた孫 (6歳) が「パタパタ紙芝居だ!」と言っていました。よくわかったねぇ。でも、どこでそんな仕掛けを見たんでしょ?
今回使ったステッピングモータは 48 ステップですが、1-2 相励磁すると 96 ステップで回すことができます。ってことは、96 枚のパタパタ紙芝居が ……
あ、まぁ、構想だけは温めておきましょうか (;´Д`)