« 2024年3月 | トップページ | 2024年5月 »

2024年4月

2024年4月28日 (日)

数値をBCD出力(表示)するルーチン #2

2022年10月8日:数値をBCD出力(表示)するルーチン
の改良版ということで、文字出力・表示ではなく
BCDの文字列に変換するようにしました。

txbcd()では変換結果の文字を、関数の中でいきなり
シリアル出力していたんで、同じデータを液晶に
表示したいときは、別の処理をしなくちゃなりま
せんでした。
変換結果を文字列にすると、同じ値をシリアル出力と
液晶表示に送り込みたいとき、変換操作が一度ですみます。

BCDへの文字変換ということで「strbcd()」という関数名
にしました。
使い方はほぼ同じです。
変換結果が入った文字列の先頭アドレスを持ってリターンす
るのでそのままSerial.printやLCD.printに渡せます。

/********************************/
/* BCD文字出力処理 */
/********************************/
/***** BCD出力用文字バッファ *****/
static char bcd_bff[16]; // 16文字 終端のnull含めて
// longは10桁
/***** 桁指定BCD文字出力 *****/
// d:変換データ long値
// n:整数部文字数(-を含めて)
// p:小数部文字数(.は含まない)
// 数値は整数を入力 浮動小数点ではない
// 小数部は整数の基数が0.01などの時に用いる
// 12345が123.56を意味する時 (d,3,2)と指定
// -1234を-123.4と表示するときは(d,4,1)と-を含めた文字数に
// bcd_bffに入った文字の先頭アドレスを持ってリターン
char *strbcd(int32_t d, byte n, byte p)
{
byte i;
byte sgn = 0; // 符号フラグ
byte zr = 0; // ゼロデータ処理済みフラグ
char *s; // 0~9書込みバッファのアドレス
s = bcd_bff+sizeof(bcd_bff) - 1; // バッファの最後尾
*s-- = '\0'; // 最後にnullをセット
if(d < 0){ // マイナス?
d = -d; // +の値にして
sgn = 1; // -フラグをオン
}
// 小数部 '.'まで
if(p){ // 小数部あり
for(i = 0; i < p; i++){ // loop
*s-- = (char)((d % 10) + '0'); // 下位桁から0~9に
d = d / 10; // 1/10して上位桁の処理
}
*s-- = '.'; // 小数点
}
// 整数部 上位ゼロサプレス
for(i = 0; i < n; i++){ // loop
if((i == 0) || // 1桁目あるいは
(d != 0)){ // ゼロ以外
*s-- = (char)((d % 10) + '0'); // 下位桁から0~9に
d = d / 10; // 1/10して上位桁の処理
}
else if((sgn != 0) && // 2桁目以降でゼロ、そしてマイナス
(zr == 0)){ // -符号処理まだ
*s-- = '-'; // マイナスを付加
zr = 1; // ゼロでマイナスを処理した
}
else{ // 2桁目以降でゼロ
*s-- = ' '; // ゼロサプレス
}
}
return (s + 1); // 文字列の先頭アドレスを持ってリターン
}

char *s;   // 文字列のアドレスを置いておくポインタ
  s = strbcd(d, 4, 2);   // -999.99~9999.99の範囲をBCDに
  Serial.print(s);   // シリアルとLCDに同じ値を
  LCD.print(s);

こんな格好で使います。
  ※次にstrbcdを使うまでは変化しません

食わせる変換元データdの指定サイズで関数の容量が
変わります。
  例のように4バイトデータ、int32_tなら264バイト
  2バイトのint16_tなら178バイト
でした。
±32768の範囲で処理できるなら、shortにしておけば
だいぶと小さくできます。

以前のtxbcdは前から変換結果を置いていましたが、
今回はバッファの最後から前に向かって詰めて行っ
てます。
そして、分かりやすくするため小数部と指数部に分けて
変換処理したので商計算と剰余計算がそれぞれ2回出て
きます。
このあたりが原因でプログラム(機械語レベルでの)の
サイズが大きくなったのかと思います。

