一、两侧通讯速度不同的测试
我们知道,对于I2C设备,单片机是可以选择不同访问速度的。比如对I2C接口的OLED,我们既可以使用100KHz驱动,也可以使用400KHz驱动。在上一帖中,我们将主机和从机都是设置为400Kz的模式进行联机测试的。那么使用不同的访问速度,能否实现像其他I2C设备那样进行互联通讯呢?
从逻辑上讲,这就像使用不同波特率的两个串口之间能否实现正常通讯一样,结果是不言而喻的:不能正常通讯。然而经过测试,在ESP8266侧将波特率改为100KHz,
Wire.setClock(100000L); // 设置 I2C 时钟为 100KHz
甚至改成50KHz,
Wire.setClock(50000L); // 设置 I2C 时钟为 50KHz
结果,扫描到的地址没变,依然是正确的。两个开发板之间依旧可以正常通讯、收发数据。这一点确实有些奇怪了。也许使用两块CH582M开发板,一个做主机,一个做从机测试更合理吧。
二、发送方修改目标地址,与从机地址不一致时的测试
从线路上讲,发送方发送的目标即使不是从机地址,在线路上应该仍旧可以得到数据。但对CH582M而言,由于这个地址匹配和硬件有关,所以从逻辑上将,作为从机的CH582M的I2C外设是无法取得发送方的数据的。这一点在实际测试的时候,在ESP8266侧,发送数据时,修改目标地址位为实际地址+1,
Wire.beginTransmission(dev_address+1);
结果CH582M侧,确实没有收到来自发送方的数据。
三、I2C地址长度改变的测试
前面的测试中,从机方设置的是7位地址模式,
I2C_Init(I2C_Mode_I2C, 400000, I2C_DutyCycle_16_9, I2C_Ack_Enable, I2C_AckAddr_7bit, address);
如果改为10位地址模式,
I2C_Init(I2C_Mode_I2C, 400000, I2C_DutyCycle_16_9, I2C_Ack_Enable, I2C_AckAddr_10bit, address);
同时修改从机地址为
#define SLAVE_ADDR 0x2A5
主机侧也要修改为10位地址模式的
#include <Wire.h>
// 10 位地址扫描的起始基址(协议要求的高位)
#define I2C_10BIT_BASE 0x78 // 1111 0xx,xx 为 10 位地址的高 2 位
uint8_t base7bit = 0; // 高 2 位地址
uint8_t low8bit = 0; // 低 8 位地址
uint8_t isok = 0;
uint8_t dat = 0;
void setup() {
Serial.begin(115200);
Wire.begin(); // ESP8266 默认 SDA=GPIO4(D2), SCL=GPIO5(D1)
Wire.setClock(400000); // 设置为 400 kHz
Serial.println("\n开始扫描 10 位 I2C 地址(400 kHz)...\n");
}
void loop() {
scan10BitBus();
delay(500); // 每 5 秒扫描一次
}
void scan10BitBus() {
int foundCount = 0;
if (isok == 0) {
// 10 位地址范围:0x0000 ~ 0x03FF
for (uint16_t addr10 = 0x0000; addr10 <= 0x03FF; addr10++) {
base7bit = I2C_10BIT_BASE | ((addr10 >> 8) & 0x03); // 高 2 位地址
low8bit = addr10 & 0xFF; // 低 8 位地址
Wire.beginTransmission(base7bit); // 发送 1111 0xx 格式的起始字节
Wire.write(low8bit); // 紧接着写入低 8 位地址
uint8_t err = Wire.endTransmission();
if (err == 0) {
foundCount++;
Serial.print("发现 10 位 I2C 设备,地址:0x");
if (addr10 < 0x100) Serial.print("0");
if (addr10 < 0x10) Serial.print("0");
Serial.println(addr10, HEX);
isok = 1;
break;
// 可选:扫描时若有设备响应,短暂延时避免总线冲突
// delay(1);
}
}
if (foundCount == 0) {
Serial.println("未发现任何 10 位 I2C 设备。");
} else {
Serial.print("扫描完成,共发现 ");
Serial.print(foundCount);
Serial.println(" 个 10 位地址设备。");
}
}
if (isok == 1) {
Serial.print("发送数据到 0x");
Serial.print(base7bit, HEX);
Serial.print(low8bit, HEX);
Serial.print(" : 0x");
Serial.print(dat, HEX);
Serial.print("\r\n");
Wire.beginTransmission(base7bit); // 发送 1111 0xx 格式的起始字节
Wire.write(low8bit); // 紧接着写入低 8 位地址
Wire.write(dat);
Wire.endTransmission();
dat=(dat+1)%10;
}
delay(500);
}编译、烧录后,运行结果:
主机侧: 
从机侧:

可以看到,从机侧的地址0x2A5,在Arduino下,扫描到的地址变成了0x0A5了。改变从机侧的地址为0x20的话,主机侧扫描到的地址为0x20, 
改变从机侧的地址为0x40的话,主机侧扫描到的地址为0x40, 
改变从机侧的地址为0x100的话,主机侧扫描到的地址为0x00, 
改变从机侧的地址为0x320的话,主机侧扫描到的地址为0x020, 
地址上的变化也是挺有规律的。如果主机方同样使用CH582M或者其他非Arduino下的程序的话,发送地址上应该和Arduino不同吧,有机会可以试试。
我要赚赏金
