« 2020年8月 | トップページ | 2020年10月 »

2020年9月

2020年9月26日 (土)

手組みするときは片面基板で:1kHz PWM発生回路

ユニバーサル基板を使って回路を手組みするときは
もっぱら片面基板。
手組みでの両面スルーホール基板はキライです。

  ジュンフロン線で配線するんですが、しっかり
  ハンダゴテを当てないとちゃんとハンダが
  乗りません。
  スルーホール基板だと、しっかりハンダした
  ハンダが穴の反対側(裏側)に盛り上がっちゃう
  ことがあるんです。 これがイヤ。

しかし、今回の製作物のように「ハンダ面側にも部品を」
という場合(7seg LEDを裏側に乗せる)は、そんなことも
言ってられません。

そんなときに重宝するのが、サンハヤトのハサミで切れる
薄いシート基板。
薄型ユニバーサル基板 UB-THN01
   シール基板よりしっかりしています。

これを部品面側に貼り付け(クズ線とハンダで固定)、ハンダ面に
取り付けた部品の足を、部品面側でハンダします。
スルーホール基板のように、反対側のハンダが盛り上がること
はありません。
今回の配線だとこんな感じ。

C11_20200926100901

C12_20200926100901

ユニバーサル基板の配線、「最短配線を考えて」とか
「できるだけ小さく」なんてことは後回し。
   ・作るのはこれ1台だけだし
配線の引き回しは部品面。
ハンダ面は電源まわりの接続と直近の信号線接続。
配線がハンダ面でウジャウジャしてると手直しでき
ないから。

※最終的な配線の様子。 あとはケース入れ。
部品面
C22_20200926175501
※写真で気がついた! コイル「100=10uH」はミス。
 ほんとは「101=100uH」が正解だぁ。

ハンダ面。 7seg LEDが見える
C21_20200926175501


こんな回路です。
電源は単3電池2本。
それをホルテックのDCコンICで5Vに昇圧。
   ※そこのコイルを間違っていた次第
P11_20200927172201

制御プログラム・・・ダウンロード - 1khz_360.c
  ※Arduinoでは動きません。

いっぱい割り込みを使ってます。
タイマー0:7seg LED表示に
     コンペアAでブランクに
     コンペアBで表示データを出力
タイマー1:1kHzPWM出力ついでに
     1msタイマー割り込み
タイマー2:チャタリング除去用タイミングに
     オーバーフロー割り込み
INT0とINT1:A相/B相↑↓パルスエッジ割り込み。


※エンコーダーの回転制御をちょいと手直し
クリックの無いグルグル回しのエンコーダー、24P/Rを
4逓倍してるんで96P/R。
これだとちょいと回り過ぎに(手で操作しにくい)。
そこで、最大カウント(+1)を360じゃなく4倍の1440に。
この値を1/4して0~359度を得るという処理にしました。
これで実質的に24度/回転。
そこに、急速回転だと4倍速という処理を入れてます。
しかし、「・358・359・0・1・2・」という、0度を中心
とした合わせ込み操作の時、このスピードアップ処理が
働くと回り過ぎることがあってちょいと使いにくい。
0度±10度ではスピードアップしないような処理にしました。
     ダウンロード - 1khz_360a.c


※箱入れして完成
B32_20200929090101

使ったのは、タカチのプラケース SW-100S
電池ボックス(単3x2)はフタに両面テープで貼り付け。

そして、これ↓で発生デューティーをチェック。
2020年8月24日:Arduino PWM波形のデューティー比測定 これで完成形か?
  発振素子がセラロックなんで、周波数は
  0.6Hzほど高い目になってました。

出力信号はJSTのXHコネクタ で出しています。

便利小物のお話し
2.5mmや2.54mmピッチコネクタの仮接続用に
こんなソケットアダプタを作っておくと便利です。
ジャンパー線でArduinoやブレードボードと手軽に
接続できます。

B33

メスソケットを対向させてハンダ。

B34

信号をつまむこともできるし、ジャンパーピンで引き出すことも
可能。
  ※ツールボックスに入れたこれを探し出す方が
   早いか、新たに作る方が早いか・・・
   「前に作ったし、どっかに有るはずやけどなぁ」
   っと悩んでいる間に作れます。


※さらに制御プログラムを変更
1分間操作しなかったら、その時のエンコーダカウント値を
EEPROMに保存。
次回起動時、その角度からスタートできるようにしました。
  ちょっと便利に。
ダウンロード - 1khz_360b.c

 

| | コメント (0)

2020年9月25日 (金)

クリック無しロータリーエンコーダー

Bournsクリック無しロータリーエンコーダ(PEC16-4020F-N0024)
が入ってきましたんでどんなものかを確かめてみました。

こんな形状。
A1_20200925111001

Arduino-UNOのATmega328PのINT0とINT1につなぐんですが、
ATmega328P入力ポートのヒステリシス幅がちょいと小さいんで、
C-MOSのシュミット入力ゲート「4584」を間に入れてみました。

A2_20200925111101
チャタリング除去の時定数は、
2020年9月12日:ロータリーエンコーダーの2相パルスをピン変化割り込みで取り込む
のプルアップ抵抗10kΩにCRフィルタが10k+0.01uF

この時の様子をオシロで観察。
A相/B相波形は「クリック有り」の時のような偏りはありません。
平均して2相パルスの列が続きます。

さて、出てくるチャタリングはこんな具合です。

まず、平和な時。 キレイなエッジが見えます。

B000_20200925111901
CH4の波形はINT1割り込み受付で出しているパルス。
  ※4584をスキップすると、INT1パルスが
   バラバラと出ます。
   ATmega328pのヒステリシスがもうちょい
   大きければば良かったのに・・・

ちょいと大きなチャタリング。
B001_20200925112101

このくらい↑なら除去してくれるんですが、
こうなると↓、10k+0.01uFでのフィルタでは除けません。

B002
4584を入れても、INT1割り込みをミスしている様子が見えます。
   ※割り込みは正しく働いてますよ。

このエンコーダのスペックには、
   Contact Bounce (15 RPM) ・・・ 5.0ms. max
と記してあるんで、このくらいのチャタリングは出てもあた
りまえと考えておかなくちゃなりません。

そこで、CRフィルタのコンデンサを10倍の0.1uFにしてみました。
時定数は10倍の約1mSに。

その結果。

B004_20200925112201
もうひとつ
B005

まぁこんなもんでしょう。
INT0とINT1でのエッジ検出後に、ソフト的にもう1~2ms
遅らせてからA相とB相のH/Lを確認することにします。

これで完成形にもって行きます。
ただし、クロック周波数を変えるんでArduinoからは離れます。
  どのみち、Arduino独自の関数ってシリアル出力だけしか
  使ってないし。

| | コメント (0)

2020年9月21日 (月)

『アトミック操作』・・・8bitマイコンに限り何か別の言い方なかったか?

2019年3月25日:割り込みで処理させるwordデータの扱い
に書きましたが、Arduino-UNOで使われているAtmega-328Pは
8ビットマイコンです。
ですんで、割り込みで処理される2バイト以上のデータをメイン側で
読み書きする時は「割り込み禁止状態にして」というのが基本です。

