えべす屋工房

色々なモノを作ります

ロータリーエンコーダで入力してみる

ロータリーエンコーダを使って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旋盤)が作れそうです。まずはソフト開発を進めたいと思います。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です