人気ブログランキング | 話題のタグを見る

(5/16追記14日に気が付いているが、ChatGPTの回答のコピーなので部分的に間違っているのを修正)

前回の記事に従って、Cソースを修正している時ACK受信感じた違和感をChatGPTに指摘したが、自分がbit0とbit1が逆の役割と勘違いしていたからだった。
正しいコードはコメントも含めてこうなる。

~~~~~
// SDA解放
(5/16追記ここだけ間違っているので修正)
pioset(1); // SDA入力、SCL出力Low
pioput(1);
(5/16追記修正おわり)

// SCL解放
pioset(3);

// クロックストレッチ待ち
do{
 w = pioget();
}while((w & 0x02)==0); // SCL=1待ち

// ACK判定
if ((w & 0x01)==0) {
 // ACK
} else {
 // NAK
}

1.スレーブにACKビットを任せるためSDAを解放する。
2.SCLを解放して9ビット目を開始する。
3.スレーブがクロックストレッチしていればSCLをLowに保持するので、SCLがHighになるまで待つ。
4.SCLがHighになったらSDAを読んでACK/NAKを判定する。

という、I²Cの仕様に沿った自然な処理になります。
~~~~~

※ このACKコードはGoogle Sheetの複数の上矢印↑のACK部分だ。

そして前後の入力切り替え処理だが、

[入力切り替え]
前の入力切り替え処理は、このACK受信処理に含まれているので不要で、
後の入力切り替え処理は、SCL/SDA両方を出力切替にして、次に⑦でSCL Low/SDA Lowから始まっているので、pioset(0);pioput(0)となり不要。
そして残る「初」の①だが、これの前の入力切り替えも①が⑦と同じSCL Low/SDA Lowなので、不要だ。

[結論]
つまり、ACK受信の前や①や⑦の前の[入力切り替え]処理は不要。
※ もちろん「初」に30msの遅延で、スレーブにSCL Low/SDL Lowを検出させるウエイト時間は必要だ。

あとでGoogle Sheetからも削除してACKの中を詳細化すべきだろう。

修正Cソース:
(結局動かなかった)

次の記事で動いたソースを載せる。

# by k1segawa | 2026-06-14 11:13 | ポケコン | Comments(0)

(5/16追記)
間違っている旧4=SCL、5=SDAの回路図だけは修正済み。
これに伴うChatGPTの回答は、4を5、5を4に置き換えて読む事。
(5/16追記おわり)

つまり、どういうことかと言うと、

マスタ側データ送信は、次のようになる。
データ1を送信する例を4ピンで、
データ0を送信する例を5ピンで説明する。

[マスタ側データ送信]

[PC-G850V] ポケコンでI2C通信 実機確認 - ピンのON/OFFを見直し 図解 (6/13)_a0034780_03442748.png

(5/16追記)4、5ピンの役割を取り違えたのでSCLとSDAをSDAとSCLに修正済み(おわり)
【SDA/SCLへの出力の場合】
(4,5)=(SDA 0,SCL 0):pioset(0),pioput(0)
(4,5)=(SDA 1,SCL 0):pioset(1),pioput(1)
(4,5)=(SDA 0,SCL 1):pioset(2),pioput(2)
(4,5)=(SDA 1,SCL 1):pioset(3)
(5/16追記修正ココまで)
と設定する。

マスタから0を送りたい時は、ポートを出力モードにして0を出力し、
マスタから1を送りたい時はポートを解放すると、入力に自然となるのだ。

オープンドレイン方式(回路的にはワイヤードAND構成)というやつだ。

※ マスタからデータを送りたいのと、ポート(ピン)の出力モードは別物だという事!
電気理論は奥が深いな~


で、このオープンドレイン方式で、マスタ側データ入力は、以下のようにする。

[マスタ側データ入力]
[PC-G850V] ポケコンでI2C通信 実機確認 - ピンのON/OFFを見直し 図解 (6/13)_a0034780_03443648.png