この手順を「何て言うの?」っと調べたら・・・
  ・アトミックに処理を
  ・アトミック操作
  ・不可分処理
っと、出てきます。

でも、アトミック操作とはで調べると、8ビットマイコンでの
割り込み処理の話が出てこずに、
  スレッドやプロセスや
  RISCやCISCや
  マルチスレッドやシングルスレッドや
っという8ビットマイコンの世界とはちょいと縁遠いお話し
ばかりが出てきます。

この「アトミック操作」ですが、昔々の8ビットマイコンの
世界じゃ(8080,6800~Z80あたりの年代で)なんかもっと他の
言い方、無かったでしょうか?

「8ビットマイコンの割り込み処理で多バイトデータを扱う時、
 メインでは割り込み禁止で読み書きを」を一言で表現できる
言葉、こんなの無かったですかね?

当時、アトミック処理や不可分処理なんて言葉で言わなかった
よう・・・

『アトミックにアクセス』なんて言い回し・・・
ラジオペンチさん に教えてもらった。
   (この↑記事のコメントの前にもあったはずだけど探し出せてない)


| | コメント (7)

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

 

| | コメント (0)

2020年9月17日 (木)

ロータリーエンコーダーの2相パルス、クリック有りの場合は

2020年9月12日:ロータリーエンコーダーの2相パルスをピン変化割り込みで取り込む

2020年9月16日:ロータリーエンコーダーの2相パルスをタイマー割り込みで
は、クリック無しでグルグル回しのロータリーエンコーダーを
想定しています。
ですんで、A相とB相の↑↓各エッジ、4つを使ってカウントし、
いわゆる4逓倍の処理を考えました。
1回転24パルスのロータリーエンコーダーだと1回転96パルスになります。

この、小型エンコーダー(コパルRE12D-300) だと、
1回転300パルスが1200パルスに。
ちょっと得した気分。

で、「クリック有りのロータリーエンコーダー」だったらどうした
ものかというお話しをちょっと。
観測波形を見ますと、静止時はA相・B相ともHレベルを保持。
左右どちらかの1クリックで2相パルスが出現という仕掛けに
なっています。

1クリックでA相とB相両方にLパルスが生じます。
その「後先」±1が決まります。
ですので、判断はどこか1つのエッジだけを使えば良いわけです。
例えばこんな具合。

A000_20200917095401
A001

下側波形の立ち下がりを使うことにして、このパルスを検出した時、
反対相のH/LによってCWかCCWを決めます。
ただし、クリックのメカ的な機構によりけっこう早い応答が必要。
パルスの抜けを防ぐにはエッジ検出は割り込みでの処理が必須でしょう。

この場合、割り込みが必要なのは片側の相だけ。
反対相はH/Lを入力するだけになりますんで、割り込みは不要。
また、エッジを検出しないほうの相が変化しても、カウント処理には
関係ありません。
  ※4逓倍処理なら、片相が変化するだけで±1します。
   しかし、エッジ検出が1つの場合だと、相が進まずに
   その片相だけがH/Lを繰り返すとミスカウントしてし
   まいます。
   クリック有りのロータリーエンコーダーはメカ的
   信号の相が進むようになっていますので、片相だけ
   の変化は心配しなくてかまいません。
     ※クリック無しのだと簡単にはいかない

ArduinoのINT0とINT1の割り込み駆動は両エッジだけでなく、
↑エッジ、↓エッジが設定できますので、↑↓どのエッジで
駆動されたのかの判断は不要です。
クリック有りタイプのロータリーエンコーダーだと2つ接続
できるということになります。


| | コメント (0)

CR2032バックアップ用リチウム電池・・・0V

先日来、ガレージのPCの調子が良くなかったんで、
昨晩、フタを開けて清掃。
  立ち上がりをミスったり、
  動画を見てたら落ちたりっと。
PCはガレージの主テーブル(食事を作るんで油も煙もひどい)の
そば。
電源を抜いてから、ケースの吸気口やファンの汚れ(コテコテだぁ)
を清掃。

11_20200917082701

ところが・・・掃除を終えてからの電源投入。
いきなりBIOS設定画面が出てきちゃいました。
いろんな設定だけでなく、日付も忘れています。
あれまっ。

文鎮 の佐藤テック君のアドバイス。
  「電池とちゃうか?!」

12_20200917083001

アタリ!でした。
電池を外してテスターで電圧を測ったら「0V」。
放電しきってます。
「まぁよぅ動いてたな」ってことで新品電池に交換にして解決。

電源コードを外して小一時間ほど掃除でごそごそしてたせいで、
完全に電源が抜け落ちてしまったのでしょう。
それでもまぁ「0V」とは・・・

| | コメント (0)

2020年9月16日 (水)

ロータリーエンコーダーの2相パルスをタイマー割り込みで

2020年9月12日:ロータリーエンコーダーの2相パルスをピン変化割り込みで取り込む
2020年9月14日:「チャタリング除去回路」じゃなくって「チャタリング発生回路」をどうぞ
2020年9月15日:今度はチャタリング除去、その考え方

これらの続きということで、2kHzのタイマー割り込み(ATmega328Pのタイマー2)で
ロータリーエンコーダの入力を処理してみました。
   ※無理やりチャタリングを入れてます
そのスケッチを示します。

A相入力がA0、B相がA1。
D8出力とD9出力にチャタリング除去して平滑化したA相とB相を出力。
D10出力はA相B相の↑↓エッジ検出タイミング。
D13出力は(LED)は2kHzタイマー割り込み処理でパルスを出力しています。

/*****  ロータリーエンコーダーテスト    *****/
// A相+B相の4エッジを使って4逓倍
// タイマー2割り込みでチャタリング除去とともにエッジ検出
// ポート使用
// A0 PC0 A相入力 (pull up)
// A1 PC1 B相入力 (pull up)
// D8 PB0 A相入力安定モニター出力
// D9 PB1 B相入力安定モニター出力
// D10 PB2 エッジ検出出力
// D13 PB5 LED 割り込みタイミング出力
// タイマー2周波数設定 → OCR2A = 125 - 1; // 2kHz(0.5mS) ★1
// ポート制御
#define D8_H (PORTB |= (1 << PB0)) // PB0 A相入力安定モニター出力
#define D8_L (PORTB &= ~(1 << PB0)) //
#define D9_H (PORTB |= (1 << PB1)) // PB1 B相入力安定モニター出力
#define D9_L (PORTB &= ~(1 << PB1)) //
#define D10_H (PORTB |= (1 << PB2)) // PB2 エッジ検出出力
#define D10_L (PORTB &= ~(1 << PB2)) //
#define D13_H (PORTB |= (1 << PB5)) // PB5 (LED)割り込みタイミング
#define D13_L (PORTB &= ~(1 << PB5)) //
// 配列のデータ数を返すマクロ
#define DIMSIZ(a) (sizeof(a)/sizeof(*a))

