質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Q&A

2回答

4083閲覧

INA260にて測定した結果を外部EEPROMへ記録したい

PAD

総合スコア1

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

0グッド

0クリップ

投稿2020/10/21 12:19

編集2020/10/26 12:44

Arduino プログラミング共に素人ながら前回「Arduinoで模型用の車載データロガーを作りたい」という質問にてアドバイスを頂き、以下のような環境を整えました。

・GingerBread(Arduino pro mini互換機)
・INA260(電流電圧測定モジュール)
・EEPROM 24FC512 (INA260からの測定結果記録用)

INA260、外付けEEPROMそれぞれ単体で動作させるプログラムは見つけ実際に動作することを確認したのですが、この2つを組み合わせた「INA260の測定結果を外付けEEPROMに記録する」プログラムを作るために、いくつか自力で理解できない点がありましたのでご教授いただければと思います。

参考にした作例はこちら(INA260)と**こちら(EEPROM)**です。

また、現状プログラムの意味を調べるのに「Arduino 日本語リファレンス」のみを使用しているので、これ以外に学習の手助けとなるようなサイトがありましたら同様にご教授いただけると幸いです。

①一部プログラムの意味について

EEPROM作例中の

Wire.write((int)(eep_add >> 8)); Wire.write((int)(eep_add & 0xff));

INA260作例中の

Wire.write((value >> 8) & 0xFF); Wire.write(value & 0xFF);

において両方とも「8ビット移動と0×ff(255)の入力?を行っている」と調べた結果認識しましたが、何故このような作業が必要なのかが分かりません。
Arduinoにモジュールを認識させるために必要な儀式のようなものなのでしょうか?

###②Serial.printlnの書き換えに関して
INA260作例中の

Serial.println();

以降でシリアルモニタに表示されてしまう記録データをEEPROMへ記載するために、EEPROM作例中の

void eep_write(int device_add, unsigned int eep_add, int data)

の部分の書き換えが必要なのだろうと思いましたが、具体的にどのように書き換えれば良いかがわかりませんでした。
ヒントでも構いませんのでどう書き換えていくのが良いかを教えていただきたいです。

##追記

教えていただきました内容を踏まえまして追加質問失礼致します。

作例のスケッチを拝見し、INA260の作例をベースとして

#include <Wire.h>

#define NELEMS(arg) (sizeof(arg) / sizeof((arg)[0]))

の間に

void eep_write(int device_add, unsigned int eep_add, int data){ Wire.beginTransmission(device_add); Wire.write((int)(eep_add >> 8)); Wire.write((int)(eep_add & 0xff)); Wire.write(data); Wire.endTransmission(); }

を追記し、

Serial.println(); snprintf(buf, NELEMS(buf) , "V:%5ldmV, I:%5dmA, P:%5ldmW" , (voltage + (1000/2)) / 1000 , current , (power + (1000/2)) / 1000 ); Serial.println(buf); dumpRegisters(); delay(1000);

int x = 0; while (x <=10){ eep_write(0x50, x*5+0, voltage&0xff); eep_write(0x50, x*5+1, (voltage>>8)&0xff); eep_write(0x50, x*5+2, (voltage>>16)&0xff); eep_write(0x50, x*5+3, current&0xff); eep_write(0x50, x*5+4, (current>>8)&0xff); x++; } delay(1000);

と書き換えました。

このスケッチを使用後、EEPROM参考サイトにあったデータ読み込み用プログラムを使用してアドレス50までの確認を行ったところ、
アドレス0,24,47にそれぞれ
226,255,0とだけ記録されていました。

INA260には測定対象を何も接続しておらず、確認でINA260の作例そのままを出力すると

