【问题标题】:I2C with Atmega168I2C 与 Atmega168
【发布时间】:2017-09-12 02:24:27
【问题描述】:

我正在尝试使用 adafruit PWM 伺服控制器控制多个伺服系统。它使用 i2c 接口与微控制器进行通信。 https://www.adafruit.com/product/815

我正在使用 Atmega 168 尝试使用简单的 i2c 库向微控制器发送 i2c 指令。

#include "i2c.h"

void initI2C(void) {
  TWBR = 32;                               /* set bit rate, see p. 242 */
                                     /* 8MHz / (16+2*TWBR*1) ~= 100kHz */
  TWCR |= (1 << TWEN);                                       /* enable */
}

void i2cWaitForComplete(void) {
  loop_until_bit_is_set(TWCR, TWINT);
}

void i2cStart(void) {
  TWCR = (_BV(TWINT) | _BV(TWEN) | _BV(TWSTA));
  i2cWaitForComplete();
}

void i2cStop(void) {
  TWCR = (_BV(TWINT) | _BV(TWEN) | _BV(TWSTO));
}

uint8_t i2cReadAck(void) {
  TWCR = (_BV(TWINT) | _BV(TWEN) | _BV(TWEA));
  i2cWaitForComplete();
  return (TWDR);
}

uint8_t i2cReadNoAck(void) {
  TWCR = (_BV(TWINT) | _BV(TWEN));
  i2cWaitForComplete();
  return (TWDR);
}

void i2cSend(uint16_t data) {
  TWDR = data;
  TWCR = (_BV(TWINT) | _BV(TWEN));                  /* init and enable */
  i2cWaitForComplete();
}

我从 Arduino 驱动程序中找到了伺服控制器的地址,但在设置电路板的 PWM 时遇到问题。这是我尝试使用的代码:

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "i2c.h"

#define SERVO_MIN 1000
#define SERVO_MAX 2000
#define SERVO_MID 1500

#define PCA9685_ADDR 0x4

#define PCA9685_MODE1 0x0

#define LED0_ON_L 0x6
#define LED0_ON_H 0x7
#define LED0_OFF_L 0x8
#define LED0_OFF_H 0x9

int main(void)
{
  initI2C();
  setupController();
  for(int i = 1; i < 17; i++) {
    setServo(i, 0, 4026);
  }
  return 0;
}

void setupController() {
    i2cStart();
    i2cSend(PCA9685_ADDR);
    i2cSend(PCA9685_MODE1);
    i2cSend(0x0);
    i2cStop();
}

void setServo(uint8_t id, uint16_t start, uint16_t stop) {
    i2cStart();
    i2cSend(PCA9685_ADDR);
    i2cSend(LED0_ON_L+4*id);
    i2cSend(start);
    i2cSend(start>>8);
    i2cSend(stop);
    i2cSend(stop>>8);
    i2cStop();
}

这里是驱动程序:https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library

我很确定我的 i2c 设置不正确?有什么建议吗?

谢谢! :)

【问题讨论】:

  • 从硬件角度检查,使用的 SDA 和 SCL 引脚是否正确上拉。
  • 我做到了,他们也做到了。一切都正确连接。我得出的结论是,这与我的代码有关。我想我可能没有将我的命令发送到正确的寄存器? PWM 地址为 0x40
  • 使用 DSO 并检查 SDA 和 SCL 引脚的信号,确保它及时产生信号。你首先做的基本测试,从master发送slave id并检查slave是否确认。
  • 谢谢,我会检查的!我如何确保奴隶承认它的 ID?可以直接发地址吗? (抱歉,我对将 i2c 与微控制器一起使用还很陌生)

标签: embedded i2c atmega servo adafruit


【解决方案1】:

您的 i2c 库对于 atmega168 是错误的。 TWI 数据寄存器是一个 8 位寄存器,您尝试向其中写入一个 16 位值。 I2C Not working with PCA9685 中的问题使用 8 位数据 TWI(i2c) 驱动程序。

i2c 已正确初始化,因为它在 atmega168 重置时默认供电和计时,您无需关心。但是您最好检查 PRR.PRTWI 寄存器,如果 TWI 外围设备已通电 - 也许您使用了关闭 TWI 的低功耗库。

此外,您没有明确确保总线上两个字节之间的等待时间,如您在此处看到的: Slave的ACK和总线上写入的下一个数据之后,需要有一个空闲窗口。

所以基本上,你错过了两个主要的事情:

  1. 8Bit 数据寄存器需要写入 1Byte 的数据而不是一个单元16
  2. 由主机(你)驱动的总线上两个字节之间的显式空闲时间

【讨论】:

    猜你喜欢
    • 2019-11-25
    • 1970-01-01
    • 2016-04-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多