/******************************/
/* エンコーダ入力 */
/******************************/
// データ
#define ENC_TOP 359 // 360度回転 0~359
volatile word enc_cnt; // 0~359カウンタ
volatile byte f_cnt; // カウンタup/down検出フラグ
// A相 B相入力 on,offチェック (Hで1)
#define INP_A (PINC & (1 << PC0)) // A相入力チェック
#define INP_B (PINC & (1 << PC1)) // B相
// ↑↓エッジのビット位置
#define ENC_A 0 // A相↑
#define ENC_B 1 // B相↓
// bit0,1にエンコーダ入力データが入る
volatile byte enc_sft[4]; // チャタリング除去用シフトデータ
// 4回ともH/L同じなら安定
volatile byte enc_inp; // 入力のon/off安定状態
// エッジをチェック
/***** エンコーダカウントアップ *****/
// 359度なら0に
void cntup(void)
{
if(enc_cnt >= ENC_TOP) enc_cnt = 0;
else enc_cnt++;
}
/***** エンコーダカウントダウン *****/
// 0度なら359に
void cntdn(void)
{
if(enc_cnt == 0) enc_cnt = ENC_TOP;
else enc_cnt--;
}
/***** カウント値読み出し *****/
// いったん割り込み禁止にして
word readcnt(void)
{
word d;
cli(); // いったん割り込み禁止して
d = enc_cnt; // 0~359度カウンタ読み出し
sei(); // 割り込み有効に戻す
return d;
}
/***** エンコーダ入力スキャン *****/
// タイマー割り込みで呼出
// 4サイクルでチャタリング除去
// ↑↓エッジを見つけてup/downカウント
// CW : A↑ B=L , A↓ B=H , B↑ A=H , B↓ A=L
// CCW : A↑ B=H , A↓ B=L , B↑ A=L , B↓ A=H
void encscan(void)
{
static byte p = 0; // 最新入力書き込み位置
static byte q1 = 0; // 安定したエンコーダ入力
byte d0, d1; // L安定,H安定 ↓↑エッジ
byte n, q2; // n:一時データ、q2:エッジ検出用
// エンコーダA,B相入力
n = 0;
if(INP_A) n |= 0b00000001; // 0:A相
if(INP_B) n |= 0b00000010; // 1:B相
enc_sft[p] = n; // 最新エンコーダ入力状態
// シフトデータをANDとORして変化点を見つける ★2
d0 = d1 = enc_sft[0]; // d0:全L / d1:全Hチェック
d0 |= enc_sft[1]; // [0]~[3]の4シフトデータ
d1 &= enc_sft[1];
d0 |= enc_sft[2];
d1 &= enc_sft[2];
d0 |= enc_sft[3];
d1 &= enc_sft[3];
n = (~d0) | d1; // 1のところが安定データ
q2 = q1; // 前の状態
q1 = (q2 & (~n)) | (enc_sft[3] & n); // 新入力状態確定
// シフトデータのポインタ+1
p++; // 次書き込み位置
if(p >= DIMSIZ(enc_sft)) p = 0; // ポインタ一周
// A相/B相安定状態をモニター出力
if(q1 & (1 << ENC_A)) D8_H; // A相 D8
else D8_L;
if(q1 & (1 << ENC_B)) D9_H; // B相 D9
else D9_L;
// エッジチェック
d1 = (~q2) & ( q1); // ↑エッジをチェック ★3
d0 = ( q2) & (~q1); // ↓エッジ
if(d0 | d1){ // エッジあり
D10_H; // A相かB相に↑↓エッジあり
f_cnt = 1; // カウントup/down検出
if(d1 & (1 << ENC_A)){ // A相↑ ★4
if(!(q1 & (1 << ENC_B))) cntup(); // B=L CW, +1
else cntdn(); // B=H CCW,-1
}
if(d1 & (1 << ENC_B)){ // B相↑
if( q1 & (1 << ENC_A)) cntup(); // A=H CW, +1
else cntdn(); // A=L CCW,-1
}
if(d0 & (1 << ENC_A)){ // A相↓
if( q1 & (1 << ENC_B)) cntup(); // B=H CW, +1
else cntdn(); // B=L CCW,-1
}
if(d0 & (1 << ENC_B)){ // B相↓
if(!(q1 & (1 << ENC_A))) cntup(); // A=L CW, +1
else cntdn(); // A=H CCW,-1
}
}
else{
D10_L; // エッジなし
}
}
/*******************************/
/* タイマー2割り込み */
/*******************************/
/***** タイマー2コンペアマッチA割込み *****/
// 2kHz(0.5mS)で割り込み
ISR(TIMER2_COMPA_vect)
{
D13_H; // (!!!)
encscan(); // エンコーダ入力処理
D13_L; // (!!!)
}
/*******************************/
/* SETUP */
/*******************************/
/***** SETUP *****/
void setup()
{
// ポートI/O指定
PORTB = 0b00000000; // data/pull up
DDRB = 0b00111111; // I/O (0:in 1:out)
// |||||+---- PB0 IO8 out A相入力安定モニター出力
// ||||+----- PB1 IO9 out B相入力安定モニター出力
// |||+------ PB2 IO10 out ↑↓エッジありモニター出力
// ||+------- PB3 IO11 out
// |+-------- PB4 IO12 out
// +--------- PB5 IO13 out (LED) 割り込みタイミング
PORTC = 0b00111111; // data/pull up
DDRC = 0b00000000; // I/O (0:in 1:out)
// |||||+---- PC0 AD0 in A相入力(pull up)
// ||||+----- PC1 AD1 in B相入力
// |||+------ PC2 AD2 in
// ||+------- PC3 AD3 in
// |+-------- PC4 AD4 in
// +--------- PC5 AD5 in
PORTD = 0b11111111; // data/pull up
DDRD = 0b00000010; // I/O (0:in 1:out)
// |||||||+---- PD0 IO0 in RXD
// ||||||+----- PD1 IO1 out TXD
// |||||+------ PD2 IO2 in
// ||||+------- PD3 IO3 in
// |||+-------- PD4 IO4 in
// ||+--------- PD5 IO5 in
// |+---------- PD6 IO6 in
// +----------- PD7 IO7 in
// タイマー2
TCCR2A = 0b00000010; // モード設定
// |||| ++--- WGM: CTCモード
// ||++------- COM0B
// ++--------- COM0A
TCCR2B = 0b00000100;
// |+++--- CS:1/64 : 250kHz
// +------ WGM02
OCR2A = 125 - 1; // 2kHz(0.5mS) ★1
TIMSK2 = 0b00000010;
// +----- OCIE2A コンペアマッチA割り込み有効
// シリアル
Serial.begin(9600);
// 最初の表示
delay(100); // 入力安定にちょい時間待ち(timer0使う)
cli(); // いったん割り込み禁止して
enc_cnt = 0; // カウンタをゼロクリア
sei(); // 割り込み有効に戻す
f_cnt = 1; // カウント値表示フラグon
}
/*******************************/
/* LOOP */
/*******************************/
/***** LOOP *****/
void loop()
{
if(f_cnt){ // カウンタup/downした
f_cnt = 0;
Serial.println(readcnt()); // カウント値をシリアル出力
}
}
/*===== end of "test_enc2.ino" =====*/

