I2C 与 Atmega168
I2C with Atmega168
我正在尝试使用 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 driver 找到了伺服控制器的地址,但我在设置电路板的 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();
}
这里是driver:https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
我很确定我的 i2c 设置不正确?有什么建议吗?
谢谢! :)
您的 i2c 库对于 atmega168 是错误的。 TWI 数据寄存器是一个 8 位寄存器,您试图向其中写入一个 16 位值。
I2C Not working with PCA9685 中的问题使用 8 位数据 TWI(i2c) 驱动程序。
i2c 已正确初始化,因为它在 atmega168 重置时默认供电和计时,您无需关心。但是你最好检查一下 PRR.PRTWI 寄存器,看看 TWI 外设是否通电——也许你使用了一个关闭 TWI 的低功耗库。
此外,您没有明确确保总线上两个字节之间的等待时间,正如您在此处看到的:
在Slave的ACK和下一个数据写入总线后,需要有一个空闲window.
所以基本上,您错过了两件主要的事情:
- 8Bit数据寄存器需要写入1Byte数据而不是unit16
- 主机(您)驱动的总线上两个字节之间的显式空闲时间
我正在尝试使用 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 driver 找到了伺服控制器的地址,但我在设置电路板的 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();
}
这里是driver:https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
我很确定我的 i2c 设置不正确?有什么建议吗?
谢谢! :)
您的 i2c 库对于 atmega168 是错误的。 TWI 数据寄存器是一个 8 位寄存器,您试图向其中写入一个 16 位值。 I2C Not working with PCA9685 中的问题使用 8 位数据 TWI(i2c) 驱动程序。
i2c 已正确初始化,因为它在 atmega168 重置时默认供电和计时,您无需关心。但是你最好检查一下 PRR.PRTWI 寄存器,看看 TWI 外设是否通电——也许你使用了一个关闭 TWI 的低功耗库。
此外,您没有明确确保总线上两个字节之间的等待时间,正如您在此处看到的:
所以基本上,您错过了两件主要的事情:
- 8Bit数据寄存器需要写入1Byte数据而不是unit16
- 主机(您)驱动的总线上两个字节之间的显式空闲时间