« ロータリーエンコーダーの2相パルス、クリック有りの場合は | トップページ | 『アトミック操作』・・・8bitマイコンに限り何か別の言い方なかったか? »

2020年9月19日 (土)

クリック有りのロータリーエンコーダーで

2020年9月17日:ロータリーエンコーダーの2相パルス、クリック有りの場合は
を具体化。
Arduino-UNOを使ってこんな回路に。

Cc1_20200918181201
3桁の7seg LEDに設定角度(0~359度)を表示します。
実験中のバラック↓

Cc2_20200918181201
エンコーダは「読み取れるかどうかの実験のため」に
2回路付けてますが、設定値の表示は1系統だけ。
これをベースに電池駆動にしたジグを製作する予定です。

Arduino-UNO、クロックが16MHz。
PWMの周波数は1kHzが目標なんですが、PWMを450分割しな
ければなりません。
Duty 10%~90%を0度~360度にということで、こんな分割比
になります。→「45 + 360 + 45」
1kHzに近いところで16MHz÷450÷35で1015.9Hzになっています。
本チャンではクロック発振子を「7.2MHz」にして、
7.2MHz÷450÷16で1000.0Hzというふうにします。


なぜ「1kHz・10%~90%」のPWMかは、旭化成のAK7401のデータシートを
参照のこと。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2020年9月12日:ロータリーエンコーダーの2相パルスをピン変化割り込みで取り込む
で示した、メーカー推奨のチャタリング吸収回路・・・
  ※10kΩ抵抗に0.01uFコンデンサのCRローパスフィルタ。

B1_20200912144901
これだと、エンコーダのon/off波形が鈍ってしまって、ATmega328Pの
入力シュミット回路でミスが発生する(ことがある)のです。
ATmega32P、それぞれのデジタル入力にはシュミットゲートが入ってい
るのですが、シュミットのヒステリシス幅が小さいので、「鈍った波形」を
うまく処置(HかLかの決め打ち)ができない(ことがある)のです。

入力信号がなだらかに増減すると、スレッショルド電圧付近で
不安定に・・・
入力して出力するだけのテストプログラムを走らせると、
「振動波形」が現れる(ことがある)のです。

キレイな信号が入ることを前提としたエッジ検出入力回路、
これがスカタンすると、ちょいと問題。

ですんで、とりあえずは「内蔵プルアップ抵抗+外付け1000PF」
が「まだマシでした」ということで、試作したのです。
  ※内蔵プルアップ抵抗が20~50KΩ。
   直列抵抗無しでそのままGND間にコンデンサ。
コンデンサが無いと・・・そりゃひどいものです。
ソフトでどうにかしろ・・・ご勘弁を・・・・

ゲートICが増えることを許容して、HC14やHC132、4584、4093
などのちゃんとしたシュミット入力ゲートICを設けるべきでしょうね。
  ※仕事の設計だと「ケチらない!」。

エッジ検出による割り込み駆動だと、チャタリング吸収がちょいと
やりにくい。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

※スケッチはこちら → ダウンロード - test_enc3.c
  (ファイルタイプを「C」にしています)

特徴的なところを。

/*****  エンコーダカウントアップダウン     *****/
// 359度以上なら0に,0度未満なら359度に
// カウンタのポインターと加算値
// 加算値は±で
void cntupdn(volatile word *p, short a)
{
short d;
d = *p; // 現在値
d += a; // ±加算
if(a >= 0){ // count upの時
if(d > ENC_TOP) d -= (ENC_TOP + 1); // 0~359
}
else{ // count downの時
if(d < 0) d += (ENC_TOP + 1); // 0~359
}
*p = d;
}
/************************************/
/* 2相パルスA相↓エッジ割り込み */
/************************************/
// D13ポート 割り込みでH/Lパルス
// D12ポート カウントup/down処理でH/Lパルス
/***** INT0割り込み *****/
// ch1 A相↓エッジ, B相がHなら+1 Lなら-1
ISR(INT0_vect)
{
short d;
D13_H; // (!!!) LED on
if((tm_enc1 >= 5) && // 前のパルスから5ms経過で新↓エッジ
(INP_1A == 0)){ // A相がHならミストリガ
D12_H; // (!!!)
if(tm_enc1 >= 40) d = 1; // 40ms経過してたら+1
else d = 2; // 以内に操作したら+2
if(INP_1B) cntupdn(&enc_cnt1, d); // up
else cntupdn(&enc_cnt1, -d); // down
f_cnt = 1; // カウント値更新
tm_enc1 = 0; // タイマー1クリアー
D12_L; // (!!!)
}
D13_L; // (!!!) LED off
}

