代码之家  ›  专栏  ›  技术社区  ›  Wezley

带Atmega168的I2C

  •  1
  • Wezley  · 技术社区  · 7 年前

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

    #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设置不正确?有什么建议吗?

    谢谢!:)

    1 回复  |  直到 7 年前
        1
  •  0
  •   fisehara    7 年前

    您的i2c库对于atmega168是错误的。TWI数据寄存器是一个8位寄存器,您尝试将16位值写入其中。 中的问题 I2C Not working with PCA9685

    i2c已正确初始化,因为它默认在atmega168重置时通电并计时,您无需在意。但你最好检查PRR。PRTWI寄存器,如果TWI外围设备通电或未通电-可能您使用低功耗库关闭TWI。

    Address and 1 Byte Transfer on TWI 在从机的ACK和总线上写入的下一个数据之后,需要有一个空闲窗口。

    所以基本上,你错过了两件大事:

    1. 8位数据寄存器需要用1字节数据写入,而不是用第十六单元写入
    2. 主(您)驱动的总线上两个字节之间的显式空闲时间