V: 1mV, I: -1mA, P: 0mW ---INA226 Registers --- Configuration Register (00h) : 6727h (26407) Shunt Voltage (01h) : FFFEh (65534) Bus Voltage (02h) : 0001h (1) Power (03h) : 0000h (0) Current (04h) : FFFFh (65535) Calibration (05h) : 0A00h (2560) Mask/Enable (06h) : 0008h (8) Alert Limit (07h) : 0000h (0) Die ID (FFh) : 2270h (8816)

を常時出力していました。

この問題を解決する手がかりを教えていただければ幸いです。

###使用条件
詳細な使用したい条件は以下の通りです。

電圧範囲 : 2.0~3.5V
電流範囲 : 0.0A~2.0A未満
サンプリング間隔 : 100ms
1回の測定時間 : 120秒未満(主な使用時間40~80秒)
使用回数 : 一度に20回未満(20回以上使用する場合はPCへデータを移動し、eepromをリセットして再記録を行うか、別のeepromに付け替えることを予定しています。)

###INA260の負荷測定結果
無負荷状態だけでなく数値変化するか確認を行ったほうが良いとのご指摘をいただき、負荷をかけたINA260の動作確認を行ったところトラブルが増えてしまいました。
問題としてはどのような負荷をかけても表示されるIの値が-1mAから変化しません。
入出力端子を経由してモーター、LEDは動いているので内部断線はしていないようですが、一先ず購入店舗に問い合わせを行いつつ電力から電流を逆算するようにしたいと思います。

・3Vボタン電池で並列接続したLED3個を稼働

V: 2734mV, I: -1mA, P: 100mW ---INA226 Registers --- Configuration Register (00h) : 6727h (26407) Shunt Voltage (01h) : FFF4h (65524) Bus Voltage (02h) : 088Bh (2187) Power (03h) : 0004h (4) Current (04h) : FFFFh (65535) Calibration (05h) : 0A00h (2560) Mask/Enable (06h) : 0008h (8) Alert Limit (07h) : 0000h (0) Die ID (FFh) : 2270h (8816)

・1.2Vニッケル水素電池でモーターを稼働

V: 1128mV, I: -1mA, P: 1150mW ---INA226 Registers --- Configuration Register (00h) : 6127h (24871) Shunt Voltage (01h) : 0170h (368) Bus Voltage (02h) : 038Fh (911) Power (03h) : 0034h (52) Current (04h) : FFFFh (65535) Calibration (05h) : 0000h (0) Mask/Enable (06h) : 0008h (8) Alert Limit (07h) : 0000h (0) Die ID (FFh) : 2270h (8816)

プログラムが旧バージョン?のINA226用だったので一部アドレスが違うかもしれない、とも考えましたが同じであるという記載を見つけたため問題なさそうです。
プログラムが原因の可能性ありましたらご指摘お願いします。

##現在の進捗に関して
昨晩から本日までに試行した内容を全て羅列致します。


ご提案いただいたスケッチ