数字の桁数を固定しての表示や出力、たいていの場合
「printf系」の処理が必要です。
確かに便利なんですが、printfを使うとプログラムが
膨れます。

それと、マイナスの数値を出したいときにちょいと不便。
  printf("%4d.%02d", d/100, abs(d%100))
とした時、-123は-1.23と出てくれますが、2桁までの
マイナス値、例えば-12だと 0.12 となり整数部の0、
この頭にマイナス記号が付いてくれません。
「-0.xx」を出すのに悩んでしまいます。

もう一つが、表示幅。
printfだと、桁数指定より大きな数が来た時でも
ちゃんと正しく変換してくれます。
でも液晶表示のように、想定しているより表示桁数が
増えると、表示がずれちゃいます。
本来は、ズレないように数値に規制をかけなくちゃい
けないのですが、「とりあえずのプログラム」だと
めんどうなものです。
今回のstrbcd()で、範囲外の値はマイナス記号も含めて
捨ててしまうので、表示幅は確定します。
  ※異常値出現が分からないというのは
   デメリットでしょうけど。


※2024-05-01追記
リターン値が「nとp」(整数部、小数部)の値で変わるというのも
けったいなので、いつも文字バッファの先頭を持ってリターン
するようにしてみました。
バッファへの文字書込みも、プリデクリメント「*--s」の記号を
使うようにしました。
AVRマイコンのメモリーへの間接アクセス命令は
  ST X,Rr のアドレスそそまま(X以外にY,Z)
そして
  ST X+,Rr のポストインクリメント
あるいは
  ST --X,Rr のプリデクリメント
の3種。
で、「*--s」を使っていみたわけです。
   ※コンパイル結果は残念ながら「ST --X,Rr」には
    展開されてませんでした。
    「ST X,Rr」も「ST --X,Rr」もクロック数は同じ
    なんですが・・・

/*****  桁指定BCD文字出力   *****/
char *strbcd(int32_t d, byte n, byte p)
{
byte i;
byte sgn = 0; // 符号フラグ
byte zr = 0; // ゼロデータ処理済みフラグ
char *s; // 0~9書込みバッファのアドレス
if(d < 0){ // マイナス?
d = -d; // +の値にして
sgn = 1; // -フラグをオン
}
i = n + p; // 文字数
if(p) i++; // 小数点あれば+1
s = bcd_bff + i; // バッファの最後尾
*s = '\0'; // 最後にnullをセット
// 小数部 '.'まで
if(p){ // 小数部あり
for(i = 0; i < p; i++){ // loop
if(d){ // 0でないときは計算
// PB2_H; // (!!!)
*--s = (byte)(d % 10) + '0'; // 下位桁から0~9に
d = d / 10; // 1/10して上位桁の処理
// PB2_L; // (!!!)
}
else{ // 0なら'0'を
*--s = '0';
}
}
*--s = '.'; // 小数点
}
// 整数部 上位ゼロサプレス
for(i = 0; i < n; i++){ // loop
if((i == 0) || // 1桁目あるいは
(d != 0)){ // ゼロ以外
// PB2_H; // (!!!)
*--s = (byte)(d % 10) + '0'; // 下位桁から0~9に
d = d / 10; // 1/10して上位桁の処理
// PB2_L; // (!!!)
}
else if((sgn != 0) && // ゼロでマイナス
(zr == 0)){ // -符号処理まだ
*--s = '-'; // マイナスを付加
zr = 1; // 始めてのゼロを処理した
}
else{ // 2桁目以降でゼロ
*--s = ' '; // ゼロサプレス
}
}
return s; // 文字列の先頭アドレスを持ってリターン
}

もう一つ問題。
printf()やdtostrf()を使った場合より、うんと全体のROM
容量は減らせるんですが、速度がでません。
ループの中にあるlongの割り算に時間がかかります。
   ※ちょいとでも速くとゼロのときをスキップする
    ようにしても、変換桁数が多いと同じ。