(5/16追記)4、5ピンの役割を取り違えたのでSCLとSDAをSDAとSCLに修正済み(おわり)
【SDA/SCLからの入力の場合】
(5/16追記修正ココまで)
(4,5)=(0,0):pioset(3),w=pioget(),(w & 0x03)==0
(4,5)=(1,0):pioset(3),w=pioget(),(w & 0x01)==1→0x03
(4,5)=(0,1):pioset(3),w=pioget(),(w & 0x02)==10x03,2
(4,5)=(1,1):pioset(3),w=pioget(),(w & 0x03)==3

となるという事。

ここで、以下のようにChatGPTにチェックをかけてもらったら、取り消し線の指摘が的確にあったので、修正した。

素晴らしい事に、「クロスストレッチ」による、ACK受信待ちの方法もついでに教えてくれた。感謝。


(5/16追記 ここからは修正できないのでそのままにしてある。↑上のピンとpio関数の関係とSDA/SCLで読み解く事。)
[ChatGPTとのやり取り]
~~~~~
質問:
これで合っていますか?
【両4,5ピン出力の場合】
(4,5)=(SCL 0,SDA 0):pioset(0),pioput(0)
(4,5)=(SCL 1,SDA 0):pioset(1),pioput(1)
(4,5)=(SCL 0,SDA 1):pioset(2),pioput(2)
(4,5)=(SCL 1,SDA 1):pioset(3) と設定
【両4,5ピン入力の場合】
(4,5)=(0,0):pioset(3),w=pioget(),(w & 0x03)==0
(4,5)=(1,0):pioset(3),w=pioget(),(w & 0x01)==1
(4,5)=(0,1):pioset(3),w=pioget(),(w & 0x02)==1
(4,5)=(1,1):pioset(3),w=pioget(),(w & 0x03)==3
回答:
はい、基本的な考え方は合っています。

ただし、**I2Cとしては「1を出力する」のではなく、「1は入力(Hi-Z)にする」**という考え方になるので、少し整理すると分かりやすくなります。

出力
SCL SDA 設定
0 0 pioset(0), pioput(0)
1 0 pioset(1), pioput(1)
0 1 pioset(2), pioput(2)
1 1 pioset(3)

ここで、

pioset(0):4,5ピンとも出力
pioset(1):4ピン入力、5ピン出力
pioset(2):4ピン出力、5ピン入力
pioset(3):4,5ピンとも入力

だとすると、

(SCL,SDA)=(0,0)
→両方を出力にして0を出力

(SCL,SDA)=(1,0)
→SCLを入力(解放)
→SDAを出力0

(SCL,SDA)=(0,1)
→SCLを出力0
→SDAを入力(解放)

(SCL,SDA)=(1,1)
→両方入力(解放)

となり、I2Cとして理想的です。

入力

ここは少し修正した方がよいです。

pioset(3); // 両方入力
w = pioget();

として、

(w & 0x03)==0 // (0,0)
(w & 0x03)==1 // (1,0)
(w & 0x03)==2 // (0,1)
(w & 0x03)==3 // (1,1)

と判定するのが自然です。

質問の

(w & 0x02)==1

は、

w & 0x02

の結果が取り得る値は

0
2

なので、

(w & 0x02)==1

は常に偽になります。

したがって

(0,1):(w & 0x03)==2

または

(w & 0x02)!=0

とする必要があります。

ACK受信

例えば、

// SDA解放
(5/16追記 下からここも意味がわかったので修正できる - ↑上から、解放は入力モードにする事)
pioset(1); // SCLDA入力、SDACL出力0
pioput(
);

// SCL解放
pioset(3);

// クロックストレッチ待ち
do{
  w = pioget();
(5/16追記 下からここも意味がわかったので修正できる)
}while((w & 0x01)==0); // SCL=1待ち

// SDA読む
(5/16追記 ここは意味がはっきりしてるので修正できる)
if((w & 0x02
1)==0)
  ACK;
else
  NAK;

のようにすると、クロックストレッチ対応のI2Cになります。


この pioset() と pioput() の仕様が、