void eep_write_data(word V,word A){ static word adrs=0; Wire.beginTransmission(INA226_ADDR); Wire.write(adrs>>8); Wire.write(adrs); Wire.write(V>>8); Wire.write(V); Wire.write(A>>8); Wire.write(A); Wire.endTransmission(); adrs+=4;// }

Wire.beginTransmission(INA226_ADDR)

がEEPROM作例と異なりEEPROMへのアドレスではなかったので

Wire.beginTransmission(eep_add)

と変更しました。


①の後検証を行うと
'eep_add' was not declared in this scope
と言われたので

const int eep_add = 0x50;

を追加しました。


VとAが何なのか定義されていないのでは?と思ったため、void loop()内に

for(int V=(voltage + (1000/2)) / 1000;int A=current;)

を追加しました。


「EEPROM作例と異なり、eep_write_dataで書き込まれる内容が全てsetup以前に定義されているということはvoid loop以降ではVとAの定義以外eep_write_dataの()の中に入れるものはないのではないか?」
と思い、③以降に

Wire.begin(); eep_write_data; delay(1000);

とだけ記載しました。

しかし実行後読み込みスケッチで読み込みを行っても何も記録されていませんでした。


やはり
eep_write_data;
には何か書き込まなければならないと思ったので

eep_write_data(V,A);

と記入したところ 'V' was not declared in this scope

eep_write_data(int V,int A);

と記入したところ expected primary-expression before 'int'

eep_write_data(word V,word A);

と記入したところ expected primary-expression before 'V'

eep_write_data("V","A");

と記入したところ エラーは出ませんでしたが実行後読み込みスケッチで読み込みを行っても何も記録されていませんでした。

for(int V=(voltage + (1000/2)) / 1000;int A=current;)

for(word V=(voltage + (1000/2)) / 1000;word A=current;)

へ書き換えました。
エラーは出ませんでしたが実行後読み込みスケッチで読み込みを行っても何も記録されていませんでした。

Wire.begin(); eep_write_data; delay(1000);

Wire.begin(); eep_write_data(); delay(1000);

と書き換えたところ
too few arguments to function 'void eep_write_data(word, word)'
と言われてしまったので⑤へと逆戻りで堂々巡りしてしまっています。

今現在スケッチは以下のようになっています
※文字数制限に引っかかってしまったため以下リンクへ記載を行いました。

https://github.com/PAD-arduino/test/blob/main/test1

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nac_tnk

2020/10/23 03:42

voltage自体は単位がuAです。 デバイスの測定範囲36V=36000000だと、24ビット(3バイト)では足りません。 (24ビットだと約16.7Vまで) ちゃんと4バイト用意した方が良いです。 電流の方はmAですから2バイトで問題ありません。 で、電力もデバイスが出力する値ですけどそれは記録しないのですか? > eep_write(0x50, x*5+0, voltage&0xff); > eep_write(0x50, x*5+1, (voltage>>8)&0xff); これは駄目です。 EEPROMは書き込み時間がかかります。 Wire.endTransmission()の戻り値で判断する手法もありますけど、 通常は簡単に、書き込み時間の分、delayを入れます。 (eep_write関数の最後に付けても良いです。) ただし、EEPROMは書き換え寿命もありますし、delayを入れるとサンプリング間隔も変わります。 なので、ページ書き込みをお薦めします。 後は、このシステム(EEPROM)がどの位の時間駆動できるのかも考えた方が良いです。 例えば1回8バイト書き込むのなら、 64KB/8=8000データ(秒)≒2.2時間です。 で、再起動した場合は、(前データが残っていれば)何処までが今回のデータなのか判りません。 なので、そういった情報もEEPROMの一部に残す事も考慮した方が良いです。 ※このあたりは、使い方次第です。別の書き出しプログラムを書き込んでEEPROMを読もうと思っても、 PCに繋いだ途端に大事なデータ(の先頭部)が消されてしまうかもしれません。 その追記で書いた、読出しデータも、プログラムを書き換える際に書かれたデータなのかもしれません。 (それとも、別のArduinoを使ったり、EEPROMに書き込まないように外したりしました?) その2つのスケッチを纏める以上に、「実際に使用する際の工夫」の方が難しいかもしれません。
PAD

2020/10/23 09:20

アドバイスありがとうございます。 測定をしたい対象が2.0V~3.5V程度、2.0A未満なのですがそれでも4バイト用意したほうが良いでしょうか? 電力に関してですが最低限電流電圧が分かれば良いと考えており、処理が増え難易度が上がってしまうようであれば電力は特に気にしていません。 表記がおかしい理由として処理が飛び飛びになってしまっている可能性があるのですね。 ページ書き込み、初めて聞いた内容ですのでこれから調べて試してみたいと思います。 時間に関しては1回の駆動回数が2分未満、サンプリング間隔は100msあれば十分と考えております。 データの開始点がわからない問題に関しては確かにどうしたものか…と思っていたのですが、1度に多くても20セット未満の記録回数ですのでアナログな解決方法としてeepromを取り外し可能にして走行毎に付け替える・・・という方法を検討しておりました。 電圧等使用したい条件を質問に追記しますので、よろしくお願い致します。
thkana

2020/10/23 12:22

> voltage自体は単位がuAです https://strawberry-linux.com/pub/ina260.pdf にはLSBが1.25mV/1.25mAとなってますけど。とりあえず既知の電圧/電流を測って安心したいところ。 > EEPROMは書き込み時間がかかります。 busyをチェックして...とか思ってて言うの忘れてた。スペックでは書き込み時間10msとかになってても実力もっと早いから、待つのはもったいないと思う。 > EEPROMは書き換え寿命もありますし 一応この辺は前の質問に話があって、ミニ四駆のモーター電圧/電流で100ms毎に60秒間程度のデータを取るような測定だそうなので、バイトで書き込んでも十分間に合うなぁ、と思ってました。10万回繰り返すことはなかなかなさそうです。
nac_tnk

2020/10/23 14:52

> PADさん あなたの思う、必要な情報だけで良いです。場合によっては、無駄な0の数を省略する(単位を変える)という手法もあります。 サンプリング間隔が100msなら尚更ページ書き込みにした方が良いです。 もしくは、millisで、サンプリング開始のタイミングをとるか。 ページ書き込みは、複数バイトを1回で書き込むだけです。 1回の取得で1書き込みにすれば書き込み時間は関係ありません。(次回にはとっくに書き込み済みになっているので) ただし、このデバイスの場合は128バイトで、1ページ(ブロック)です。 128を割り切れるデータ(バイト数)の方が都合が良いです。 (「そのブロックを超えて書き込めない」という所が唯一の気を付ける所だと思います) ※それ以前にWIREライブラリのバッファが32バイトらしいので、WIREライブラリ上、32バイトが1回で書ける上限になります。 ちょっとテストデータを取得するような使い方ですね。 機器の中に仕込んでおくような使い方か判らなかったもので。 (今、前回の質問を見ました。すいません) いずれにしても、書き込みからデータの取得まで一通りの事(ブログラムと自分の作業順)を考えて作った方が良いです。 起動直後に先頭アドレスからいきなり書き始める仕様を考え直した方が良いと思います。 EEPROMに現在の書き込み位置を残しておいて、その後から追記していく方が良いです。 起動時に前回書き込んだのを読み込むようなのが結構普通のEEPROMの使い方です。 > thakanaさん 電圧なので、uAじゃなくて、uVでした。 レジスタ値はLSBが1.25mVです。 > voltage = (long)((short)readRegister(INA226_REG_BUS_VOLTAGE)) * 1250L; と1250をかけています。 このチップはデータシート上では最大5msになっていました。サンプリング間隔(delay)が1sだったんで、時間が勿体ない、というのは無いのですけど(その分delay値を調整すれば良い)。 もし私が今回のがを作るなら1回のサンプリングで最大で1回ですね。複数回のを纏めて書き込むからもしれません。 使用条件については見ていませんでした。すいません。 そういえばあっちのサイトは発言履歴が見えなくなりましたね。残念です。
nac_tnk

2020/10/25 04:07

「INA260の負荷測定結果」の雑感 ・「3Vボタン電池」の方は、初期化はされています。一方、「1.2Vニッケル水素電池」の方は初期化自体がされていません。 (CalibrationやConfiguration Register値) 測定途中でVSやGNDが一瞬外れて、センサーが再起動したのかも?とも思ったのですけど、リセット時の Currentは0ですから、(リセット後に)変化はしている事になります。 なので、ニッケル水素の方の電流データは無視(取りあえず置いておく)した方が良いです。 で、ボタン電池の方のデータを見ると、 Shunt Voltage (01h) : FFF4h と数値は-12です。その場合、Calibrationに0xA00が入っていれば、計算結果から、-15mAになる筈です。 (その時、Currentのレジスタ値が0xFFF1になっている筈) つまり、内部計算も狂っているようです。 ※私の理解がおかしい場合(足りない)場合もあります。
PAD

2020/10/25 06:21 編集

>nac_tnkさん ありがとうございます。 さらに調べて言ったところINA226にて逆接でGNDラインが焼損したという事例も見つけましたが、これも目視で異常が見られないのでやはり不良の可能性が高いのかもしれませんね… 購入元と連絡を取っている間、先にスケッチの理解を進めていきたいと思います。 ところでページ書き込みに関してですが、そのまま「ページ書き込み」と明言している解説サイトがこちら(http://www.picfun.com/pic18/i2c10.html)しか見当たらず、こちらで使用されていた「EPageWrite」を検索しても独自に定義された関数?のようで結果が出てこなかったため迷ってしまいました。 寄り道で「EEPROM.put()」という似たようなものを発見したのですが、これとはまた違うものでしょうか?
nac_tnk

2020/10/25 07:24 編集

そのサイトに人は、PICで最も有名(圧倒的な著作数)の人です。 PICに関して書いています。 そこに書かれている事は「通常ページは64バイトが単位になっています。」以外はおおよそ正しいです。(デバイスの容量によりそれぞれ異なります。)まぁ全部見た訳では無いですけど。 バイト書き込みとページ書き込みの仕組みに違いはほぼありません。どちらもSTOPの段階でバッファに書き込んだものを本当のEEPROMに書き込みます。 ただ、1バイトずつ書き込めば、ページを意識しなくて済む、という事です。 例として、ページサイズが8だった場合は、アドレスを7(1ページ目の最期)から3バイト(ページ書き込みで)を書き込むと、アドレス7に最初のバイト、アドレス0と1にのこりの2バイトが書き込まれてしまいます。(アドレスがロールバック?します。) バイト書き込みは、1回ずつのアドレス位置を指定した書き込みなので、そういった間違いは起こりません。 元々のINA260のスケッチで言えば、bufは64bitですけど、実際にシリアル表示している個所、 Serial.println(buf); では、31バイトだけ表示しています。なので、 buf[31]='\n';//最後にシリアル表示と同じようになるように改行追加 static data_num=0;//データ番号(行とほぼ同じ意味) Wire.beginTransmission(device_add);//※←device_addは直接数値を入れる Wire.write(data_num>>3); Wire.write(data_num<<5); Wire.write(buf,32);//32バイトを書き込む Wire.endTransmission();//実際に通信 data_num++; で、おおよそ、シリアルモニタに表示しているそのものを記録する事になります。 (参考サイトの下2つのシリアルモニタ画像) ※beginTransmissionやwriteは実際に書き込んでいなくて、送信情報を並べているだけです。  endTransmissionで、全て送って、STOPまでしています。 上記のように、単純に、配列に入れたのを、先頭から○バイトでも良いですし、 ↓のように関数を作っても良いです。 void eep_write_data(word V,word A){ static word adrs=0; Wire.beginTransmission(INA226_ADDR); Wire.write(adrs>>8); Wire.write(adrs); Wire.write(V>>8); Wire.write(V); Wire.write(A>>8); Wire.write(A); Wire.endTransmission(); adrs+=4;//この例だと4バイトずつ書き込むので } 例えば、情報が6バイトだったりしたら、1回に8バイト書き込むようにして、余った所はインデックスにでもした方が良いです。 (本来なら、インデックスを読み取ったり、ヘッダ部(或いはフッダ部)を作って、前回の記録のあとから追記するようにします。)
PAD

2020/10/25 11:32

>nac_tnkさん 作例までありがとうございます。 関数を作成する場合は元のEEPROMスケッチの void eep_write(int device_add, unsigned int eep_add, int data){ Wire.beginTransmission(device_add);// Wire.write((int)(eep_add >> 8)); Wire.write((int)(eep_add & 0xff)); Wire.write(data); Wire.endTransmission(); } と入れ替えればよいでしょうか? また、元スケッチ内にはデバイスアドレスとeepアドレスの指定がありますが、作例の場合はstatic word adrsという部分が関係しますか? よろしくお願いします。
nac_tnk

2020/10/25 12:00

入れ替えるというか・・・ 関数を使うのなら、とにかく他の関数の外に書きます。 そしてvoltageやcurrentを算出した後に eep_write_data(voltage/1000,current); みたいにすれば良いと思います。単位はmV、mAです。 staticは関数を終わっても値を残しておく、という事です。次回、その関数を読んだ時に、前回書き込んだ進ませた位置(adrs)になっています。毎回初期化した0の位置に書いたら駄目なので。 ※どうせ1回(同じ場所)でしか使わないので、関数は作らなくても良いです。
thkana

2020/10/25 12:02

> 同じであるという記載 とか、 > 解説サイト はあくまで参考。データシートを確認しましょう。これが原則です。情報は可能な限り源流から。 販売店の転載は古いかも知れないので、メーカーから最新のドキュメントを取ってもいいです。時としてメーカー発行のデータシートでも日本語版で誤訳なんて話もあったりします。 そこまで気合いれてないので、以前に紹介したストロベリーリナックスのリンクにdatasheetがあるので INA226 https://strawberry-linux.com/catalog/items?code=12031 INA260 https://strawberry-linux.com/pub/ina260.pdf を見比べてみるわけですよ。そうすると、違うんじゃないですか? レジスタの使い方。260の方はシャント抵抗内蔵なのでシャント抵抗の両端電圧から電流への計算は勝手にやってくれています。 数値を当ててみると、 LEDの方はFFF4は-000cなので-15mA(逆接続ですね。スペック上問題ないですが)、電圧は2734mVで掛けて41mW(LSB10mWで40mW) モーターの方は電流が460mA, 電圧が1138mVで掛けて523mW あってますよ。
thkana

2020/10/25 12:32

24FC512はマイクロチップですか。http://ww1.microchip.com/downloads/en/DeviceDoc/21754M.pdf もちろんページ書き込みをやりたいなら書き込み方法も書いてあります。 ちなみに、私は未だにバイト書き込みで十分、と思ってますけれど、まぁそんなにクリチカルではないのでお好きに。EEPROMの寿命は100万回消去ですから、1分走行毎にEEPROM全域に書き込みを行うとして100万分=694日なので、2年弱寝食を忘れてミニ四駆を走らせてデータを取り続けると寿命が来る計算になります。 もう少し実際の数字を入れると、100ms毎に5Byteのデータとして120秒で6000バイト、8Kバイト毎に書き込みエリアを区切ってやるとエリアあたり1/8の書き込み頻度になるので、EEPROMを使い潰すには10年以上頑張らなきゃいけません。さらに、カタログ値は「最小」100万回なので実力はその数倍はあると予想出来ます。
nac_tnk

2020/10/25 19:20

あぁ、元のスケッチは別のデバイスのスケッチだったんですか。 っていうか、私自身INA226のデータシートを見ていました。 これじゃ違う訳ですね。 それでもまぁよくここまで動いたものだなぁ。 PADさん、INA260のデータシートを見てください。 兄弟のようなデバイスでも、同じレジスタになっているとは限りません。 基本的な誤りは、INA260なのに、INA226のスケッチを使った事です。 INA260なら、INA260の作例を探してください。 00h Configuration Register 01h Current Register 02h Bus Voltage Register 03h Power Register とレジスタ位置が異なっています。 問題にしていた Current (04h) : の4番のアドレスにはアクセス出来るレジスタがありません。 何故、同じ値を書いたはずのConfiguration Register値が異なっているのか?は不明ですけど、 まずは正しく動作するスケッチに直す事です。 (アクセスしたらいけない6番地にCalibration値を書き込もうとしたりして、そういった不具合がでたのかもしれません)
PAD

2020/10/26 12:19

>thkanaさん >nac_tnkさん ご指摘ありがとうございます。 おっしゃる通り #define INA226_REG_CONGIGURATION_REG 0x00 // Configuration Register (R/W) #define INA226_REG_CURRENT 0x01 // Current (R) #define INA226_REG_BUS_VOLTAGE 0x02 // Bus Voltage (R) #define INA226_REG_POWER 0x03 // Power (R) #define INA226_REG_MASK_ENABLE 0x06 // Mask/Enable (R/W) #define INA226_REG_ALERT_LIMIT 0x07 // Alert Limit (R/W) #define INA226_REG_DIE_ID 0xFF // Die ID (R) と書き換えましたところ正常に数値が表示されました。 この件再度購入元へ報告し、既に発送の手続きが行われていれば振込にて代品は購入させて頂きたいと連絡を取っています。 以降データシートをしっかりと注視したいと思います。 正常に表示されたことを踏まえまして、アドバイスを受け本日までに試した内容をご報告したいのですが、かなり長くなってしまいましたので質問の方へ記載致します。 よろしくお願い致します。
thkana

2020/10/26 14:35

え~っと、C/C++の文法は一通り勉強してから(一通りのあとは本をみながらとかで構わないので)プログラムをいじって下さいね。あてずっぽうで動くほどプログラミングは甘くないです。
nac_tnk

2020/10/26 15:26

もう、その変更したものを「INA226」→「INA260」で「すべて置換」をした方が良いです。 で、ログ記録以外の無駄な事を省けば void loop(){ eep_write_data(readRegister(INA260_REG_BUS_VOLTAGE),readRegister(INA260_REG_CURRENT)); delay(1000); } だけです。(レジスタ値をそのまま記録) 読み出し時、或いは読みだした後に、EXCELとかでデータを検証する時に、 補正値×1.25[mV]、×1.25[mA]をすれば良いんじゃないですか?
guest

回答2

0

まず。
ArduinoはC++言語をベースにしています。つまり、Arduinoのリファレンス類は、C++の知識を前提としていて、C++に関することはリファレンスには書いてありません。もしその知識に不安があるなら、C++の入門書かなにかを手元においてください。そんなに高度なことはやっていないので古い入門書レベルでまず間に合うと思います。C++は2010年代に結構規格が大きく改訂されているのですが、Arduinoで使う場合は殆どそこには踏み込まないでしょう。
さらに言えば、C++はC言語から派生していて、多くをCから引き継いでいます。つまり、なにかを調べるときはC言語で調べたほうがいろいろ引っかかることもある、ということです。

>> とか & はビットレベルで(つまり2進数として)値を操作する演算子です。
>>はビットシフト。2進数0b11110000があったとして、0b11110000 >> 1は0b1111000、0b11110000 >>5は0b111を返します。8bitは1byteですから、2バイトのデータ0b0001000100100010(0x1122)に対して0x1122>>8とすると、0x11が得られます。つまり、2バイトデータの上位バイトだけが得られたわけです。

&はビット論理積。左辺と右辺でどちらもビットが1の場所は1に、そうでなければ0を返します。
例えば、0b1010 & 0b0011 は0b0010を返します。ここで、0x1122と0xff(0b11111111)との&を取るならば、0x22が得られることになります。この処理は、一方のビットが0のところは全部0にして1のところだけを取り出すので、「(ビット)マスク」などと呼ばれることもあります。ビット1を窓(□)に置き換えてみると、0b1010 を0b00□□の窓を覗いてみる、みたいなイメージですね。
で、0xffでマスクするということはつまり下位バイトだけを取り出す、ということになります。

Arduino UNOのint型は2バイトなので上位、下位バイトしかありませんが、long型であれば4バイトありますので、こいつらを組み合わせて、long value=0x11223344;のとき
value & 0xff で 0x44が得られる
(value >> 8) & 0xff ->0x33
(value >> 16) & 0xff ->0x22
(value >> 24) ->0x11
として各バイトを取り出すというのはほぼ常套手段です。(もっとも、(unsigned) char型変数に収めるなら、& 0xffの部分は不要かも知れません。8bitしか変数に収まらないので。でも、今どきのコンパイラはそういうのを勝手に「最適化」してくれるので、つけておいたほうが無用な事故を防げるでしょう)

printlnからの書き換えにおいては、もちろん「人間が見るための情報」は必要ないので、変数の中身だけをEEPROMに記録していくことになります。
電圧測定については、1LSB(最小ビットの重み)が1.25mVとのことなので0~4095の12bit=3byteあれば今回の用途には足りますね。電流は、さすがに255mAでは足りないでしょうから2byte、つまり5byteが一つのデータの組になるでしょう。そうすると、EEPROMには例えば

EEPROM addressデータ番号データ
00000電圧1バイト目
00010電圧2バイト目
00020電圧3バイト目
00030電流1バイト目
00040電流2バイト目
00051電圧1バイト目
00061電圧2バイト目
00071電圧3バイト目
00081電流1バイト目
00091電流2バイト目
以下略

みたいな形式で格納することになるでしょう。データ番号を変数idxとするなら、書き込みは

C++

1eep_write(device_add, idx*5+0, voltage&0xff); 2eep_write(device_add, idx*5+1, (voltage>>8)&0xff); 3eep_write(device_add, idx*5+2, (voltage>>16)&0xff); 4eep_write(device_add, idx*5+3, current&0xff); 5eep_write(device_add, idx*5+4, (current>>8)&0xff);

といったあたりでしょうか。データの配置は、書き込みと読み出しでスジが通っていればいいので、好きにアレンジしてください。

(なお、addというと加算のaddと紛らわしいので、addressを略すならadrとかaddr, adrsとか略した方がよいかと思います)

投稿2020/10/22 00:21

編集2020/10/22 00:24
thkana

総合スコア7703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

PAD

2020/10/22 13:33 編集

丁寧に教えていただきありがとうございます。 >>8と0×ff、&がどういう意味なのかを理解でき、スッキリとすることができました。 ※以降内容を質問追記に転載しました。
thkana

2020/10/22 13:14

すみません、今日はなんだか眠いので... > 追加質問失礼致します。 コメント欄はマークダウンも使えずゴチャるので質問に追記していただけませんか。
PAD

2020/10/22 13:34

お世話になっております。 内容、質問の方へ移動致しました。 お時間ある時で構いませんので是非よろしくお願いします。
thkana

2020/10/22 23:51

電圧測定端子オープンだともう少しノイズで値が振れそうに思いますけれど、なんともいえないので とりあえず、電圧測定端子にArduino基板から3.3Vを(あるいは乾電池で1.5Vとか3Vとか)かけて、 電流測定端子に適当な抵抗を通して電流を流して、それらしい測定値が得られるかやってみたらいかがですか。 経験のないパーツなら、全部をいっぺんに動かさないでそれぞれのパートを動かしてから組み合わせた方がよろしいかと。
guest

0

INA260とEEPROMが使っているIICという通信方式は、1バイトごとの転送を行います
ということで、センサの測定値が2バイト幅になる場合は、その測定値の上位バイト、と、下位バイトを分けて、(バイトごとに)書き込みを行う必要が出てきます
①の双方とも同じことをしてまして、それぞれ上位バイトと下位バイトを順番に書き込んでいる、ということを行っています

②println関数は文字列をうけて出力しますが、先に言ったようにEEPROMの書き込みは1バイトごとに行われます
そこらへんちょっと考え方を変える必要が出てきますね

投稿2020/10/21 12:58

編集2020/10/21 12:59
y_waiwai

総合スコア88042

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問