longの割り算、商と剰余を使っています。
コンパイル結果は一度の割り算で商と剰余が出る「ldiv()」関数
を使っているようなのですが、割り算の時間はおよそ「40μs」。
変換桁数ぶんだけ時間がかかります。

ところが、浮動小数点を文字列に変換する「dtostrf()」は桁数が
多くなってもそんなに遅くならず、70μs~120μs(8桁)程度。
   ※8桁だとstrbcd()の時間は2倍を超えてしまいます。

binデータの数字文字変換、10で割ってその余りを使う以外に
高速な手法あるのかな。
↓のZ80で使ってるMSBからのcarryを見て10進加算という手法。
32bitなら10文字なんで、あっという間か。
   ※機械語ならあれこれ思いつくんだけど。

=============================
※ちょっと昔話・・・
Z-80でのBCD変換、こんなルーチンを使っていました。

; 16 bit binary カラ BCD ヘ ヘンカン
; HL --->AHL
; FFFF--->65535
BCD:
LD B,16
LD DE,0
LD C,D
BCD01:
ADD HL,HL
LD A,E
ADC A,A
DAA
LD E,A
LD A,D
ADC A,A
DAA
LD D,A
LD A,C
ADC A,A
DAA
LD C,A
DJNZ BCD01
EX DE,HL
RET

16bitのペアレジスタ 、HLに入った0x0000~
0xFFFFの16進数をBCDに変換して「AHL」に
入れてリターン。
  00・00・00 ~ 06・55・35
の数値が得られます。
「DAA」命令が役立っています。
  ※このアセンブラ・ニーモニックを見て動きを
   理解していただける人がどれだけいるか・・・

このようにHEXをBCDに変換した後、次の
16進文字変換ルーチンでASCII文字に直して
「TX」でシリアル出力します。

TXHEXH:         ;上位4ビットの変換 0~9,A~F
RLCA ;hex data (H nibble)
RLCA
RLCA
RLCA
TXHEXL: ;下位4ビットの変換
AND 0FH ;hex data (L nibble)
ADD A,90H
DAA
ADC A,40H
DAA
JP TX ;0~9,A~Fを1文字出力

TXHEX: ;00~FF 2文字16進数出力
PUSH AF ;hex data (byte) (2 chr)
CALL TXHEXH
POP AF
JR TXHEXL
TXHL: ;0000~FFFFF 4文字16進数出力
LD A,H ;H,L (4 chr)
CALL TXHEX
LD A,L
JR TXHEX

ここでも「DAA」が活躍。
0x90を加算してDAA。
その後、carryを含めて0x40を加算してDAA。
これで、「0~9」の10進数字と「A~F」の
16進文字が得られるのです。
この謎の手法を知ったときはほんと驚きました。
条件分岐しないで16進文字が生まれるのですから。

※テストプログラム
ロータリーエンコーダーとI2C液晶(8文字×2行)を
つないでます。
   ・ダウンロード - strbcd02.zip

strbcd()とdtostrf()の速度差をオシロで
見れるようにしました。

| | コメント (0)

2024年4月26日 (金)

治具作りは面白い:2相パルスの発生

仕事を進める上で役立つ動作確認のための「治具」。
本業分野の電子回路だけじゃなく、ちょいとしたメカ工作
が楽しいのです。

今回の出てくる信号は「2相パルス」。
ただ・・・電子的にパルスを出すんじゃなく、現場で使われる
メカを模倣しての細工です。
2相パルスの発信元は「近接スイッチ」。
半分だけアルミテープを巻いた樹脂の円筒をステッピングモータ
で回します。
90度離れた位置に近接スイッチを置いて、2相パルスを得ます。
Mm11_20240426175701

 ・むちゃゆっくりの時、チャッタは出ないか?
 ・ちゃんと正逆を判別して、周期が得られるか。
 ・ケーブルを伸ばしたらどうだ?
 ・供給電圧の変動は?
 ・正逆回転が不安定になった時は?
など、電子的に出す2相パルスでは味わえないホンマモン
の信号が得られます。
速いほうは1200RPMくらいまで上げられました。
  速すぎると脱調!