bit0 = 4ピン(SCL)←(5/16追記 残念。ここ以降ChatGPTの誤回答がわからなくなるので残す)
bit1 = 5ピン(SDA)
pioset():1=入力、0=出力
pioput():出力時の値

であるなら、PC-G850VのソフトウェアI2Cとしてかなり美しい実装になっていると思います。特に (1,1)=pioset(3) だけで両線を解放できるので、START、STOP、ACK、クロックストレッチの処理が非常に書きやすそうです。
~~~~~(ChatGPTの回答おわり)

これで、メインである旧出力pioput(n)をそれぞれ書き換えると、
マスタ側データ送信の上から順に対応するので、

☆ 次の記事でやらかしたので、逆と勘違いしやすいのであえてここに書く。
(これより上の内容にも間違いがありそうなので見直すように!)

(5/16追記やっと追いついた。ここからは逆だったことに気が付いている)
☆ bit 0が4ピンでSDA、bit 1が5ピンでSCLであるので、

旧pioput(0)→pioset(0),pioput(0) /* bit 0:SDA 0,bit 1:SCL 0 */
旧pioput(1)→pioset(1),pioput(1) /* bit 0:SDA 1(入力モードで1を出力しても無効なのがポイント), bit 1;SCL 0 */
旧pioput(2)→pioset(2),pioput(2) /* bit 0:SDA 0,bit 1:SCL 1 */
旧pioput(3)→pioset(3) /* bit 0,1:SDA 1,SCL 1(入力モードにするとオープンドレインでHiになる) */

に書き換えればよい。

そして、ACK受信処理は、
例えばの後のSDA解放・SCL解放・クロックストレッチ待ち・SDA読むをそのまま採用する。

Cソースを書き換えよう。出力側のコメントも、1をxxx入力、0をxxx解放、に修正しよう。

# by k1segawa | 2026-06-13 22:28 | ポケコン | Comments(0)

(5/16追記)
間違っていた旧4=SCL、5=SDAの回路図を与えてしまった時のChatGPTの回答なので、
正しく、4ピンは5ピン、5ピンは4ピンへと修正済み。
(5/16追記おわり)

その後、ChatGPTに聞いたところ、こんな点を指摘されてしまった。
~~~~~
一つ気になる点

PC-G850Vの11ピンの4、5番端子が、
CMOS入出力でHighインピーダンスにできる
Low出力が可能

ならそのままI2Cをソフトウェアで実装できます。

しかし、
High出力(プッシュプル)しかできない
出力モードで常にHを駆動する
ような仕様だと、I2CデバイスがLowを出力したときに衝突します。


PC-G850Vでは通常、ポートを

High(入力状態)
Low(出力)

のように切り替えてI2Cを実装するため、ポート仕様の確認が重要です。
~~~~~
なんだか、聞き覚えのある(プッシュプル・High Low・衝突)ような、無い(インピーダンス)ような言葉を使われてしまった。
そして、「ポートの仕様の確認が重要」との事。

赤の部分が理解できない。

なので、「ソフトウェアI2Cを実装予定です。理想の回路はどうなりますか?」で、出てきたのが前の記事の回路。

そして、その説明が衝撃だった。
~~~~~
回答:

I2Cでは High を出力するのではなく、


  • Lowを出力する
  • Highにしたい時は入力(High-Z)にする

という制御を行います。


例えばSDAなら、


状態ポート設定
Low出力0
High入力

SCLも同様です。

こうすると、4.7kΩのプルアップ抵抗によって自然にHighになります。

~~~~~
あれ?
クロックに合わせて、データHigh,Lowと送るだけじゃないの?

ポートを入力にしてHighを出力する?
どういうこと?

~~~~~
質問:
この場合、PC-G850VからのHiは1ですか?また相手側からのHiも1ですか?

回答:
はい、ソフトウェアI2Cではそのように考えてよいです。

ただし、「1を出力する」というより、

0(Low)を出力する
1(High)は出力しないで、入力(High-Z)にする

というのが正確な表現です。

