I2C transmite y recibe entre ALS OPT3006 y 8051

0

Me gustaría pedir una solución para que el microcontrolador (MCU) obtenga datos del ALS (sensor de luz ambiental). Me pregunto por qué mi MCU no puede tener un ACK (señal de reconocimiento) bajo En este programa tengo 2 funciones: ALS_config () es enviar un comando desde MCU para modificar las configuraciones en el ALS. MCU_read () es permitir que MCU lea datos de lux de ALS.

Actualmente, ALS_config () puede obtener ACK = 0 después de que se envió el byte de datos. Significa que funciona bien. Pero la función MCU_read () obtiene ACK = 1, significa que no hay señal de reconocimiento. Creo que mi programa está en la forma correcta en comparación con el protocolo I2C convencional. enlace

Por favor, ayúdame a señalar la parte incorrecta en mi código.

void main(void)
{                           

    MCU_Initial();

    Initial_Variable();  

    delay1m(500); //Wait FPGA Ready

    FPGA_TEST();
    delay1m(5);



    while(1)                                        
    {               
        RS232Control();

            ALS_to_MCU();
        if(flagstep==1 || flagstep_down==1)
        {
            Main_Pattern();     
        }  

    }
}

 void I2C_START(void)
{
    delay1m(6);
    ACK_f = 0;
    I2C_SDA = 1;
    delay1m(2);
    I2C_SCL = 1;
    delay1m(8);
    I2C_SDA = 0;
    delay1m(5);
    I2C_SCL = 0;
    delay1m(5);
}

//=======================================================================================
// I2C_1 Ack (EEPROM)
//=======================================================================================
void I2C_ACK(void)
{
    delay1m(3);
    I2C_SDA = 1;
    delay1m(1);
    I2C_SCL = 1;
    delay1m(3);
    if(!I2C_SDA)
        ACK_f = 1;
    delay1m(2);
    I2C_SCL = 0;
    delay1m(1);
    I2C_SDA = 0;
    delay1m(5);
}

void I2C_NAK()
{
    I2C_SDA = 1;
    I2C_SCL = 1;
    delay1m(1);
    I2C_SCL = 0;
    I2C_SDA = 1;
}

//=======================================================================================
// I2C_1 Stop (EEPROM)
//=======================================================================================
void I2C_STOP(void)
{
    I2C_SCL = 0;
    I2C_SDA = 0;
    delay1m(8);
    I2C_SCL = 1;
    delay1m(2);
    I2C_SDA = 1;
}

void I2C_RESET(void)
{
    unsigned char x;

    I2C_START();
    for(x=0x00;x<=0x09;x++) //EEPROM restart 9 times is avoided unexpected state
        {   
            I2C_SDA = 1;
            I2C_SCL = 0;
            delay1m(2);
            I2C_SCL = 1;
            delay1m(2);
        }  
    I2C_START();
    I2C_STOP();
    delay1m(2);
}

//=======================================================================================
void I2C_TX(unsigned char Tx_data)
{
    unsigned char x;
    for(x=0;x<8;x++)
    {
        I2C_SCL = 0;
        delay1m(1);
        if(Tx_data & 0x80)
            I2C_SDA = 1;
        else
            I2C_SDA = 0;
        Tx_data <<= 1;
        delay1m(1);
        I2C_SCL = 1;
        delay1m(2);
    }
    I2C_SCL = 0;
}


//=======================================================================================
unsigned char I2C_RX(void)
{
        unsigned char x;
    I2C_SDA = 1;
    delay1m(2);
    for(x=0;x<8;x++)
    {
        I2C_rx_buf <<= 1;
        I2C_SCL = 1;
        delay1m(1);
        if(I2C_SDA)
            I2C_rx_buf |= 0x01;
        else
            I2C_rx_buf &= 0xfe;
        delay1m(2);
        I2C_SCL = 0;
        delay1m(3);
    }
        return I2C_rx_buf;
    delay1m(2);

}

/////        Configuration register     ///////////
void ALS_config(unsigned char slave_write,unsigned char dataA,unsigned char dataB)   
{   
        I2C_START();
    I2C_TX(slave_write);
        I2C_ACK();  
    I2C_TX(0x01);
        I2C_ACK();
        I2C_TX(dataA);
//  I2C_RX();
        I2C_ACK();
        I2C_TX(dataB);
//  I2C_RX();
        I2C_ACK();  
    I2C_STOP();
}