こんな治具作り、むちゃ楽しいです。

ステッピングモータのドライブ回路はこれ。
  ・2021年7月30日:ステッピングモータを「ゆっくり回す」
ボリュームのツマミでCW/CCWを連続的に変化させれます。

※樹脂製円筒の加工は「文鎮:ハンダ付け補助ツール」
 佐藤テック君に依頼。

| | コメント (0)

「細々」は「ほそぼそ」か「こまごま」か?

トラ技への投稿原稿、あれこれと編集部の手直しが
入ります。
  良い言い直しもありますし、スカタンも出ますし
  いろいろです。
来月6月号に掲載される私の記事の中で、<編集部>の
記名入りでこんな文が校正原稿の中に出てきました。

 『・・・不安定な電池電圧でどう安定動作させるかなど,
  細々と考えるポイントがあります.』
 ~~~~

この「細々」という漢字表記ですが、最初は「ほそぼそ
と読んでしまいました。
で、「あれっ?」っとなって「こまごま」かっと思い直
したのです。

辞書や新聞社の用語集(古いけど毎日新聞と時事通
信社のを置いてある)を見ても両方「細々」で出てきます。
用例でも、両方の読み方とも「細々と」なんてなってい
て「どう読むねん」・・・

私が使った言葉じゃないのですが、日本語は難しいです。


※追記 2024-05-09
トランジスタ技術2024年6月号掲載の記事、
このように「ひらがな」になっていました。
Cc22_20240509083801
p.88の第6章 意外とめんどい電源まわりを解決!
乾電池でマイコンを動かす! 使える基本回路集
というタイトルです。

| | コメント (0)

2024年4月22日 (月)

ユニバーサル基板、ズレている!

共立で買ったICB-96互換のユニバーサル基板 を使って
配線中、基板のパターンに違和感。
  「間隔が狭い!
基板の端の文字を見たら・・・
Y11_20240422084701
  ズレて文字が重なってます

顕微鏡でざっと観察した限り、パターンの接触は回避で
きていました。
24Vを乗り込ますんで、その部分は厳重にチェック。
  配線をだいぶと進めてたんで作り直す
  元気は無かった。

共立のこの基板、すでに販売を終えていますんで、
手持ちもあとわずか。
  ・【販売終了】ユニバーサル基板 /21-116
代替品はこれかな。
  ・ユニバーサル基板 片面フェノール 115×160mm UP-201
1枚440円。

| | コメント (0)

2024年4月18日 (木)

AliExprssで買った小型針式テスター「QQ2.0」

3月末に買ったのが カイセ「KF-6」
K11_20240328124901

もっと他に小型のテスターはないものかと探していたら
AliExpressで 「QQ2.0」 というのが見つかりました。
安価だったのでさっそく注文。

こんな箱。
Qq15

  超薄、超小型 指針式万用表
  THINNER & SMALLER MULTITESTER
というタイトルがプリントされています。
Qq16

Qq11
実際、小さいです。
先日の「カイセ KF-6」と比べても圧倒的。
Qq13
Qq14
レンジも面白くって抵抗レンジの低抵抗側が
「X1」になっていて、「X10、X1K」とは別目盛
になっています。
「1Ωや2Ωが読める」っと。

9V電池用の電池チェックレンジはありませんが、3.7Vを
チェックできる目盛が付いています。

しかし・・・致命的欠点がありました。
メータのダンピングが十分じゃないのです。
制動力が不足しているため、指針の振動が
激しくって行ったり来たり(左右を)を繰り返します。
抵抗レンジでのゼロオーム調整もやりにくいくらいの
針の振れです。
「カイセ KF-6」でも制動不足を感じましたが
それどころではありません。
  ※ひょっとしたら不良品だった?

X(Twitter)にちらりと動画をアップしました。
  ・https://twitter.com/i/status/1780513698924421305

サンワのGP-5、さすがに安定した動きです。

 

| | コメント (0)

2024年4月14日 (日)