PC-G850V側
Lowを送りたいとき
(5/16追記)ここの4、5をに修正済み(おわり)
5ピン(SCL) = 出力0
4ピン(SDA) = 出力0

電圧は約0Vになります。

Highを送りたいとき
5ピン(SCL) = 入力
4ピン(SDA) = 入力
(5/16追記ここまでで修正おわり)

すると4.7kΩのプルアップ抵抗によって、

+5V

4.7kΩ

SCL,SDA

が約5Vになり、論理1になります。

I2Cデバイス側

相手側も同じです。

相手が0を送りたいとき

内部トランジスタで線をGNDへ引き下げます。

相手が1を送りたいとき

何もしません(High-Z)。

その結果、プルアップ抵抗によって線は+5Vとなり、論理1になります。

まとめ
動作 PC-G850V I2Cデバイス 線の状態
1 解放(入力) 解放 High
0 Low出力 解放 Low
1 解放 解放 High
1 解放 Low出力 Low
0 Low出力 Low出力 Low

つまり、

「0は誰かが作る、1はみんなが手を離すことで自然にできる」

というのがI2Cの特徴です。

したがって、PC-G850Vから見ても、相手側から見ても、

Low = 0
High = 1

であり、双方とも「1」はプルアップ抵抗によって作られた同じ5Vの状態を見ています。

このため、送信側と受信側が同時に通信線を共有でき、ACK信号やクロックストレッチなどのI2C特有の動作が可能になります。

~~~~~


~~~~~

質問:

まさにクロスストレッチだと思うので、スレーブ側がACKの処理が長引いている時、SCL=Hiにしたままなので、SCLがLowになるのを待ち、SDAがLowになればACK、HiならNAK処理をしようと思っています。

回答:

その考え方はほぼ正しいですが、ACKの判定タイミングだけ少し注意が必要です。

クロックストレッチを考慮した場合、マスター(PC-G850V)側の処理は次のようになります。

SDAを解放(入力)
SCLを解放(入力)
実際にSCLがHighになるまで待つ
SCLがHighになったらSDAを読む
SDA=0ならACK、SDA=1ならNAK
SCLをLowにする

擬似コードで書くと、

; ACK受信

SDA ← 入力 ; 解放
SCL ← 入力 ; 解放

; クロックストレッチ待ち
while (SCL == 0)
;

; この時点でSCLは実際にHigh
if (SDA == 0)
ACK
else
NAK

SCL ← 0 ; 次のクロックへ

つまり、

SCLがLowになるのを待つ

ではなく、

SCLがHighになるのを待つ

になります。

なぜか?

スレーブがクロックストレッチしている間は、

マスター:SCLを解放(Highにしたつもり)
スレーブ:SCLをLowに保持

となっており、実際のSCL線はLowです。

SCL線
────┐ ┌────
     │____│

クロックストレッチ

スレーブの準備が終わるとSCLを解放するので、プルアップ抵抗によってSCLがHighになります。

そのHigh期間中にSDAをサンプリングして、

SDA=0 → ACK
SDA=1 → NAK

を判定します。

したがって、PC-G850VでソフトウェアI2Cを実装するなら、

SCLを解放

SCL端子を読み続ける

SCL=1になった

SDA端子を読む

ACK/NAK判定

という流れにすれば、クロックストレッチ対応の完全なI2Cマスターになります。

PC-G850Vの4、5ピンが入出力兼用であることを利用すると、まさにこの方式を自然に実装できます。Z80アセンブラでも比較的簡単に組めます。

質問:
なるほど。スレーブ側はACKを返す前にSCL Lowになっているので、処理が間に合わなければ、SCLをLowのままにして処理を引っ張っているのですね。
回答:
その理解で正しいです。

I2Cのクロックストレッチは、まさに

「ACKを返したいが、まだ準備が終わっていないので、SCLをLowのままにして待ってもらう」

という仕組みです。

1バイト送信後を例にすると、

マスター スレーブ
SCL ____|‾|_|‾|_|‾|_|‾|___________
              ↑
9ビット目(ACK)

SDA D7 D6 D5 D4 D3 D2 D1 D0 ACK