割り込み処理の確認のため、
・D13(LEDポート)に割り込み応答パルスを出力。
・D12に、カウントアップダウンが成功したらパルスを出力。

誤パルス除去のため、
・前パルスより5ms内の新パルスは無視。
・A相立ち下がりエッジの確認。
  割込直後のA相がHなら無視。

回転をちょっとスピードアップするため、40ms内のカウントアップ
ダウンを「±2」に。
ラジオペンチさんところ の、「50ms内は10倍速」という処理を
真似たのですが、でも10倍速は早すぎました!

試しに使った「クリック有り」のロータリーエンコーダー
(BOURNSE社製)の回転、素早く回すと1クリック
数ミリ秒で回せます。

こんな感じ。
A000_20200919102201

△(1)」のところで、立ち下がりではなく立ち上がりで
割り込みが入ったことが見えています。
△(2)」ではラインが太く見えているので、割り込みが続け
さまに2発入ったようです。
  ※ATmega328Pのシュミット入力のヒステリシスが
   もうちょい大きければ避けられたかも。

このくらいのミスパルスなら、先ほどの「誤パルス除去」
が防いでくれて、「◎」のカウントだけが有効になっています。

シュミット入力のミス、もうちょい時間を広げると
こんな感じです。
右端の「△」部がミストリガー。
チャタリング除去用のコンデンサで立ち上がりが波形が
鈍っているせいかと。

A001_20200919102901
「誤パルス除去」処理で、「◎」の1発カウントだけになって
いて、なんとか正しくカウントが進みました。



3桁7seg LEDのダイナミック表示はタイマー2割り込み
を使ってます。
コンペアマッチAで1ms(1kHz)周期を作ります。
その割り込みでLEDをブランクに。

そして、20us後に起動するコンペアマッチB割り込みで、
LEDのセグメントとコモンラインを駆動して点灯します。
この中で1msのタイマーをカウント。

3バイトの「led_bff[]」に書いたLEDのセグメント点灯情報を
割り込みが勝手に表示するという仕掛け。

ライブラリは使わず、ATmega328Pのレジスターを直接操作。
処理の遅いdigitalWritedigitalReadも使いません。

/*******************************/
/* タイマー2割り込み */
/*******************************/
// 1kHz(1mS)で割り込み
// コンペアAでLEDブランクに
// 20us後のコンペアBでLED点灯
/***** タイマー2コンペアマッチA割込み *****/
// LED出力ブランクに
ISR(TIMER2_COMPA_vect)
{
PORTC |= 0b00111111; // セグメントをオフ(Hでoff)
// ++++++---- seg F~A
PORTB |= 0b00001000;
// +------- seg G
PORTD |= 0b01110000; // COM駆動オフ(Hでoff)
// +++-------- COM3,2,1
}
/***** タイマー2コンペアマッチB割込み *****/
// ブランク後20usに起動
// LED出力オンとタイマー処理
ISR(TIMER2_COMPB_vect)
{
byte d;
d = ~led_bff[led_ptr]; // Lアクティブ
PORTC &= (d | 0b11000000); // bit6~0:seg F~A
d >>= 3; // 3bit右に
PORTB &= (d | 0b11110111); // seg G
d = led_com[led_ptr]; // COM1~COM3
PORTD &= d; // Lでオン
// 次桁
led_ptr++; // 次ポインター
if(led_ptr >= DIMSIZ(led_bff)) led_ptr = 0;
// タイマー処理
if(tm_enc1 != 255) tm_enc1++; // タイマー1 +1
if(tm_enc2 != 255) tm_enc2++; // タイマー2 +1
}


