// En bmp180.c #include #include #include #include "bmp180.h" // --- FUNCIÓN AUXILIAR PARA LEER VLOQUES DE DATOS --- int leer_bloque_i2c(int fd, uint8_t registro_inicial, uint8_t *buffer, int longitud) { // Le decimos al sensor desde qué registro queremos empezar a leer // (El sensor cuenta con un puntero autoincrementado que inicia del registro inicial enviando una rafaga) if (write(fd, ®istro_inicial, 1) != 1) { perror("Fallo al escribir el registro inicial"); return -1; // Falló } // Leemos la cantidad de bytes que pedimos if (read(fd, buffer, longitud) != longitud) { perror("Fallo al leer los bytes del sensor"); return -1; // Falló } return 0; // Éxito } // --- MÉTODO DE INICIALIZACIÓN PARA RECONSTRUIR LOS DATOS DE CALIBRACIÓN --- int bmp180_init(int fd, BMP180_CalibData *calib) { uint8_t buffer[22]; // Necesitamos un arreglo de 22 espacios para guardar los 22 bytes printf("Iniciando BMP180 y leyendo calibracion...\n"); // Leemos los 22 bytes empezando desde el registro 0xAA if (leer_bloque_i2c(fd, 0xAA, buffer, 22) < 0) { printf("Error fatal: No se pudo leer la EEPROM.\n"); return -1; // Falló } // Unimos los bytes. // El sensor envía primero el byte "pesado" (MSB) y luego el "ligero" (LSB). // Tomamos el MSB, lo desplazamos 8 espacios a la izquierda (<< 8) y le sumamos el LSB (|). calib->ac1 = (buffer[0] << 8) | buffer[1]; calib->ac2 = (buffer[2] << 8) | buffer[3]; calib->ac3 = (buffer[4] << 8) | buffer[5]; // Estos tres deben ser tratados como sin signo (unsigned) según el datasheet calib->ac4 = (buffer[6] << 8) | buffer[7]; calib->ac5 = (buffer[8] << 8) | buffer[9]; calib->ac6 = (buffer[10] << 8) | buffer[11]; calib->b1 = (buffer[12] << 8) | buffer[13]; calib->b2 = (buffer[14] << 8) | buffer[15]; calib->mb = (buffer[16] << 8) | buffer[17]; calib->mc = (buffer[18] << 8) | buffer[19]; calib->md = (buffer[20] << 8) | buffer[21]; // Verificamos que se realizo correctamente // Si la comunicación falla o el cable está mal, a veces el I2C devuelve puros ceros (0) // o puros unos (0xFFFF = -1 en short) if (calib->ac1 == 0 || calib->ac1 == -1) { printf("Advertencia: Los datos de calibración parecen inválidos.\n"); return -1; // Falló } printf("Calibracion exitosa. Valor AC1: %d\n", calib->ac1); return 0; // Todo listo para medir } // --- MÉTODO PARA LEER LA TEMPERATURA CRUDA --- long bmp180_read_ut(int fd) { // 0xF4 es el registro de control, 0x2E es el comando de temperatura uint8_t cmd[2] = {BMP180_REG_CTRL_MEAS, BMP180_CMD_TEMP}; // Escribimos el comando write(fd, cmd, 2); // Esperamos a que el hardware del sensor termine la conversión (4.5ms) usleep(4500); uint8_t buf[2]; // Leemos los 2 bytes resultantes en el registro 0xF6 leer_bloque_i2c(fd, BMP180_REG_ADC_MSB, buf, 2); // Ensamblamos los 16 bits return (buf[0] << 8) | buf[1]; } // --- MÉTODO PARA LEER LA PRESIÓN CRUDA --- long bmp180_read_up(int fd, int oss) { // Calculamos el comando exacto basado en la resolución (oss) uint8_t cmd_val = 0x34 + (oss << 6); uint8_t cmd[2] = {BMP180_REG_CTRL_MEAS, cmd_val}; write(fd, cmd, 2); // El tiempo de espera del hardware aumenta si pides más resolución switch(oss) { case 0: usleep(4500); break; case 1: usleep(7500); break; case 2: usleep(13500); break; case 3: usleep(25500); break; } uint8_t buf[3]; // Leemos 3 bytes (MSB, LSB, XLSB) desde 0xF6 leer_bloque_i2c(fd, BMP180_REG_ADC_MSB, buf, 3); // Desplazamiento a nivel de bits exigido por el fabricante return ((long)buf[0] << 16 | (long)buf[1] << 8 | (long)buf[2]) >> (8 - oss); } // --- MÉTODO PARA MEDIR LA PRESIÓN CALIBRADA --- int bmp180_get_pressure(int fd, BMP180_CalibData *calib, int oss, double *pressure) { // Medimos la temperatura y presión crudas long UT = bmp180_read_ut(fd); long UP = bmp180_read_up(fd, oss); // Declaramos las variables locales según la hoja de datos (página 15) long X1, X2, X3, B3, B5, B6, p; unsigned long B4, B7; // --- Ecuaciones de Temperatura (Para obtener B5) --- X1 = ((UT - calib->ac6) * calib->ac5) >> 15; X2 = ((long)calib->mc << 11) / (X1 + calib->md); // Cast a long obligatorio en mc B5 = X1 + X2; // --- Ecuaciones de Presión --- B6 = B5 - 4000; X1 = (calib->b2 * (B6 * B6 >> 12)) >> 11; X2 = (calib->ac2 * B6) >> 11; X3 = X1 + X2; B3 = ((((long)calib->ac1 * 4 + X3) << oss) + 2) >> 2; X1 = (calib->ac3 * B6) >> 13; X2 = (calib->b1 * ((B6 * B6) >> 12)) >> 16; X3 = ((X1 + X2) + 2) >> 2; B4 = (calib->ac4 * (unsigned long)(X3 + 32768)) >> 15; B7 = ((unsigned long)UP - B3) * (50000 >> oss); if (B7 < 0x80000000) { p = (B7 * 2) / B4; } else { p = (B7 / B4) * 2; } X1 = (p >> 8) * (p >> 8); X1 = (X1 * 3038) >> 16; X2 = (-7357 * p) >> 16; p = p + ((X1 + X2 + 3791) >> 4); // El cálculo arroja Pascales, dividimos entre 100 para Hectopascales (hPa) *pressure = p / 100.0; return 0; // Éxito }