8ビット目を送り終えた後、

マスターはSDAを解放(入力)
マスターはSCLを解放(Highにしたつもり)
スレーブはまだ忙しいのでSCLをLowに保持
スレーブ内部で
データを取り込む
EEPROMなら書き込み準備
センサなら変換結果を準備
ACKを返せる状態になったら
SDAをLowにする(ACK)
SCLを解放
SCLがHighになったところでマスターがSDAを読む

という流れになります。

つまり、

SCLをHighにしたつもり

実際にはLowのまま

「まだ待って」

準備完了

SDAをACK状態にする

SCLを解放

マスターがACKを読む

という順番です。

そのため、ソフトウェアI2Cのマスターでは、

; SCLを解放
; ↓
Wait:
SCLを読む
Lowなら Wait
; ↓
; SCLが本当にHighになった
; ↓
SDAを読む
; ↓
0ならACK
1ならNAK

という実装が、クロックストレッチ対応の正しい実装になります。

ちなみに、I2Cの仕様上は SCLをLowに保持できるのはスレーブだけでなくマスターも可能 です。クロックの主導権はマスターにありますが、「Lowは誰でも作れる、Highはみんなが手を離した結果」というオープンドレイン方式のおかげで、クロックストレッチという非常に巧妙な同期機構が実現されています。

PC-G850VのようなポケコンでソフトウェアI2Cを実装する場合、この仕組みを理解していると、ACK待ちやバス競合の処理を非常に自然に書けると思います。

質問:
オープンドレイン方式というのですね。ワイヤードAND方式と言うのも効いた事があります。
回答:
はい、その通りです。

オープンドレイン方式(Open Drain)
ワイヤードAND方式(Wired-AND)

は密接に関係しており、I2Cでは両方の言葉が使われます。

オープンドレイン方式

これは、各デバイスの出力回路の構造を表す言葉です。

+5V

4.7kΩ

───────●──── 信号線

Tr

GND

トランジスタONで Low を出力し、

トランジスタOFFで「何もしない(High-Z)」状態になります。

つまり、

ON → 0
OFF → 解放

であり、Highを直接出力する回路はありません。

ワイヤードAND方式

これは複数のオープンドレイン出力を1本の線に接続したときの論理動作を表す言葉です。

例えば、

+5V

4.7kΩ

●───共通線
/\
A B

A、BのどちらかがLowを出せば、

A=0 B=0 → 線=0
A=0 B=1 → 線=0
A=1 B=0 → 線=0
A=1 B=1 → 線=1

となります。

これは論理積(AND)の真理値表と同じです。

A B 線
0 0 0
0 1 0
1 0 0
1 1 1

そのため、ワイヤードANDと呼ばれます。

負論理で見るとワイヤードOR

電子回路の教科書では、

「オープンコレクタはワイヤードOR」

という説明が出てくることがあります。

これは負論理で考えているためで、

Low = TRUE
High = FALSE

とすると、

Low OR Low → Low
Low OR High → Low
High OR Low → Low
High OR High → High

となるからです。

I2Cでは

回路的には

オープンドレイン出力

複数接続した結果の論理として

ワイヤードAND

と呼ぶのが一般的です。

PC-G850VでソフトウェアI2Cを実装する場合、

「0は積極的に作る」
「1はみんなで手を離して作る」

という感覚で考えると、クロックストレッチやACKの動作も非常に理解しやすくなります。

実際、I2Cは「オープンドレイン+ワイヤードAND」を最も巧みに利用した通信方式の一つと言えます。

~~~~~


# by k1segawa | 2026-06-13 21:10 | ポケコン | Comments(0)

(6/15追記)
ここの「結果」は、回路図が4=SCL、5=SDAだと思い込んでた頃の物なので、無効。
ソースはちゃんとしてるのに~
(6/15追記おわり)

BASICだと、定型パターンならOKだが色々試すには、
C言語で、それぞれの初期化や設定を関数化してパラメータを変えて呼び出すようにしないとやっかいだ。