★1でタイマー2割り込みの周波数を設定。
2kHz(0.5ms)にしています。
チャタリング除去用のシフトレジスタが4段ですので、入力した信号が2mS遅れます。
これで2相パルスに対する応答速度が決まります。
ダイヤルを早く回すと追いつかないという状態に。

★2がチャタリング除去の処理。
ANDとORを重ねながらシフトレジスタを読み出しています。

★3がエッジ検出処理。
チャタリング除去されて確定したq1とq2からエッジを得ます。

★4で、A相B相の↑↓エッジ(4つある)から、相対する相の
状態を見て、カウントアップとカウントダウンの処理を行っています。


その状態。 オシロスコープで。
A000

一番下の波形、このタイミングでカウンタのup/downが
行われて、カウント値をシリアル出力しています。

エンコーダのぐるぐる回しをちょいと早くすると、
こんな感じに。
A003

模擬的なチャタリングをうまく取り除いている様子が見えます。
しかし、応答速度はこのあたりが限界。
対策は、タイマー割り込みの周期をもっと短くっという方法に
なるのですが、毎割り込みで取られる時間がちょいもったいな
いかと。
パルスが入ってカウント処理されると10usくらいです。
待機時は7~8usくらい。

割り込み機能の無い入力ピンを使っての2相パルスカウント、
高速応答はできませんが、手動で操作するエンコーダだと
こんなものでしょう。

シフトレジスタは8bitです。
今は2bitしか使っていないんで、エンコーダは4系統まで
拡張できるかと。


※試行錯誤

シフトレジスタのAND、OR処理、Cの書き方を
ちょいと変えると、出てくるコードが変わりました。
これが最初の。
enc_sft[0]~enc_sft[3]の並びをうまくやってくれるかと、
コンパイラに期待しましたが・・・

//  シフトデータをANDとORして変化点を見つける ★2
d0 = d1 = enc_sft[0]; // d0:全L / d1:全Hチェック
d0 |= enc_sft[1]; // [0]~[3]の4シフトデータ
d1 &= enc_sft[1];
d0 |= enc_sft[2];
d1 &= enc_sft[2];
d0 |= enc_sft[3];
d1 &= enc_sft[3];
n = (~d0) | d1; // 1のところが安定データ
q2 = q1; // 前の状態
q1 = (q2 & (~n)) | (enc_sft[3] & n); // 新入力状態確定

500: 90 91 18 01 lds r25, 0x0118 ;enc_sft[0]
504: 20 91 19 01 lds r18, 0x0119 ;enc_sft[1]
508: 29 2b or r18, r25
50a: 80 91 19 01 lds r24, 0x0119 ;enc_sft[1]
50e: 98 23 and r25, r24
510: 80 91 1a 01 lds r24, 0x011A ;enc_sft[2]
514: 28 2b or r18, r24
516: 80 91 1a 01 lds r24, 0x011A ;enc_sft[2]
51a: 98 23 and r25, r24
51c: 40 91 1b 01 lds r20, 0x011B ;enc_sft[3]
520: 80 91 1b 01 lds r24, 0x011B ;enc_sft[3]
524: 24 2b or r18, r20
526: 20 95 com r18
528: 98 23 and r25, r24
52a: 92 2b or r25, r18
52c: 80 91 17 01 lds r24, 0x0117 ;q1
530: 20 91 1b 01 lds r18, 0x011B ;enc_sft[3]
534: 49 2f mov r20, r25
536: 40 95 com r20
538: 48 23 and r20, r24
53a: 92 23 and r25, r18
53c: 94 2b or r25, r20
53e: 90 93 17 01 sts 0x0117, r25 ;q1

別の書き方で。
こっちのほうがメモリの読み出しを省いている
分、ちょいだけと早そう。


// シフトデータをANDとORして変化点を見つける ★2
d0 = d1 = enc_sft[0]; // d0:全Lチェック,d1:全Hチェック
n = enc_sft[1]; // [0]~[3]の4シフトデータ
d0 |= n;
d1 &= n;
n = enc_sft[2];
d0 |= n;
d1 &= n;
n = enc_sft[3];
d0 |= n;
d1 &= n;
n = (~d0) | d1; // 1のところが安定データ
q2 = q1; // 前の状態
q1 = (q2 & (~n)) | (enc_sft[3] & n); // 新入力状態確定


500: 90 91 18 01 lds r25, 0x0118 ;enc_sft[0]
504: 80 91 19 01 lds r24, 0x0119 ;enc_sft[1]
508: 29 2f mov r18, r25
50a: 28 2b or r18, r24
50c: 89 23 and r24, r25
50e: 40 91 1a 01 lds r20, 0x011A ;enc_sft[2]
512: 24 2b or r18, r20
514: 98 2f mov r25, r24
516: 94 23 and r25, r20
518: 80 91 1b 01 lds r24, 0x011B ;enc_sft[3]
51c: 28 2b or r18, r24
51e: 20 95 com r18
520: 89 23 and r24, r25
522: 92 2f mov r25, r18
524: 98 2b or r25, r24
526: 80 91 17 01 lds r24, 0x0117 ;q1
52a: 20 91 1b 01 lds r18, 0x011B ;enc_sft[3]
52e: 49 2f mov r20, r25
530: 40 95 com r20
532: 48 23 and r20, r24
534: 92 23 and r25, r18
536: 94 2b or r25, r20
538: 90 93 17 01 sts 0x0117, r25 ;q1

 

 

| | コメント (0)

2020年9月15日 (火)

今度はチャタリング除去、その考え方

2020年9月12日:ロータリーエンコーダーの2相パルスをピン変化割り込みで取り込む
に絡んで、まずはこんなものを作りました。
2020年9月14日:「チャタリング除去回路」じゃなくって「チャタリング発生回路」をどうぞ

エンコーダのA相・B相信号、チャタリングを取り除きながら
エッジ検出してCW・CCW方向のパルス計数をする方法。
このように考えて作っています。

・INT0やINT1、あるいはピン変化割り込みを使う場合は、
 ハードウェア的にチャタリングを取り除いておかないと
 不要パルスが入った時にミスカウントするかも。

・これらの直接的パルス駆動割り込みを使わない場合は、
 タイマー割り込みでの定期的なA相・B相信号の入力処理
 が必要。

・定期的な処理ができるのなら、チャタリング除去も
 ソフトでできる。

・ただし・・・「入力波形が安定するまで時間待ち」など
 という恥ずかしい処理は×。

・こんなロジックでチャタリングを防ぎます。

C1_20200915170901

とりあえずシフトレジスタは4段。
タイマー割り込みの周期で入力信号をシフトしていきます。
4つとも全部がH、あるいは全部がLなら信号が安定した
ということで、入力を確定。
H/Lが混じっていたら不安定=チャタリング中ということで
安定していた時の昔のデータを用います。

