ATtiny402でロータリーエンコーダーを使うテストをします。
Arduino UNOなどでは、Rotary.hというライブラリを利用することができます。確認はしていないのですが、ライブラリでは割り込みを使っているのではと考えています。
ATtiny402では、ピン状態割り込みが使えないようなので、割り込みを使わない方法でロータリーエンコーダの制御プログラムを組みました。このプログラムは「wsnakのブログ」のロータリーエンコーダの記事のプログラムを利用させていただきました。ありがとうございます。
今回のテストでは、ロータリーエンコーダはAmazonで購入した安価なものを使い、ロータリーエンコーダの回転方向が時計回りの時にカウントアップ、反時計回りの時にカウントダウンするようにして、カウント値をLCD1602に表示するようにしました。
テストした回路図です。ロータリーエンコーダのA端子をD0(PA6)にB端子をD1(PA7)に接続し、それぞれを10KΩでプルアップします。
ロータリーエンコーダの回転方向の判定方法を簡単に説明します。
下の図のように、ロータリーエンコーダのA,Bの値を読み取り、Aをbit1、Bをbit0としてCurDatの値に加えます。A,Bの値が変わったらCurDatの値を左に2ビットシフトし、A,Bの値を加えます。エンコーダの1クリックで、A,Bの値が4回変わりますので、その都度同じ操作をします。
1クリックが終わったとき、エンコーダが時計回りの時、CurDatの値は0x4Bに、反時計回りの時は0x87になりますので、この値で回転方向が判定できます。
スケッチです。
機械的なロータリーエンコーダを使う場合、チャタリング対策が必要です。
スケッチでは、その対策をソフトで行っています。ひとつは、入力が安定するまで1msのdelayを入れました。それから、入力が同じかどうかmatchCntでカウントして、2回以上一致したら処理するようにしています。wsnackさんは5回以上の一致を確認していますが、1msのdelayを入れたので2回で十分のようです。
---------------------------------------------------
/*
ATtiny402 Rotary Encoder test
2023.8.19
JH7UBC Keiji Hata
*/
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
//Rotary Encoder関係定義
#define REA 0 //D0
#define REB 1 //D1
byte curDat;
byte befDat = 0;
byte rotDir = 0;
int Count = 0;
byte inputMatch;
byte matchCnt;
byte rotPat = 0;
void setup() {
pinMode(REA, INPUT);
pinMode(REB, INPUT);
//ロータリーエンコーダ初期値設定
curDat = 0;
if(digitalRead(REA)){
befDat |= 2;
}
if (digitalRead(REB)){
befDat |= 1;
}
//LCD初期設定と初期画面表示
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Rotary Encoder");
lcd.setCursor(0,1);
lcd.print(Count);
}
//Rotary Encoderの回転方向判定
signed char CheckEnc(byte dat) {
rotPat <<= 2;//左に2bitシフト
rotPat |= (dat & 0x03);//datの下位2bitを加える
if (rotPat == 0x4B) {
return 1; //時計回り(CW))
} else if (rotPat == 0x87) {
return -1; //反時計回り(CCW)
} else {
return 0; //どちらでもない
}
}
void loop() {
signed char val;
curDat = 0;
if (digitalRead(REA)) {
curDat |= 2;
}
if (digitalRead(REB)) {
curDat |= 1;
}
if (befDat == curDat) {
//befDatとcurDatが一致したときの処理
if (!inputMatch) {
matchCnt++;
if (matchCnt >= 2) { //2回以上一致したらフラッグを立てる
inputMatch = 1;
val = CheckEnc(curDat);
if (val != 0) {
Count += val;
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(Count);
}
}
}
} else {
//befDatとcuDatが一致しなかった時の処理
delay(1);//1ms待つ(チャタリング対策)
befDat = curDat;
matchCnt = 0;
inputMatch = 0;
}
}
---------------------------------------------------
ブレッドボードです。ロータリーエンコーダを回すごとに科カウントアップ、カウントダウンされます。このプログラムは、クリックの取りこぼしも少なく、けっこう優秀です。