そのため、組んだがうまく動かない。
BASICでもそうだったが、スレーブのACK応答が返ってこない。

Cソース:
/* SDA(4pin=bit 0) SCL(5pin=bit 1) */
send_start()
{
pioput(0);
pioput(1);
pioput(3); /* SDA 1+SCL 1 */
pioput(2);
pioput(0);
}
send_stop()
{
pioput(1);
pioput(3);
pioput(3);
}
send_i2c(unsigned char i2c)
{
/* pioput (SDA x+2*SCL x) DATA => Bit Pulse */
unsigned char b,c;

/* DATA=i2c(bit 7-0) */
for(c=0x80;c>1;c=(c>>1)) {
b = i2c & c;
if(b != 0) b=1;
pioput(b); /* SDA x + SCL 0 */
pioput(b+2); /* SDA x + SCL 1 */
pioput(b); /* SDA x + SCL 0 */
}
}
int recv_ack()
{
int c;
    unsigned char d;

pioset(3); /* 61H=3 4,5pin input */

c=0;
do
{
d = pioget(); -----> そもそもクロックのタイミングで受け取れてるのか?
/* ACK=(SCL 1 && SDA 0) */
if( (d & 3) == 2 ) /* recv_ack */ ---> Trace Onで遅い十分なスピードにしてもif文が成立しない。おかしい。
{
/* ACK OK */
pioput(0);
pioput(2);
pioput(0);

return 0;
}
c++;
} while(c<8);
return 1;
}
main()
{
int rtn;
FILE* fp;
unsigned char sadr,mode;
int i;

fp = fоpen("pio","a+"); /* 60H=1 paralell mode */ ---> オープンが使えないので全角文字

pioset(0); /* 61H=0 all output */

send_start();

/* slave addr */
sadr = 0x3E;
mode = 0; /* R/W=0 */
send_i2c((sadr << 1) | (mode & 0x01));
rtn = recv_ack();
if(rtn == 1)
{
printf("Slave ACK Err\n");
exit(1);
}

/* Set Data = Interface is 8bit long. */
for(i=0;i<3;i++)
{
/* Function Set Control Byte */
send_i2c(0x80 | 0x00); /* 0x80:Co=1 0x00:RS=0 */
rtn = recv_ack();
if(rtn == 1)
{
printf("Func8bit %i Ctrl ACK Err\n",i);
exit(1);
}
/* Function Set Data 8bit long. */
send_i2c(0x30);
rtn = recv_ack();
if(rtn == 1)
{
printf("Func8bit %i Data ACK Err\n",i);
exit(1);
}
}

/* Function Set Control Byte */
send_i2c(0x80 | 0x00); /* 0x80:Co=1 0x00:RS=0 */
rtn = recv_ack();
if(rtn == 1)
{
printf("Func Ctrl ACK Err\n");
exit(1);
}
/* Function Set(DB5=1) Data DL(DB4),N(DB3),F(DB2) */
/* DL=1(8bit Set),N=1(2Line),F=0(5x8dot) */
send_i2c(0x20 | 0x10 | 0x08 | 0x04);
rtn = recv_ack();
if(rtn == 1)
{
printf("Func Data ACK Err\n");
exit(1);
}

/* Display ON/OFF Control */
send_i2c(0x80 | 0x00);
rtn = recv_ack();
if(rtn == 1)
{
printf("DispOnCtrl ACK Err\n");
exit(1);
}
/* Display ON/OFF(DB3=1) Data D(DB2) | C(DB1) | B(DB0) */
/* Display ON,Cursor ON,Blinking OFF */
send_i2c(0x08 | 0x04 | 0x02 | 0x00);
rtn = recv_ack();
if(rtn == 1)
{
printf("DispOnData ACK Err\n");
exit(1);
}

/* Display Clear Control */
send_i2c(0x80 | 0x00);
rtn = recv_ack();
if(rtn == 1)
{
printf("DispClrCtrl ACK Err\n");
exit(1);
}
/* Display Clear(DB0=1) Data */
send_i2c(0x01);
rtn = recv_ack();
if(rtn == 1)
{
printf("DispClrData ACK Err\n");
exit(1);
}

/* Entry Mode Set Control */
send_i2c(0x80 | 0x00);
rtn = recv_ack();
if(rtn == 1)
{
printf("EntryCtrl ACK Err\n");
exit(1);
}
/* Entry Mode Set(DB2=1) Data I/D(DB1) | S(DB0) */
/* I/D=0(No LShift),S=0(No RShift) */
send_i2c(0x04 | 0x00 | 0x00);
rtn = recv_ack();
if(rtn == 1)
{
printf("EntryData ACK Err\n");
exit(1);
}


/* CG/DDRAM DATA ADDRESS Control */
send_i2c(0x80 | 0x00); /* 0x80:Co=1 0x00:RS=0 */
rtn = recv_ack();
if(rtn == 1)
{
printf("DATA WR. ACK Ctrl Err\n");
exit(1);
}
/* CG/DDRAM DATA ADDRESS(DB7) Data DB6-0 */
/* DB6-0=0(Home) */
send_i2c(0x80 | 0x00);
rtn = recv_ack();
if(rtn == 1)
{
printf("DATA WR. ACK Data Err\n");
exit(1);
}


/* CG/DDRAM DATA WRITE Control */
send_i2c(0x80 | 0x40); /* 0x80:Co=1 0x40:RS=1 */
rtn = recv_ack();
if(rtn == 1)
{
printf("DATA WR. ACK Ctrl Err\n");
exit(1);
}
/* CG/DDRAM DATA WRITE(R/W=RS=1) Data DB7-0 */
/* DB7-0=(0011 0000)b "@" */
send_i2c(0x30);
rtn = recv_ack();
if(rtn == 1)
{
printf("DATA WR. ACK Data Err\n");
exit(1);
}

send_stop();
fclose(fp);
}

