JH7UBCブログ

アマチュア無線 電子工作 家庭菜園など趣味のブログです

ESP32 ロータリーエンコーダ テスト

2020-01-31 20:48:19 | ESP32

 前の記事のGPIO割込みを利用して、ロータリーエンコーダの回転方向を検出するテストをします。

 回転方向の検出は、秋月電子でロ-タリーエンコーダを買うとついてくる説明用紙に出ている方法を使います。

 ロータリーエンコーダのA端子とB端子をプルアップしておいて、エンコーダを回転させると各端子の電圧は、時計回り、反時計回りのとき、下の図のように変化します。

 前のBAの値を1ビット左にシフトした値と現在のBAの値のXORをとり、下位2ビットだけ取り出すと時計回りのときは、0か1(2未満)であり、反時計回りのときは、2か3(2以上)です。このことを使って回転方向を判定します。

 GPIO12とGPIO13を使います。回路図です。(内部でプルアップしますので、プルアップ抵抗は不要です)

 テストしたスケッチです。

--------------------------------------------

/*
 *  ESP32 Rotary Encoder test
 *  2020.1.31
 *  JH7UBC Keiji Hata
 */

#define ENC_A 12
#define ENC_B 13

volatile int old_value = 0x11;
volatile int value = 0;
volatile int D;
volatile int count = 0;

void setup() {
  pinMode(ENC_A, INPUT_PULLUP); //内部でプルアップ
  pinMode(ENC_B, INPUT_PULLUP); //内部でプルアップ
  attachInterrupt(ENC_A, rotary, CHANGE); //GPIO割込みセット
  attachInterrupt(ENC_B, rotary, CHANGE); //GPIO割込みセット
  Serial.begin(115200); //シリアル通信初期化
}

void loop() {

}

//割込みサービスルーチン

void rotary(){
  value = (digitalRead(ENC_B)<<1) | digitalRead(ENC_A);
  if(old_value != value){
    D = ((old_value << 1) ^ value) & 3;
    if(D < 2){
      count +=1;
    }else{
      count -=1;
    }
  if(count >= 4){
    Serial.println("Right");
    count = 0;
    }else if(count <= -4){
    Serial.println("Left");
    count = 0;
    }
  old_value = value;
  }
}

--------------------------------------------

 時計回りのとき「Right」、反時計回りのとき「Left」とシリアルモニタに表示します。

ロータリーエンコーダを回してみます。

モニターの表示です。

回転方向と表示が逆の場合は、A,Bの配線を逆にします。

機械式ロータリーエンコーダには、チャタリングがありますので、回転と表示が若干ずれることがありますが、問題なく動作すると思います。

Arduinoのライブラリには、RotaryEncoderというものがあり、それを使う方法が簡単なのですが、使いにくい点もあるので、PICで使っている方法でテストしてみました。


ESP32 GPIO割込みテスト

2020-01-28 19:23:50 | ESP32

 ESP32の割込みには、ハードウェア割込み(GPIO割込みとタッチ割込み)とソフトウェア割込み(タイマー割込みとウォッチドックタイマ割込み)があります。

 今回は、GPIO割込みのテストをします。

 GPIO割込みでは、GPIOピンの信号値が変化したときに割込みが発生し、割込みサービスルーチン(ISR)が実行されます。この割込みはすべてのGPIOピンで利用できます。

 書式は、attachInterrupt(GPIOPin, ISR, Mode); です。

 Modeは、LOW,HIGH,CHANGE,FALLING,RISING が使えます。

 割込みを停止するには、

 detachInterrupt(GPIOPin); とします。

 「Arduinoをはじめよう」の本の外部割込みのスケッチを参考に、簡単なスケッチを作りました。

-------------------------------------------

/*
 *  ESP32 GPIO interrupt test
 *  2020.1.28
 *  JH7UBC Keiji Hata
 */

#define LED_Pin 27
#define SW_Pin 33
volatile int state = LOW;
 
void setup() {
  pinMode(SW_Pin, INPUT_PULLUP);
  pinMode(LED_Pin, OUTPUT);
  attachInterrupt(SW_Pin, LED_blink, FALLING);
}

void loop() {
  digitalWrite(LED_Pin, state);
}

void LED_blink(){
  delay(10);
  state = !state;
}

----------------------------------------------

配線回路図です。

ブレッドボードです。

 タクトスイッチにチャタリングがあるため、押し方によっては、誤動作しますが、スイッチを押すたびに点灯・消灯を繰り返し、GPIO割込みを確認することができました。

 ただ、入力専用のピンA0,A3,A6,A7を割込み入力に設定するとうまくいきません。

どうして?

 

1月29日追記

 入力専用ピンでの内部プルアップしたGPIO割込みが不安定なことについて、今朝実験をしてみました。

 10kΩの外付け抵抗で入力専用ピンをプルアップしたら、正常に動作しました。

 入力専用ピンは、内部プルアップ(ソフトウェアプルアップ)ができないのかもしれません。(コンパイルではエラーは出ませんが)


HP Pavillion dv6 のHHDをSSDに交換

