【Arduino】Arduino Mega2560 I2C速率调节

文章详细描述了在使用ArduinoMega2560和Wire.h库进行I2C通信时,尝试通过setClock()方法改变时钟频率至10kHz遇到的问题。默认的100kHz无法降至10kHz,作者通过查阅库源码和芯片数据手册,发现需要调整TWPS预分频数并修改TWBR的计算方式,最终通过设置TWPS0为1和调整TWBR公式实现了目标频率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题

使用Arduino Mega2560板,Wire.h库进行I2C通信时,需要调节I2C通信的速率。

setClock()方法

直接使用Wire.h库的setClock()方法修改I2C通信的时钟频率。
setClock()介绍
机翻如下:
setClock()介绍机翻

新的问题

默认I2C通信的时钟频率为100kHz,计划使用10kHz频率时,直接调节上述setClock()函数参数为10000,但用示波器测量得到的SCL频率仍约为40kHz。

解决过程

翻了翻Wire库的代码以及Mega2560芯片的数据手册,截取了部分内容如下:
Wire.cpp片段

void TwoWire::setClock(uint32_t clock)
{
  twi_setFrequency(clock);
}

Wire库还依赖了twi.c文件,twi.c片段

void twi_init(void)
{
  ...
  // initialize twi prescaler and bit rate
  cbi(TWSR, TWPS0);
  cbi(TWSR, TWPS1);
  TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
  // 此处TWI_FREQ在twi.h文件中宏定义为1000000,即IIC默认时钟频率为100kHz
  // #define TWI_FREQ 100000L
  ...
}

void twi_setFrequency(uint32_t frequency)
{
  TWBR = ((F_CPU / frequency) - 16) / 2;
  
  /* twi bit rate formula from atmega128 manual pg 204
  SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
  note: TWBR should be 10 or higher for master mode
  It is 72 for a 16mhz Wiring board with 100kHz TWI */
}

SCL时钟频率计算公式
SCL时钟频率计算公式
TWPS预分频数表
TWPS预分频数表
由上代码片段结合数据手册可知,在初始化时,预分频数为1,TWBR为8位寄存器,其最大值为255,则SCL频率在此情况下最低为 16 M H z 16 + 2 ∗ 255 ≈ 30.4 k H z \frac{16MHz}{16+2*255} \approx 30.4kHz 16+225516MHz30.4kHz
所以为了满足SCL时钟频率达到10kHz的目的,需要将预分频器调节为4分频,即把TWPS0置1,同时修正TWBR计算公式。
最终将twi.c文件中

cbi(TWSR, TWPS0);
TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;

修改为

sbi(TWSR, TWPS0);
TWBR = ((F_CPU / TWI_FREQ) - 16) / 2 / 4;

补充

//-----------位操作定义------------------------
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))

可知为sbi(sfr, bit)为将寄存器指定位置1,cbi(sfr, bit)为将寄存器指定位置0。

参考资料

setClock() - Arduino Reference
请教:cbi()/sbi()的用法 (amobbs.com 阿莫电子论坛 - 东莞阿莫电子网站)
ATmega640-1280-1281-2560-2561-Datasheet-DS40002211A.pdf

### Arduino Mega 2560 I2C通信教程及实例 #### 理解I2C协议 I2C(Inter-Integrated Circuit),即内部集成电路总线,是一种用于连接微控制器及其外围设备的简单双向二线制同步串行总线。该总线仅需两根电线即可实现全双工数据传输:一根为SDA(Serial Data Line,串行数据线),另一根为SCL(Serial Clock Line,串行时钟线)。这两条线路负责在主机和从机之间传递信息。 对于Arduino Mega 2560而言,其支持标准模式下的I2C通讯速率可达100 kbit/s以及快速模式下400 kbit/s的速度[^3]。 #### 连接硬件 当涉及到Arduino Mega 2560上的I2C接口配置时,应当注意到特定引脚分配如下: - **SDA (Data line)**: Pin 20 - **SCL (Clock line)**: Pin 21 这些引脚已经预设好作为I2C通信专用,并且板载了上拉电阻来确保信号稳定。如果额外添加外部传感器或其他组件到此电路,则应将其对应的SDA与SCL分别接到上述指定位置。 #### 初始化库函数 为了简化编程过程并提高效率,在编写涉及I2C操作的代码之前,建议先加载Wire.h库文件。这可以通过在草图顶部加入`#include <Wire.h>`语句完成。之后便可以调用各种方法来进行读写动作。 ```cpp #include <Wire.h> ``` #### 编程示例 下面给出一段简单的程序用来展示如何利用Mega 2560通过I2C向另一个设备发送请求并接收响应。 ##### 主节点(Host Node) 这段代码展示了怎样设置为主控端并向地址为0x68处的目标发起查询命令;随后等待回应并将获取的数据打印出来。 ```cpp void setup() { Wire.begin(); // 加入I2C总线成为主站 Serial.begin(9600); // 启动串口监视器以便观察结果 } void loop() { byte data; Wire.beginTransmission(0x68); Wire.write('R'); // 发送字符'R'给从属装置表示准备接受返回值 Wire.endTransmission(false); delay(10); // 给对方一点时间处理 Wire.requestFrom(0x68, 1); // 请求来自相同地址的一个字节的信息 while(Wire.available()) { data = Wire.read(); Serial.println(data, HEX); // 输出收到的内容至串口显示窗口 } } ``` ##### 从节点(Slave Node) 这里提供了一个基本框架供其他Arduino充当被访问方使用。它会监听是否有新的消息到达,一旦检测到则回复一个固定的数值回去。 ```cpp const int SLAVE_ADDRESS = 0x68; void setup(){ pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); Wire.begin(SLAVE_ADDRESS); // 成为具有固定ID号的从站成员 Wire.onReceive(receiveEvent); // 注册回调函数以应对收到指令的情况 } // 当有新输入到来时触发执行本体内的逻辑判断流程 void receiveEvent(int howMany){ char command = Wire.read(); if(command == 'R'){ Wire.write((byte)0xAA); // 返回十六进制AA代表确认已准备好交流 digitalWrite(LED_BUILTIN,HIGH); // 可选指示灯亮起示意正在工作状态中... }else{ digitalWrite(LED_BUILTIN,LOW); // 默认关闭LED保持静默姿态 } } void loop(){} ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值