スイッチ入力だと、1mSサイクルで10段ほど読んでおけば
ひどいチャタリングのあるスイッチでも大丈夫。
スイッチのオートリピートや長押し処理も、タイマー割り込み内
で完結します。

そして、エンコーダのA相・B相から正逆をカウントする処理は、
そのパルスエッジの検出が不可欠です。

これもやはりシフトレジスタを使って処理、こんな
「回路」で↑↓エッジを作り出します。

C2_20200915170901

このロジックをマイコンの命令に置き換えてプログラム
するわけです。

チャタリング除去の所、全Lを検出している「負論理4入力のAND」
は「正論理4入力・負論理出力のOR」と等価です。
これもプログラムの命令で実現します。

実際のプログラムの様子はこの次に。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
※2相パルスの弁別回路について
2017年9月12日:C-MOS 2相パルスカウンタの入力部回路
2017年3月6日:29年前に製作したツール

| | コメント (1)

パナソニックeneloopスタンダード単3、JIS C8708:2019充放電テスト850サイクル目

パナソニックeneloopスタンダード単3 BK-3MCCのJIS C8708:2019(新JIS)
充放電実験を始めたのが2020年4月4日
ざっと5ヶ月で850サイクルの充放電を終えました。

21_20200915143001

450サイクル目が2020年7月7日でしたんで、充放電時間が徐々に短くなって
きてるのが経過日数からも分かります。
  ※製作した充放電実験装置、連続して試験できるのが
   400サイクルです。ですので、400サイクル、800サイクル
   と試験が進むはずなんですが、850サイクルと中途半端なの
   は、途中でプログラムを変更したから。
   その時点で50サイクルほど充放電が進んでいたのです。

まず、50サイクルごとの0.2C放電(5時間率)のグラフ。
JISの寿命判定はこの放電時間が3時間未満になった時。
Vd850
  ※まだもうちょい、というところですんで実験を
   継続します。
   850サイクル終了後に電池を外して内部抵抗を
   計ったら208mΩでした。
   まだもうちょい行けそうです。
    初期の内部抵抗は15mΩ

そして、毎1~49サイクルでの0.5C(2時間率)充放電時間と
充電完了電圧を記録したのがこのグラフ。

E850

0.5Cですので、2時間は放電していてもらいたい。
0.2Cのゆっくり放電で寿命を見るより、このくらいの
放電電流のほうが実用に近いかと。

500サイクルは安心して使える結果がでています。
また、0.5Cでの充電開始後、「偽の-ΔV」は出ていません。
ReVOLTESではこれが激しく出たんですが、エネループでも
見てみたい。
ダイソーReVOLTE単3 JIS C8708:2019充放電試験(-ΔV検出有) 偽の-ΔV発生

ほんとの寿命まであともうちょいイジメてみます。

ブログ記事まとめ:電池あれこれ

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
※JIS C8708:2019の試験手順ですでに結果を出した電池

ダイソーReVOLTES
V517_20200512173401

富士通の黒(HR-3UTHC)
V0259a

エネループ・プロ(BK-3HCD)
Tv0170

| | コメント (0)

操作スイッチ接触不良 →大阪魂の出番に

ずいぶん昔に使ったとある装置のテストジグ。(30年以上前だわ!)
ひさしぶりに引っ張り出してきて使おうとしたら、操作スイッチが接触不良に。

ミヤマ電器 DS-193 という小型のプッシュスイッチ。
ずっと押してれば、ちゃんと接点は接触はしてくれます。
しかし、「ちょん・ちょん」と寸動するとダメ。
ツン・ツン」と動くはずが「バ・バ・バ・バ・バ」っと振動して
しまうのです。
回路的にはハードウェアーで10mS程度のチャタリング除去はしてい
ますんで、たいていは大丈夫なはずなんですが・・・

とりあえずオシロで接点の状態を見たら、チャタリングなんてもんじゃ
ありませんでした。
「チョン」押しで100mSほどオンしたら、その間、明確なオン・オフ
の断続が2~3回。
接点のチャタリングじゃなく、接触不良状態というか、素早く手で
オン・オフしたような信号、正規の信号のようになってます。
これじゃチャタリング除去回路では吸収できません。
同じような不良のスイッチが2つ。

とりあえず手持ちの新品押しボタンスイッチに交換。
小型のスイッチだったんで、元の穴が大きすぎたんでワッシャ
をかまして無理やり取り付け。

取り外したDS-193↓
11_20200915114001

ジグを使い終わってから、アウトになったスイッチをバラしてみました。
接点部が取り付け金具部にねじ込まれています。
これを緩めると、接点金具と小さなバネが出てきます。

12_20200915114201

接点部の奥に、ハンダ付けする接触が見えてます。
   (リングライトを出すのが面倒だったんで
    懐中電灯で照明)
13_20200915114201

接点も接点金具もキレいです。
これで接触不良?というのがちょい不思議。
  ※過去、ひどい接触不良を見てますんで

さてここからが「ものは試し」。 使うのは「大阪魂 」。
接点と接触片の両方をプシューしてから組み直します。
すると・・・
あらま、ちゃんと回復しちゃいました。
単純な構造の接点ですんでチャタリングは発生します。
しかし、「バ・バ・バ・バ」というむちゃな接触不良は無くなりました。
導通チェック しても大丈夫。
  ※抵抗値の変動があれば音ですぐに分かるんで。

まぁ、一度トラブったスイッチです。
とりあえず非常用の予備品に。

しかしまぁ「大阪魂」。こいつはなかなかやってくれます。

※関連
2018年8月27日:モノタロウのパーツクリーナ
2018年8月24日:はじめてのArduino MICRO
2018年2月22日:ローランド ミキシングアンプ「VX-55」修理!
2018年10月22日:タクトスイッチ接触不良
2011年01月27日:電源スイッチ接触不良 
2013年06月12日:タクトスイッチ接触不良
2013年04月26日:照光式タクトスイッチ…接点が死んでました

| | コメント (2)

2020年9月14日 (月)

コテペンの柄、割れてきた・・・

大事に使ってきたコテペン40(もう作っていないんでパーツも含めて入手不可)。
今朝のこと、ハンダ付け作業をしてましたら・・・
コテを手に持った時に突然の違和感。
「くにゃっ」とした感触。
コテの柄を見たら、ひび割れがぁぁ。

もう2本同じものをストックしてあるんですが、お気に入りの
ツールです。
ひび割れに瞬着を流し込んで(百均のじゃなくちょいとエエやつで)
から、「アクリルレジン」で固めちゃいました。

A11_20200914175901

以前にも、
2013年03月05日:コテペン落下→折損→応急修理
てなことがありました。
  ↑これ、まだ生きてます。
  おもちゃ病院で使ってます。
今回は落としはしていません。
使っていたら、ある時「んんん? なに?」でした。
ほんと、手になじむハンダゴテを探しとかなあかんです。

2014年12月06日:半田ごて落下→ヒータ折損

| | コメント (0)

「チャタリング除去回路」じゃなくって「チャタリング発生回路」をどうぞ

