• 締切済み

PIC I2C について

8ビットのデータを送り、そのままスレーブのLEDに反映させるプログラムを組んでいます。 マスターからはリピートして何度もデータを送ります。 このとき、なぜか一瞬アドレスのビットデータをLEDに反映させてから本来のデータを表示します。 つまり、アドレスとデータを交互にLEDに表示する状況です。 たとえば、アドレスが 0b1111111 データが 0b00000000 だとします。 本来LEDは消灯状態にならなくてはいけないのですが、なぜか一瞬アドレスデータの内容で光ります 原因がお分かりの方はいらっしゃいますか? 使用PIC PIC16F873A //master #use i2c(MASTER, SDA=PIN_C4, SCL=PIN_C3, SLOW, RESTART_WDT, FORCE_HW) output_float(PIN_C3); output_float(PIN_C4); while (1) { i2c_start(); i2c_write(AddData << 1); i2c_write(sBitData); i2c_stop(); delay_ms(50); } //slave #use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, ADDRESS=0x00, SLOW, RESTART_WDT, FORCE_HW) output_float(PIN_C3); output_float(PIN_C4); while (1) { if (i2c_poll()) { indata = i2c_read(); output_b(indata); } }

みんなの回答

  • inara1
  • ベストアンサー率78% (652/834)
回答No.3

zero-spicaさんは締め切るのが早すぎます。 「オペアンプ通過後の波形のゆがみについて」の回答です。 > NJM4580DD もしくは LM386N が利用でき LM386はオペアンプでなくパワーアンプですが、LM358Nの間違いでしょうか。 >波の一番下は 2V 程度に見えます。上はおそらく 5V 程度です。 その電圧だと反転現象は起きないはずですが・・・ NJM4580を5Vの単一電源で使ったとき、入力電圧範囲は +1.6V~+3.4V なので、振幅が1.8Vpp未満信号しか扱えません。LM358の場合、入力電圧範囲は 0V~+3.5V なので、振幅が3.5Vppまでの信号を入力できます。入力信号が 2V~5Vの範囲で振れるのなら、NJM4580はダメです。LM358を使うべきです。 添付回路では、入力信号に重畳されたDC電圧がコンデンサC1でカットされます。DC成分がカットされた入力信号には1.667VのDC電圧が重畳されます。1.667Vの電圧というのは、抵抗R1とR2を使って電源電圧(5V)を1/3倍して作ったものです。1.667Vを中心にした信号に変換すると、LM385の入力電圧範囲を有効に使えるようになります(入力信号が3.333Vppの信号のとき、LM358の入力電圧は0V~3.333V)。その信号をLM358のバッファで1倍し、バッファの出力信号はコンデンサC2で再びDC成分がカットされ、AC信号だけが出力されます。途中でいじっているのはDC成分だけで、振幅は入出力とも同じです。入力信号にDC成分が重畳していても構いませんが、振幅は最大3.3Vpp程度が限度です。この回路の周波数帯域は1Hz~1MHzです。

  • inara1
  • ベストアンサー率78% (652/834)
回答No.2

「オペアンプからプラスマイナスで出力変換」でお答えしようとしたら既に締め切られていました。質問が違いますがここでお答えします。 添付図のような回路でできます。この回路はDC信号も扱えるので入力信号がどんな波形でも、±5Vを0Vから12Vの信号に変換できます。 +側電源を12Vとしたとき、+12Vの出力電圧を出すために、出力電圧が電源電圧いっぱいに振れるCMOSオペアンプのLMC662 [1] を使いました。LMC662の最大電源電圧(±電源電圧の差)は+16Vなので、-側の電源電圧は-3Vとしています(-側を-12Vとすると壊れる)。 入力信号の±5V を R1 と R2 で3/5倍し、±3Vに変換してLMC662に加えています。そうするとLMC662の入力電圧は電源電圧範囲内(-3V~+12V)に収まります。この±3Vの入力信号を2倍し、オフセット電圧を加えることで、±6Vにオフセット電圧が加わった信号が出力されます。オフセット電圧は可変抵抗VRを変えることで、0Vから12Vの範囲で変えることができます。図の回路では可変抵抗の位置が半分程度のところで6Vのオフセット(出力電圧が0V~12V)になるようになっています。 LMC663の-側の電源電圧はダイオード(1S4148) [2] で作っていますが、ダイオードの順方向電圧(Vf)のバラツキのために、LMC663の-側の電源電圧が-3Vより高くなる(-2.9Vなど)ことがあるかもしれません。そのときはダイオードをもう1本追加して5個直列としてください。LMC662の最大電源電圧は16Vなので、+側電源電圧(12V)と-側電源電圧(-3V)の差が16Vを越えないように注意してください。 [1] LMC662(2個150円) http://akizukidenshi.com/catalog/g/gI-00067/ [2] 1N4148(50本100円) http://akizukidenshi.com/catalog/g/gI-00941/

  • Yorisin
  • ベストアンサー率54% (364/663)