3桁数字の表示ルーチンはこれだけ。
下位桁からセグメント情報に変換し、上位はゼロサプレス処理
しています。

/*******************************/
/* LED表示 */
/*******************************/
/***** LED 3桁変換表示 *****/
void led3disp(word d)
{
byte i;
for(i = 0; i < 3; i++){ // 3桁 LSBから
if((i != 0) && (d == 0)) // ゼロサプレス
led_bff[i] = 0b00000000; // ブランク
else
led_bff[i] = led_seg[d % 10]; // 0~9
d /= 10; // 1/10
}
}

3バイトのled_bff[]に表示データ(LEDのセグメントデータ)を一度
書き込めば、あとは勝手にタイマー2割り込みが表示処理を実行し
てくれます。
毎回表示ルーチンを呼ばなくても、メモリーの内容に従い割り込みが
勝手に表示してくれるのです。

 ※「delay()」を使って表示タイミングを作っているような
  スケッチは実用的ではありません。
  しかし、「arduino 7seg LED ダイナミックスキャン」を検索
  しても、なかなかタイマー割り込みによる表示実行例に行き着
  きません。
  もう一つ。
  このようなスピード優先、マイコンチップの機能を直接操作する
  ようなプログラムでは、汎用的関数digitalWriteなんかを使わな
  くってもイイじゃないですか。
  速度優先で「素」のチップを制御するということで、ポートの
  直接操作、これでエエでしょう。
 

タイマーと割り込み関連の初期設定もそんなにややこしいこ
とはありません。
ATmega328Pのマニュアルをよく読めば、へんにライブラリーを
探すより早いかと。
マイコンが持つ機能、これを「素」で使います。

//  タイマー1 PWM出力 (A:PB1,B:PB2)
// エンコーダ値 0~359度でPWM 10%~90%を出力
// 16MHz/35/450 = 1015.9kHz
// ICR1AのTOP値は450*35 - 1
// 16MHz / 450
TCCR1A = 0b11110010;
// |||| ++---- PWM 高速PWM ICR1 モード
// ||++-------- PWM B (Negモード)
// ++---------- PWM A (Negモード)
TCCR1B = 0b00011001;
// || ||+++---- クロックセレクト 16MHz / 1 16MHz
// || ++------- PWM ICR1 モード
// |+---------- ICES1
// +----------- ICNC1
ICR1 = PWMTOP; // 0~449で0%~99.78%
OCR1A = OCR1B = 0xFFFF; // PWM off
// タイマー2
TCCR2A = 0b00000010; // モード設定
// |||| ++--- WGM: CTCモード
// ||++------- COM0B
// ++--------- COM0A
TCCR2B = 0b00000100;
// |+++--- CS:1/64 : 250kHz 4uS
// +------ WGM02
OCR2A = 250 - 1; // 1kHz(1mS)
OCR2B = 5 - 1; // 20uS
TIMSK2 = 0b00000110;
// |+----- OCIE2A コンペアマッチA割り込み有効
// +------ OCIE2B コンペアマッチB割り込み有効
// INT0,INT1 ↓エッジ割り込みに
EICRA = 0b00001010; // 割り込み入力エッジ
// ||++---- ISC0 INT0 ↓
// ++------ ISC1 INT1 ↓
EIMSK = 0b00000011; //外部割り込み有効
// |+---- INT0
// +----- INT1

 

|

« ロータリーエンコーダーの2相パルス、クリック有りの場合は | トップページ | 『アトミック操作』・・・8bitマイコンに限り何か別の言い方なかったか? »

Arduino」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




« ロータリーエンコーダーの2相パルス、クリック有りの場合は | トップページ | 『アトミック操作』・・・8bitマイコンに限り何か別の言い方なかったか? »