町会長旅行、中止に
この日・月に予定していた中川連合・町会長旅行(牡蠣を食べに行こう)、中止(延期)です。
コロナ騒動が落ち着いてから行こうということに。
ガレージのシャッター上に取り付けていたコーナンの
「LDA6N-H 6.0W 昼光色」LED電球、先日来
「えらい暗なってきたな~」ということで、昨晩交換しました。
取り外したLED電球、ベースに「2013-2-6」と日付が書いてあった
ので、使用期間はざっと7年。
自動点滅器で夜になったら一晩中点灯という接続にしていたので、
点灯時間の推定は3年半、3万時間というところ。
「電源回路のコンデンサでもアウトになったかな~」っと解体。
すると・・・
電源部のコンデンサや部品は大丈夫そう。
液漏れや部品の焼け、ハンダ割れは見当たりません。
使ってあるLEDは全部で10個。
2パラしたものが5直になっています。
チップLEDそのものも中のLED素子が2つ直列に。
32V加えてやっと点灯。
すると・・・
10個のうち3つがアウト。
直列ですので、どこかが切れたら完全に消灯するはず。
LEDは光らないけれど、断線はしてませんでしたんでとりあえず
点いていたという状況です。
さらによく観察すると・・・
7時方向のLED、内部に2つあるLEDのうち1つしか生きていません。
正常なLEDはこんな光りかた。
光っていない方のLEDが破裂したみたいになっていました。
※関連
・2016年01月03日:パナソニックLED電球 LDA7D-A1 寿命!
・ダイソーの400円LED電球 (LDA8L-G-T/60W)長期間点灯実験終了
・修理:LEDクリップライト、点滅!
電球形蛍光灯の故障原因、電源回路のコンデンサやらパーツの焼けが
目立ってましたが、LEDランプのトラブルは電源回路よりLEDそのもの
がアウトになってますなぁ。
JIS C8708:2019充放電試験 「又は」の解釈はの続き。
今回の制御ソフト、こんな設定パラメータを持っています。
※設定値はEEPROMに保存。
データの
アドレス 初期値
↓ ↓
NULL ,EP_CK // 0 - Ret Menu -
&cur_c010 , 190 // 1 0.1C 充電電流設定値 (0~1600mA) ※1
&cur_c050 , 950 // 2 0.5C 充電電流設定値 ※1
&cur_d020 , 380 // 3 0.2C 放電電流設定値 ※1
&cur_d050 , 950 // 4 0.5C 放電電流設定値 ※1
&cur_d49 , 950 // 5 49cyc 放電電流設定値 ※1
&time_c010, 960 // 6 0.1C 充電時間 (分) 960分:16時間
&time_c050, 132 // 7 0.5C 充電時間 (分) 132分:2時間12分
&wait_c49 , 20 // 8 1~49cyc 充電後待ち時間 (分) 20~30分
&wait_d49 , 10 // 9 1~49cyc 放電後待ち時間 (分) 10~90分
&wait_c50 , 60 // 10 50cyc 充電後待ち時間 (分) 60~240分
&wait_d50 , 60 // 11 50cyc 放電後待ち時間 (分) 十分な
&v_stop48 , 100 // 12 1~48cyc 放電停止電圧 1.00V
&v_stop49 , 100 // 13 49cyc 放電停止電圧 1.00V
&v_stop50 , 100 // 14 0cyc,50cyc 放電停止電圧 1.00V
&dv_mv , 10 // 15 -ΔV (mV) 5,10mV
&dv_time , 10 // 16 -ΔV 検出開始時間 (分)
&ad_ref100, 120 // 17 A/D基準値 1.00V ※2
&ad_ref180, 776 // 18 A/D基準値 1.80V ※2
&pwm_c010 , 242 // 19 充電電流PWM 0.1A基準値(0~4095) ※2
&pwm_c150 , 3632 // 20 充電電流PWM 1.5A基準値 ※2
&pwm_d010 , 240 // 21 放電電流PWM 0.1A基準値 ※2
&pwm_d150 , 3767 // 22 放電電流PWM 1.5A基準値 ※2
&txcyc_1m , 0 // 23 1分ごとデータ送出有無 0/1
&tx_d50 , 0 // 24 50cyc放電時電圧送出有無 0/1
&t_spdup , 100 // 25 タイマー加速データ 通常100
&chk_cyc , 50 // 26 測定最大サイクル 通常50回目で放電記録
&end_cyc , 8 // 27 最終測定サイクル 1~8 EEPROMの容量
NULL ,EP_CK // 28 - Ret Menu -
// ※1 電池により設定 ※2 要調整の数値
データ番号0と28、「- Ret Menu -」となっているところには
マジックナンバーを入れて、初めての電源オン(EEPROMに
有効なデータが書かれていない)をチェックしています。
そして、「-ΔV又は132分」制御に関係するのは以下の3つ。
データ番号7 time_c050
データ番号15 dv_mv
データ番号16 dv_time
time_c050は1cyc~49cycでの0.5C充電時間 (分)で、
132分のタイムアップ時間を設定。
dv_mvは-ΔVの検出電圧を「mV」値で設定。
dv_timeは-ΔV検出を有効にするまでの遅延時間(分)。
タイマーに関する制御条件の設定、こんな具合になります。
(1) 「dv_time < time_c050」 だと、dv_time経過後に
-ΔV検出が有効になる。 (普通はこれで)
ただし、-ΔVが見つからなかったらtime_c050で
充電停止。
(2) 「dv_time >= time_c050」 だとtime_c050経過まで
-ΔV検出が始まらないので、-ΔVは無視してtime_c050
で充電停止。
(3) 「dv_time < time_c050」という設定で、time_c050を
規定の132分より長くしておけば、その時間内で-ΔV
を待って充電停止。
もし-ΔVが見つからなくても最大はtime_c050まで。
だもんで、132分で充電を止めるのではなく、
「電池が元気な間は-ΔVを見つけたい」という制御にも
パラメータの設定で対応できます。
(1)と(2)で「-ΔV又は132分」の切り替え(どちらか一方)
ができます。
(3)にすると「132分で止めない-ΔV」という制御になります。
意図して設けた区分ではありません。
設定値によって「たまたま」こういう制御になるなぁということで。
私が使っている2015年11月製の鉄製文鎮:ハンダ付け補助ツール、
無塗装、無メッキ、手入れしていない・・・
でも、そんなに錆びてないでしょ。
せっかくですんで、クリップを外して油を塗っておきますわ。
ついでに、他の鉄製工具(ペンチ、ニッパ、ストリッパ、圧着器など)も
油をつけたウエスでゴシゴシと。
※文鎮:ハンダ付け補助ツールまとめ
使い勝手や感想などは、↑の適当な記事にどうぞ。
昨日より新しい「ReVOLTES単3」を使っての充放電実験を始めています。
こんなチャートが出てきてます。
そして、ログ用のシリアル出力データはこんな具合。
~~~~~~~~~~~~~~~~~~~
#Start
#D 0.2C 0cyc 0/8 0h00m 1.293V
#D 0.2C 0cyc 0/8 4h03m 1.000V
#D-Wait 0cyc 0/8 1h00m 1.167V
#Next
#C 0.5C 1cyc 1/8 2h12m 1.549V #1
#C-Wait 1cyc 1/8 0h20m 1.440V
#D 0.5C 1cyc 1/8 1h59m 1.000V @1
#D-Wait 1cyc 1/8 0h10m 1.177V
#C 0.5C 2cyc 1/8 2h12m 1.557V #2
#C-Wait 2cyc 1/8 0h20m 1.449V
#D 0.5C 2cyc 1/8 2h01m 1.000V @2
#D-Wait 2cyc 1/8 0h10m 1.176V
#C 0.5C 3cyc 1/8 2h12m 1.562V #3
#C-Wait 3cyc 1/8 0h20m 1.454V
#D 0.5C 3cyc 1/8 2h01m 1.000V
~~~~~~~~~~~~~~~~~~~
#1~#3、@1、@2がチャートと対応しています。
「#C」が充電、「#D」が放電制御です。
その充電完了の時間を見ますと、
「-ΔV検出で止まったのじゃなく132分経過で充電停止」
しています。
充放電の時間比率は、
放電 / 充電
1cyc 119分/132分 90.2%
2cyc 121分/132分 91.7%
3cyc 121分/132分 91.7%
と、およそ9割。 こうなると、
「0.5C充電(2時間)の1割増しの時間にしておく」という
132分の充電時間、合ってそうな気がします。
ニッ水電池のJIS規格 C8708:2019 で定められた充電制御方法の
「又は」の解釈に悩みが出てきました。
・1~49サイクル:
充電:0.5Cで-ΔV又はタイマー制御(a)で充電。
静置:20~30分間静置。
放電:0.5Cで1.0Vまで放電。
静置:10~90分間静置。
(a)-ΔV=5~10mV又は132分間。
132分ということは、0.5C容量の1割増しの時間。
この充電制御方法の「又は」の解釈。「OR」条件で、
・「-ΔV」あるいは「132分」どっちでもOKよ。
こう考えられます。
今回の制御プログラムではこんな処理を行ってます。
・充電開始とともにタイマースタート。
・-ΔV検出処理を遅らせるタイマー値を設定していて、
充電開始直後の何分間は-ΔV処理をしない。
・「-ΔV検出」あるいは 「132分」経過で充電停止。
-ΔVが見つからなくても充電は132分で停止。
(a)の「又は」解釈なんですが、
(1)132分で充電する時は-ΔVは無視してもokよ。
(2)-ΔVで充電制御する時は132分を越えて充電してもokよ。
(1)の解釈は「又は = OR条件」というふうに考えると正しいかと。
しかし、(2)はいかがでしょう。
「-ΔV」を選んだ時は「132分」を無視して良いのかどうか・・・。
今は132分をリミットにして充電しています。
今回のように新品電池での充電では、-ΔV検出より先に132分が経過
しちゃいました。
132分を越えても「-ΔV」を待つべきだったか・・・
※市販の充電器は電池容量が不明なので「-ΔV」でしか
充電完了を知るすべがないわけでして。。。
方法としては、
・-ΔV充電か132分充電かどちらかを選ぶ。
(又はの解釈→「どちらでも」ではなく「どちらかを」)
・132分充電を選んだのなら-ΔV制御はなし。
・-ΔV充電を選んだのなら132分での充電停止は無し。
(安全のため、別の停止用タイマーを設けておく)
こんな制御方法も考えられます。
どんなもんなんでしょうね。
仕事場のほうで、イベント用機材
・大声コンテスト用・大声測定器「大声トライアル」
・「ボコスカ・ハンマー」
を貸し出しています。
新型コロナウィルスによる感染防止ということで、レンタル予約していただいて
いたイベントが中止になったとの連絡がやってきました。
地元生野区でも、講演会や音楽会、防災リーダーの訓練講習が中止になったりと
あれこれ影響が出ています。
地元中川では、4月の第一日曜に「桜まつり」を予定しています。
今のところ「決行」ということで準備を進めていますが、さてどうなりますか。
次の「日・月」は広島への町会長旅行。
はてさて。
試運転中のJIS C8708:2019充放電試験回路
その「-ΔV」検出の様子をご覧ください。
※テストですんで新品の電池ではなく、
「ダイソーReVOLTES」JIS C8708:2019充放電試験 50サイクル目
で、ソフトのバグでデータ取得をミスった時に使ったダイソーの
ReVOLTES単3。
すでに200回の充放電試験を経ています。
新JISでの充電条件が(サイクル1~49)
「0.5Cで-ΔV又は132分のタイマー制御」
「-ΔVは5~10mV」
と記されています。
このテストでは-ΔV値をとりあえず「10mV」に設定。
1分サイクルでシリアル出力する経過時間と電圧値
を観察してみます。
(7サイクル目の途中まで)
~~~~~~~~~~~~~~~~~~~~~
#C 0.5C 1cyc 1/5 1h39m 1.670V
#C 0.5C 1cyc 1/5 1h40m 1.670V
#C 0.5C 1cyc 1/5 1h41m 1.670V ★Peak #1
#C 0.5C 1cyc 1/5 1h42m 1.668V
#C 0.5C 1cyc 1/5 1h43m 1.668V
#C 0.5C 1cyc 1/5 1h44m 1.667V
#C 0.5C 1cyc 1/5 1h45m 1.666V
#C 0.5C 1cyc 1/5 1h46m 1.665V
#C 0.5C 1cyc 1/5 1h47m 1.663V
#C 0.5C 1cyc 1/5 1h48m 1.662V
#C 0.5C 1cyc 1/5 1h49m 1.661V
#C 0.5C 1cyc 1/5 1h49m 1.660V ★Stop
#C-Wait 1cyc 1/5 0h01m 1.520V
:
#D 0.5C 1cyc 1/5 1h07m 1.000V ←放電時間
~~~~~~~~~~~~~~~~~~~~~
#C 0.5C 2cyc 1/5 1h09m 1.689V
#C 0.5C 2cyc 1/5 1h10m 1.689V
#C 0.5C 2cyc 1/5 1h11m 1.689V ★Peak #2
#C 0.5C 2cyc 1/5 1h12m 1.688V
#C 0.5C 2cyc 1/5 1h13m 1.687V
#C 0.5C 2cyc 1/5 1h14m 1.685V
#C 0.5C 2cyc 1/5 1h15m 1.684V
#C 0.5C 2cyc 1/5 1h16m 1.682V
#C 0.5C 2cyc 1/5 1h17m 1.680V
#C 0.5C 2cyc 1/5 1h17m 1.679V ★Stop
#C-Wait 2cyc 1/5 0h01m 1.529V
:
#D 0.5C 2cyc 1/5 1h05m 1.000V ←放電時間
~~~~~~~~~~~~~~~~~~~~~
#C 0.5C 3cyc 1/5 1h06m 1.698V
#C 0.5C 3cyc 1/5 1h07m 1.698V
#C 0.5C 3cyc 1/5 1h08m 1.698V ★Peak #3
#C 0.5C 3cyc 1/5 1h09m 1.696V
#C 0.5C 3cyc 1/5 1h10m 1.695V
#C 0.5C 3cyc 1/5 1h11m 1.694V
#C 0.5C 3cyc 1/5 1h12m 1.691V
#C 0.5C 3cyc 1/5 1h13m 1.690V
#C 0.5C 3cyc 1/5 1h13m 1.688V ★Stop
#C-Wait 3cyc 1/5 0h01m 1.533V
:
#D 0.5C 3cyc 1/5 1h03m 1.000V ←放電時間
~~~~~~~~~~~~~~~~~~~~~
#C 0.5C 4cyc 1/5 1h03m 1.704V
#C 0.5C 4cyc 1/5 1h04m 1.705V
#C 0.5C 4cyc 1/5 1h05m 1.705V ★Peak #4
#C 0.5C 4cyc 1/5 1h06m 1.704V
#C 0.5C 4cyc 1/5 1h07m 1.702V
#C 0.5C 4cyc 1/5 1h08m 1.701V
#C 0.5C 4cyc 1/5 1h09m 1.700V
#C 0.5C 4cyc 1/5 1h10m 1.698V
#C 0.5C 4cyc 1/5 1h10m 1.695V ★Stop
#C-Wait 4cyc 1/5 0h01m 1.535V
:
#D 0.5C 4cyc 1/5 1h01m 1.000V ←放電時間
~~~~~~~~~~~~~~~~~~~~~
#C 0.5C 5cyc 1/5 1h02m 1.710V
#C 0.5C 5cyc 1/5 1h03m 1.710V
#C 0.5C 5cyc 1/5 1h04m 1.710V ★Peak #5
#C 0.5C 5cyc 1/5 1h05m 1.709V
#C 0.5C 5cyc 1/5 1h06m 1.707V
#C 0.5C 5cyc 1/5 1h07m 1.706V
#C 0.5C 5cyc 1/5 1h08m 1.704V
#C 0.5C 5cyc 1/5 1h09m 1.701V
#C 0.5C 5cyc 1/5 1h09m 1.700V ★Stop
#C-Wait 5cyc 1/5 0h01m 1.538V
:
#D 0.5C 5cyc 1/5 1h00m 1.000V ←放電時間
~~~~~~~~~~~~~~~~~~~~~
#C 0.5C 6cyc 1/5 0h59m 1.713V
#C 0.5C 6cyc 1/5 1h00m 1.715V
#C 0.5C 6cyc 1/5 1h01m 1.716V ★Peak #6
#C 0.5C 6cyc 1/5 1h02m 1.715V
#C 0.5C 6cyc 1/5 1h03m 1.715V
#C 0.5C 6cyc 1/5 1h04m 1.713V
#C 0.5C 6cyc 1/5 1h05m 1.711V
#C 0.5C 6cyc 1/5 1h06m 1.710V
#C 0.5C 6cyc 1/5 1h07m 1.707V
#C 0.5C 6cyc 1/5 1h07m 1.706V ★Stop
#C-Wait 6cyc 1/5 0h01m 1.540V
:
#D 0.5C 6cyc 1/5 0h59m 1.000V ←放電時間
~~~~~~~~~~~~~~~~~~~~~
#C 0.5C 7cyc 1/5 0h57m 1.716V
#C 0.5C 7cyc 1/5 0h58m 1.718V
#C 0.5C 7cyc 1/5 0h59m 1.720V
#C 0.5C 7cyc 1/5 1h00m 1.720V ★Peak #7
#C 0.5C 7cyc 1/5 1h01m 1.718V
#C 0.5C 7cyc 1/5 1h02m 1.717V
#C 0.5C 7cyc 1/5 1h03m 1.716V
#C 0.5C 7cyc 1/5 1h04m 1.715V
#C 0.5C 7cyc 1/5 1h05m 1.712V
#C 0.5C 7cyc 1/5 1h05m 1.710V ★Stop
#C-Wait 7cyc 1/5 0h01m 1.541V
:
~~~~~~~~~~~~~~~~~~~~~
0.5Cでの充電をはじめておよそ1時間してピーク電圧を
検出。
その数分後に10mVのドロップを検知して充電停止。
こんな充電制御が続いています。
2時間12分(132分)のタイマーで止まったのは、この7つ
のサイクルの中ではありませんでした。
※200サイクルの試験を経た古い電池だから
充電の次の工程、時間待ち後0.5Cで1.0Vまでの放電。
充電時間と放電時間を抜き出してみると・・・
充電時間 放電時間 充放電時間比
1cyc 1h49m 1h07m 67/109 = 61.5%
2cyc 1h17m 1h05m 65/77 = 84.4%
3cyc 1h13m 1h03m 63/73 = 86.3%
4cyc 1h10m 1h01m 61/70 = 87.1%
5cyc 1h09m 1h00m 60/69 = 87.0%
6cyc 1h07m 0h59m 59/67 = 88.1%
1サイクル目は0.2Cで1.0Vまでゆっくりと放電したんで、
充電時間が長くなったようです。
その後は84%~88%の時間比で放電が行われています。
そしてチャートで記録している電池側面の温度変化を
見ると温度上昇は5℃ほど。
-ΔV制御無しで132分充電した場合に比べると、
優しい温度上昇になっています。
※以前の実験の温度変化 15℃ほど上昇。
a1_20200210151501.jpg
もう少し様子を見てから(初めて動かすプログラムなんで)
新品電池をセットして試験をしてみます。
※追記
「-ΔV検出」による充電停止と、「132分充電」で電池の
側面温度がどうなるかしらべてみました。
#1~#7が「-ΔV充電」の時。 (↑の記録を採った時の)
およそ5℃くらいの温度上昇。
@1~@3が「132分充電」。
電圧波形を見ると、-ΔVが現れているのにまだ充電が行わ
れている様子がわかります。
それに連れて温度も上昇。 10℃くらい上がっています。
※ナダ電子のプリンターシールドでの記録
「132分充電」後の放電結果を見てみると・・・
(チャートの@1~@3のところ)
放電時間 充放電時間比
@1 1h09m 69分/132分 = 52.3%
@2 1h07m 67分/132分 = 50.8%
@3 1h07m 67分/132分 = 50.8%
1.0Vまでの放電時間は-ΔV制御で充電したのと
(↑の#1~#6)ほとんど同じでした。
つまり、-ΔV発生以降の充電エネルギーは無駄に
なっていて、電池を暖めているだけということが
見えてきます。
このあたりもニッ水電池の寿命に関係してくるかと
推測できます。
市販の急速充電器での充電と自作放電器 での充放電繰り返し実験
では見えてこない部分が、今回の「-ΔV検出制御」で見えてきた
ような気がします。
2019年11月 7日文鎮:SUS304・16mm厚ハンダ付け補助ツール あと7コの
「2020年2月20日 19時19分」にコメントしましたように、
2018年6月20日文鎮:ハンダ付け補助ツ-ル …形状違いの素材
の穴あけ試作品を佐藤テック君が持ってきてくれました。
M5タップが2カ所開けているんで、クリップをいろんな方向に付けられます。
こんな穴(M5タップ)位置です。
「22mm厚」の素材バーを「シカル」で「V字」に切削。
その加工されたものの端材をクリップ幅に切断しています。
で、この材質ですが、佐藤テック君曰く、
「S50CかS45C・・・たぶんハガネ だろう。」
「SS400などの普通の鉄ではない。」かっと。
※ちゃんと調べてくると。 →SS400でした。っと。
重さが「515グラム」。
だもんで、クリックポストでは一つしか送れません。
レターパック・ライト(370円)、レターパック・プラス(520円)
とも、制限重量が3kgですので、2つ以上の場合はこちらを。
※クリックポストとレターパック・ライトは、郵便受け
へ放り込まれますんで、受け口が狭いと入りません。
そんな場合はレターパック・プラスを使ってください。
手渡しになります。
頒布価格ですが「1,200円」でよろしくっと。
これにクリックポスト代金「188円」が加わります。
M5のキャップボルトとワッシャ、クリップ口に付けるゴム板
を添付します。
素材を削ったまま、塗装もメッキも無しで。
クリップはご自身で入手してください。
集めた端材で何個作れるかは現時点不明ですが、ご希望の方は、
この記事にコメントして(メールアドレスを記入して)ください。
※ハンダ付け補助ツール(文鎮)まとめ
※2020-02-25
今回の製作、残1つです。 (4月15日、完売しました)
佐藤テック君、昨晩ガレージにやってきて「ドリルの刃、折ったぁ」
っと、泣いていました。
JIS C8708:2019充放電試験回路製作中、ざっと
制御ソフトが出来たので試運転中です。
今回はJIS C8708:2019の充電条件へ対応。
「0.5Cで132分 又は -ΔV(5mV~10mV)」
これに対応するため、電池電圧を読むA/D入力に
アンプを入れました。
Arduino(ATmega328P)のA/Dコンバータは10bit。
基準電圧を2.5Vにして0~2.5Vをそのまま入力
すると1ビットが約2.44mV。
5~10mVの-ΔVを拾うとすると、その変化量は
2~4ビットと微少。
もうちょい分解能が欲しいか、ということでこんな
アンプをA/Dの前段に入れました。 (U6 1,2,3のところ)
考え方
・電池の寿命試験で電池電圧を測るのに0V付近は不要。
・0.9Vくらいから2.0Vの範囲を測れたらよいんじゃないか。
・A/Dの分解能を1ビットを1mVくらいにしたい。
・とりあえず、入力範囲を0.85V~2.1Vにして、測定スパン
を1.25Vに。
・これを2倍に増幅。
・1ビットはきっちり1mVにはならないで約1.22mV。
こんな回路になっています。
また、A/D入力処理も、速度は不要なんで
・1mSごとのA/D変換で、256回の加算平均処理。
256回分10ビットのA/D値を加算合計して、256回目に
1/256して平均値を算出。256mSごとにA/Dデータが確定。
・この平均値を16回移動平均。
リングバッファの古いのを捨てて新しいのを加える。
・さらに、バッファのデータをソートして、上下それぞれ
4つのデータを捨て(maxに近い4つとminに近い4つ)、
8つの中央値で平均計算。
・256mSごとにこのスムージング処理したデータが確定。
16回なんで、A/D入力値が安定するまで約4秒。
・これで、一瞬の短絡や開放はデータに出てこない。
こんな処理で-ΔVを見つけるようにしました。
これでうまく処理できるか、試運転中です。
※OP-AMPについて
今回使ったMCP6072、電源電圧5V以下で使うならおすすめです。
特徴
・安価 100円くらい ただしDIPは無い
・レール to レール入力/出力
・ゲインバンド幅 1.2MHz
・低オフセット電圧 0.15mV(max) ★
・入力バイアス電流 1pA (CMOSなんで)
・低消費電流 0.11mA
・動作電圧範囲 1.8V~6V
オフセット電圧の小さなCMOSアンプって、なかなか
ないんですよね。
ただ、DIP品が無いので試作にはピッチ変換基板が必須です。
※追記
・1msタイマー処理とその中で起動されるA/D変換。
・A/D割り込みで行う256回のA/D値平均処理。
↑
この2つの処理は割り込みで行うので、時間待ちは無し。
勝手にA/D平均データが上がってきます。
この中でスイッチ入力処理とブザー報知処理も実行。
液晶画面表示を行っていると、スイッチのチャタリング除去
処理やブザー報知の処理が遅れることがあるんで、タイマー
割り込みの中で勝手に処理するようにします。
・メインルーチン内でf_adokフラグをチェックして
行う256msごとのA/D値スムージング処理。
ソートを行うので、割り込み内からは出してます。
これを示しておきます。 (スペースは全角で)
/********************************/
/* 1ms タイマー割り込み */
/********************************/
// 関数プロトタイプ宣言 (タイマー割込み内で処理)
void swscan(void); // SW入力スキャン
void bzzexc(void); // ブザー報知実行
/***** タイマーデータ *****/
volatile byte tm_1ms; // 1msダウンカウントタイマー
volatile byte tm_10ms; // 10msダウンカウントタイマー
volatile byte f_1sec; // 1秒経過フラグ
volatile byte f_1min; // 1分経過フラグ
// 測定用タイマー(カウントアップ)
byte f_tmion; // 計時指令
// onで計測タイマーをカウントアップ
volatile word tmi_1min; // 1分 カウントアップタイマー
// 24時間で1440分 999分で16時間39分
volatile byte tmi_1sec; // 1秒 カウントアップタイマー
// 00~59
volatile byte tmi_10ms; // 10ms カウントアップタイマー
// tmmreadで読む測定タイマー
word tmm_1min; // 1分 max5999分=99時間59分
byte tmm_1sec; // 1秒 0~59
/***** タイマー0コンペアマッチA割込み *****/
// 割り込みでパルス出力(1kHz周期)
ISR(TIMER0_COMPA_vect)
{
static byte cnt10 = 0;
PB0_H; // (!!!) 14pin
if(tm_1ms) tm_1ms--; // 1msダウンカウント
// 10msタイマー
cnt10++;
if(cnt10 >= 10){
cnt10 = 0;
if(tm_10ms) tm_10ms--; // 10mS ダウンカウント
if(f_tmion){ // 計時する?
tmi_10ms++;
if(tmi_10ms >= t_spdup){ // 100カウントで1秒
tmi_10ms = 0;
f_1sec = 1; // 1秒フラグをオン
tmi_1sec++; // +1秒
if(tmi_1sec >= 60){ // 60秒
tmi_1sec = 0;
f_1min = 1; // 1分フラグをオン
tmi_1min++; // +1分
if(tmi_1min >= 6000){ // 6000分越え?
tmi_1min = 5999;
tmi_1sec = 59; // 99時間59分59秒に
}
}
}
}
}
// 1ms処理関数
swscan(); // SW入力スキャン
bzzexc(); // ブザー報知実行
// 内蔵A/D開始
ADCSRA |= (1 << ADSC); // A/D変換開始
PB0_L; // (!!!) 14pin
}
/******************************/
/* 内蔵A/D処理 */
/******************************/
/**** A/D データ *****/
#define ADAVR_ADD 256 // A/D平均回数
volatile word ad_avr; // A/D変換データ 0~1023
// 平均処理された結果
volatile ulong ad_add; // A/D平均処理用加算データ
volatile byte f_adok; // A/D変換完了フラグ
// 割り込みでセット
// 平均処理確定でad_avrを転送 電池電圧に変換
byte f_advolt; // A/Dデータ転送変換完了フラグ
word ad_data; // 電圧A/D値 (平均値)
word bat_ad; // スムージング処理結果A/D値 (0~1023)
word bat_volt; // 電池電圧 bat_adをmV値に変換
word bat_peak; // 電池電圧ピーク値(mV)
word bat_deltav; // ΔV値 ピーク-現在値 (mV)
byte f_peakon; // ピーク検出開始フラグ
/***** A/D割り込み処理 *****/
// 1msタイマー割り込みでA/D変換開始
// 256回で平均値算出
ISR(ADC_vect)
{
word d;
static word cnt = 0; // A/D変換平均回数
PB4_H; // (!!!) 18pin
d = (word)ADCL; //
d |= (ADCH & 0x03) << 8; // 符号なしで 0~3FF
// 測定値
ad_add += (ulong)d; // 平均用に加算
// 平均処理
cnt++; // 平均加算回数
if(cnt >= ADAVR_ADD){ // 256回?
cnt = 0;
ad_avr = (word)(ad_add / ADAVR_ADD); // 平均
ad_add = 0L; // 次加算データクリア
f_adok = 1; // 変換完了
}
PB4_L; // (!!!) 18pin
}
/***********************************/
/* A/Dデータスムージング処理 */
/***********************************/
// 処理バッファ
word ad_smzbff[16]; // A/Dデータ保存バッファ
word ad_sort[16]; // ソート用バッファ
/***** qsort用データ比較 *****/
// wordで比較
int wordcmp( const void *p, const void *q ) {
if( *(word *)p > *(word *)q ) return 1;
if( *(word *)p < *(word *)q ) return -1;
return 0;
}
/***** スムージング処理 *****/
// 16コのA/Dデータを順にサンプル
// ソートして上下4コ(8コ)を捨て、中央の8コを平均
// 256ms X 16 = 4.096秒後に安定
word adsmz(word d)
{
static byte f1 = 0; // はじめてフラグ
static byte wp; // 書き込みポインタ
byte i;
long a;
word b;
if(f1 == 0){ // 初めて
f1 = 1;
for(i = 0; i < DIMSIZ(ad_smzbff); i++){
ad_smzbff[i] = d; // バッファを初期データで埋める
}
wp = 0; // データ書き込みポインタ
}
else{ // 2回目以降
ad_smzbff[wp] = d; // A/Dデータをストア
wp++; // 書き込みポインタを進める
if(wp >= DIMSIZ(ad_smzbff)) wp = 0; // 一周回って先頭に
}
memcpy(ad_sort, ad_smzbff, sizeof(ad_smzbff)); // バッファにコピー
qsort(ad_sort, DIMSIZ(ad_sort), sizeof(word), wordcmp); // qsort実行
// 中央の8つで平均処理 上下4コは捨てる
a = 0; // 合計
for(i = 0; i < 8; i++){ // 中央の8コを加算
a += ad_sort[4 + i]; // 4コ目から8コを加算
}
b = word(a / 8); // 1/8して平均値
if((a % 8) >= 4) b += 1; // 四捨五入
return b;
}
全体のスケッチはまた今度に。
JIS C8708:2019充放電試験回路製作中、この中の定電流回路
(充電用と放電用の2つ)この電流検出抵抗をあれこれ模索。
今回使ったのは手持ちの関係で5W・0.3Ω。
その発熱が悩みどころ。
セメント抵抗に電力を食わせた時の温度上昇。
こんなグラフが出ていました。
https://www.e-globaledge.com/products/ecomponents/tdo/
温度特性が「±400ppm/℃」。
ということは、10℃変化で0.4%。
触れないくらいの50℃も上がると2%の変動。
電流検出抵抗としてはちょいとなぁ~なんですが、
とりあえず手持ち部品の関係で「5W0.3Ω」というのを
用いました。
今回の回路、最大1.5Aで0.3Ωだと0.7Wほど。
5W定格の14%ほど。
十分に定格内なのですが、↑のグラフを見ると、
上昇温度が30℃ほどと読み取れます。
ということは抵抗値として1%ほどの変動を覚悟しな
くてはとなります。
仕事の装置ではこんな抵抗を使っていました。
※手持ちが無いので今回は使えなかった。
「PWR4412」という金属でできたコの字のバー。
これで「±20ppm/℃」。
ただし、ラインナップされている最高の抵抗値が「0.1Ω」。
抵抗値を小さくすると、電力が減って発熱も少なくなりますが、
定電流回路の制御電圧を下げなければなりません。
今は制御電圧0.5Vで1.6A。
電流検出抵抗を0.1Ωにすると、0.16Vで1.6Aという制御に
なり、ちょっと電圧が低いかな~というところです。
※参考
・ねがてぃぶろぐ セメント抵抗の温度特性 その1
・ねがてぃぶろぐ セメント抵抗の温度特性 その2
※追記
手持ちの「コの字状抵抗」を引っ張り出してきました。
30mΩのと50mΩのが各2つ。
調べてると・・・
「PWR4412」、廃番になってました!
えらいこっちゃ。
代替品を探さなくてはなりません。
ビシュイでSR3R、SR5Rというのが使えそう。
ちょいと温度係数が悪いか・・・。
SR3R(3Wタイプ)だと0.1Ωがある。
RiedonというメーカーでMSR5というのでも0.1Ωがある。
抵抗値を小さくすると、同じ電流なら電力がダウン。
1.5Aで0.3Ωだと0.675Wだったのが、0.1Ωにすると0.225Wに。
これで、発熱がずいぶんと減ります。
↑にあるグラフのように「負荷率に対する温度上昇曲線」あれば
発生誤差が推定できるんですけれどねぇ。
2018年4月にマイコン型導通チェッカー、10年目に という記事を書いてます。
※現在も(有)アクト電子で頒布しています。
先日も、「新人の研修で使いたい」ということで、まとまった数の注文を
いただきました。 ※ありがとうございます。
ケース加工も丸穴だけだし、回路のハンダ付けや組み立ても難しくありません。
※面実装ICはこちらでハンダしてます。
組み立てておけば、電子回路工作で役立つ一生もののツールになること間違い
なしです。
回路図もソースファイルも(アセンブラですが)公開してますし、教材として
の価値もあるかと。
どうぞご検討ください。
※「導通チェックなんてテスターに付いてるやん」という意見もありますが、
このチェッカーの手軽さは、実物で体験してもらわないと分かってもらえ
ないかな。
そうそう。郵便局のクリックポスト が4月から198円に値上げです。
(現在は188円)
ダイソーReVOLTES単3 JIS C8708:2019充放電試験 200サイクル目完了
の続き。 400サイクル目、完了です。
400サイクル目で、放電持続時間が2時間ほどに。
寿命と判断して、今回の実験はこれで終了します。
実験回路 から取り外したReVOLTES、その内部抵抗を
計ってみると「481mΩ」。
0.5C、つまり650mA流すと「0.3V」のドロップが発生。
充電時も同じで、内部抵抗で充電電圧が上昇します。
そのため、充電時に1.8Vを越えてしまっています。
※そのあたりは電圧と温度変化のグラフで
※350回目後に電圧レンジのゼロ点を下げた。
フルスケールを1.8Vに。
今回は「充電0.5Cで132分 (-ΔV制御はしない)」という
充放電繰り返し条件でした。
これを-ΔV制御するとどうなるか・・・
無駄な温度上昇がマシになるんじゃないかと。
※制御プログラムを作り直さなくちゃなりません。
※関連
・ダイソーReVOLTES単3 JIS C8708:2019充放電試験 続行中
・ダイソーReVOLTES単3 JIS C8708:2019充放電試験 200サイクル目完了
・パナソニックのニッケル水素電池、新JIS 8708:2019による充放電繰返し回数
・「ダイソーReVOLTES」JIS C8708:2019充放電試験 50サイクル目
・ダイソーReVOLTESでJIS C8708:2019サイクル試験開始
・ニッ水電池のJIS規格 C8708:2019
・電池イジメ、もうやめます
ミスが広まる 1/1023 vs 1/1024 はA/Dコンバータのスケーリングの話。
Arduinoのタイマー OCRレジスタは「n」じゃなく「n - 1」の値を設定せよ
はタイマーコンペアレジスタ設定の話。
そして今度は「analogWrite」、ArduinoのPWM出力の話をちょっと。
Arduino-UNOだと3つのタイマーを使った6つのPWM出力が可能です。
仕様では分解能8bit。
void analogWrite(uint8_t pin, int val)
という関数で使います。
ピン番号で使うタイマーが決まり、例えば5,6ピンならタイマー0が
用いられます。
タイマーのクロックが250kHzで8ビットですので、1.024ms周期で
1ビットが4usの分解能になります。
valの値がPWMのデューティー比で、設定できるのは0~255。
0で出力LOW固定になり、255で出力HIGH固定。
128でデューティー50%の方形波。
analogWriteを単にPWM出力ということではなく「D/Aコンバータ」
として使った時、その出力範囲をどう考えればよいでしょうか?
(「1/1023 vs 1/1024」に近い話になります)
8ビットの0~255のデータを、可変範囲が0~5VのD/Aコンバータで
出力する時、最大値は「(255×5V)/256」で、フルスケールの5Vより
約20mV低いおよそ4.98Vがmax値となります。
ところがanalogWriteは「0V=LOWに張り付いてパルス無し」
「5V=HIGHに張り付いてパルス無し」まで出力できます。
本来ならフルスケール「(255×1.024ms)/256」で、
1020usのHIGHパルスに4usのLOWパルスが残るはず。
それがなぜか255でHIGHに張り付いちゃいます。
1/256ではなく1/255で処理されているのじゃないかと考え
られるのです。
analogWriteは「wiring_analog.c」内で処理されていますので、
ソースをちょいと覗いてみると・・・
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void analogWrite(uint8_t pin, int val)
{
pinMode(pin, OUTPUT); // 指定ピンを出力に
if (val == 0){ // ★1
digitalWrite(pin, LOW); // 値が0ならLOWに張り付き
}
else if (val == 255){ // ★2
digitalWrite(pin, HIGH); // 値が255ならHIGHに張り付き
}
else { // ArduinoCPUによる区別
switch(digitalPinToTimer(pin)) { // その代表で
case TIMER0A: // タイマー0
sbi(TCCR0A, COM0A1); // OC0Aピン非反転PWM出力モード
OCR0A = val; // set pwm duty ★3 値が1~254の時
break;
:
}
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
★1と★2で0と255を分離処理して、★3で1~254の時だけ
PWMパルスが出るようにしています。
そこで、タイマー0のanalogWriteに対して、0~255の数値を順に
与えてみると・・・周期1.024msのパルスに対して、
0ならずっとLOW
1だと8usのHIGHパルス ▼1
2だと12usのHIGHパルス
:
253だと8usのLOWパルス
254だと4usのLOWパルス
255だとずっとHIGH
が観察されます。
タイマー0に関して、値0と1のところ▼1で、ほんとなら4usステップ
になって欲しいのが8usとなっていて、値1~255とは異なるピッチに
なっていることがわかります。
※この部分の注意点
これ、タイマー0だからなんです。
OCR0A = val
とコンペアレジスタに設定値を与えているから。
OCR0A = val - 1
にすると、値1で4usのHIGHパルスが得られます。
そして★2の処理を無くせば255で4usのLOWパルスとなり、
「(255×1.024ms)/256」、「(255×5V)/256」の値が得られます。
なお、タイマー0が「8bit高速PWMモード」で初期化されている
ことに注意してください。
タイマー1とタイマー2は「8bit位相基準PWMモード」に設定されて
いて、動作が異なるのです。
このあたりの差が、数値に対するPWM波形出力に影響を与えます。
analogWriteにD/A変換機として純粋な精度を求める場合はちょいと
ご注意を。
ハードウェアマニュアルをよく読み、テストプログラムを書いて
動きを確かめてということで。
※追記
デューティー50%の方形波を得ようとして
analogWrite(6,128);
しても、HIGH=512us、LOW=512usの波形にはなりません。
HIGHが516us、LOWが508usになり、デューティ50.4%くらいの
方形波が出てきます。
きっちり50%にしたいのなら、
analogWrite(6,127);
です。 (タイマー0で)
※PWMでのD/A変換、こんな回路を使ってます。
Arduinoの5Vは不安定なので、基準電圧ICで4.096Vとか
2.5Vなどを発生。
PWM波をアナログマルチプレクサ(74HC4053など)を使って
GND-VREF電圧を切り替える。
それをLPFで平滑。
OP-AMPでバッファして電圧出力に。
タイマー1を使うと分解能を10bitとか12bitに拡張できる。
analogWriteじゃなく自前のプログラムで制御。
※PWM出力の様子をオシロスコープで観察する
ためのテストプログラム。 (注:スペースを全角で)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include "wiring_private.h"
// I/O MACRO
#define PB0_H (PORTB |= (1 << PB0)) // (!!!)PB0 H/L D8
#define PB0_L (PORTB &= ~(1 << PB0))
#define PB4_H (PORTB |= (1 << PB4)) // (!!!)PB4 H/L D12
#define PB4_L (PORTB &= ~(1 << PB4))
#define PB5_H (PORTB |= (1 << PB5)) // (!!!)PB5 H/L D13
#define PB5_L (PORTB &= ~(1 << PB5))
/***** タイマー0 オーバーフロー回数読み出し *****/
extern volatile unsigned long timer0_overflow_count;
unsigned long readovf0(void)
{
unsigned long t;
cli(); // 割込禁止
t = timer0_overflow_count;
sei(); // 割込許可
return t;
}
/***** PWM出力 *****/
// val : PWM設定値 0~255
// OC0A,OC1A,OC2Aに出力
void pwm3ch(int val)
{
analogWrite(6,val); // タイマー0 OC0A
analogWrite(9,val); // タイマー1 OC1A
analogWrite(11,val); // タイマー2 OC2A
}
/***** セットアップ *****/
// ATmega328Pのレジスタを直接制御
void setup()
{
cli(); // 割込禁止
// I/Oイニシャル
PORTB = 0b00000000; // data/pull up
DDRB = 0b00111111; // port指定
// |||||+---- PB0 IO8 out test pulse
// ||||+----- PB1 IO9 out OC1A
// |||+------ PB2 IO10 out OC1B
// ||+------- PB3 IO11 out OC2A
// |+-------- PB4 IO12 out test pulse
// +--------- PB5 IO13 out (LED) test pulse
PORTD = 0b00000000; // data/pull up
DDRD = 0b11111100; // port指定
// |||||||+---- PD0 IO0 RXD
// ||||||+----- PD1 IO1 TXD
// |||||+------ PD2 IO2 out
// ||||+------- PD3 IO3 out OC2B
// |||+-------- PD4 IO4 out
// ||+--------- PD5 IO5 out OC0B
// |+---------- PD6 IO6 out OC0A
// +----------- PD7 IO7 out
sei(); // 割込許可
}
/***** LOOP *****/
void loop()
{
unsigned long ovf0;
unsigned long ovfck;
byte cnt = 0; // オーバーフローカウンタ
byte kubun = 0; // PWM出力区分
static int val[]={ // PWM設定値
0, 1, 2, 127, 128, 253, 254, 255, // 8つのPWM値
}; // 0:LOW~255:HIGH
ovf0 = readovf0(); // オーバーフロー回数
while(1){
ovfck = readovf0();
if(ovf0 != ovfck){ // 変化あり
ovf0 = ovfck; // 1.024msタイマー0オーバーフロー
PB0_H; // 1.024msごとにパルス出力
if(cnt == 0){
PB4_H; // 先頭カウントの時
if(kubun == 0) PB5_H; // 区分0の時パルス
else PB5_L;
pwm3ch(val[kubun]); // 区分によりPWM出力
}
else{
PB4_L;
}
cnt++;
if(cnt >= 6){ // 6回オーバーフロー
cnt = 0;
kubun++; // PWM区分
if(kubun > 7) kubun = 0; // 0~7
}
PB0_L;
}
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
・timer0_overflow_countがタイマー0割り込みでインクリメントされるので、
これを見て1.024ms経過を検出。
・PB0は1.024msごとにパルス出力。
PB4はPWM値設定ごとに、PB5は区分一周でパルス出力。
オシロのトリガー源に。
・タイマー0のPWMはこのパルス周期に同期しているが、
タイマー1、2のPWMは同期しない。
タイマー0は1/256処理。タイマー1,2は1/255で処理されている
ので、周期が異なるから。
・タイマー1,2でデューティー、ジャスト50%を得ようとしても、できない。
127だと、H:1.016ms + L:10.24msに。
128だと、H:1.024ms + L:1.016msになってしまう。
(タイマー0は周期1.024msだけど、タイマー1,2は2.040ms周期)
ミスが広まる 1/1023 vs 1/1024は、Arduino-UNO(ATmega328pマイコン)
のA/Dコンバータ・スケーリングのお話しでしたが、今回はタイマーのコンペアマッチ
レジスタのお話しです。
Arduinoのタイマーを直接操作する時(例えばMsTimer2などのタイマー
ライブラリーを使わずにタイマー割り込みを使いたい時など)、CTCモードで
アウトプットコンペアレジスタにタイマーの最大カウント値を設定します。
※Arduinoから「タイマー0」を取り上げる(ユーザーが使う) では
「1m秒」割り込みを例にしました。
1msつまり1kHzの割り込み周期を得るには、
・CTCモードに。 (コンペアマッチでカウンタゼロクリアー)
・16MHzのクロックをプリスケーラーで1/64して250kHzに。
・それを1/250して1kHzに。
この1/250するのがアウトプットコンペアレジスタへの設定です。
↑の例では
OCR0A = 250 - 1; // 250カウントで1kHzを
の所。
1/250なんで「250 - 1」を設定しています。
これをミスして「-1していない」プログラム例や解説を見かけるのです。
なぜ「n - 1」なのかは、このタイミング図を見れば分かるかと。
TOP値がOCR:コンペアレジスタへの設定値。
そして、CTCモードだとBOTTOM値はゼロになります。
TOP値を検出した次のサイクルがゼロとなるわけです。
例えば「1/4」したい時、TOP値つまりコンペアレジスタの値を
「4」にしてしまうと・・・
「0 1 2 3 4 0 1 2 3 4 0・・・」と繰り返しが「5」になってしまいます。
TOP値としてOCRに設定するのは「カウント周期 - 1」でなければいけません。
「-1」しないと、「1/4」が欲しいのに「1/5」になってしまうという
スカタンが発生します。
これに気付かない原因の推測ですが、
・とりあえず、それらしい動きをしてるから。
・16ビットタイマーであるタイマー1に対して、大きな値をセットしてる。
そのままの値と-1した場合とで、タイマー周期にほとんど違いが出ない
から気がつかない。
・8ビットタイマーでも、ミスを測定する手段を持ってない、あるいは
積極的に結果を計ろうとしていない。
※周波数カウンタやオシロスコープなどの測定器をつなぎ
テストパルスを出せばすぐに気がつくはず。
・ハードウェアの非同期カウンタを思い浮かべている。
※1/10カウンタなら、7→8→9→[10=0]→1→2→
と、10検出で直ちにリセットされて0になるので。
こんなところかと。
※見かけたミスの例
・ArduinoのTimerを初心者が1からなんとなくわかるためのメモ - Qiita
16MHzクロックを1/256し、「OCR1A = 62500;」として「1秒」としている。
・Arduinoでtimerを使った割込み処理の方法 ? 自作のいろいろ
「OCR2A=100; //100カウントごと(50μs)毎」と。。。
・Timer1 - FreeStyleWiki
ちょっと違う。
・タイマー割り込みを使う - arduino始めました
惜しいような。。。
・Timer0 & 1
アセンブラでもミス。
多くの正しい解説もありますが、ミスしたのが目立っちゃいます。
そして、もうひとつ気になるのが割り込み処理内で走らせるプログラム。
「呼んですぐに戻ってくる関数」が基本。
そして、それがメインの処理とぶつからないこと。
他の割り込み処理に影響(長い時間待たせる)を与えてもダメ。
割り込みの中で「Serial.println(xxx)」を使ってる例を見かけるのですが、
これはいかがなものかと・・・。
最近のコメント