2020年9月12日:ロータリーエンコーダーの2相パルスをピン変化割り込みで取り込む
に絡んで、接点式ロータリーエンコーダーの「チャタリング」を
ソフトでどうにかできないかと試しています。

ただ・・・
件の接点、たいへん状態が良くって、オシロで見てても頻繁に
は発生しません。
たまに出る」という状態です。
しかし、チャタリング除去回路無しでは、「出ればカウントミス
が発生します。
やはり、これではあきません。
外付けチャタリング除去回路(抵抗+コンデンサ)無しでなんとかな
らないかと、試行錯誤中です。

その試行錯誤するためには、信号源として
チャタリングが出る接点」が必要です。
「リレーをカチャカチャ」なんてこともありなんですが、
エンコーダーなんで2相パルスが欲しい所です。

そんな時のためのツールが『チャタリング発生回路』。
1chだけのを作ってあったんで2chに拡張しました。
これで、2相パルスの両方に模擬的な「チャタリング信号」
を乗せることができるようになりました。

こんな回路です。

C11_20200914081201
まず、X-ORゲートを使ったエッジ検出回路で↑↓エッジからちょいと
遅れたゲート信号を作ります。
別の発振回路で作ったチャタリング信号を、そのゲートの時間だけ
X-ORゲートで元の2相パルスと合成します。

こんなタイミング。
C12_20200914081201
X-ORゲート、2つの入力信号のH/Lが一致で出力L。
2つの入力のH/Lが異なったら出力H。
ということは、
片方がLならもう片方の信号をそのまま出力。
片方がHならもう片方を反転して出力すると
いう性質があります。
これでエッジ検出やチャタリング信号の合成を
行っています。

オシロで見たところ。

C022  

手組みした基板の様子。
C24

チャタリング時間とチャタリング信号の周波数を半固定ボリュームで
可変できるようにしてるんで、あれこれ試せます。


※2相パルス発生回路はあれこれ製作しています。
2005年09月09日:トラ技2005年10月号
2015年12月08日:んっ? トグルスイッチが
2014年07月01日:高速2相パルス発生回路



| | コメント (0)

2020年9月12日 (土)

ロータリーエンコーダーの2相パルスをピン変化割り込みで取り込む

2020年8月11日:14pinのAVRマイコン、ATtiny24が動かん!
2019年9月29日:360度グルグル回したろ
に絡むんですが、1kHzのPWM波発生回路を作ろうとしています。

旭化成のAK7401 、PWMで角度を出力してくれます。
その回路検証に使います。
周波数が1kHzで、検出角によりPWMのデューティを10%から90%
まで可変。
デューティーの10%が0度に対応して、50%が180度で
359.9度が90%という仕様です。
このパルスを模擬的に出そうという回路です。

この角度の設定にロータリーエンコーダを使おうとしたのです。
右に左にぐるぐる回せば0~359度自在に設定という目論見です。

14pinのAVRマイコン、ATtiny24が動かん! では、ロータリーDIP SW
を使ったんですが、これは「リニア」に設定できません。
角度の設定ならやはりグルグル回しでしょう。

「確かどこかに残ってたはずや」っとパーツボックスを
探すと出てきました。
BOURNSのECW1J-B23-BC0024L

11_20200912143701

1回転が24クリック。
360度回そうとすると15回転。
   ちょっとクリクリするのがたいへんか・・・

1クリックでこんなパルスが出てきます。
右回しと左回しで波形がちょいと異なります。
A2_20200912143801

A1_20200912143801
A相B相とも途中では止まりません。
両方信号オフ状態で止まります。
これ、2相パルスには違いないのですが、クリック機構があると
途中で止められないので、4逓倍は無理。

そこで・・・「つぶしてもエエやん」っと、基板部を固定してある
ポッチリを削ると、中身が出てきました。
A相・B相のコード板と接点。
13_20200912143901

そしてクリックはこんな機構。
14_20200912144001

スプリング部に出たチョッポリで回転軸のギザギザを押さえ
ています。
このスプリングを外せば、クリック無しで自由回転するんですが、
接点端子部をコード板に押さえているのもこの機構です。
スプリングを取ると接触が安定しません。

そこで、「ポッチリを反対にしてみたろ」っとスプリングを裏返したと
ころ、「まぁエエやん」っとクリック感無しで360度クルクル回転でき
るようになりました。

これで4逓倍すれば、3.75回転で360度の角度をセットできます。
回すとこんなパルスが出てきます。
A3_20200912144201
ほんとは各パルス90度位相差なんですが、コード板の構造で
しょう、1箇所周期が長いところがあります。

接点のチャタリング、こんな様子です。
A4_20200912144301
いつも出るわけじゃなく、「たまに出る」というヒゲですが、
CRでのチャタリング吸収回路は必須です。
ちなみにBOURNSのカタログにはこんな回路が。

・単純にCRで
 10k+0.01uFですんで時定数0.1mSくらい。
B1_20200912144901

・そして・・・あらま懐かしいMC14490 が出てきました。
B2
チャタリング除去専用のICです。
大昔、使ったことあります。
C-MOS4000番シリーズの「けったいなIC」系列に登場する
石ですなぁ。

まずはArduino UNOでエンコーダーの計数を試してみます。
ネットを探すと・・・INT0・INT1エッジ割り込みを使った
例題ばかり。

面白くないんで、こんな接続に。
ピン変化割り込み」を使ってみます。

B5

ピン変化割り込みは、ポートB群、ポートC群、ポートD群、
3つの割り込みが独立して使えます。
ただし、それぞれのポート群の中での入力ピンは一つだけ。
  (どのピンが変化したかのチェックを省略する処理では)
INT0とINT1はPD2、PD3でポートD群ですんでこれは除外。
PB0とPC0に2相パルスを入れることにします。

エンコーダ入力のテストはこんなスケッチ。
  ※PWM出力制御と設定角度の表示はこれから
   とりあえずシリアル出力で。

/*****  ロータリーエンコーダーテスト    *****/
// A相+B相の4エッジを使って4逓倍
// ポート使用
// A0 PC0 A相入力 PCINT8
// D8 PB0 B相入力 PCINT0
// D13 PB5 LED テスト出力
// データ
#define ENC_TOP 359 // 360度回転 0~359
volatile word enc_cnt; // 0~359カウンタ
volatile byte f_cnt; // カウンタup/downフラグ
// ポート制御
#define INP_A0 (PINC & (1 << PC0)) // A相 A0入力 PC0 PCINT8
#define INP_D8 (PINB & (1 << PB0)) // B相 D8入力 PB0 PCINT0
#define D13_H (PORTB |= (1 << PB5)) // PB5 D13 H/L
#define D13_L (PORTB &= ~(1 << PB5)) // テストパルス

/***** エンコーダカウントアップ *****/
// 359度なら0に
void cntup(void)
{
if(enc_cnt >= ENC_TOP) enc_cnt = 0;
else enc_cnt++;
}
/***** エンコーダカウントダウン *****/
// 0度なら359に
void cntdn(void)
{
if(enc_cnt == 0) enc_cnt = ENC_TOP;
else enc_cnt--;
}
/***** カウント値読み出し *****/
// いったん割り込み禁止にして
word readcnt(void)
{
word d;
cli(); // ★いったん割り込み禁止して
d = enc_cnt; // 0~359度カウンタ読み出し
sei(); // 割り込み有効に戻す
return d;
}