ACKそのものが送れていないのか、ACK応答が返ってこないのか、そもそも回路は正しいのか?
仕方ない。ChatGPTに回路図を見せて正しいか聞いてみたら、合ってはいるが出力に設定してスレーブから出力Highが来るとショートする恐れがあるとの事。なるほどな~

元の回路
(5/16追記)回路図を修正済み。元の回路も。詳しくは文頭へ(おわり)
[PC-G850V] ポケコンでI2C通信 実機確認 - C言語 (6/13)_a0034780_01574062.png

そのため、4ピンとスレーブとの間に抵抗が必要との事。

それで、教えられた回路図がこれ。
抵抗値が4.7kΩで、330Ωの安全を高めるための抵抗が入った。
(6/15追記)回路図を修正済み。詳しくは文頭へ(おわり)
[PC-G850V] ポケコンでI2C通信 実機確認 - C言語 (6/13)_a0034780_03010363.png

この抵抗バランスはさっぱりわからない。やっぱりハードは難しい。


# by k1segawa | 2026-06-13 20:54 | ポケコン | Comments(0)

(6/15追記)
ここの確認は、回路図が4=SCL、5=SDAだと取り違えていた頃の結果なので、無効。
(6/15追記おわり)

実機での確認をする。

ポケコンにテキストをシリアルで転送し、Basic ← text でBASICで変換。

回路は、前の記事
(6/15追記)図を4=SDA、5=SCLに修正。前の記事も修正済み。(6/15追記おわり)

修正済みの回路図
[PC-G850V] ポケコンでI2C通信 実機確認  - テストBASIC [GAME] (6/10)_a0034780_01574062.png
実行

まず、2ピンを繋いだところ、液晶の1行目の各16キャラクタ部分が黒くなり、バックライトは未点灯だ。
実行してみると、30秒ほど時間が経ってエラー無く終了した。
PRINT A;PRINT N
3 457
と表示され、最後までDATAを送信し終わっている。

どうもLCDが光ってないのがそもそもあれなので、やはりRGBバックライトの方も(I2C=0x62)点灯しないといけなさそう。


# by k1segawa | 2026-06-10 14:41 | ポケコン | Comments(0)