Comunicación Interfaz coche mediante I2C.


Subo unas primeras funciones de I2C que parecen funcionar para ir ordenando código en algún sitio. Se envia y recibe un byte en los 4 modos posibles del bus I2C: MT, MR, ST y SR.

El coche será el maestro ya que el tiempo disponible para las comunicaciones tiene que ir sincronizado con el resto de acciones a realizar, el interfaz funciona como esclavo respondiendo mediante una interrupción a la comunicación I2C del maestro. Se ha añadido una variable en los while() de espera del coche para no quedarse nunca bloqueado, en los while() de espera del interfaz se puede quedar encerrado pero es muy poco probable, además cuando esto ocurra está el botón del reset...


INTERFAZ

ISR(TWI_vect)
{
    if(programa==2)
    {
        if((TWSR & 0xF8) == 0x60)
            i2c_recibido=i2c_SR();
        else if((TWSR & 0xF8) == 0xA8)  
            i2c_ST(i2c_enviar);    
        else
            i2c_error();
    }
    TWCR |= (1<<TWINT);
}

void i2c_ST(unsigned char dato)
{

    TWDR=dato;                        //Cargar el dato a enviar.
    TWCR &= ~((1<<TWSTO)|(1<<TWSTA));  //ea?
    TWCR |= (1<<TWINT);                //Enviar dato.

    while (!(TWCR & (1<<TWINT)))    //Esperar a TWINT
    {
    }

    if((TWSR & 0xF8) != 0xC8);        //Dato enviado, no esperamos ACK.
        i2c_error();

    TWCR &= ~((1<<TWSTO)|(1<<TWSTA));//Dejamos el módulo preparado.
    TWCR |= ((1<<TWINT)|(1<<TWEA));
}

unsigned char i2c_SR(void)
{
    unsigned char dato=0;

    TWCR &= ~(1<<TWSTO);                //Preparados para recibir dato y devolver ACK
    TWCR |= ((1<<TWINT)|(1<<TWEA));

    while (!(TWCR & (1<<TWINT)))        //Esperar a TWINT
    {
    }

    if((TWSR & 0xF8) != 0x80);            //Hemos recibido dato y generado ACK.
        i2c_error();
    dato=TWDR;                            //Almacenamos dato recibido.

    TWCR &= ~(1<<TWSTO);                //Preparados para recibir STOP
    TWCR |= ((1<<TWINT)|(1<<TWEA));

    while (!(TWCR & (1<<TWINT)))        //Esperar a TWINT
    {
    }

    if((TWSR & 0xF8) != 0xA0);            //STOP
        i2c_error();

    TWCR &= ~((1<<TWSTO)|(1<<TWSTA));    //Dejamos el módulo preparado.
    TWCR |= ((1<<TWINT)|(1<<TWEA));

    return(dato);
}


COCHE

void i2c_MT(unsigned char direccion, unsigned char dato)
{  
    TWCR |= (1<<TWEA);                                //Se enciende el módulo
    TWCR &= ~(1<<TWSTO);                              //enviar señal de start.
    TWCR |= ((1<<TWINT)|(1<<TWSTA)|(1<<TWEN));

    while (!(TWCR & (1<<TWINT)))                      //Esperar a TWINT
    {
        if(comunicaciones!=0)
            break;
    }
                                                      //comprobar resultado de la operación anterior.
    if ((TWSR & 0xF8) != 0x08)                        //(xxxxx000) != (0x08 Start)
        i2c_error();

                                                                        
    TWDR = ((direccion)&(0b11111110));                //Enviar dirección y escritura
    TWCR &= ~((1<<TWSTO)|(1<<TWSTA));
    TWCR |= ((1<<TWINT)|(1<<TWEN));

    while (!(TWCR & (1<<TWINT)))                      //Esperar a TWINT
    {
        if(comunicaciones!=0)
            break;
    }
                                                      //comprobar condición.
    if ((TWSR & 0xF8) != 0x18)                        //(xxxxx000) != (0x18 SLA +W)
        i2c_error();


    TWDR = dato;                                      //Cargar byte a enviar
    TWCR &= ~((1<<TWSTO)|(1<<TWSTA));
    TWCR |= ((1<<TWINT)|(1<<TWEN));

    while (!(TWCR & (1<<TWINT)))                      //Esperar a TWINT
    {
        if(comunicaciones!=0)
            break;
    }
                                                      //comprobar condición.
    if ((TWSR & 0xF8) != 0x28)                        //(xxxxx000) != (0x28 dato+ack)
        i2c_error();   
                                     
    TWCR &= ~(1<<TWSTA);                              //enviar señal de stop.
    TWCR |= ((1<<TWINT)|(1<<TWEN)|(1<<TWSTO));
    _delay_us(20);
}

unsigned char i2c_MR(unsigned char direccion)
{
    unsigned char dato=0;

    TWCR |= (1<<TWEA);   
    TWCR &= ~(1<<TWSTO);                   //enviar señal de start.
    TWCR |= ((1<<TWINT)|(1<<TWSTA)|(1<<TWEN));

    while (!(TWCR & (1<<TWINT)))        //Esperar a TWINT
    {
        if(comunicaciones!=0)
            break;
    }
                                         //comprobar resultado de la operación anterior.
    if ((TWSR & 0xF8) != 0x08)           //(xxxxx000) != (0x08 Start)
        i2c_error();

                                        //enviar byte.
    TWDR = ((direccion)|(0b00000001));  //Cargar byte de dirección
    TWCR &= ~((1<<TWSTO)|(1<<TWSTA));
    TWCR |= ((1<<TWINT)|(1<<TWEN));

    while (!(TWCR & (1<<TWINT)))        //Esperar a TWINT
    {
        if(comunicaciones!=0)
            break;
    }
                                        //comprobar condición.
    if ((TWSR & 0xF8) != 0x40)          //(xxxxx000) != (0x40 SLA +R)
        i2c_error();

    TWCR &= ~((1<<TWSTO)|(1<<TWSTA)|(1<<TWEA));//Leer segundo byte NO ACK
    TWCR |= ((1<<TWINT)|(1<<TWEN));

    while (!(TWCR & (1<<TWINT)))        //Esperar a TWINT
    {
        if(comunicaciones!=0)
            break;
    }
   
    if ((TWSR & 0xF8) != 0x58)          //(xxxxx000) != (0x58 dato+ no ack)
        i2c_error();

    dato=TWDR;

    TWCR &= ~(1<<TWSTA);                //enviar señal de stop.
    TWCR |= ((1<<TWEA)|(1<<TWINT)|(1<<TWEN)|(1<<TWSTO));
    _delay_us(20);

    return(dato);
}

void i2c_error(void)
{
}

Código completo: Atmega32, Atmega1280.

El ejemplo para probar las funciones consiste en apagar y encender los leds del coche desde el interfaz. Para ello el coche (maestro) le pide al interfaz (esclavo) que que le mande un byte de datos en el que va el estado de cada led y se encienden o apagan en el coche.  A continuación el coche  manda al interfaz un byte de datos con el estado de sus leds y lo escribe en la pantalla del LCD. La primera columna de ON/OFF es el byte que manda el interfaz y la segunda el que recibe, deben de ser iguales si el funcionamiento es correcto.

Captura de una transmisión.



Video del funcionamiento.

.

Comunicación completa.

Código: AVR32, AVR1280.

blog comments powered by Disqus