/***** A相入力 ↑↓ PC0 A0 *****/
// CW : A↑ B=L / A↓ B=H
// CCW : A↑ B=H / A↓ B=L
ISR(PCINT1_vect)
{
D13_H; // (!!!)
if(INP_A0){ // A↑
if(!INP_D8) cntup(); // B=L CW, +1
else cntdn(); // B=H CCW,-1
}
else{ // A↓
if(INP_D8) cntup(); // B=H CW, +1
else cntdn(); // B=L CCW,-1
}
f_cnt = 1; // カウントup/down
D13_L; // (!!!)
}
/***** B相入力 ↑↓ PB0 D8 *****/
// CW : B↑ A=H / B↓ A=L
// CCW : B↑ A=L / B↓ A=H
ISR(PCINT0_vect)
{
D13_H; // (!!!)
if(INP_D8){ // B↑
if(INP_A0) cntup(); // A=H CW, +1
else cntdn(); // A=L CCW,-1
}
else{ // B↓
if(!INP_A0) cntup(); // A=L CW, +1
else cntdn(); // A=H CCW,-1
}
f_cnt = 1; // カウントup/down
D13_L; // (!!!)
}

/***** SETUP *****/
void setup()
{
pinMode(8, INPUT); // D8 PB0 PCINT0 B相入力
pinMode(A0, INPUT); // A0 PC0 PCINT8 A相入力
pinMode(13, OUTPUT); // D13 PB5 (test LED port)
// ピン変化割り込み
PCMSK0 = 0b00000001; // 1で許可
// +---- PCINT0 PB0 D8 B入力
PCMSK1 = 0b00000001; // 1で許可
// +---- PCINT8 PC0 A0 A入力
PCICR = 0b00000011; // 1で割り込み許可
// ||+---- PCIE0 PCINT0~7 (PB)
// |+----- PCIE1 PCINT8~14 (PC)
// +------ PCIE2 PCINT16~23 (PD)
// シリアル
Serial.begin(9600);
// 最初の表示
f_cnt = 1; // カウント値表示フラグon
}
/***** LOOP *****/
void loop()
{
if(f_cnt){ // カウンタup/downした
f_cnt = 0;
Serial.println(readcnt()); // カウント値をシリアル出力
}
}


INT0・INT1以外にエンコーダをもう一つ付けたいという時の
参考になりますでしょうか。

・カウントアップ・ダウンの処理
B11_20200912150301
   ※おっと、2カ所ミスあり。
    B相↓のとき「B相=」というところ「A相=」です。

・逆転する様子
B12_20200912150301
入力のA相・B相パルスと、割り込み処理の関係、こんな具合です。
割り込みでD13・PB5ポートをon/offしています。
各エッジで割り込みが入っていることが見えます。

A6_20200912145501

※注意点
0~359という16bit値を扱っていますが、Arduino-UNOは
8bitマイコン。
割り込みで処理される2バイト以上のデータを扱う時は、
メイン側での読み書きは必ず割込禁止状態でしなくちゃ
なりません。
ネットで見かけるロータリーエンコーダの処理、これを
していない例題が
多数です。

2019年3月25日:割り込みで処理させるwordデータの扱い
2016年02月19日:Arduinoのタイマー処理
2018年10月11日:魔法の言葉「volatile」

※2相パルス、ロータリーエンコーダー絡みの記事
2014年07月01日:高速2相パルス発生回路
2017年9月12日:C-MOS 2相パルスカウンタの入力部回路
2010年01月30日:U/Dカウンタ
2018年5月25日:アナログ入力で2相パルスの周波数と正転逆転を制御する発振器
2018年6月17日:RX220マイコンで2相パルスカウント:グルグル回る角度を


※問題のある割り込み処理内データの読み出し例。

いずれも、読み書きのタイミングが「ゆっくり」だから
割り込みとの競合が露呈しないのでしょう。

割り込み内で下位桁からの桁上がりで上位桁が変化する
時などが問題。
割込を禁止しないで2バイト以上のデータを読み出すと、
そのタイミングで、割り込みによるカウントアップや
カウントダウンが起こると、誤ったデータを読み出
してしまいます。
下位バイトと上位バイトが処理される隙間に割り込みが
入るとアウトかも!という現象です。
16bitマイコンや32bitマイコンを触っていると、意識
しなくても正しい処理をしてくれるんですが、低機能
な8bitマイコンではしかたありません。

めったにないことでも、起こる可能性があるものは確実に
起こります。
それがプログラム(のバグ)というものです。

割り込みで処理される2バイト以上のデータを扱う時は、
めんどうがらずに「割込禁止」と「割込許可」を挿入のこと。
C言語のコンパイラ、変数にvolatileを付けていても、割り込み
との競合は防いでくれません。
プログラマの責任です。

ラジオペンチ Arduinoでロータリーエンコーダーを使う
  intのカウンター。
