MPLABX XC8環境においてPIC16F88で、ロータリーエンコーダを使うプログラムのテストその2です。
今回は、PIC16F88のピン状態変化割り込みを利用してロータリーエンコーダの回転方向を判定するプログラムを考えてみます。
まず、PIC16F88でピン状態変化割り込みを利用できるのは、RB4~RB7で、このうち1つでもピンの状態が変化すれば、RBIFが1になります。
そこで、RB6とRB7を使うことにし、次のようにロータリーエンコーダを配線します。結果はシリアル通信でTeraTermで表示することにします。nRBPU = 0;として、PORTBはプルアップしておきます。
ロータリーエンコーダの1つの変化に対して2~3回の割り込みが発生しています。チャタリングによるものと思われます。チャタリング対策が必要です。
次に、回転方向を判別する方法です。今回は、ロータリーエンコーダを購入したときについてくる秋月電子の説明書にある方法でやってみます。
BAの値の前の値を左に1ビットシフトし、現在のBAの値と排他的OR(XOR)をとり、下位2ビットだけを見ると
時計回りの時は、0か1の値(すなわち<2)をとり、反時計回りの時は2か3の値(すなわち>=2)をとります。
これを利用して、回転方向を判定することができます。
プログラムです。シリアル通信の部分は省略します。前の記事を参照してください。
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include "serial.h"
#include <stdio.h>
#include <stdlib.h>
#include "serial.h"
// CONFIG1
#pragma config FOSC = INTOSCIO //内臓発振器を使う
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config MCLRE = OFF
#pragma config BOREN = OFF
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CCPMX = RB0
#pragma config CP = OFF
#pragma config FOSC = INTOSCIO //内臓発振器を使う
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config MCLRE = OFF
#pragma config BOREN = OFF
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CCPMX = RB0
#pragma config CP = OFF
// CONFIG2
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#define ECA RB6 //エンコーダB
#define ECB RB7 //エンコーダA
#define _XTAL_FREQ 8000000
#define ECB RB7 //エンコーダA
#define _XTAL_FREQ 8000000
unsigned char curDat = 0;
unsigned char befDat = 0;
unsigned char EA;
unsigned char EB;
signed char count= 0;
unsigned char befDat = 0;
unsigned char EA;
unsigned char EB;
signed char count= 0;
void interrupt isr(){
RBIE = 0; //RB割り込み禁止
RBIF = 0; //RB割り込みフラッグクリア
__delay_ms(2);
EA = ECA;
EB = ECB;
curDat = EA + (EB<<1);
if (befDat != curDat){
unsigned char d = ((befDat<<1)^curDat) & 3; //回転方向判定
if(d < 2){
count++;
}else{
count--;
}
befDat = curDat;
}
if(count >= 4){
printf("RIGHT\r\n");
count = 0;
}else if(count <= -4){
printf("LEFT\r\n");
count = 0;
}
RBIE = 1; //RB割り込み許可
}
RBIE = 0; //RB割り込み禁止
RBIF = 0; //RB割り込みフラッグクリア
__delay_ms(2);
EA = ECA;
EB = ECB;
curDat = EA + (EB<<1);
if (befDat != curDat){
unsigned char d = ((befDat<<1)^curDat) & 3; //回転方向判定
if(d < 2){
count++;
}else{
count--;
}
befDat = curDat;
}
if(count >= 4){
printf("RIGHT\r\n");
count = 0;
}else if(count <= -4){
printf("LEFT\r\n");
count = 0;
}
RBIE = 1; //RB割り込み許可
}
void main() {
ANSEL = 0x00; //アナログポートを使わない
OSCCON = 0b01110000;//内部クロック8MHz
TRISA = 0b00100000; //RA5はinput 他はoutput
TRISB = 0b11000100; //RB3.RB6,RB7はinput 他はoutput
PORTA = 0x00; //PORTA初期化
PORTB = 0x00; //PORTB初期化
OPTION_REGbits.nRBPU = 0;//PORTB Pull up
serial_init(); //AUSART設定
EA = ECA;
EB = ECB;
befDat = EA + (EB<<1);
RBIE = 1; //RBピン割り込み許可
GIE = 1; //全割り込み許可
while(1){ //無限ループ
}
}
時計回りに回転すると「RIGHT」と反時計回りに回転すると「LEFT」とTeraTermで表示されます。