目次
前
次
ロータリーエンコーダ信号生成
ロータリーエンコーダの測定キットを半田付けしました。
ロータリーエンコーダは、回すと位相が
異なる信号が出力されてきます。
タイミングチャートで見ると、以下。
この信号をArduinoの7から10、14から17を利用して
出力することにします。
PORTB 13 - 10
PB5 (output) LED
PB4 (output) --
PB3 (output) B phase
PB2 (output) A phase
PB1 (output) B phase
PB0 (output) A phase
PORTC 19 - 14
PB5 (output) --
PB4 (output) --
PB3 (output) B phase
PB2 (output) A phase
PB1 (output) B phase
PB0 (output) A phase
A、Bの2相が、時計回りと反時計回りにあるので
ポートB、Cの各4ビットに、割て当します。
出力は、タイマー割込みを利用して、loopの中で
次のように定義します。
if ( eflag == ON ) {
/* clear flag */
eflag = OFF ;
/* blank */
bport = 0x00 ;
/* display */
if ( tflag == ON ) { bport = *(xpat+state) ; }
/* impress */
PORTB = bport | (PORTB & 0x20) ;
PORTC = bport ;
/* update */
state++ ;
state &= 0x03 ;
}
タイマー割込み発生を、イベント通知フラグeflagで扱い
実際にロータリーエンコーダの擬似信号を出力するかは
制御フラグtflagで指定します。
制御フラグのセット、クリアは、コマンドインタプリタで
扱えるようにします。
コマンドインタプリタは、1文字をコマンドとして
次の機能を与えます。
- ? ヘルプ
- G パターン出力開始(制御フラグをセット)
- g パターン出力停止(制御フラグをクリア)
- p 格納しているパターン表示
機能を定義したので、loopには、コマンドインタプリタの
コードを追加。
if ( uflag == ON ) {
/* clear flag */
uflag = OFF ;
/* new line */
crlf() ;
/* get command */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help(); }
/* enable */
if ( cmd == 'G' ) {
state = 0 ;
tflag = ON ;
}
/* disable */
if ( cmd == 'g' ) { tflag = OFF; }
/* show pattern */
if ( cmd == 'p' ) {
for ( i = 0 ; i < 4 ; i++ ) {
show_byte( *(xpat+i) );
crlf();
}
}
コマンドインタプリタは、受信割込みで扱えるように
するため、受信バッファにコマンドが格納されたこと
を、フラグuflagで通知しておきます。
コマンドインタプリタ内で利用する、通信関連の関数を
定義しておくと、以下。
void show_help()
{
rs_puts("? help") ; crlf();
rs_puts("G enable") ; crlf();
rs_puts("g disable") ; crlf();
rs_puts("p show pattern") ; crlf();
}
void rs_putchar(char x)
{
Serial.write(x);
}
void rs_puts(char *ptr)
{
while ( *ptr ) {
rs_putchar( *ptr );
ptr++;
}
}
void crlf()
{
rs_putchar('\r');
rs_putchar('\n');
}
void show_byte(char x)
{
char xtmp[5] ;
/* delimiter */
*(xtmp+4) = '\0' ;
/* separate */
*(xtmp+3) = (x & 1) + '0' ; x >>= 1 ;
*(xtmp+2) = (x & 1) + '0' ; x >>= 1 ;
*(xtmp+1) = (x & 1) + '0' ; x >>= 1 ;
*(xtmp+0) = (x & 1) + '0' ;
/* show */
rs_puts( xtmp );
}
コマンドインタプリタと信号出力の仕様を決めたので
setupでコンフィグレートしていきます。
void setup()
{
/* initialize serial */
Serial.begin(9600);
sindex = 0 ;
rs_puts("Hello !");
crlf();
/* clear flags */
tflag = OFF ;
eflag = OFF ;
uflag = OFF ;
/* initialize port values */
PORTB = 0x00 ;
PORTC = 0x00 ;
PORTD = 0x00 ;
/* initialize port direction */
DDRB = 0xff ;
DDRC = 0xff ;
DDRD = 0xfe ;
/* variables */
state = 0 ;
*(xpat+0) = 15 ;
*(xpat+1) = 9 ;
*(xpat+2) = 0 ;
*(xpat+3) = 6 ;
xcnt = 0 ;
/* 5ms period */
MsTimer2::set(XINTERVAL,update_trigger);
/* enable */
MsTimer2::start();
}
ロータリーエンコーダの信号は、配列xpatに格納し
変数stateの値で、どの格納値を利用するのか指定
できるように考えました。
変数xcntは、ポートBの5ビット目に接続されている
LEDの点滅を制御する目的で利用。
時間間隔は、タイマー2を利用して生成。
タイマー2に関係する処理は、ライブラリ
を使って処理します。
タイマー2の割込みで呼び出される関数の内容は、以下。
void update_trigger()
{
/* set flag */
eflag = ON ;
/* LED handling */
PORTB &= ~(1 << 5) ;
if ( xcnt & ON ) { PORTB = (1 << 5); }
/* increment timer counter */
xcnt++ ;
}
タイマー割込み発生のイベント通知フラグを
セットするのと、ポートBの5ビットに接続
しているLEDの点滅を担当させています。
スケッチとして、まとめると以下。
/*
rtst.ino
Pin assignment
PORTB
PB5 (output) LED
PB4 (output) --
PB3 (output) B phase
PB2 (output) A phase
PB1 (output) B phase
PB0 (output) A phase
PORTC
PB5 (output) --
PB4 (output) --
PB3 (output) B phase
PB2 (output) A phase
PB1 (output) B phase
PB0 (output) A phase
PORTD
PD7 (output)
PD6 (output)
PD5 (output)
PD4 (output)
PD3 (output)
PD2 (output)
PD1 (output)TxD
PD0 (input) RxD
*/
#include <MsTimer2.h>
#define OFF 0
#define ON OFF+1
#define XINTERVAL 50
/* function prototype */
void update_trigger();
void show_help();
void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
void show_byte(char x);
/* variables */
boolean tflag ;
boolean eflag ;
boolean uflag ;
byte xpat[4] ;
byte state ;
byte sbuf[8] ;
byte sindex ;
byte cmd ;
byte i ;
byte bport ;
byte xcnt ;
void setup()
{
/* initialize serial */
Serial.begin(9600);
sindex = 0 ;
rs_puts("Hello !");
crlf();
/* clear flags */
tflag = OFF ;
eflag = OFF ;
uflag = OFF ;
/* initialize port values */
PORTB = 0x00 ;
PORTC = 0x00 ;
PORTD = 0x00 ;
/* initialize port direction */
DDRB = 0xff ;
DDRC = 0xff ;
DDRD = 0xfe ;
/* variables */
state = 0 ;
*(xpat+0) = 15 ;
*(xpat+1) = 9 ;
*(xpat+2) = 0 ;
*(xpat+3) = 6 ;
xcnt = 0 ;
/* 5ms period */
MsTimer2::set(XINTERVAL,update_trigger);
/* enable */
MsTimer2::start();
}
void loop()
{
/* command interpreter */
if ( uflag == ON ) {
/* clear flag */
uflag = OFF ;
/* new line */
crlf() ;
/* get command */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help(); }
/* enable */
if ( cmd == 'G' ) {
state = 0 ;
tflag = ON ;
}
/* disable */
if ( cmd == 'g' ) { tflag = OFF; }
/* show pattern */
if ( cmd == 'p' ) {
for ( i = 0 ; i < 4 ; i++ ) {
show_byte( *(xpat+i) );
crlf();
}
}
}
/* handling */
if ( eflag == ON ) {
/* clear flag */
eflag = OFF ;
/* blank */
bport = 0x00 ;
/* display */
if ( tflag == ON ) { bport = *(xpat+state) ; }
/* impress */
PORTB = bport | (PORTB & 0x20) ;
PORTC = bport ;
/* update */
state++ ;
state &= 0x03 ;
}
}
void update_trigger()
{
/* set flag */
eflag = ON ;
/* LED handling */
PORTB &= ~(1 << 5) ;
if ( xcnt & ON ) { PORTB = (1 << 5); }
/* increment timer counter */
xcnt++ ;
}
void show_help()
{
rs_puts("? help") ; crlf();
rs_puts("G enable") ; crlf();
rs_puts("g disable") ; crlf();
rs_puts("p show pattern") ; crlf();
}
void rs_putchar(char x)
{
Serial.write(x);
}
void rs_puts(char *ptr)
{
while ( *ptr ) {
rs_putchar( *ptr );
ptr++;
}
}
void crlf()
{
rs_putchar('\r');
rs_putchar('\n');
}
void show_byte(char x)
{
char xtmp[5] ;
/* delimiter */
*(xtmp+4) = '\0' ;
/* separate */
*(xtmp+3) = (x & 1) + '0' ; x >>= 1 ;
*(xtmp+2) = (x & 1) + '0' ; x >>= 1 ;
*(xtmp+1) = (x & 1) + '0' ; x >>= 1 ;
*(xtmp+0) = (x & 1) + '0' ;
/* show */
rs_puts( xtmp );
}
/* receive interrupt */
void serialEvent()
{
char ch;
if ( Serial.available() > 0 ) {
/* get 1 character */
ch = Serial.read();
/* store */
*(sbuf+sindex) = ch ;
/* increment */
sindex++ ;
/* judge */
if ( ch == '\r' ) {
sindex = 0 ;
uflag = ON ;
}
}
}
次のようにロータリーエンコーダドライブ回路に接続。
ボートB、Cの下位4ビットには、同じ値を出力して
いるので、LED表示基板を接続すると、Arduinoが転送
している信号の論理値を格納できます。
端末ソフトで、Arduinoに接続すると、以下の表示になります。
コマンドG、gを利用して、ロータリーエンコーダドライブ
基板の7セグメントLEDの表示が、変化することを確認。
出力パターンが正しいのかを、コマンドpで確かめられます。
このスケッチで、基板の半田付け不良と部品位置の間違いを
発見できました。
目次
前
次