2020-01-27 12:00:57 | パソコン
 シャックで使っているパソコン、HP Pavillion dv6がしばらく前から起動時にディスクエラー表示が出るようになりました。CrystalDiskInfoで調べてみると、「注意」の状態でした。
 このパソコンは2009年製ですから、しかたがないと思いますが、もう少し働いてもらうために、HDDをSSDに交換することにしました。
 今回Amazonから購入したのは、シリコンパワーの256GBのSSDです。
 まず、HHDからSSDへのクローンをやってみました。
 EaseUS Todo Backup無料版を使って、クローンを実行。
 Pavillion dv6は、USB2.0ですので、時間がかかり、約3時間かかって99%まで進みましたが、そこで進まなくなりました。この段階でストップして、HHDとSSDを交換して、電源を入れてみましたが、立ち上がらず。
 
 Pavillion dv6では、HDDへのアクセスは非常に簡単で、まずバッテリーをはずし、
 
 黄色い丸印のビス2本をはずだけで裏蓋がはずせ、HDDを取り出すことができます。
 交換は、簡単なのですが、クローンはうまくいかず、残念。
 そこで、装着したSSDにWindows10をクリーンインストールすることにしました。
 
 例によってWindows10のダウンロードのページを参考にして、Windows10をインストールしました。
 1時間くらいかかって、無事インストールできました。
 その後、必要なソフトをインストールしました。10年以上働いてくれたパソコンですが、もう少し頑張って働いてね。

ESP32 PWM テスト

2020-01-25 21:15:06 | ESP32
 パソコンの修復が終了したので、再びESP32の勉強を進めます。
 今回は、ESP32のPWM(Pulse Width Moduration)のテストをします。
 PWM出力できるポート(GPIO)は
ポート GPIO
A4         32
A5         33
A10        4
A11        0
A12        2
A13      15
A14      13
A15      12
A16      14
A17      27
A18      25
A19     26
です。A0,A3,A6,A7は入力専用なので、利用できません。
 
PWMに使う関数は、
ledcSetup(chan,freq,bit_num); //チャンネル,周波数,ビット数
ledcAttachPin(pin,chan); //ピン番号,チャンネル
ledcWrite(chan,duty); //チャンネル,デューティ
です。
 
ledcSetup()で、チャンネル(0~15),PWM周波数(~40MHz),ビット数(1~16)を設定します。PWM周波数は、PWMに供給されるがクロックが80MHzですので、ビット数(分解能)によって、ビットごとの最大周波数は次のようになります。
ビット数 分解能 最大周波数(Hz)
16             65536     1220.70
15             32768     2441.41
14             16384     4882.81
13               8192     9765.63
12               4096     19531.25
11               2048     39062.50
10               1024        78125
9                   512      156250
8                   256      312500
7                   128      625000
6                     64     1250000
5                     32      2500000
4                     16      5000000
3                       8     10000000
2                       4     20000000
1                       2     40000000
 
ledcAttachPin()で、出力ピンをどのチャンネルに接続するかを設定します。
ledcWrite()で、チャンネルのデューティ比を設定します。デューティ比は、
 デューティ比=duty/bit_numです。
例として、1000HzのPWM出力をデューティ比50%で出力してみます。チャンネル0を使い、A19(GPIO26)に出力します。
 
スケッチです。
void setup() {
ledcSetup(0,1000,8);
ledcAttachPin(26, 0);
ledcWrite(0,128);
}
void loop() {
}
出力波形です。1000Hz デューティ比50%
 
ledcWrite(0,64);とするとデューティ比25%になります。
出力波形です。
 
ledcWrite(0,192);とするとデューティ比75%になります。出力波形です。
 
最大周波数を出力してみます。
ledcSetup(0,40000000,1);
ledcAttachPin(26, 0);
ledcWrite(0,1);
とすると確かに40MHzが出力されました。ただし、デューティ比は、50%だけです。
 
 それでは、任意の周波数は、出力できるでしょうか。
 freq=7000000と設定したときの出力です。
 
 かなりずれた周波数を発生させました。
 1000Hz,10000Hz,100000Hz,1000000Hzなどは、正しい周波数を発生させることができますが、周波数によっては、かなりずれを生じます。分周期のせいでしょうか。
 正確な周波数を発生させることができるなら、VFOとして使えるかな、などと期待したのですが、ちょっと無理みたいです。
 チャンネルについても、いくつか実験をしたのですが、最後に指定した1つしか使えないようです。これについて、情報がありましたら、教えてください。
 

QSOパーティのステッカ到着

2020-01-24 11:33:07 | アマチュア無線
 今年のQSOパーティのステッカが今日届きました。


 当局JH7UBCは、2000年からQSOパーティに参加しています。
 毎年1月2日に144MHzか430MHzで参加し、ローカル各局と新年のあいさつをするのが恒例になっていました。
 しかし、今年は暮れから1エリアに移動したため、1月3日に7MHz CWでの参加になりました。
 この20年間、1年だけ参加できないだけで、毎年QSOパーティに参加しています。
 毎年元気にパーティに参加できることに感謝しています。
 今年も無線を楽しんでいきましょう。