使えてあたりまえのものが動かない! 導通チェッカー

電子工作関係のツール類、仕事場に行けばあれこれ
あるのですが、自宅(ガレージ)にもある程度のモノは
置いてあります。
  工具はどちらかというと大モノが対象。
  木工関連の道具や、大きなハンマーやスパナ。
  カンナやノコギリは仕事場には置いてないけど
  自宅にはあるという状態です。

先日のこと、とある電気製品(女房の仕事場からの依頼)
につながった接続リードを通電チェックしようと
したところ(接触不良の調査)、自宅に置いてある
  ・旧バージョンの導通チェッカー
が動かないという事態に遭遇したのです。
V11_20240414162901
設計は古いですが自信作。
すみからすみまで分かっている自作品です。
電源スイッチを押しても反応無し!
単4電池2本で動いているのですが、電池そのものはOK。
でも、家に置いてある 三和の針式テスター「GP-5」
で、基板上のいつも電源につながっているはずの
74HC00の14pin、7pin間電圧を計ってもゼロ。
電源がチェッカーの回路に来ていません。
「そんなあほな」

「そうや。こんなこともあったぞ」と思い出したのが
このトラブル。
自動電源オンの改造をしてからしばらくたった2022年1月。
  ・導通チェッカーに入れていた単4電池が液漏れ
ひょっとしてと、液漏れ跡を探しますと、
マイナス側の黒色リード線を基板に入れている
ところが変色しています。
V12_20240414162901
黒線を引っ張ったら・・・電池ホルダーの根元から
切れてしまいました。
V13_20240414162901
電池の電解液が黒線の内部に侵入、導線を腐食
させて切れてしまったため、通電しなかったのです。
原因が分かれば、納得。
V14
液漏れトラブルの後始末をちゃんとしてなかった
というのが原因でしょう。
面倒でも液漏れ被害にあった電池ホルダーを外して
状態を確認。
洗浄して同時に黒色リードを交換しておけばこんなことは
起きなかったかと。

「自作品が動かない!」というトラブル、なかなか
ダメージ(精神的な)が大きいです。

| | コメント (0)

2024年4月12日 (金)

I2C液晶のアクセス、割り込みで処理しないようにすると

I2C液晶のアクセス、割り込み処理で遅れる原因らしきもの

I2C液晶の処理と高レートのタイマー割り込みとの競合、
その原因がI2C液晶アクセスでの割り込み処理だという
ことがわかりました。

I2Cアクセスでの最後、I2Cバスを待機状態に戻す
「ストップコンディション」の処理に時間待ちが
入れられていました。
  割り込み処理の中での時間待ちはちょっとなぁ。
そのせいで、こんな具合に抜けや遅れが出たのです。
Aa004

Aa000_20240408135301

そこで、I2C液晶の表示ルーチンを割り込みを使わない方法で
書いてみました。
   詳細(スケッチ例)は、また報告します。

普通は液晶アクセスでの遅れなんて問題にしないでしょうが、
特殊な場合はアカンでぇ!ということで、その解決方法の
一例と見てください。

10μ秒割り込みルーチンの抜けや遅れが無くなりました。
Ff000
Ff001
Ff002

割り込みを使うことで処理が早くなったり便利(次の処理に
早く移れる)になるんなら良いのですが、現状の液晶表示
手順の場合は、割り込み処理にするメリットがありません。

I2Cでの割り込み処理、I2Cアクセスでのエラーが生じた時に
対応しやすいという面は否定しません。
でも、液晶表示の場合はエラーが生じても、一連の表示ルーチン
さえ抜ければ次に進めるという処理でかまわないでしょう。
  ロックせずに「STOP」まで進めれば、なんとかなるかと。

I2Cでのエラー解除、本来はSDA=Hの状態(マスター側がHにする
つもりで)でダミークロックを流し込むという手法を使います。
  ※昔のI2C解説本ではよく見たけれど
現状、そういった処理はしていませんので、せっかくの割り込みが
生かされていません。

