简体   繁体   English

具有Atmega168的I2C

[英]I2C with Atmega168

I'm trying to control several servos using the adafruit PWM servo controller. 我正在尝试使用adafruit PWM伺服控制器来控制多个伺服器。 It uses i2c interface to communicate from the micro controller. 它使用i2c接口与微控制器通信。 https://www.adafruit.com/product/815 https://www.adafruit.com/product/815

I'm using an Atmega 168 to attempt to send i2c instructions to the micro controller using a simple i2c library. 我正在使用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();
}

I found the addresses of the servo controller from the Arduino driver but I'm having issues setting the PWM of the board. 我从Arduino驱动程序中找到了伺服控制器的地址,但是在设置板的PWM时遇到问题。 Here is the code I'm attempting to use: 这是我尝试使用的代码:

#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();
}

Here is the driver: https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library 这是驱动程序: https : //github.com/adafruit/Adafruit-PWM-Servo-Driver-Library

I'm pretty sure my i2c isn't set up correctly? 我很确定我的i2c设置不正确吗? Any suggestions? 有什么建议么?

Thank you! 谢谢! :) :)

Your i2c library is wrong for the atmega168. 您的i2c库对于atmega168是错误的。 The TWI data register is an 8bit register and you attempt to write a 16bit value into it. TWI数据寄存器是8位寄存器,您尝试将16位值写入其中。 The issue in I2C Not working with PCA9685 uses an 8bit data TWI(i2c) driver. I2C中的问题不适用于PCA9685,使用8位数据TWI(i2c)驱动程序。

The i2c is initialized properly, due to it is per default powered and clocked at the reset of the atmega168, you don't need to care. i2c已正确初始化,因为它默认情况下为atmega168的复位供电并提供时钟,因此您无需担心。 But you should better check PRR.PRTWI register, if the TWI peripheral is powered or not - maybe you use a low power library that turns the TWI off. 但是,如果TWI外设是否通电,则最好检查PRR.PRTWI寄存器-也许您使用了低功率库来关闭TWI。

Furthermore, you are not explicitly ensuring for the wait time between two bytes on the bus, as you can see here: 此外,您没有明确确保总线上两个字节之间的等待时间,如您在此处看到的: TWI上的地址和1字节传输 After the ACK of the Slave and the next data written on the bus, there needs to be an idle window. 从设备的ACK和下一个写入总线的数据之后,需要有一个空闲窗口。

So basically, you miss two major things: 因此,基本上,您错过了两件事:

  1. 8Bit data register needs to be written with 1Byte of data not with a unit16 8Bit数据寄存器需要用1Byte的数据写入而不是用unit16
  2. Explicit idle time between two bytes on the bus driven by master (you) 由主机(您)驱动的总线上两个字节之间的显式空闲时间

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM