Introducción
Llevo años trasteando con microcontroladores. Y sí. El AT89C51 es un clásico que muchos damos por muerto. Pero no lo está. Sigue siendo una bestia para proyectos educativos y aplicaciones industriales donde la fiabilidad importa más que la velocidad bruta. El problema es que conectar sensores modernos como el acelerómetro ADXL345 a este «dinosaurio» de 8 bits puede ser un dolor de cabeza si no sabes cómo manejar las diferencias de voltaje y protocolo.
Aquí te cuento exactamente cómo lo hice yo. Sin rodeos. Sin teoría inútil. Solo lo que funciona.
¿Qué es el ADXL345 y por qué usarlo con un AT89C51?
El ADXL345 es un acelerómetro digital de 3 ejes de la casa Analog Devices. Pequeño. Preciso. Y con una característica que lo salva todo: funciona tanto por I2C como por SPI. Eso es clave porque el AT89C51 no tiene periféricos I2C o SPI nativos. Vas a tener que implementarlos por software (bit-banging). Pero no te asustes, es más fácil de lo que parece.
Características clave del ADXL345:
- Rango de medición: ±2g, ±4g, ±8g, ±16g seleccionable.
- Resolución: 10 bits por defecto, hasta 13 bits en modo completo.
- Interfaz: I2C (hasta 400 kHz) y SPI (hasta 5 MHz).
- Consumo: Ultrabajo, 23 µA en modo medición.
- Voltaje de operación: 2.0V a 3.6V. Ojo aquí: el AT89C51 trabaja a 5V.
Ese último punto es el que más quebraderos de cabeza da. No puedes conectar directamente las patas del ADXL345 a los 5V del AT89C51 sin un conversor de nivel lógico. Si lo haces, quemas el sensor. Punto.
Materiales Necesarios
Para este proyecto vas a necesitar:
- Microcontrolador AT89C51 (o cualquier variante como AT89S51, AT89C52).
- Módulo ADXL345 (los chinos venden unos por menos de 2€ en AliExpress, una ganga absoluta).
- Conversor de nivel lógico 3.3V a 5V (un módulo con MOSFET BSS138 va perfecto).
- Cristal de cuarzo de 11.0592 MHz (para generar baud rates exactos si usas UART).
- Condensadores de 22pF (para el cristal).
- Resistencias de pull-up de 4.7kΩ (para las líneas I2C).
- Protoboard y cables Dupont.
- Programador USB para AT89C51 (yo uso un USBasp modificado).
Conexión Física: I2C vs SPI
Aquí tienes que decidir. Yo prefiero I2C porque solo necesitas dos líneas (SDA y SCL) y dejas pines libres para otras cosas. Pero el SPI es más rápido si necesitas leer datos a alta frecuencia. Para un proyecto de medición de inclinación o detección de movimiento, I2C va sobrado.
Conexión por I2C (Recomendada)
Esquema de conexión:
- ADXL345 VCC (3.3V) → Salida de 3.3V del conversor de nivel.
- ADXL345 GND → GND común.
- ADXL345 SDA → Conversor de nivel (lado 3.3V).
- ADXL345 SCL → Conversor de nivel (lado 3.3V).
- Conversor de nivel (lado 5V) SDA → P3.0 (RXD) del AT89C51 (o cualquier pin GPIO que elijas).
- Conversor de nivel (lado 5V) SCL → P3.1 (TXD) del AT89C51.
- Resistencias de pull-up de 4.7kΩ en las líneas SDA y SCL del lado de 3.3V (importante).
- Pin CS del ADXL345 → VCC (3.3V) para seleccionar modo I2C.
- Pin SDO/ALT ADDRESS → GND para dirección 0x53, o VCC para 0x1D.
Nota importante: El AT89C51 no tiene pines específicos I2C. Elegí P3.0 y P3.1 porque son los que uso para depuración serial, pero puedes usar cualquier pin GPIO. Solo asegúrate de configurarlos como salida drenador abierto (open-drain) o usa las resistencias de pull-up externas.
Conexión por SPI
Si prefieres SPI (por ejemplo, para un proyecto de captura de vibraciones a alta velocidad):
- ADXL345 CS → Pin P1.0 (chip select).
- ADXL345 SDO → Pin P1.1 (MISO).
- ADXL345 SDA/SDI → Pin P1.2 (MOSI).
- ADXL345 SCL → Pin P1.3 (SCK).
Recuerda: siempre con conversor de nivel entre medias. No lo olvides.
Programación del AT89C51 para Leer el ADXL345
Aquí viene lo bueno. El AT89C51 no tiene librerías I2C. Vas a tener que implementar el protocolo a mano. Pero no te preocupes, te dejo el código base que uso yo.
Inicialización del ADXL345
El primer paso es configurar el sensor. El registro clave es el 0x2D (POWER_CTL). Tienes que escribir 0x08 para ponerlo en modo medición. Sin eso, el sensor no hace nada.
// Función para escribir un byte en el ADXL345 vía I2C (bit-banging)
void ADXL345_Write(uint8_t reg, uint8_t data) {
I2C_Start();
I2C_WriteByte(0x53 << 1 | 0); // Dirección + escritura
I2C_WriteByte(reg); // Registro destino
I2C_WriteByte(data); // Dato a escribir
I2C_Stop();
}
// Configuración inicial
void ADXL345_Init() {
ADXL345_Write(0x31, 0x0B); // DATA_FORMAT: rango ±16g, resolución completa
ADXL345_Write(0x2D, 0x08); // POWER_CTL: modo medición
ADXL345_Write(0x2C, 0x0A); // BW_RATE: 100 Hz (buen balance velocidad/ruido)
}
Lectura de los Ejes
Los datos de los ejes X, Y, Z están en los registros 0x32 a 0x37. Son valores de 16 bits en complemento a 2. O sea, tienes que leer dos bytes por eje y combinarlos.
// Leer los 6 bytes de datos (X, Y, Z)
void ADXL345_ReadAxis(int16_t *x, int16_t *y, int16_t *z) {
uint8_t buffer[6];
I2C_Start();
I2C_WriteByte(0x53 << 1 | 0); // Dirección + escritura
I2C_WriteByte(0x32); // Registro inicial (DATAX0)
I2C_Start(); // Repeated start
I2C_WriteByte(0x53 << 1 | 1); // Dirección + lectura
for (int i = 0; i < 6; i++) {
if (i < 5)
buffer[i] = I2C_ReadByte(1); // ACK
else
buffer[i] = I2C_ReadByte(0); // NACK (último byte)
}
I2C_Stop();
*x = (int16_t)(buffer[1] << 8 | buffer[0]);
*y = (int16_t)(buffer[3] << 8 | buffer[2]);
*z = (int16_t)(buffer[5] << 8 | buffer[4]);
}
Ojo: El valor leído está en unidades LSB. Para convertirlo a gravedades (g), tienes que multiplicar por la escala que elegiste. Si usas ±16g con resolución completa, cada LSB son 3.9 mg (0.0039 g).
Función I2C Bit-Banging
Aquí te dejo las funciones base para I2C. Ajusta los retardos según la frecuencia de tu cristal. Con 11.0592 MHz, unos pocos microsegundos de delay bastan.
#define SDA P3_0
#define SCL P3_1
void I2C_Delay() {
// Ajusta según tu velocidad de reloj
_nop_(); _nop_(); _nop_(); _nop_();
}
void I2C_Start() {
SDA = 1;
SCL = 1;
I2C_Delay();
SDA = 0;
I2C_Delay();
SCL = 0;
}
void I2C_Stop() {
SDA = 0;
SCL = 1;
I2C_Delay();
SDA = 1;
I2C_Delay();
}
uint8_t I2C_WriteByte(uint8_t data) {
uint8_t i;
for (i = 0; i < 8; i++) {
SDA = (data & 0x80) ? 1 : 0;
data <<= 1;
SCL = 1;
I2C_Delay();
SCL = 0;
}
// Leer ACK
SDA = 1; // Liberar línea
SCL = 1;
I2C_Delay();
uint8_t ack = SDA;
SCL = 0;
return ack;
}
uint8_t I2C_ReadByte(uint8_t ack) {
uint8_t data = 0, i;
SDA = 1; // Liberar línea
for (i = 0; i < 8; i++) {
data <<= 1;
SCL = 1;
I2C_Delay();
if (SDA) data |= 1;
SCL = 0;
}
SDA = ack ? 0 : 1; // Enviar ACK o NACK
SCL = 1;
I2C_Delay();
SCL = 0;
SDA = 1;
return data;
}
Troubleshooting y Errores Comunes
Aquí es donde la mayoría de la gente tira la toalla. Y por eso esta sección es la más larga. He visto todos los fallos posibles en mis años de taller.
1. El sensor no responde: Dirección I2C incorrecta
Síntoma: El ACK nunca llega después de enviar la dirección. Solución: El ADXL345 tiene dos direcciones posibles: 0x53 (si SDO está a GND) o 0x1D (si SDO está a VCC). La mayoría de los módulos chinos vienen con SDO a GND, así que usa 0x53. Pero verifica con un multímetro la tensión en el pin SDO de tu módulo. Si está flotando, puede dar valores aleatorios.
2. Datos basura o siempre cero
Síntoma: Lees valores que no cambian, o son siempre 0. Solución: Revisa el registro POWER_CTL. Si no escribiste 0x08, el sensor está en modo standby y no mide nada. También verifica que el registro DATA_FORMAT esté bien configurado. A veces los módulos vienen con la configuración de fábrica en modo ±2g y 10 bits, y si esperas 16 bits, los datos parecen ruido.
3. El I2C se cuelga después de unos segundos
Síntoma: El programa funciona unos segundos y luego se queda pillado. Solución: Esto pasa cuando el bus I2C se queda en un estado inválido (por ejemplo, SDA baja y SCL alta). Implementa una rutina de timeout en tus funciones I2C. Si después de X iteraciones no hay ACK, fuerza una condición de stop y reinicia la comunicación. Es un error típico de bit-banging sin protección.
4. El AT89C51 no arranca después de grabar el código
Síntoma: El micro no ejecuta nada. Solución: Revisa el pin EA (External Access). En el AT89C51, el pin EA debe estar conectado a VCC para que ejecute código desde la memoria flash interna. Si lo dejas flotando o a GND, intentará arrancar desde memoria externa y no hará nada. Es el error más tonto y más común.
5. Lecturas inestables: el sensor vibra aunque esté quieto
Síntoma: Los valores de los ejes oscilan ±50 LSB incluso con el sensor inmóvil. Solución: El ADXL345 tiene un filtro interno configurable en el registro BW_RATE (0x2C). Por defecto viene a 100 Hz. Si tu proyecto no necesita alta velocidad, baja la tasa a 12.5 Hz (valor 0x09). Eso reduce el ruido drásticamente. También puedes hacer un promedio móvil en software de 4 o 8 muestras.
6. No hay comunicación: el conversor de nivel no funciona
Síntoma: Mides 0V en las líneas SDA/SCL del lado de 3.3V. Solución: Los conversores de nivel con MOSFET BSS138 necesitan que ambos lados tengan alimentación. Si solo conectas 5V al lado alto y dejas el lado bajo sin 3.3V, el MOSFET no conduce. Conecta VCCB (3.3V) y VCCA (5V) correctamente. Y no olvides las resistencias de pull-up en el lado de 3.3V. Sin ellas, las líneas no suben a nivel alto.
FAQ
¿Puedo conectar el ADXL345 directamente a 5V sin conversor?
No, no y no. El ADXL345 tiene una tensión máxima absoluta de 3.6V en sus pines de entrada/salida. Conectar 5V directamente lo fríe en segundos. He visto a gente hacerlo y el humo mágico sale rápido. Usa siempre un conversor de nivel lógico. Cuestan menos de 1€ en AliExpress y te ahorran un sensor.
¿Es mejor usar I2C o SPI con el AT89C51?
Para proyectos sencillos como medir inclinación o detectar movimiento, I2C es más que suficiente y solo necesitas dos pines. Para aplicaciones que requieren altas tasas de muestreo (por ejemplo, análisis de vibraciones a más de 800 Hz), necesitas SPI. Pero ten en cuenta que con SPI ocupas 4 pines y la implementación bit-banging es más compleja porque tienes que manejar el chip select manualmente.
¿Puedo usar un Arduino en lugar del AT89C51?
Claro, pero entonces no estarías leyendo este artículo. El AT89C51 tiene su encanto: es barato, robusto y te obliga a entender realmente cómo funciona el protocolo I2C a bajo nivel. Si solo quieres que funcione rápido, cómprate un Arduino y usa la librería Wire. Pero si quieres aprender de verdad, quédate con el 8051.
Conclusión
Conectar un ADXL345 a un AT89C51 no es trivial, pero tampoco es imposible. La clave está en respetar los niveles de voltaje, implementar bien el bit-banging I2C y no olvidar configurar el registro POWER_CTL. Una vez que lo tienes funcionando, las posibilidades son enormes: desde un inclinómetro para un brazo robótico hasta un detector de golpes para un sistema de alarma casero.
En DunaTech nos pasamos el día cribando el desierto de AliExpress para encontrar componentes que funcionen sin arruinarte. Y el ADXL345 es uno de esos chollos que merecen la pena. Si te ha gustado esta guía, échale un ojo a nuestro análisis de tablets baratas o a nuestra guía de ratones gaming calidad-precio. Seguimos buscando tesoros en la arena para que tú no tengas que hacerlo.
Ver precio actual y cupones en AliExpress