回答No.1

I2CのデータバスにLEDを直結して(もしくはトランジスタか何かを用いて)、データバスの状態に応じてLEDを点灯・消灯させようとしていますか? I2CのSDAはInput/Output共用のため、アドレス:11111111からデータ:000000000をリードしたらSDAから直接制御している場合、 バスに流れるデータとしては111111110000000000 となりますので、LEDは点灯×9回、消灯×9となります。 (ACKを含む) 時間は非常に短いでしょうから、一瞬の点灯と消灯のように見えるのではないでしょうか?

zero-spica
質問者

補足

I2C の通信内容を視覚的に表示する意図では LED は接続してません I2C のネットワークバスはあくまで I2C 通信のためだけに存在しています LED は RB の足にひとつずつ、計8個付いています たとえば 01001001 というデータを送ると ●○●●○●●○ という風に発光します。 ACK や スタートコンディションなどを省いた例ですが、アドレスが 0b0111001 データが 0b00001111 だとします I2C の通信フォーマットでは以下のように送信されています  01110010 00001111 これを受信した場合、本来以下のように LED が発光します  ●●●●○○○○ ですが、実際には以下のようになります  ●○○○●●○○ (一瞬発光)      ↓  ●●●●○○○○ 書き方が悪かったようで、申し訳ありません

