ジョイスティック KY-023の制御
2022.10.24

前回はロータリーエンコーダを調査しましたが、
今回はジョイスティックです。
良く使われるパーツはKY-023とよばれるもの。
2次元の座標を読み取れるだけでなく、
スティックを押し込むとスイッチとしての機能もあります。
とても安いので扱いやすいパーツです。

接続するにあたって、デュポンコネクタのケーブルを作成しました。
5V、GND、VRx、VRy、SW
の5本。

VRxとVRyは倒している量を計測したいのでアナログピンに接続。
SWはスイッチなのでデジタルピンに接続します。
ただし、SWのデジタルピンはインプットプルアップにします。

テストプログラムはこんな感じ。
世に出回っている一般的なソースを少し改造したものです。
このジョイスティックという部品は、
X方向とY方向の可変抵抗の値を読み取って傾斜量と向きを判別しています。
X軸、Y軸それぞれで0~1023までの値を読み取ることができ、
ニュートラル状態ではその中央値である512を返します。
512より小さければ左か上方向、大きければ右か下方向を示すわけですね。
ところが、そうはうまくいかないのが世の常で、
個体差が必ずありニュートラル位置でキレイに512を返すことは稀です。
道具として組み込むならその誤差を修正する機能が必要になるので、
その部分だけ付け足しています。

実行してみました。
成功のようです。
シリアルモニタで状況を見ていると、
±1は頻繁にブレることがわかります。
逆にスティックを少々傾けても値は大きく変化しないことがわかりました。
検知に遊びがあるんですね、触った感じゆっくり倒しても100刻みくらい?
丁寧に倒せば50刻みくらいできる? そんな感じです。
プレステとかSwitchのコントローラーはどれくらいの感度なんでしょうかねぇ・・
ロータリーエンコーダ(ホイールエンコーダ)の使い方。
2022.10.14
マウスに良く使われているロータリーエンコーダ(ホイールエンコーダ)。
これの使い方を調べてみたいと思います。

↑ロータリーエンコーダというとこれが一番有名ですが、
捻るタイプのエンコーダなので今考えている用途には使えません、
今回はもっと小型でマウスのホイールと同じものを使います。

最近のマウスは、このようなパーツでホイールを検知しているようですね。
一昔前は回転する網が何回光を遮ったかを検知する構造で
センサーが露出しているタイプだったのに、
今はこれらの機能が内包し小型化がすすんでいるという。
進化が早いです(;´Д`)
さて、このロータリーエンコーダーは3ピンです。
1本が電源線、2本が信号線。
先人の知恵を借りるためにネットで使用例を検索してみると、
電源線をGNDにつなげている人が多く見えます。
しかもそのようなソースに限って、
pinMode(1, INPUT);
となっています。
中学レベルの電気しか学んでいない私は「え?インプット?入力?なのにGND?」
とちょっと疑問に思ってしまうのですが、
GNDのマイナス電圧を利用するん?とか考えてしまいますよね?
これが
pinMode(1, INPUT_PULLUP);
だったなら理解はできますが・・・。
しばし悩んだら、
pinMode(1, INPUT);
digitalWrite(1, HIGH);
と2行がセットになっていることに気が付きました。
INPUTなのに、HIGHを出してる。
このパターンでも、INPUT_PULLUPと同様に内部抵抗(最小20KΩ~最大50KΩ)
がオンになるという話。
Arduinoではあまり推奨していない方法だけど、
こういった使い方もできるんだねと。
話はそれましたが、電源線はGNDに繋いで問題ないようです。

そうそう、Arduinoはモデルによって割り込みが使えるピンが違います。
私が良く使うモデルだけ載せておきます。
UNOとMEGAとMicroとLeonardoの4つがわかればok
今回のテストで使うUNOは2ピンと3ピンね。

動作の検証なので、とりあえずシンプルに接続。
2本の信号を組み合わせて回転の方向と量を検知する仕組み。

ソースはとりあえずこんなところかな。
ロータリーエンコーダーの回転量(位置)を導き出す関数だけど、
今回はどの程度の速さで処理できるのか見たかったので、
シリアルモニターに表示させてみました。

1ノッチ動かすだけでも数回割り込みしているのがわかる。
結構デリケートなのね。
カチッって言うノッチの振動で判定がぶれるのかな。
これは割り込み処理内で位置情報だけ確保しておいて、
LOOP内で適切なタイミングで移動量を計算させて使用したほうが安定しそうだ。
これの使い方を調べてみたいと思います。

↑ロータリーエンコーダというとこれが一番有名ですが、
捻るタイプのエンコーダなので今考えている用途には使えません、
今回はもっと小型でマウスのホイールと同じものを使います。

最近のマウスは、このようなパーツでホイールを検知しているようですね。
一昔前は回転する網が何回光を遮ったかを検知する構造で
センサーが露出しているタイプだったのに、
今はこれらの機能が内包し小型化がすすんでいるという。
進化が早いです(;´Д`)
さて、このロータリーエンコーダーは3ピンです。
1本が電源線、2本が信号線。
先人の知恵を借りるためにネットで使用例を検索してみると、
電源線をGNDにつなげている人が多く見えます。
しかもそのようなソースに限って、
pinMode(1, INPUT);
となっています。
中学レベルの電気しか学んでいない私は「え?インプット?入力?なのにGND?」
とちょっと疑問に思ってしまうのですが、
GNDのマイナス電圧を利用するん?とか考えてしまいますよね?
これが
pinMode(1, INPUT_PULLUP);
だったなら理解はできますが・・・。
しばし悩んだら、
pinMode(1, INPUT);
digitalWrite(1, HIGH);
と2行がセットになっていることに気が付きました。
INPUTなのに、HIGHを出してる。
このパターンでも、INPUT_PULLUPと同様に内部抵抗(最小20KΩ~最大50KΩ)
がオンになるという話。
Arduinoではあまり推奨していない方法だけど、
こういった使い方もできるんだねと。
話はそれましたが、電源線はGNDに繋いで問題ないようです。

