Arduino 9) 4連 Digital Tube LED Displayを試す
2019.02.28
注文してから1ヶ月以上かかりました。長かった・・orz
左からVCC、SCLK、RCLK、DIO、GND
この5ピンを接続し、SCLK、RCLK、DIOの3ピンで制御します。
基本配線は上記でいいと思います。
どうせなら変化があったほうが面白いので
前回の可変抵抗を読み取って表示することを踏まえて配線しています。
LED文字には各パーツごとに光るようになっています。
それらを組み合わせて人間が数字として読み取れるように
場所を指定し光らせます。
ビットが0なら光る。1なら消えるを意味します。
つまり
0なら 0b11000000
1なら 0b11111001
2なら 0b10100100
3なら 0b10110000
4なら 0b10011001
5なら 0b10010010
6なら 0b10000010
7なら 0b11111000
8なら 0b10000000
9なら 0b10010000
といった2進数コードを使用します。
ではコーディングですが、いちから作るのは面倒なので、
どこぞから拾ってきたものをカスタマイズして仕上げました。
//接続するピンを設定する
#define SCLK 3
#define RCLK 4
#define DIO 5
byte digitBuffer[4]; //キャラ数(文字数を設定)この配列に入れた数字がそのまま表示される。
void setup(){
pinMode(RCLK, OUTPUT);
pinMode(SCLK, OUTPUT);
pinMode(DIO, OUTPUT);
}
void loop()
{
digitBuffer[0] = 1; //1文字目に1を表示
digitBuffer[1] = 2; //2文字目に2を表示
digitBuffer[2] = 3; //3文字目に3を表示
digitBuffer[3] = 4; //4文字目に4を表示
showDisplay();
}
//表示するために関数を定義
void showDisplay(){
const byte digit[10] = {
0b11000000,//0
0b11111001,//1
0b10100100,//2
0b10110000,//3
0b10011001,//4
0b10010010,//5
0b10000010,//6
0b11111000,//7
0b10000000,//8
0b10010000 //9
};
const byte chr[4] = {
0b00001000,//1
0b00000100,//2
0b00000010,//3
0b00000001,//4
};
for(byte i = 0; i <= 3; i++)
{
digitalWrite(RCLK, LOW);
shiftOut(DIO,SCLK,MSBFIRST, digit[digitBuffer[i]]);
shiftOut(DIO,SCLK,MSBFIRST, chr[i]);
digitalWrite(RCLK, HIGH);
delayMicroseconds(1000);
}
}
無事光りました。
では可変抵抗の値を表示するプログラムに改造してみたいと思います。
int Denatu = 0;
int OutNum = 0;
int StackNum = 0;
//接続するピンを設定する
#define SCLK 3
#define RCLK 4
#define DIO 5
byte digitBuffer[4]; //キャラ数(文字数を設定)この配列に入れた数字がそのまま表示される。
void setup(){
Serial.begin( 9600 ); //シリアルモニタを使うときの儀式
pinMode(13, OUTPUT); //ボードのLEDを使用する
pinMode(RCLK, OUTPUT);
pinMode(SCLK, OUTPUT);
pinMode(DIO, OUTPUT);
}
void loop()
{
//digitalWrite(13, HIGH); //LEDを光らせる
Denatu = analogRead(0); //A0ピンの電圧を測る0(0V)~1023(5V)
if (Denatu != StackNum) { //前回と値が違うときだけ処理を行う
Serial.println(Denatu); //シリアルモニタに値を出力
OutNum = Denatu;
//4文字目に数字を表示
digitBuffer[3] = OutNum % 10; //10で割ってあまりを求める。
OutNum = OutNum / 10; //値を10で割って結果を元の数字に返す。これで4ケタが3ケタにシフトする。
//3文字目に数字を表示
digitBuffer[2] = OutNum % 10; //10で割ってあまりを求める。
OutNum = OutNum / 10; //値を10で割って結果を元の数字に返す。これで3ケタが2ケタにシフトする。
//2文字目に数字を表示
digitBuffer[1] = OutNum % 10; //10で割ってあまりを求める。
OutNum = OutNum / 10; //値を10で割って結果を元の数字に返す。これで2ケタが1ケタにシフトする。
//1文字目に数字を表示
digitBuffer[0] = OutNum % 10; //10で割ってあまりを求める。
//結果を4LEDに表示
showDisplay();
//今回の電圧を記録する。
StackNum = Denatu;
}
delay(Denatu); //読み取った値分処理を止める1023=1.023秒
digitalWrite(13, LOW); //LEDを消す
delay(Denatu); //読み取った値分処理を止める1023=1.023秒
}
//表示するために関数を定義
void showDisplay(){
const byte digit[10] = {
0b11000000,//0
0b11111001,//1
0b10100100,//2
0b10110000,//3
0b10011001,//4
0b10010010,//5
0b10000010,//6
0b11111000,//7
0b10000000,//8
0b10010000 //9
};
const byte chr[4] = {
0b00001000,//1
0b00000100,//2
0b00000010,//3
0b00000001,//4
};
for(byte i = 0; i <= 3; i++)
{
digitalWrite(RCLK, LOW);
shiftOut(DIO,SCLK,MSBFIRST, digit[digitBuffer[i]]);
shiftOut(DIO,SCLK,MSBFIRST, chr[i]);
digitalWrite(RCLK, HIGH);
delayMicroseconds(1000);
}
}
赤字の部分はこの仕組のキモで、
可変抵抗の4ケタまでの数字を分解して4つのLEDに表示する。
プログラマーを長くやっていると定番のアルゴリズムですが、
ここでも役立つとは思いませんでした。
では実行。
表示がオカシイ。
値が1024でも一桁目の4しか正常に表示しない。
他の桁はチカチカしてしまう。
いろいろソースを変えて試してみたけど
Delayで処理を止めるとその間だけ表示も止まっているようだ。
今の所解決方法が見つからない。
よく使われる部品でこんなトラブルとはがっかり(;´Д`)
Arduino 8) EEPROMを使って電源を切っても変数が消えないようにする
2019.02.15
プログラムを作るに当たって、電源を切ったらデータが消えてしまうというのは
考えられません。あってはならないことです。
Windowsはデータベースに保存したり、iniファイルを使用したりと様々な方法で
環境の保存を行っております。
Arduinoは頻繁に電源を入り切りするコンピュータです。
Windowsのようにアプリの終了やシャットダウンで環境保存することはできません。
そこでプログラム動作中に変数を退避する必要が出てくるわけですが、
それを実現するのがEEPROMに記憶するという方法です。
EEPROMのエリアは基本0~255の256個(256Byte)となってますが、
Unoの場合1KB(1024Byte)Megaの場合4KBまで使用可能です。
一般的には10万回の書き込みに耐えられるとされていますが、
実際にテストを行った方が居て、300万回は耐えたという情報もあります。
1秒毎にカウントして記憶するプログラムを組んでみました。
EEPROM.hを覆っている<>はhtmlの都合上全角になっております。
#include <EEPROM.h>
int Access_count;
void setup() {
Serial.begin( 9600 ); //シリアルモニタを使うときの儀式
pinMode(13, OUTPUT); //ボードのLEDを使用する
Access_count = EEPROM.read(0); //0番地にEEPROMから値を読み込む
}
void loop() {
digitalWrite(13, HIGH); //LEDを光らせる
delay(1000); //1秒
Access_count = Access_count + 1; //アクセスカウンターを追加
Serial.println(Access_count); //シリアルモニタに値を出力
EEPROM.write(0, Access_count); //0番地からEEPROMに値を書き込む。
}
シンプルにまとめてみました。
正常にEEPROMに書き込まれたかは電源入れた都度
シリアルモニタで確認できるようにしています。
このプログラムは1秒毎にカウントしていくものですが、
1Byteを超える数字256以上まで進んだ場合は正常に保存できません。
255より大きい数字は自分で分割して保存エリアを分ける必要があります。
それではちょっと勝手が悪いので、別の方法を模索していると、
ちょうどいい命令を見つけました。
EEPROM.put (番地, データ); //保存
EEPROM.get (番地, データ); //読込
INT型であれば、-32768から32767まで扱うことができます。
これは2byte使うので0番地で保存した場合同時に1番地も使用しているとみた方がいいです。
他の変数も保存する場合はぶつからないように2番地から使うと行った配慮が必要になるかと思われます。
ためしに以下のようなプログラムを作って検証してみました。
#include <EEPROM.h>
int TestNum = 12345;
void setup() {
Serial.begin( 9600 ); //シリアルモニタを使うときの儀式
EEPROM.put(0,0);
EEPROM.put(1,0);
EEPROM.put(2,0);
EEPROM.put(3,0);
EEPROM.put(0,TestNum);
Serial.println(EEPROM.read(0));
Serial.println(EEPROM.read(1));
Serial.println(EEPROM.read(2));
Serial.println(EEPROM.read(3));
Serial.println(EEPROM.get(0,TestNum));
}
結果は以下の通り
0番地に57(2進数00111001)
1番地に48(2進数00110000)
連結すると0011000000111001 = 12345
計算は合ってます。
想像通り自動的に2byte使ってますね。
これは大変便利な機能ですが大きいプログラムを組むときは
アドレスマップを作らないと危険ですね。
では次の疑問に行きたいと思います。
intをlong(-2147483684から2147483647)の変数に変えた場合はどうなるのか。
上の経験を踏まえれば32bitなので4byte使われると思いますが。
ソースを以下のように変更して実行してみます。
#include <EEPROM.h>
long TestNum = 1234567890;
void setup() {
Serial.begin( 9600 ); //シリアルモニタを使うときの儀式
EEPROM.put(0,0);
EEPROM.put(1,0);
EEPROM.put(2,0);
EEPROM.put(3,0);
EEPROM.put(4,0);
EEPROM.put(5,0);
EEPROM.put(0,TestNum);
Serial.println(EEPROM.read(0));
Serial.println(EEPROM.read(1));
Serial.println(EEPROM.read(2));
Serial.println(EEPROM.read(3));
Serial.println(EEPROM.read(4));
Serial.println(EEPROM.read(5));
Serial.println(EEPROM.get(0,TestNum));
}
結果は想像したとおりになりました。
では事前に0番地から5番地に255を入れ込んでおき、
long TestNum = 123;
とした場合はどうなるのでしょうか。
#include <EEPROM.h>
long TestNum = 123;
void setup() {
Serial.begin( 9600 ); //シリアルモニタを使うときの儀式
EEPROM.put(0,255);
EEPROM.put(1,255);
EEPROM.put(2,255);
EEPROM.put(3,255);
EEPROM.put(4,255);
EEPROM.put(5,255);
EEPROM.put(0,TestNum);
Serial.println(EEPROM.read(0));
Serial.println(EEPROM.read(1));
Serial.println(EEPROM.read(2));
Serial.println(EEPROM.read(3));
Serial.println(EEPROM.read(4));
Serial.println(EEPROM.read(5));
Serial.println(EEPROM.get(0,TestNum));
}
値は1Byte、変数は4Byteのもの。
命令が変数のサイズで反応しているなら5番地と6番地は255のまま。
値のサイズで反応しているなら0番地以外全て255のままとなります。
結果は・・
つまり値ではなく、変数の種類で書き込み場所が決まるようです。
これはとても重要なことですよ。ぜひ頭に焼き付けて置くべき事柄です。
実験してよかった(*´ω`*)
あと問題があるとすればEEPROMの書き込み寿命ですかね。
今、F-RAMっていうのが登場しているようですが、
F-RAMはCypressのFM25W256を使うと、ほぼ制限を気にすることなく書き込みができるという記事があります。
https://www.switch-science.com/catalog/1406/
結構いい値段がしますね。庶民にはまだまだ手が出ないかなぁ。
考えられません。あってはならないことです。
Windowsはデータベースに保存したり、iniファイルを使用したりと様々な方法で
環境の保存を行っております。
Arduinoは頻繁に電源を入り切りするコンピュータです。
Windowsのようにアプリの終了やシャットダウンで環境保存することはできません。
そこでプログラム動作中に変数を退避する必要が出てくるわけですが、
それを実現するのがEEPROMに記憶するという方法です。
EEPROMのエリアは基本0~255の256個(256Byte)となってますが、
Unoの場合1KB(1024Byte)Megaの場合4KBまで使用可能です。
一般的には10万回の書き込みに耐えられるとされていますが、
実際にテストを行った方が居て、300万回は耐えたという情報もあります。
1秒毎にカウントして記憶するプログラムを組んでみました。
EEPROM.hを覆っている<>はhtmlの都合上全角になっております。
#include <EEPROM.h>
int Access_count;
void setup() {
Serial.begin( 9600 ); //シリアルモニタを使うときの儀式
pinMode(13, OUTPUT); //ボードのLEDを使用する
Access_count = EEPROM.read(0); //0番地にEEPROMから値を読み込む
}
void loop() {
digitalWrite(13, HIGH); //LEDを光らせる
delay(1000); //1秒
Access_count = Access_count + 1; //アクセスカウンターを追加
Serial.println(Access_count); //シリアルモニタに値を出力
EEPROM.write(0, Access_count); //0番地からEEPROMに値を書き込む。
}
シンプルにまとめてみました。
正常にEEPROMに書き込まれたかは電源入れた都度
シリアルモニタで確認できるようにしています。
このプログラムは1秒毎にカウントしていくものですが、
1Byteを超える数字256以上まで進んだ場合は正常に保存できません。
255より大きい数字は自分で分割して保存エリアを分ける必要があります。
それではちょっと勝手が悪いので、別の方法を模索していると、
ちょうどいい命令を見つけました。
EEPROM.put (番地, データ); //保存
EEPROM.get (番地, データ); //読込
INT型であれば、-32768から32767まで扱うことができます。
これは2byte使うので0番地で保存した場合同時に1番地も使用しているとみた方がいいです。
他の変数も保存する場合はぶつからないように2番地から使うと行った配慮が必要になるかと思われます。
ためしに以下のようなプログラムを作って検証してみました。
#include <EEPROM.h>
int TestNum = 12345;
void setup() {
Serial.begin( 9600 ); //シリアルモニタを使うときの儀式
EEPROM.put(0,0);
EEPROM.put(1,0);
EEPROM.put(2,0);
EEPROM.put(3,0);
EEPROM.put(0,TestNum);
Serial.println(EEPROM.read(0));
Serial.println(EEPROM.read(1));
Serial.println(EEPROM.read(2));
Serial.println(EEPROM.read(3));
Serial.println(EEPROM.get(0,TestNum));
}
結果は以下の通り
0番地に57(2進数00111001)
1番地に48(2進数00110000)
連結すると0011000000111001 = 12345
計算は合ってます。
想像通り自動的に2byte使ってますね。
これは大変便利な機能ですが大きいプログラムを組むときは
アドレスマップを作らないと危険ですね。
では次の疑問に行きたいと思います。
intをlong(-2147483684から2147483647)の変数に変えた場合はどうなるのか。
上の経験を踏まえれば32bitなので4byte使われると思いますが。
ソースを以下のように変更して実行してみます。
#include <EEPROM.h>
long TestNum = 1234567890;
void setup() {
Serial.begin( 9600 ); //シリアルモニタを使うときの儀式
EEPROM.put(0,0);
EEPROM.put(1,0);
EEPROM.put(2,0);
EEPROM.put(3,0);
EEPROM.put(4,0);
EEPROM.put(5,0);
EEPROM.put(0,TestNum);
Serial.println(EEPROM.read(0));
Serial.println(EEPROM.read(1));
Serial.println(EEPROM.read(2));
Serial.println(EEPROM.read(3));
Serial.println(EEPROM.read(4));
Serial.println(EEPROM.read(5));
Serial.println(EEPROM.get(0,TestNum));
}
結果は想像したとおりになりました。
では事前に0番地から5番地に255を入れ込んでおき、
long TestNum = 123;
とした場合はどうなるのでしょうか。
#include <EEPROM.h>
long TestNum = 123;
void setup() {
Serial.begin( 9600 ); //シリアルモニタを使うときの儀式
EEPROM.put(0,255);
EEPROM.put(1,255);
EEPROM.put(2,255);
EEPROM.put(3,255);
EEPROM.put(4,255);
EEPROM.put(5,255);
EEPROM.put(0,TestNum);
Serial.println(EEPROM.read(0));
Serial.println(EEPROM.read(1));
Serial.println(EEPROM.read(2));
Serial.println(EEPROM.read(3));
Serial.println(EEPROM.read(4));
Serial.println(EEPROM.read(5));
Serial.println(EEPROM.get(0,TestNum));
}
値は1Byte、変数は4Byteのもの。
命令が変数のサイズで反応しているなら5番地と6番地は255のまま。
値のサイズで反応しているなら0番地以外全て255のままとなります。
結果は・・
つまり値ではなく、変数の種類で書き込み場所が決まるようです。
これはとても重要なことですよ。ぜひ頭に焼き付けて置くべき事柄です。
実験してよかった(*´ω`*)
あと問題があるとすればEEPROMの書き込み寿命ですかね。
今、F-RAMっていうのが登場しているようですが、
F-RAMはCypressのFM25W256を使うと、ほぼ制限を気にすることなく書き込みができるという記事があります。
https://www.switch-science.com/catalog/1406/
結構いい値段がしますね。庶民にはまだまだ手が出ないかなぁ。
ジャンプスターターのその後
2019.02.11
激寒の北海道
2019.02.10
2/8は極寒でした。
私はここまでの寒波は経験がありません。
深夜の気温は-14.1度。最高気温は-9.9という予報よりもさらに下回った気温でした。
早朝は車の温度計で-11℃。風もあるので体感はもっと寒かったと思います。
事務所はタイマーでストーブが点く様になっていますが、
それでも到着時は5℃もありませんでした。寒い(;´Д`)
そんな中で3Dプリンターを動かす私。
温度はきっちり上がってくれます。ベッドも100度まで問題なし。
印刷面も完璧です。
いいぞいいぞ(*´ω`*)
去年は大雪で苦労しましたが気温はプラスの日が結構ありました。
今年は雪は少なめですが、連日マイナス気温ですねぇ。
大雪対策でジムニーを買ったのですが、なかなか出番がありません(;´Д`)
Arduino 7) 可変抵抗器でボリューム値を知る
2019.02.05
Arduinoはアナログピンの入力電圧を0~1023段階で測ることができます。
Arduinoの5Vを可変抵抗器につなげ、その抵抗の変化を読み取り数値化するのです。
可変抵抗は電圧をコントロールできます。
一般的に抵抗と言えば電圧が一定の場合は電流を制御するものというイメージがあります。
可変抵抗はキルヒホッフの第二法則を利用した分圧を行い電圧をコントロールできるのです。
Arduinoのアナログピンは0vで0、2.5Vで512、5Vで1023という値を返します。
では実際に読み取ってみます。
変化を目視するためにボードについているLEDを点滅させその速度で判断してみましょう。
配線はこのようにして
ソースは以下のようにします
int Denatu = 0;
void setup() {
Serial.begin( 9600 ); //シリアルモニタを使うときの儀式
pinMode(13, OUTPUT); //ボードのLEDを使用する
}
void loop() {
digitalWrite(13, HIGH); //LEDを光らせる
Denatu = analogRead(0); //A0ピンの電圧を測る0(0V)~1023(5V)
Serial.println(Denatu); //シリアルモニタに値を出力
delay(Denatu); //読み取った値分処理を止める1023=1.023秒
digitalWrite(13, LOW); //LEDを消す
delay(Denatu); //読み取った値分処理を止める1023=1.023秒
}
実行した結果はこちら
ダイヤルに合わせてLEDの速度が変化しているのがわかります。
TXのLEDがチカチカしているのはシリアルモニタと通信しているためです。
この仕組は頻繁に使われ応用される基礎なので、
自分自身の再確認のために記録を残しておきます。
Arduinoの5Vを可変抵抗器につなげ、その抵抗の変化を読み取り数値化するのです。
可変抵抗は電圧をコントロールできます。
一般的に抵抗と言えば電圧が一定の場合は電流を制御するものというイメージがあります。
可変抵抗はキルヒホッフの第二法則を利用した分圧を行い電圧をコントロールできるのです。
Arduinoのアナログピンは0vで0、2.5Vで512、5Vで1023という値を返します。
では実際に読み取ってみます。
変化を目視するためにボードについているLEDを点滅させその速度で判断してみましょう。
配線はこのようにして
ソースは以下のようにします
int Denatu = 0;
void setup() {
Serial.begin( 9600 ); //シリアルモニタを使うときの儀式
pinMode(13, OUTPUT); //ボードのLEDを使用する
}
void loop() {
digitalWrite(13, HIGH); //LEDを光らせる
Denatu = analogRead(0); //A0ピンの電圧を測る0(0V)~1023(5V)
Serial.println(Denatu); //シリアルモニタに値を出力
delay(Denatu); //読み取った値分処理を止める1023=1.023秒
digitalWrite(13, LOW); //LEDを消す
delay(Denatu); //読み取った値分処理を止める1023=1.023秒
}
実行した結果はこちら
ダイヤルに合わせてLEDの速度が変化しているのがわかります。
TXのLEDがチカチカしているのはシリアルモニタと通信しているためです。
この仕組は頻繁に使われ応用される基礎なので、
自分自身の再確認のために記録を残しておきます。