2017-09-12 5 views
1

J'essaie de contrôler plusieurs servos en utilisant le servo-contrôleur adafruit PWM. Il utilise l'interface i2c pour communiquer depuis le micro-contrôleur. J'utilise un Atmega 168 pour tenter d'envoyer des instructions i2c au micro-contrôleur en utilisant une simple bibliothèque i2c.I2C avec Atmega168

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

Je trouve les adresses du servo-contrôleur du pilote Arduino mais je vais avoir des problèmes de réglage PWM de la carte. Voici le code que je tente d'utiliser:

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

Voici le pilote: https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library

Je suis sûr que mon i2c est pas configuré correctement? Aucune suggestion?

Merci! :)

+1

vérifiez la perspective matérielle si les broches SDA et SCL utilisées sont correctement tirées. –

+0

Je l'ai fait et ils le sont. Tout est branché correctement. Je suis arrivé à la conclusion que c'est quelque chose avec mon code. Je pense que je ne peux pas envoyer mes commandes au bon registre? L'adresse PWM est 0x40 – user2536897

+1

Utilisez DSO et vérifiez le signal sur les broches SDA et SCL, assurez-vous qu'il génère des signaux en temps opportun. Test de base que vous faites en premier, envoyer l'identifiant de l'esclave du maître et vérifier si l'esclave reconnaît. –

Répondre

0

Votre bibliothèque i2c est incorrecte pour l'atmega168. Le registre de données TWI est un registre de 8 bits et vous essayez d'y écrire une valeur de 16 bits. Le problème de I2C Not working with PCA9685 utilise un pilote de données TWI (i2c) de 8 bits.

L'i2c est initialisé correctement, car il est alimenté par défaut et cadencé à la réinitialisation de l'atmega168, vous n'avez pas besoin de soins. Mais vous devriez mieux vérifier PRR.PRTWI registre, si le périphérique TWI est alimenté ou non - peut-être vous utilisez une bibliothèque de faible puissance qui éteint le TWI.

De plus, vous n'êtes pas garantissez explicitement le temps d'attente entre deux octets sur le bus, comme vous pouvez le voir ici: Address and 1 Byte Transfer on TWI Après l'ACK de l'esclave et les données suivantes écrites sur le bus, il faut une fenêtre inactive.

Donc, fondamentalement, vous manquez deux choses importantes:

  1. registre de données 8Bit doit être écrit avec 1 octet de données non avec un unit16
  2. explicite le temps d'inactivité entre deux octets sur le bus conduit par le maître (vous)