ロータリーエンコーダで入力してみる
ロータリーエンコーダを使ってLCDの表示を変更するプログラムコードです。
今回もおなじみAVRのATMega88を使います。LCDは以前と同じです。
ロータリーエンコーダ

秋月電子で購入しました。DIP化基板も合わせて購入しました。24パルス/周です。
ロータリーエンコーダにはインクリメンタル形とアブソリュート形があるそうです。今回使用するのはインクリメンタル形です。

0ビット目と1ビット目の値が右回転の時は0(00)、1(01)、3(11)、2(10)、0(00)…となります。
配線図

実験なのでロータリーエンコーダとマイコンの接続は内蔵プルアップ抵抗を使用しました。PB0にA、PB1にBを接続します。
ソースコード
以前作ったLCD関連のプログラムは省略します。
ロータリーエンコーダに関するコードはChaNさんのページから流用しています。こういったコードが自分で考えられるようになりたいです。それではコードをどうぞ。
#define F_CPU 1000000UL // 1MHz
/* ロータリーエンコーダ */
#define RE_PIN PINB // ロータリーエンコーダのAをPB0にBをPB1に接続する
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "lcd4bit.h"
volatile struct
{
long position; // 軸位置
int moved; // 移動フラグ
} Encoder;
void sample_encorder(void)
{
static const int dir[] = {0,1,-1,0,-1,0,0,1,1,0,0,-1,0,-1,1,0}; // 回転方向テーブル
static int i; // インデックス
int n;
i = (i << 2) + (RE_PIN & 3); // 前回値と今回値でインデックスとする
n = dir[i & 15]; // 変数パターンから動きを得る
/* ポジションを-100~100までとする */
if(n)
{
Encoder.position += n;
Encoder.moved = 1;
if (Encoder.position > 200)
{
Encoder.position = 200;
} else if (Encoder.position < -200)
{
Encoder.position = -200;
}
}
}
ISR(TIMER0_COMPA_vect)
{
sample_encorder();
}
void lcd_re_pos()
{
long posnum = Encoder.position;
char str_pos[3];
int i;
if (Encoder.position < 0)
{
str_pos[0] = '-';
posnum = -(posnum); // 「-」があるとキャラクターコードとマッチしない
} else {
str_pos[0] = ' ';
}
for (i = 3; i > 0; i--)
{
str_pos[i] = ((posnum /2) % 10) + 0x30; // 数値を数字に変換
posnum /= 10;
}
lcd_clear();
for (i = 0; i <= 3; i++)
{
lcd_data(str_pos[i]);
}
Encoder.moved = 0;
}
int main(void)
{
/* LCD設定 */
DDRD = 0b11111111; // LCDピンに使用
PORTD = 0b00000000; // ポートD初期化
lcd_init();
/* ロータリーエンコーダ */
DDRB = 0b00000000;
PORTB = 0b00000011;
/* タイマ割り込み設定 */
TCCR0A = 0b00000010; // CTC
TCCR0B = 0b00000101; // 1MHz/1024 = 約977Hz→約1kHz
OCR0A = 5; // 5msで割り込み
TIMSK0 = 0b00000010; // COMPA割り込み
lcd_str("Rotary Encoder");
sei(); // 全体の割り込み許可
/* Replace with your application code */
while (1)
{
if (Encoder.moved)
{
lcd_re_pos();
}
}
}
14〜41行目までが流用したコードです。変更点は26行目のPA.PIN.BYTEをRE_PINにしました。PA.PIN.BYTEはAVR用ではなくH8用なのか使えなかったので書き換えました。#define RE_PIN PINB
としてロータリーエンコーダーと接続するピンを指定しました。
33〜39行目は上下限値を設定する為に追加しています。ロータリーエンコーダを回すと上手く数字が1つずつ増減出来ませんでした。-200〜200として表示する時に値を半分にした所、完璧ではありませんが想定した動作になりました。
今回タイマ割り込みという機能を使ってロータリーエンコーダの状態を監視しています。タイマ割り込みについてはまたにします。タイマ割り込みも剣菱Pさんの動画を参考にしています。約5ミリ秒毎に割り込みが発生するように設定しています。
数値を数字に
ロータリーエンコーダに変化があるとlcd_re_pos( )関数を実行します。Encoder.positionには数値が入っているのでそのままLCDに送っても正しく表示されません。
str_pos[ ]という配列に数値を数字に変換して代入します。今回は3桁と決めていたのでfor文の繰り返しは4回(符号と3桁分)と固定していますが、文字数が決まっていない場合while文の条件に’¥0’でない場合などとすると良いかもしれません。
一文字ずつデータを送信するのでlcd_str( )ではなくlcd_data( )を使いました。
「% 10」は10で割った余りという意味でint a = 85 % 10;
とするとaに5が代入されます。
余りに「+ 0x30」とすることでキャラクターコードの文字に合わせています。LCDのキャラクターコード表には「0」は0x30とされています。数値の「0」は0x00なのでそのまま送るとバグが発生します。char a = 0 + 0x30;
とすればaには’0’が代入されます。
-200〜200を-100〜100としているので2で割っています。
動作
動画でどうぞ\(^o^)/
これでスタンドアローン型のねじ切り旋盤(NC旋盤)が作れそうです。まずはソフト開発を進めたいと思います。