void MCU_read(unsigned char slave_write,unsigned char slave_read)    
{   
    unsigned char i, ALS_MSB, ALS_LSB;
    unsigned int ALS_lux;

    //////                      Partial write   ////////
        I2C_START();
        I2C_TX(slave_write);
        I2C_ACK();
        I2C_TX(0x00);
        I2C_ACK();
//      I2C_STOP();

////////////////    Read from ALS       /////////////////////////////

        I2C_START();
        I2C_TX(slave_read);
        I2C_ACK();
    I2C_RX();
        ALS_LSB = I2C_rx_buf;
        ALS_MSB = I2C_rx_buf<<8;
        I2C_ACK();

/*  This part doesn't work. So I marked it. 
        I2C_SDA = 0;
        delay1m(1);
        I2C_SCL = 1;
        delay1m(1);
        I2C_SCL = 0;
        delay1m(1);
        I2C_SDA = 0;
*/  
        delay1m(1);

        I2C_RX();
        ALS_MSB = I2C_rx_buf;
    I2C_ACK();
        //      I2C_NAK();
        I2C_STOP(); 

        ALS_lux = ALS_MSB | ALS_LSB;

}

//                  MCU read data from ALS
//////////////////////////////////

//void ALS_to_MCU(unsigned char slave_write,unsigned char slave_read,unsigned char dataA,unsigned char dataB)
void ALS_to_MCU(void)
{
    ALS_config(0x88,0xC4,0x10);
    MCU_read(0x88,0x89);
}
    
pregunta Hector Ta

1 respuesta

0

No tengo tiempo para revisar todo tu código, pero el código parece incorrecto en algunos lugares. Aquí hay dos ejemplos:

void MCU_read(unsigned char slave_write,unsigned char slave_read)    
{   
    unsigned char i, ALS_MSB, ALS_LSB;
    unsigned int ALS_lux;

    //////                      Partial write   ////////
        I2C_START();
        I2C_TX(slave_write);
        I2C_ACK();
        I2C_TX(0x00);
        I2C_ACK();
//      I2C_STOP();

////////////////    Read from ALS       /////////////////////////////

        I2C_START();
        I2C_TX(slave_read);
        I2C_ACK();
    I2C_RX();
        ALS_LSB = I2C_rx_buf;
        ALS_MSB = I2C_rx_buf<<8;
        I2C_ACK();
[...]
  • Has leído un byte en I2C_RX() pero luego intentas usar el mismo byte dos veces como ALS_LSB y ALS_MSB . Eso no tiene sentido.
void I2C_ACK(void)
{
    delay1m(3);
    I2C_SDA = 1;
    delay1m(1);
    I2C_SCL = 1;
    delay1m(3);
    if(!I2C_SDA)
        ACK_f = 1;
    delay1m(2);
    I2C_SCL = 0;
    delay1m(1);
    I2C_SDA = 0;
    delay1m(5);
}
  • Cuando lee del OPT3006 en MCU_read() , es I²C Master el que debe enviar el ACK después de recibir cada byte, excepto el último. Pero mire la función I2C_ACK() que aparece arriba: solo se escribe para verificar si I²C Slave ha enviado un ACK (y luego establece ACK_f si se detectó un ACK del Slave). Debe crear una función ACK (o mejorar la que ya tiene) y luego utilizarla cuando el Master debe enviar ACK.

    Es por eso que no estabas detectando un ACK del Esclavo durante MCU_read() . ¡Se supone que el Esclavo no envía uno al Maestro! :-) Es el Maestro quien debe ACK cada byte recibido desde el Esclavo hasta el último byte, que el Maestro normalmente debe NACK (aunque la hoja de datos dice que este dispositivo también permitirá que el Maestro acceda a ACK) y luego se detiene. Consulte la Figura 21 en la hoja de datos OPT3006 que muestra un ejemplo de I²C Read by the Master. (Es posible que también desee aclarar su comprensión de la definición de "Transmisor principal" y "Receptor principal" en la Especificación I²C).

No garantizo que esos sean los únicos errores. Sin embargo, ahora puede ver que su código no cumple con los requisitos de la Figura 21 de la hoja de datos del OPT3006, por lo que le da un lugar para comenzar su depuración.

    
respondido por el SamGibson

Lea otras preguntas en las etiquetas