I2C簡単そうだけどトラブったときの対策、けっこうやっかいです。
  ノイズが多い環境でスカタンしたら
  そのリカバリーがたいへんなんです。
昔々、マイコンに搭載されたI2C機能を使うのが面倒くさくって、
H/Lパルスを自分で出してI2Cを制御したこともありました。
エラー発生時の手順が自由になりますので。

※参考
ROHMのBR24Lxxx EEPROMデータシートより
https://fscdn.rohm.com/jp/products/databook/datasheet/ic/memory/eeprom/br24lxxx-w-j.pdf

・基本のタイミング
Ep11
・リセット方法
Ep12
・コマンドのキャンセル
   SCLをHにしてSDAをL・H
Ep13

※テストプログラムをアップしておきます。
  ・ダウンロード - test_i2c_lcd_acm0802_2b.zip

ちなみに、超低速2相パルス発生回路 のI2C液晶表示を
wireライブラリを使わないようにしたら(wireの中からtwi
を呼んでいる)、プログラムのサイズが1.8kバイトほど減少。
RAMエリアも200バイトほど減りました。
単一の液晶表示のように、単純に「書くだけ」だとずいぶん
処理が簡単になるというのが理由かと。



| | コメント (0)

Ni-Cd組み電池をニッケル水素電池に交換

とある計測器の修理案件。
装置に内蔵されていたニッカド電池が寿命で5セルの
うち2セルが短絡して死亡。
電池を装置から取り外し、別電源で充電しても電圧が
上がらないという状態になっていました。
これをニッ水電池に交換できればという修理依頼でした。

元の電池は単2サイズのNi-Cd電池を5本直列にして
定格6Vで使われています。
ところが、組み込むスペースの関係で「3本+2本」
という変則的な形状になったのが使われていたのです。

装置の消費電流はさほど大きいものではなく、60~80mA。
そこで、単3サイズのニッ水組み電池を使うことにしました。
しかし・・・ 
5本を並べて直列につないである電池だと、元のスペースに
収まりません。
そこで、「3本+2本」と山形になった組み電池を使うことに
したのです。

新しく買った電池と古いNi-Cd電池の形状。
Ba10
ずいぶん小さくなりました。
Ba11

問題は充電器。
5本直列をうまいこと充電してくれなければなりません。

一つは組電池に付属していたUSBタイプのもの。
入力5Vで出力が6V・250mAとスペックが記されています。
Ba12

もう一つはACアダプタ形状のもので、10直までの組み電池に
対応しています。
別売りのを買いました。
「-ΔV」を検出して充電を止めるようになっていると説明書に
記されていました。
Ba13
Ba14

アマゾンの広告ページ。
Baa2

Baa1

まずはやってきたばかりの電池の放電テスト。
47Ωの抵抗をつなぎ、5.0Vジャストまで電圧が
下がったら放電を止めるようにしました。

Bd1
電流およそ130mAで4.6時間でしたので600mAhほど
の容量が残っていたと計算できます。

放電したところで、ACアダプタタイプの充電器での充電を
試しました。
パルス状の電流で充電が進みます。
Bd2
チャートレコーダがとらえた充電電流のピーク電流が0.8A。
1.6時間ほどで「-ΔV」が現れ、主充電が止まりました。
その後は、ゆるいデューディ比で補充電が行われます。

この状態で放電したのがこのグラフ。
Bd3
33Ωの負荷抵抗で8.7時間経過で5.0Vまで下がりました。
推定容量およそ1600mAh。
電池には2400mAhと記されているんですが、まぁ
こんなもんでしょう。

付属のUSB充電器での様子がこれ。
Bd4
6時間ほど経過すると充電ランプが消えました。
しかし、いつまでたっても充電電流は流れたままで、
自動では止めてくれないようなのです。
150mAほどの充電電流ですが、過充電は気持ち悪いの
で手で止めました。

さて・・・このモノ。 こんなのです。
  (クリックで拡大↓)
Be1

これでは読めないので、翻訳結果ももらっておりました。
Be2