関連するQ&A

  • I2C通信のスレーブアドレスについて

    電子回路初学者です。 I2C通信は、まず自分が (例としてマイコンが) マスターになる宣言をし、バスの所有権を得て、次に通信相手となるスレーブアドレスを指定し、データを送受信するものだと理解しています。そこで質問があります。 このスレーブアドレスとは製品固有のものなのでしょうか。 例えば、X社製のXというセンサーはスレーブアドレスが0x74である、といった具合です。 それとも、マイコンのポートxのyビット目 (SDAまたはSCL) にぶら下がっているスレーブにスレーブアドレス0x74を持たせる、といった具合に任意に決定できるのでしょうか。 実際に使用する場合の解説が見当たらず悩んでおりました。 よろしくお願い致します。

  • Arduino INA219 I2C通信できない

    Arduinoのsda, sclにINA219のsda, sclを接続すると出力が止まってしまいます。 確認のためLCDを使ってI2C通信を試してみましたが問題なく動作しました。

  • PIC24FでI2C

    PIC24FでRTCを制御するためのI2C通信がうまくいかず困っています。 そこでSDA/SCLから信号が出ているかのみを確認するため 下記のようなプログラムをPICに書込みました。 (STARTの出力のみ) 当方オシロを持っていませんので汎用のテスタでSDA/SCL電圧の一時的な変化を読み取ろうと試みましたが全く電圧の変化はありません。 #include "p24FJ64GA002.h" _CONFIG1( JTAGEN_OFF & GCP_OFF & GWRP_OFF & BKBUG_OFF & COE_OFF & ICS_PGx1& FWDTEN_OFF ) _CONFIG2( IESO_ON & FNOSC_FRC & FCKSM_CSDCMD & OSCIOFNC_OFF & IOL1WAY_ON & I2C1SEL_SEC & POSCMOD_NONE) int main(void) { AD1PCFG = 0xffff; CLKDIV = 0; TRISA = 0xFFE3; TRISB = 0x006F; LATB = 0x0010; CNPU1 = 0x003C; /// I2Cの初期設定 I2C1BRG = 0x27; I2C1CON = 0x8000; I2C1RCV = 0x00; I2C1TRN = 0x00; while(1){ I2C1CONbits.SEN = 1; while(I2C1CONbits.SEN); } } 心ある方、どなたかご教示お願いいたします。

  • H8/SX で I2C通信

    H8/SX 1655 を使ってI2C通信を試みています。 マニュアルには、送信レジスタ(ICDRT)にデータを書き込めば 自動的にシフトレジスタ(ICDRS)に転送されて、SCL SDA 端子から クロックパルスが出力されると書かれています。 とすると、パルスの出力だけなら Reset 後 MSTP.CRB.BIT._IIC0 = 0;  /* 寝ているI2C0を叩き起こす */ IIC20.ICDRT = 0x90;  /* [Start byte] Slave Address + Write */ この2行で事足りると思うのですが、実際にはクロックパルスは 出力されません。きっと必要な何かが不足しているのだと 思うのですが、当方、初心者にて皆目見当がつきません。 どなたかご教示いただけないでしょうか。 因みに動作モードは、モード6とモード7で試してみました。 よろしくお願いいたします。

  • PICでのプログラミングについて教えて下さい。

    現在電圧計を製作していて4桁の7セグダイナミック点灯で行き詰っております(超初心者です)。 PICは16F873Aを使用、コンパイラはCCS、書き込みはピックライタ、あとシリアルデバッカを使用しています。 外部から電圧をかけそれをAD変換し、AD変換結果(0~5V)を7セグに表示させようとしています。 一応今の状態でも電圧表示はできていることはできているのですが一桁目から4桁目まで目で追えるくらい遅いスピードでこれを改善したいです。ソースは下記のソースを製作しました。この状態で3日間悩んでおります...知恵をお貸しいただけないでしょうか。 よろしくお願いします。 #include <16F873a.h> #device ADC=10 //A/D変換10bitモード #use fast_io(A) /* TRISレジスタの設定が必要 */ #use fast_io(B) #use fast_io(C) #use delay (clock=10000000) //10MHz #use RS232( BAUD = 9600, XMIT = PIN_C6, RCV = PIN_C7, PARITY = N, BITS = 8 ) #fuses HS,NOWDT,PUT,NOPROTECT,NOBROWNOUT,NOLVP #define VOLTAGE PIN_A0 // (in) #define CORRENT PIN_A1 // (in) #define VREF1 PIN_A2 // (in) #define VREF2 PIN_A3 // (in) #define RESERVE1 PIN_A4 // (out) #define RESERVE2 PIN_A5 // (out) #define LED_DP PIN_B0 // (out) #define LED_A PIN_B1 // (out) #define LED_B PIN_B2 // (out) #define LED_C PIN_B3 // (out) #define LED_D PIN_B4 // (out) #define LED_E PIN_B5 // (out) #define LED_F PIN_B6 // (out) #define LED_G PIN_B7 // (out) #define DIG_0 PIN_C0 // (out) #define DIG_1 PIN_C1 // (out) #define DIG_2 PIN_C2 // (out) #define DIG_3 PIN_C3 // (out) #define INI_TRIS_A_VAL 0x0F // 7:x 6:x 5:out 4:out 3in 2:in 1:in 0:in #define INI_TRIS_B_VAL 0x00 // 7:out 6:out 5:out 4:out 3out 2:out 1:out 0:out #define INI_TRIS_C_VAL 0x80 // 7:in 6:out 5:out 4:out 3:out 2:out 1:out 0:out int ct;//数字の更新間隔 long val;//表示する数字 int digit;//表示する桁 //表示パターン int segment_data[]={0x81,0xF3,0x49,0x61,0x33,0x25,0x05,0xF1,0x01,0x31}; char st[4]; void main() { float ata1,data2,data3,data4; long data5; long val; SET_TRIS_A( INI_TRIS_A_VAL ); SET_TRIS_B( INI_TRIS_B_VAL ); SET_TRIS_C( INI_TRIS_C_VAL ); setup_adc_ports(AN0_AN1_VSS_VREF); setup_adc(ADC_CLOCK_DIV_32); //Fosc/32 最高速度 digit=0; ct=1;//数字を更新する周期 val=0;//表示する値 while(1) { output_low(RESERVE2); //動作ランプ //////////////////////電圧測定///////////////////////////////// set_adc_channel(0); delay_us(50); //アクイジションタイム待ち(マイクロ秒) data1 = read_adc(); //AD変換結果読み込み printf("ADC V %9.3f \r\n", data1 ); //AD変換データ表示 data2 = (data1 * 4.959695) / 1024; //BCDに変換 printf("Volt %6.3f \r\n", data2 ); //変換データ表示 data5 = data2 * 1000 ; //data2を整数に変換 val = data5 ; printf("val %ld \r\n", val); //整数にし表示 /////////////////////7SEG表示////////////////////////////////// ct --; if(ct == 0){//数字の更新 st[3]=val/1000; //4桁目数値取り出し st[2]=val/100-st[3]*10;//3桁目数値取り出し st[1]=val/10-((st[3]*100)+(st[2]*10));//2桁目数値取り出し st[0]=val%10;//あまり val++; if(val==1000) val=0; ct=20; } if(digit== 3){//第4桁の表示 output_b( segment_data[st[3]]); output_bit(DIG_0,1);  //4桁表示開始 output_low(LED_DP);  //小数点表示  delay_us (5); //表示期間(ミリ秒) output_bit(DIG_0,0); //表示を消す output_high(LED_DP); //小数点を消す delay_us(50); //待ち(マイクロ秒) } if(digit== 2){ output_b( segment_data[st[2]]); output_bit(DIG_1,1); delay_ms (5); output_bit(DIG_1,0); delay_us(50); } if(digit== 1){ output_b( segment_data[st[1]]); output_bit(DIG_2,1); delay_ms (5); output_bit(DIG_2,0); delay_us(50); } if(digit == 0){ output_b( segment_data[st[0]]); output_bit(DIG_3,1); delay_ms (5); output_bit(DIG_3,0); delay_us(50); } digit ++;//表示桁を変更 if(digit ==4 ) digit=0; } }

  • PICマイコンによるI2C通信について

    私は高専の学生で、マイコンを使う部活に所属しております。 今回の活動で、複数のPICを使用することになり、I2C通信を使おうと思っています。 そこで、ある問題が発生しました。 PICによるI2C通信の解説を行っているとある方のサイトには、 「I2Cの通信方式は+5VにプルアップされたSDAとSCLの各信号線を、それぞれのデバイスがオープンドレイン等によるワイヤードオア接続で信号の操作と共有を行っている関係から、 電気的にはあまり強い環境ではありません。 なので、沢山のデバイスを接続したり、通信距離を長くしたりといったことには不向きなので、 ハードウエアの構築には細心の注意が必要でしょう。」 とあります。 今回の活動で使うPICは、事情により700~800mm程度離れた状態になると思われます。 距離が長い通信には不向きとありますが、この場合は大丈夫なのでしょうか。 また、I2C通信が不可能な場合はどのような通信手段を使えばよいのでしょうか。 知っている方がいらっしゃったら、御回答をよろしくお願いいたします。

  • PCA9564の使用方法

     PCA9564を用いて、PCのパラレルポートでI2Cのコントロールを行おうと考えています。PCA9564にスレーブとして、アドレスが0101111のICを接続して、SDA,SCLラインに接続しています。START CONDITIONを制御して、SDAがLowになり、SCLもLowになることを確認してから、SLA+W(アドレス指定と書き込み指定)を送るために、01011110(8bit目はWriteを示す0)を添付のように送っています。最後の9bit目にはACKがスレーブの端末から帰ってくるため、本来は0が返ってくるはずですが、1が返ってきておりNACKを示し、正しく制御できていません。以下に制御方法を記載しますので、ご存じある方はご指導のほどよろしくお願いします。 1.17番端子のResetを1⇒0⇒1にして実行 2.A1A0を11にして、I2CCON状態にして、ENSIOとSTAを1にする(01100100)。 WRを1⇒0⇒1にして実行。このときにSCLとSDAはLowになる 3.A1A0を01にして、I2CDATにして、D7:D0を01011110にして、WRを1⇒0⇒1にして実行。 このときは何も出力されない 4.A1A0を11にして、I2CCON状態にして、STAを0にする(01000100)。 WRを1⇒0⇒1にして実行。このときに添付のクロックが見える。最後の9bit目のSDAが Highになるため、おかしい。  疑問点として、3の時に実行してもSDAとSCLラインには何も出力されませんが、 これは正しい動作なのでしょうか?

  • I2Cについて

    現在、DALLASセミコンダクター社のDS1307というリアルタイムクロックICを制御しようとしています。 仕様書を見ると、I2Cという言葉が出てきたので、自分なりに調べて制御を試みています。 今は、SDA,SCLに与える信号をタイミングが合うように1bit毎に出力していますが、うまくいきません。 具体的には、DS1307からACK信号が帰って来ないためタイムアウトエラーなります。 何かアドバイスがある方がいましたらお願いします。

  • picのループ

    昨日、picの割り込みに関してご質問させていただいたものです。 割り込みに関しては皆様のおかげで解決できましたが、別の問題に直面いたしました。 while(1)を1回処理した後は、動作が停止してしまい、割り込みも受け付けなくなってしまいます。 #INT_RB//割り込み定義 void RB_isr(){         割り込み処理        } void main() { while(1) { output_low(PIN_C4); delay_ms(200); output_high(PIN_C4); delay_ms(200); //自動起動ボタンONで起動 if(input(PIN_B6) == 0) { 入力があった場合の処理          } } } 上記のように、while(1)の先頭部に動作確認用のled点滅プログラムをいれていますが、入力があった場合の処理が終了した後はledも点滅しません。 入力があった場合の処理の最後にリレーをoffしているのですが、その処理はきちんと行われています。 どうしてこのようなことがおこるのか分かる方がいらっしゃいましたら、ご教授ねがいます。

  • I2C通信について

    マイコンにI2C通信対応ICを5個接続して使用しようとしています. 基板上で5個のICのI2Cバスを接続して通信したところ,1個だけ(型番 : INA231)データが正常に返ってきませんでした. オシロで波形を確認すると,INA231と通信する時のみ,SDA/SCLともに波形の電圧が正常時の半分程度でした.他の4個のICとの通信時は正常な電圧(highが電源電圧)でした. 試しに,マイコンとINA231を1:1で接続してI2C通信すると問題なくデータを取得できたため,プログラムは問題ないことが確認できました. 上記のような現象の発生原因と,対策など,お分かりになられる方がいらっしゃいましたら何卒ご教授よろしくお願い致します.