そうそう、Arduinoはモデルによって割り込みが使えるピンが違います。
私が良く使うモデルだけ載せておきます。
UNOとMEGAとMicroとLeonardoの4つがわかればok
今回のテストで使うUNOは2ピンと3ピンね。

動作の検証なので、とりあえずシンプルに接続。
2本の信号を組み合わせて回転の方向と量を検知する仕組み。

ソースはとりあえずこんなところかな。
ロータリーエンコーダーの回転量(位置)を導き出す関数だけど、
今回はどの程度の速さで処理できるのか見たかったので、
シリアルモニターに表示させてみました。

1ノッチ動かすだけでも数回割り込みしているのがわかる。
結構デリケートなのね。
カチッって言うノッチの振動で判定がぶれるのかな。
これは割り込み処理内で位置情報だけ確保しておいて、
LOOP内で適切なタイミングで移動量を計算させて使用したほうが安定しそうだ。
Arduinoでボタン1つで行うストップウォッチ
2022.02.23
知り合いに相談を受けたのでサササっと記述。
条件はストップウォッチの機能をボタン1つでスタート、ストップ。
リセット機能は要件になし。
液晶にはストップしたときにH:M:S:MSで表示する。
ボタンの動作はデジタル3番ピンを使用。
不安定防止の為、5Vで受けるようにする。
やり方はいろいろあると思うけど、深夜の殴り書き程度ならこんなもんかな?
もっと最適化できる? ウン、ソウダネ。
CASE文を嫌う人って結構いるけど、
IFの階層が深いよりはコードが見やすく
バグも発見しやすいので、私はためらいもなく使います。
インデントをタブで行ってたところは
ブログにコピペしたら消されちゃった(;´Д`)
なので「}」なんかは左寄せになってしまって読みにくくなってしまったけど
我慢してください(;´Д`)
#include
LiquidCrystal_I2C lcd(0x27,16,2);
unsigned long W_time = 0; //タイマーの値
unsigned long W_counttime = 0; //経過時間
int W_msec = 0; //ミリ秒の保存
int W_sec = 0; //秒の保存
int W_min = 0; //分の保存
int W_hr = 0; //時間の保存
int W_amari = 0;
int Push_Count = 0; //何回押したか。1回目ならスタート、2回目ならストップ&表示
int Push_Flg = 0; //現在押しているかのフラグ
unsigned long Click_konkai = 0; //長押し誤動作の対策
unsigned long Click_zenkai = 0;
int Work_int = 0;
int B_Switch = 0; //スイッチの判断用
void setup() {
//***シリアル定義*******************
Serial.begin(9600);
//***液晶初期化******************
lcd.init();
lcd.begin(20,2); //LCD2004の表示範囲を指定
//LCD2004は20x2キャラクタ表示なので、20,2といれる。
lcd.clear(); //表示をクリアしてカーソルを上段の先頭の位置に移動
lcd.backlight(); //LCD2004のバックライトを点ける
lcd.print("READY");
//***ピン定義*******************
pinMode(3,INPUT); //デジタルピン3番をスイッチ用として使用する
}
void loop(){
B_Switch = digitalRead(3);//ボタンが押されたかを確認する
if(B_Switch == HIGH){
delay(10); //チャタリングじゃないかを判断するために10ms後も押し続けたかで判断
B_Switch = digitalRead(3);//ボタンが押されたかを確認する
if(B_Switch == HIGH){
Push_Flg = 1;
}else{
Push_Flg = 0;
}
}else{
Push_Flg = 0;
}
if (Push_Flg == 1){
Click_konkai = millis();
Work_int = Click_konkai - Click_zenkai;
if (Work_int > 1000 ){ //1秒未満の再クリックは押しっぱなしの可能性があるので無視する
Click_zenkai = Click_konkai;
switch(Push_Count){
case 0:
W_time = millis(); //開始時刻を記録
lcd.clear();
lcd.print("START");
Push_Count = 1;
break;
case 1:
W_counttime = millis() - W_time; //経過時間を導く
W_msec = W_counttime % 1000; //1000で割った余りをmsにする
W_counttime = W_counttime /1000; //経過時間を1000で割って最小単位を秒にする。
W_hr = W_counttime / 3600; //経過時間を3600で割って時間を導く。
W_amari = W_counttime % 3600; //経過時間を3600で割った余りを保存。
W_min = W_amari / 60; //経過時間を60で割って分を導く。
W_sec = W_amari % 60; //経過時間を60で割った余りを秒にする。
lcd.clear();
lcd.print("STOP");
lcd.setCursor(0,1);
lcd.print(W_hr); lcd.print("h:");
lcd.print(W_min); lcd.print("m:");
lcd.print(W_sec); lcd.print("s:");
lcd.print(W_msec); lcd.print("ms");
Push_Count = 0;
break;
}
}
}
}
条件はストップウォッチの機能をボタン1つでスタート、ストップ。
リセット機能は要件になし。
液晶にはストップしたときにH:M:S:MSで表示する。
ボタンの動作はデジタル3番ピンを使用。
不安定防止の為、5Vで受けるようにする。
やり方はいろいろあると思うけど、深夜の殴り書き程度ならこんなもんかな?
もっと最適化できる? ウン、ソウダネ。
CASE文を嫌う人って結構いるけど、
IFの階層が深いよりはコードが見やすく
バグも発見しやすいので、私はためらいもなく使います。
インデントをタブで行ってたところは
ブログにコピペしたら消されちゃった(;´Д`)
なので「}」なんかは左寄せになってしまって読みにくくなってしまったけど
我慢してください(;´Д`)
#include
LiquidCrystal_I2C lcd(0x27,16,2);
unsigned long W_time = 0; //タイマーの値
unsigned long W_counttime = 0; //経過時間
int W_msec = 0; //ミリ秒の保存
int W_sec = 0; //秒の保存
int W_min = 0; //分の保存
int W_hr = 0; //時間の保存
int W_amari = 0;
int Push_Count = 0; //何回押したか。1回目ならスタート、2回目ならストップ&表示
int Push_Flg = 0; //現在押しているかのフラグ
unsigned long Click_konkai = 0; //長押し誤動作の対策
unsigned long Click_zenkai = 0;
int Work_int = 0;
int B_Switch = 0; //スイッチの判断用
void setup() {
//***シリアル定義*******************
Serial.begin(9600);
//***液晶初期化******************
lcd.init();
lcd.begin(20,2); //LCD2004の表示範囲を指定
//LCD2004は20x2キャラクタ表示なので、20,2といれる。
lcd.clear(); //表示をクリアしてカーソルを上段の先頭の位置に移動
lcd.backlight(); //LCD2004のバックライトを点ける
lcd.print("READY");
//***ピン定義*******************
pinMode(3,INPUT); //デジタルピン3番をスイッチ用として使用する
}
void loop(){
B_Switch = digitalRead(3);//ボタンが押されたかを確認する
if(B_Switch == HIGH){
delay(10); //チャタリングじゃないかを判断するために10ms後も押し続けたかで判断
B_Switch = digitalRead(3);//ボタンが押されたかを確認する
if(B_Switch == HIGH){
Push_Flg = 1;
}else{
Push_Flg = 0;
}
}else{
Push_Flg = 0;
}
if (Push_Flg == 1){
Click_konkai = millis();
Work_int = Click_konkai - Click_zenkai;
if (Work_int > 1000 ){ //1秒未満の再クリックは押しっぱなしの可能性があるので無視する
Click_zenkai = Click_konkai;
switch(Push_Count){
case 0:
W_time = millis(); //開始時刻を記録
lcd.clear();
lcd.print("START");
Push_Count = 1;
break;
case 1:
W_counttime = millis() - W_time; //経過時間を導く
W_msec = W_counttime % 1000; //1000で割った余りをmsにする
W_counttime = W_counttime /1000; //経過時間を1000で割って最小単位を秒にする。
W_hr = W_counttime / 3600; //経過時間を3600で割って時間を導く。
W_amari = W_counttime % 3600; //経過時間を3600で割った余りを保存。
W_min = W_amari / 60; //経過時間を60で割って分を導く。
W_sec = W_amari % 60; //経過時間を60で割った余りを秒にする。
lcd.clear();
lcd.print("STOP");
lcd.setCursor(0,1);
lcd.print(W_hr); lcd.print("h:");
lcd.print(W_min); lcd.print("m:");
lcd.print(W_sec); lcd.print("s:");
lcd.print(W_msec); lcd.print("ms");
Push_Count = 0;
break;
}
}
}
}
Arduino 9-1) 4連 Digital Tube LED Displayの点滅問題を考える
2019.03.03
その後、いろんな角度からテストをしてみました。
まず、5, 6ピンを使うとmillis(), micros(), delay(), delayMicroseconds()などの関数が正常に動かなくなるという情報をネットでみたので、接続するピンを
#define SCLK 4
#define RCLK 7
#define DIO 8
としてみる。
失敗
電源をUSB供給から電池に変えてみる。
失敗
Deleyの代わりにmillisを使ってみる。
Deleyのように簡単に使えるようにするため
void milliswait(int loop_i){
old_time=millis(); //最新の実行時間を保存
while (millis() - old_time < loop_i);
}
このような関数を作って実行してみた。
どうやらDelayが悪いのではなく、
処理能力が低下すると高速書き換えができなくなるだけのことだった。
複雑な処理を乗せるとDelayじゃなくても起きる現象ということで
失敗
先人のライブラリを使ってみる。
TM74HC595で検索すると結構使ってる人がいるもので、
Youtubeに投稿してる人も何人かいました。
https://www.youtube.com/watch?v=S_Hnx20GzGs
↑この方の意見を全面的に取り入れて試してみます。
https://github.com/kostarev/TM74HC595-4dig-display
にアクセスしてダウンロードしインストール。
ソースコードを書き換えて実行。
同じ症状でした。
失敗
結局の所、ネットで調べ倒して見た結果、
この製品は4キャラクタのうち、1文字を表示した直後、
他のモジュールの文字が消えてしまう仕様のようで
高速に4モジュールを表示し直して、目をごまかすような処理が必要のようだ。
Loop内でDelayを使うとその更新が阻害されるため
点滅したように見えてしまうというのが真実らしい。
これの解決策として、割り込みを利用し
ある一定周期で更新させることができれば、
Loop内だろうがDelayで止めようが
表示は安定するのではというのが最適解のようです。
#include <mstimer2.h>
int Denatu = 0;
int OutNum = 0;
//接続するピンを設定する
#define SCLK 4
#define RCLK 7
#define DIO 8
byte digitBuffer[4]; //キャラ数(文字数を設定)この配列に入れた数字がそのまま表示される。
void setup(){
Serial.begin( 9600 ); //シリアルモニタを使うときの儀式
pinMode(13, OUTPUT); //ボードのLEDを使用する
pinMode(RCLK, OUTPUT);
pinMode(SCLK, OUTPUT);
pinMode(DIO, OUTPUT);
MsTimer2::set(1, showDisplay); // 1msの周期で結果を4LEDに表示
MsTimer2::start();
}
void loop(){
digitalWrite(13, HIGH); //LEDを光らせる
Denatu = analogRead(0); //A0ピンの電圧を測る0(0V)~1023(5V)
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で割ってあまりを求める。
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(1);
}
}
最初の実験の影響で、ピンの位置を先日のものと変えています。注意。
そして実行
イエ━ヽ(*´∇`)人(´∇`*)━ィ!!
ただこの方法、人間には区別はつかないけど高速点滅しているので目には優しくないと思われる。
まず、5, 6ピンを使うとmillis(), micros(), delay(), delayMicroseconds()などの関数が正常に動かなくなるという情報をネットでみたので、接続するピンを
#define SCLK 4
#define RCLK 7
#define DIO 8
としてみる。
失敗
電源をUSB供給から電池に変えてみる。
失敗
Deleyの代わりにmillisを使ってみる。
Deleyのように簡単に使えるようにするため
void milliswait(int loop_i){
old_time=millis(); //最新の実行時間を保存
while (millis() - old_time < loop_i);
}
このような関数を作って実行してみた。
どうやらDelayが悪いのではなく、
処理能力が低下すると高速書き換えができなくなるだけのことだった。
複雑な処理を乗せるとDelayじゃなくても起きる現象ということで
失敗
先人のライブラリを使ってみる。
TM74HC595で検索すると結構使ってる人がいるもので、
Youtubeに投稿してる人も何人かいました。
https://www.youtube.com/watch?v=S_Hnx20GzGs
↑この方の意見を全面的に取り入れて試してみます。
https://github.com/kostarev/TM74HC595-4dig-display
にアクセスしてダウンロードしインストール。
ソースコードを書き換えて実行。
同じ症状でした。
失敗
結局の所、ネットで調べ倒して見た結果、
この製品は4キャラクタのうち、1文字を表示した直後、
他のモジュールの文字が消えてしまう仕様のようで
高速に4モジュールを表示し直して、目をごまかすような処理が必要のようだ。
Loop内でDelayを使うとその更新が阻害されるため
点滅したように見えてしまうというのが真実らしい。
これの解決策として、割り込みを利用し
ある一定周期で更新させることができれば、
Loop内だろうがDelayで止めようが
表示は安定するのではというのが最適解のようです。
#include <mstimer2.h>
int Denatu = 0;
int OutNum = 0;
//接続するピンを設定する
#define SCLK 4
#define RCLK 7
#define DIO 8
byte digitBuffer[4]; //キャラ数(文字数を設定)この配列に入れた数字がそのまま表示される。
void setup(){
Serial.begin( 9600 ); //シリアルモニタを使うときの儀式
pinMode(13, OUTPUT); //ボードのLEDを使用する
pinMode(RCLK, OUTPUT);
pinMode(SCLK, OUTPUT);
pinMode(DIO, OUTPUT);
MsTimer2::set(1, showDisplay); // 1msの周期で結果を4LEDに表示
MsTimer2::start();
}
void loop(){
digitalWrite(13, HIGH); //LEDを光らせる
Denatu = analogRead(0); //A0ピンの電圧を測る0(0V)~1023(5V)
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で割ってあまりを求める。
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(1);
}
}
最初の実験の影響で、ピンの位置を先日のものと変えています。注意。
そして実行
イエ━ヽ(*´∇`)人(´∇`*)━ィ!!
ただこの方法、人間には区別はつかないけど高速点滅しているので目には優しくないと思われる。
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で処理を止めるとその間だけ表示も止まっているようだ。
今の所解決方法が見つからない。
よく使われる部品でこんなトラブルとはがっかり(;´Д`)