装置の外観と試料としてやってきた怪しい石。
Bb12_20240412171801
近づけると・・・計器が反応します!

・テストピース:フェルグソン石
Ssy

倉敷市自然史博物館:放射性鉱物の例



| | コメント (0)

2024年4月 7日 (日)

トラ技2024年5月号に「3.3/65535」

トランジスタ技術の最新号、2024年5月号を
パラパラめくりしていたら、p.70のリスト1に
怪しい記述を発見。
A/D値から電圧値を計算するための定数を出す
のに「3.3/65535」と。

Pp21
65536と65535の差はほんの僅か。

でも、リストの7行目のPID演算のところで、
6桁の数値が出ているんで、5桁数値の最小桁で
の1違いは大きくないかいなとちょいと心配。

電源電圧「3.3V」も、「ほんまかいな」だし。

元データはA/D値のまま使い、「CAL(校正)したらこうなった」
にして、「浮動小数点化したmap関数」を使って線形補間して
答えを出すてなほうが「理にかなっている」ような気がします。

ラズピコだと1/65535が出現:トラ技2022年5月

※検索
ラズパイマガジン2022年12月12日の訂正
   ・・・本文中の「1023」は「1024」、図2下の式の
  「4095」は「4096」の誤りです。
   ・・・Raspberry Piのところで分割数が「4095」と
  あるのは「4096」の誤り、Raspberry Pi Picoでは
  「65535」が「65536」、micro:bitとArduinoでは
  「1023」が「1024」の誤りでした。
訂正が出ています。

 

| | コメント (2)

I2C液晶のアクセス、割り込み処理で遅れる原因らしきもの

超低速2相パルス発生回路・ケース入れでの処理遅れ、
I2Cの処理をしているソース「twi.c」をざっと追いか
けてみると、

・TWI(I2C)の割り込み処理
  ISR(TWI_vect)
 この中にtwi_stop()というルーチンが出てくる。

・twi_stop()の処理を見ると、
  _delay_us(10); という時間待ちがある。
     ※実際にこれが動いているのかどうかは不明

・_delay_us()がどこにあるのか探してみると
  util\delay.hの中
・関数のヘッダは void _delay_us(double __us)
  「double __us」って何よ。

・もし、_delay_us(10)で10us遅らせているとしたら、
 オシロでの観察結果と合っている気がする。

割り込み処理の中では時間待ちはするなぁ~
  っと叫びたくなるゾ!

※追記
波形観察できるよう、簡単にテスト。
・タイマー0を停止
   じゃまされないよう
・タイマー1で10us割り込みを作る
   割り込み期間、Hパルスを出力
・I2C液晶を使い1秒間隔で2文字を表示
   カーソル位置指定+2文字書込みの3データ
・10usパルスはいつも見えるはず
・I2Cの割り込みと重なった時にズレが出る

ところが・・・そのズレの量が大。
I2Cのストップコンディションと重なった部分の
割り込みパルスが1つ消失して、その後の1つ
が遅れて出現しました。

Aa000_20240408135301
終端部を拡大 (時間経過でSDA波形が↑のと異なります)
Aa004

I2C(TWI)の割り込みが悪さをしてるとしか考えられない。
割り込みを使わないでI2Cを処理するプログラムを
書かないといけないなぁ。
マスターだけならそんなに難しくないけどついつい
ライブラリを頼ってしまうんで。

もう一度言います!
  『割り込み処理の中では時間待ちはするなぁ~

Wire.cはI2C処理の手順を示すだけで実際の
ハードウェアアクセスはutility/twi.cの中でごそごそ。

※さらに追記
メインループの先頭でLEDポート(PB5)をトグル出力させると
いろんな処理時間が見えてきます。

今回の10usタイマー割り込みと液晶アクセスは
こんな具合。
A1000

一番下のch4の波形がトグル出力。
なにもせず(メインループがヒマ)グルグル回っていると
フルスピードでパルスが出ます。
しかし、何かの処理が長引くとトグル出力が一次停止
します。

