Estoy tratando de implementar I2C usando un controlador AVR sin los registros TWI internos designados.
El protocolo I2C requiere que el dispositivo maestro controle las líneas SDA y SCL para comenzar con el fin de abordar y comenzar una transacción de comunicación. El problema que tengo es que después de enviar una dirección a través de la línea serial, debe dejar que la línea de datos "flote" (es decir, que la resistencia pull-up la levante) para que el esclavo baje la línea. para una señal ACK.
Puedo abordar con éxito el dispositivo I2C, pero cuando intento dejar que la línea "flote", tengo algunos problemas. Tenía la impresión de que en un estado de entrada HIGH-Z (tres estados, es decir, DDRX 0, PORTX 1 para un pin en particular) se modelaría esencialmente como:
Sin embargo, el estado de la línea SDA permanece alto a pesar de que el dispositivo I2C está respondiendo con un bit ACK al hacer que la línea sea baja. Sé que esto es cierto porque configuré un retraso considerable después de configurar el pin como entrada. Durante este retraso, la línea permanece alta. Sin embargo, si quito el cable que une la MCU a la línea SDA, caerá a BAJO debido al dispositivo esclavo.
En resumen, ¿cómo maneja el "soltar" una línea para garantizar que su potencial sea impulsado por los dispositivos en su línea de datos I2C en lugar de ser influenciado por la MCU?
/* Pin and direction register manipulations */
#define I2C_CLKDEL 10 //10uS
#define I2C_PORT PORTB
#define SDA PB0
#define SCL PB1
#define set_high(port, pin) (port |= (1<<pin))
#define set_low(port, pin) (port &= ~(1<<pin))
#define set_in(portDDR, pin) (portDDR &= ~(1<<pin))
#define set_out(portDDR, pin) (portDDR |= (1<<pin))
void clkStrobe(void){
set_high(I2C_PORT, SCL);
_delay_us(I2C_CLKDEL);
set_low(I2C_PORT, SCL);
_delay_us(I2C_CLKDEL);
}
uint8_t sendByte(uint8_t byte){ //MSB first
uint8_t count = 8, ack;
set_low(PORTB, SCL);
while( count-- ){
if( byte & 0x80 )
set_high(PORTB, SDA);
else
set_low(PORTB, SDA);
byte <<= 1;
_delay_ms(I2C_CLKDEL);
clkStrobe();
}
//set as input and read in the I2C port data
set_in(I2C_PORT, SDA);
_delay_ms(1000);
ack = PINB;
set_out(I2C_PORT, SDA);
clkStrobe(); //clock in the ACK bit
return (ack & (1<<SDA)); //return ACK bit
}
Se insertó un gran retraso después de configurar SDA en la MCU como entrada para la prueba. La línea sigue siendo alta. Si la línea SDA se elimina de la MCU (el cable ya no está conectado), la línea SDA se reduce debido al dispositivo I2C que se está direccionando (el dispositivo está enviando ACK). Claramente estoy haciendo algo mal aquí.
Para set_in, está pasando I2C_PORT
, que es PORTB
, pero necesita pasar DDRB
.
mate joven
sherrellbc
mate joven
sherrellbc
Dzarda
sherrellbc
Dzarda