PIC16F1705でロータリーエンコーダを利用するためのテストをします。
ロータリーエンコーダの回転方向反転には、いくつか方法がありますが、今回は、IOC(ピン状態変化割り込み)を使う方法です。
回転方向の判定方法を簡単に説明します。
ロータリーエンコーダを回転させるとロータリーエンコーダのA,B端子の電圧は下の図のように変化します。(A,B端子ともプルアップされています。)
AとBの値の変化は、回転方向により異なります。BAの値の前の値を左に1ビットシフトし、今の値との排他的ORをとると、下位2ビットの値が時計回りなら00か01になり、反時計回りなら10か11になります。このことを利用して、回転方向を判定することができます。
回路図です。
ロータリーエンコーダは、RC4とRC5に接続しました。この2つのピンは、PIC側でウィークプルアップしておきます。
(PIV16F1705では、すべてのI/Oピンがプルアップ可能です。)
回転方向判定結果(RIGHT,LEFT)は、シリアル変換モジュールFT234Xを通してパソコンのTeraTermに表示させます。
(PPSを使ってRA0にTXをRA1にRXを割り当てました)
ブレッドボードです。
判定結果(TeraTermの画面)です。
プログラムです。
通信速度は、9600bpsです。クロックは、内臓クロック8MHz×4=32MHzです。
--------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <stdlib.h>
#include <xc.h>
// CONFIG1
#pragma config FOSC = INTOSC //内部クロックを使う
#pragma config WDTE = OFF //ウォッチドックタイマー無効
#pragma config PWRTE = ON //パワーアップタイマーを有効にする
#pragma config MCLRE = OFF //MCLRピンをRA3として使用する
#pragma config CP = OFF //プログラムメモリを保護しない
#pragma config BOREN = ON //ブラウンアウトリセットを有効にする
#pragma config CLKOUTEN = OFF //クロック出力を無効とし、RA4ピンとして使用する
#pragma config IESO = OFF //内部・外部クロックの切り替えでの起動を行わない
#pragma config FCMEN = OFF //外部クロックを監視しない
#pragma config FOSC = INTOSC //内部クロックを使う
#pragma config WDTE = OFF //ウォッチドックタイマー無効
#pragma config PWRTE = ON //パワーアップタイマーを有効にする
#pragma config MCLRE = OFF //MCLRピンをRA3として使用する
#pragma config CP = OFF //プログラムメモリを保護しない
#pragma config BOREN = ON //ブラウンアウトリセットを有効にする
#pragma config CLKOUTEN = OFF //クロック出力を無効とし、RA4ピンとして使用する
#pragma config IESO = OFF //内部・外部クロックの切り替えでの起動を行わない
#pragma config FCMEN = OFF //外部クロックを監視しない
// CONFIG2
#pragma config WRT = OFF //フラッシュメモリを保護しない
#pragma config PPS1WAY = OFF //ロック解除シーケンスで何度でもPPSLOCKをセット/クリアできる
#pragma config ZCDDIS = ON //ゼロクロス検出回路無効
#pragma config PLLEN = ON //×4PLLを動作させる
#pragma config STVREN = ON //スタックオーバーフローリセットを行う
#pragma config BORV = HI //ブラウンアウトリセット電圧を高(2.7V)に設定
#pragma config LPBOR = OFF //低消費電力ブラウンアウトリセット無効
#pragma config LVP = OFF //低電圧プログラミングを行わない
#pragma config WRT = OFF //フラッシュメモリを保護しない
#pragma config PPS1WAY = OFF //ロック解除シーケンスで何度でもPPSLOCKをセット/クリアできる
#pragma config ZCDDIS = ON //ゼロクロス検出回路無効
#pragma config PLLEN = ON //×4PLLを動作させる
#pragma config STVREN = ON //スタックオーバーフローリセットを行う
#pragma config BORV = HI //ブラウンアウトリセット電圧を高(2.7V)に設定
#pragma config LPBOR = OFF //低消費電力ブラウンアウトリセット無効
#pragma config LVP = OFF //低電圧プログラミングを行わない
#define _XTAL_FREQ 32000000 //クロック32MHz
/* ロータリーエンコーダ関係定義*/
#define ECA RC5 //エンコーダA
#define ECB RC4 //エンコーダB
unsigned char EA;
unsigned char EB;
volatile unsigned char curDat;
volatile unsigned char befDat;
volatile signed char count= 0;
#define ECA RC5 //エンコーダA
#define ECB RC4 //エンコーダB
unsigned char EA;
unsigned char EB;
volatile unsigned char curDat;
volatile unsigned char befDat;
volatile signed char count= 0;
void serial_init(unsigned long BR){
TX1STA = 0x24; //SYNC=0 TXEN = 1 BRGH = 1
BRG16 = 1; //BRG 16bit mode
RC1STA = 0x90; //非同期、継続受信可
unsigned int X= _XTAL_FREQ/BR/4 - 1;
SP1BRGH = X / 256;
SP1BRGL = X % 256;
}
TX1STA = 0x24; //SYNC=0 TXEN = 1 BRGH = 1
BRG16 = 1; //BRG 16bit mode
RC1STA = 0x90; //非同期、継続受信可
unsigned int X= _XTAL_FREQ/BR/4 - 1;
SP1BRGH = X / 256;
SP1BRGL = X % 256;
}
void putch(unsigned char byte){
while(!TXIF);
TX1REG = byte;
}
while(!TXIF);
TX1REG = byte;
}
void interrupt isr(){
IOCIF = 0; //割り込みフラッグクリア
IOCCF4 = 0;
IOCCF5 = 0;
__delay_ms(2);
curDat = ECA + (ECB<<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;
}
}
IOCIF = 0; //割り込みフラッグクリア
IOCCF4 = 0;
IOCCF5 = 0;
__delay_ms(2);
curDat = ECA + (ECB<<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;
}
}
void main() {
OSCCON = 0b01110000 ; // 内部クロック8MHz ×4=32MHz
ANSELA = 0b00000000 ; // AN0-AN3を使わない
ANSELC = 0b00000000 ; // AN4-AN6を使わない
TRISA = 0b00000010 ; // RA1は入力他は出力
TRISC = 0b00110000 ; // RC4,RC5は入力、他は出力
PORTA = 0b00000000 ; // PORTAクリア
PORTC = 0b00000000 ; // PORTCクリア
/* TX RXピンの割り当て*/
RA0PPS = 0x14; //RA0にTXを割り当てる。
RXPPS = 0x01; //RXをRA1に割り当てる。
OPTION_REGbits.nWPUEN=0; // ウィークプルアップ許可
WPUC = 0b00110000; // RC4,RC5をプルアップ
/* IOC割り込み設定 */
IOCCN = 0b00110000; //RC4,RC5立下り割り込み設定
IOCCP = 0b00110000; //RC4,RC5立ち上がり割り込み設定
IOCIE = 1; //IOC割り込み許可
PEIE = 1; //周辺割り込み許可
GIE = 1; //全割り込み許可
serial_init(9600); // Serial通信初期化とBaud Rateの設定
/* Roatry Encoder 初期値 */
befDat = ECA + (ECB<<1);
while(1){
}
}
OSCCON = 0b01110000 ; // 内部クロック8MHz ×4=32MHz
ANSELA = 0b00000000 ; // AN0-AN3を使わない
ANSELC = 0b00000000 ; // AN4-AN6を使わない
TRISA = 0b00000010 ; // RA1は入力他は出力
TRISC = 0b00110000 ; // RC4,RC5は入力、他は出力
PORTA = 0b00000000 ; // PORTAクリア
PORTC = 0b00000000 ; // PORTCクリア
/* TX RXピンの割り当て*/
RA0PPS = 0x14; //RA0にTXを割り当てる。
RXPPS = 0x01; //RXをRA1に割り当てる。
OPTION_REGbits.nWPUEN=0; // ウィークプルアップ許可
WPUC = 0b00110000; // RC4,RC5をプルアップ
/* IOC割り込み設定 */
IOCCN = 0b00110000; //RC4,RC5立下り割り込み設定
IOCCP = 0b00110000; //RC4,RC5立ち上がり割り込み設定
IOCIE = 1; //IOC割り込み許可
PEIE = 1; //周辺割り込み許可
GIE = 1; //全割り込み許可
serial_init(9600); // Serial通信初期化とBaud Rateの設定
/* Roatry Encoder 初期値 */
befDat = ECA + (ECB<<1);
while(1){
}
}
※コメント投稿者のブログIDはブログ作成者のみに通知されます