ラジオペンチ ピンチェンジ割込みを使ってロータリーエンコーダーを読む (Arduino)
  Xの変化は小さそうなんで8bit→16bitへの桁上がりはなさそうだけど・・・
   if (X != 0) {   // エンコーダーの値が変化していたら
    data += X; ←★1
    X = 0;   ←★2
    :
    ★1と★2の間に割り込みがあってXが増減したら、
    ★2でクリアされてしまいその増減が無視されてしまう・・・
    この間でも,割込禁止・割込許可が必要。

第二十一項 ロータリーエンコーダとノイズ対策・割り込み kusamura
  longのカウンターを処理。
ロータリーエンコーダを使う part 1 : 外部割込みとチャタリング対策 jumbleat
  intのカウンター。
  割り込み内でSerial.printを使うのは気持ち悪い。
【Arduino】マウスホイール(ロータリーエンコーダ)の回転量を取得する - おもちゃラボ
  intのカウンター。
迷走の果て・Tiny Objects Arduinoでロータリーエンコーダを試す(2)
  intのカウンター。
ロータリーエンコーダテスト 割り込みを使う場合 ・ GitHub
  intのカウンター。

| | コメント (0)

2020年9月 9日 (水)

明るすぎた~

新造基板の動作チェックをしてるんだけど・・・
「プログラムはちゃんと走ってるよ表示」(2秒周期で点滅)の
LEDが明るすぎちゃいました。
部品表を見たら・・・「高輝度・純緑」のを選んでました。
2mAしか流してないのに、むちゃ明るい。
じっと見つめられません。
11_20200909165901

普通のに変えよう。

※シリアル通信の送受信タイミングとか、たまにピカッと
光るにはこのくらいでイイんでしょうが、1秒点灯・1秒消灯
というゆっくりした点滅ですんで・・・


| | コメント (4)

書籍でもやってる「1/1023」と「map(x, 0, 1023, 0, 255)」

ちょっと気になってたんで、Arduino関連の書籍を図書館にリクエストしてました。
とりあえずこの2冊。

(1)Arduino電子工作実践講座

A11_20200909091401

(2)Arduinoをはじめよう

A21_20200909091401

(1)からはこれ。
analogReadで読んだA/D値を電圧値へ変換する処理。
1/1023」と「Vref値の決め打ち」が蔓延っています。

A12_20200909091501


(2)では。
10bit→8bitへのスケーリングで「map」関数。
  map(val, 0, 1023, 0, 255);

A22_20200909091501

※関連
Arduino なんとかして誤用を正したい:A/Dの1/1023とmap関数
ミスが広まる 1/1023 vs 1/1024
Arduino 10bit A/D値をmap関数でスケーリングする例
線形補間って「LERP」って言うんだ!


| | コメント (0)

2020年9月 8日 (火)

青木奈緒著『動くとき、動くもの』

2020年9月1日:今日のGoogle・・・誰? このお姉さんは?
幸田文さんの『崩れ』を紹介しました。
『崩れ』は幸田文さん没後にまとめられた本ということなんですが、
この『崩れ』に続編が・・・

といってもご本人はもうこの世に居られません。
書かれたのは幸田文さんのお孫さんの青木奈緒 さん。
タイトルが動くとき、動くもの
さっそく図書館で借りてきました。

A1_20200908163601

まさに『崩れ』の続編。
幸田文さんも青木奈緒さんも「文系」というか「文学」の人。
本に写真が無くても「文字」で情景を浮かび上がらせる技術は
さすが。
砂防」とその歴史に興味をお持ちでしたらぜひご一読を。

ちなみに「砂防:SABO」という語、これ「津波:TSUNAMI」と
同じように世界に通じるそうです。国際語になっていると。
この本で知りました。

・日本語の「砂防」は外国語でも「SABO」といいます。

| | コメント (0)

2020年9月 4日 (金)

テキサスインスツルメンツ SN6501 絶縁型電源向けトランスドライバーIC

アイソレーション・アンプ(アナログ信号を絶縁して伝達する)を調べていて、
こんなICに遭遇しました。
  ・https://www.tij.co.jp/product/jp/SN6501

絶縁電源用のトランスを300kHzで駆動します。
これ用のトランスが売られてるみたい。

A1_20200904121301

LDOレギュレータを入れて安定化。
A3_20200904121401

トランスですんで「±電源」や「倍電圧整流」も。
A4_20200904121401
市販のDC-DCコンバータ(数百円か)と比べてどうでしょか?


| | コメント (0)

NEC製照明用リモコンRL12

NECの照明コントローラRL12、スイッチが接触不良で
修理して欲しいという依頼。

11_20200904083801

解体すると、基板銅箔が腐食。
原因は・・・
電池電極に液漏れ跡があるんで、電池の液漏れを疑ったんですが、
主基板と電池ホルダー部は離れています。
ひょっとして、結露とかの水分侵入?

こんなタクトスイッチが使われていました。
12_20200904084001
13_20200904084001

丸形で5mmピッチの足
基板上面からの高さは9.5mm
常備してあるオムロンのB3F-1072も同じ高さなんですが、
足の構造が異なります。

14_20200904084101
  ※左側の黄色いのがオムロン

対角にして取り付けできないかと試してみましたが、
元の基板穴にはうまく入りません。
無理に入れると安定しないし・・・
別の穴をあけてからベースを基板に接着すれば、なんて考えていました。

修理方法を悩みながら、「この丸形スイッチ、どこのだろう?」っと
調べてみましたらパナソニックで発見。

21_20200904084401

22_20200904084401

「EVQ11x09」が高さ9.5mm。
   「x」は作動力の違いです。
型番が分かったんで、発注することにしました。
  ※結局、他の品と一緒にDigi-Keyへ注文

しかし、パナのHPにもカタログpdfにも不気味な言葉。
   『受注終了』

「代替品は?」っとHPを探してみると・・・

23_20200904084901

無情に・・・代替推奨品はございません。

~~~~~~~~~~~~~~~~~~~~~~~~~~
※パナのスイッチが届いて修理完了。
   返却して実機チェック待ち。
で、離れた場所への電池液漏れ浸潤、どうやらこれかと。
41_20200908154701

電池ホルダーのマイナス側にハンダされた黒色リード線。
これの中を漏出液が伝ったみたいです。
ハンダ付け部に緑色の怪しい痕跡が残っています。

| | コメント (1)

2020年9月 3日 (木)

『宇宙【そら】へ』

宇宙へ』っと書いて「そらへ」と読ませてます。

Cc1
Cc2
メアリ・ロビネット・コワルさん著、 酒井昭伸さん訳
2020年8月発行のハヤカワ文庫のSF。上下巻の2冊。
これを長男が買ってきました。
https://www.hayakawabooks.com/n/ne70619aa2248
   ※私みたいに図書館で借りるんじゃなく、
    彼は書籍を買ってきます。エライ!

ところが件の長男・・・
 「あかん。 1冊目の半分で挫折や」
 「おとん、読んでみぃ」
っと。
彼曰く、
 「出だしはエエねん。」
 「テンポも良くって、はらはらどきどき・・・」
 「せやけど、そっからあかん・・・」
だと。

で、さらっぴんの本を借りて読んでみました。
私の意見。
 「まっとうなSFやで。 90点!」
っと。

読んでみて、彼が挫折した原因が判明。
著者さん、女性なんです。
出だしの大騒ぎ、どきどきわくわくの話が落ち着くと・・・
  なに食った?  なに食えない。
  なに着てる。  服の色は?
  部屋がどうの。 電話代がどうの。
  宗教がどうの。
こんなのが出てくるんです。上巻の真ん中手前あたり。
  ※これを過ぎると、また「ハードなSF話」も出て
   くるんですが。。。

NASAでのコンピュータの黎明期を描いた映画「ドリーム」。
時代背景がこの頃と重なります。

この本、私は大丈夫。 面白いです。
続きがあれば、読みたいです。
  ※SFマガジンには掲載されてると。

女性作家のSF、たしかに主題でないところの脇話が多いような
気がします。
でも、全体の話がおもしろけりゃ、そんなの気にしない。

航路」のコニー・ウィリスさんも女性作家。
http://act-ele.c.ooco.jp/blogroot/igarage/article/3400.html
これもエエ話でしたが、思えば、「宇宙へ」と似たような匂いを感じます。






| | コメント (0)

2020年9月 1日 (火)

今日のGoogle・・・誰? このお姉さんは?

11_20200901085801

今日のGoogle・・・誰? このお姉さんは?

ということで、幸田文さん 生誕116周年記念だそうです。
幸田文さんの本で「ずごいぞ~」っと思ったのが崩れ
   ※ずいぶん前ですが、図書館で借りて
    むちゃ印象的だった。

「おばあちゃんなのに、何!? この活動的なのは?」
「この本って『科学』だよ」っと。
知識欲ってすごいと感じました。

| | コメント (1)

« 2020年8月 | トップページ | 2020年10月 »