液晶アクセス中にメインが回っていないということは、
何のための割り込み処理なの?
っと、思っちゃいます。
割り込み処理してるんだったら、ひとかたまりを
書き終わったら、メインに戻ってきて欲しいところ。
I2Cの送出完了でバッファから読み出し、無くなるまで
順次転送ということをしてくれたら良いのになぁっと。
  シリアル送信なんかはそうなっている。

10us割り込みのところを拡大すると。
A1001

割り込み処理そのものに加えて、その前準備と後始末に
けっこう時間が食われているのが見えます。
割り込み内で出しているパルスの前後に見えない
時間があるということが、メインループで出す
トグルパルスで見えてきます。

| | コメント (0)

2024年4月 3日 (水)

超低速2相パルス発生回路・ケース入れ

2024年3月25日:超低速2相パルス発生回路 の続き。
こんな回路に落ち着きました。
Cw_ccw1b
・電池3本運用。
・秋月の昇圧DC-DCモジュール
   AE-XCL102D503CR-G で5Vを発生。
   ただし、ちょい改造(EN端子のプルアップを外す)
・電源スイッチと操作スイッチを共用。1つだけ。
   長押しで電源のon/off操作。
   短押しでCW/CCW/stop選択。
   このためにあれこれややこしい回路に。(黄色部)
・最低周波数が0.1Hz。
 最高周波数を(無理やり)9990.0Hzに。
・周波数によって設定できる最小桁が変化。
 150Hzまでは0.1Hz。2800Hzまでが1Hz。それ以上が10Hz。
・1.5kHz程度までは、設定値から0.01%内の誤差。
 10Hzステップになる2.8kHzあたりだと0.016%。
 5kHzあたりまで上がると0.03%。
 最高周波数に近づくと分周比が小さくなり誤差が目立ちます。
 0.06%ほどの誤差が生じることがあります。
・例えば9810Hzの設定なら分周比が815で
 出てくる周波数が9815.95Hzとなって+0.061%の差。
 また、9970Hzも9980Hzも同じ分周比802になり
 出てくるのはどちらも9975.06Hz。
 でも、8000Hzの設定は誤差ゼロで出てきます。

バックアップがわりのスケッチ。
  ・ダウンロード - cw_ccw2k1b.txt
    ※inoではなくtxtにしてます。

箱はダイソーで買ったプラケース。
  (電池保管用のものだったか・・・)
Cc11_20240404142901

Cc12_20240404142901

LowBat警報表示
Cc14_20240404142901
Cc15
電池電圧が3Vを切ると、空電池マークと半分電池
マークを交互に点滅表示します。
  重要アラームは点滅させて欲しい
   なんて記事も書いてますし。

内部処理でキツいのが周波数を上げたとき。
最高が9990Hzですので、その2倍の周波数
(トグルさせるので2倍に)でタイマー1の
コンペエマッチ割り込みが発生します。
周期が50μ秒ほどとなって、16MHzのATmega328P
にはなかなかキツい。
この割り込みの他に、システムタイマーであるタイマー0の
オーバーフロー割り込みを止めて、別の周期、
3.90625kHz=0.256msのタイマー割り込みを
使っています。
これの主目的はロータリーエンコーダのチャタリング除去。

2つの割り込み処理のタイミングを見てみます。
   オシロの無限残光モードがありがたい
Cs000

Cs001

B相出力が変化する前にタイマー1のコンペエマッチ
割り込みを終えなければ、2つのパルスを正しい
タイミングで出力できません。

タイマー割り込みの処理時間がけっこう長いので、
これが問題。
シリアル出力すると、この割り込み処理による
遅延も入ってきます。
  ※I2C液晶制御でも割り込み絡むのか?
最高周波数になると、タイミングはなかなか
キビシイです。

ロータリーエンコーダの読み取りタイミング。
Cs003
I2C液晶での文字表示(xxxx.xHzの8文字)に
いがいと時間がかかります。

| | コメント (2)

« 2024年3月 | トップページ | 2024年5月 »