¿Qué es este blog?

La idea de este blog nace para compartir los avances que se vayan realizando a lo largo de un estudio sobre cómo interconectar los distintos sensores que se pueden encontrar en el mercado, o fabricar de forma casera, con la plataforma Mindstorms de LEGO. Para ello se hará uso ARDUINO, un entorno de desarrollo abierto basado en microcontrolador.

viernes, 17 de junio de 2011

Sensor SCP 1000 y su conexión con Arduino por SPI

El sensor SCP1000 es un sensor de presión barométrica preciso y de alta calidad. En condiciones ideales, es capaz de medir presiones de una capa de aire de 9 centímetros y está pensado para mediciones tales como en altímetros por ejemplo, con un gran rango de temperaturas de funcionamiento que van desde -20 a 70 grados centígrados. La calibración y compensación se realiza internamente, por lo que siempre dispondremos de una medición precisa. El sensor se controla mediante un bus SPI y su consumo puede ser de apenas 4 micro Amperios. El sensor se puede ver en la siguiente figura:




Conexiones realizadas



Como se ha comentado en el epígrafe anterior, este sensor se va a conectar mediante el protocolo SPI. Las conexiones que se han realizado entre dicho sensor y nuestro sistema de desarrollo han sido las siguientes:
  • Pines de tierra de ambos conectados
  • Alimentación del sensor al pin de 3,3 de Arduino
  • Pines MISO y MOSI del protocolo SPI a los pines 50 y 51 de Arduino respectivamente
  • La señal de reloj, SCK, se ha conectado pin 52 de Arduino
  • Los pines de indicación de dato listo (DRDY) y de selección del chip (CSB) se han conectado a los pines 30 y 31 de Arduino respectivamente




Código implementado



El código está estructurado de la siguiente forma:
  • En el apartado de setupo(), se configuran los registros del sensor
  • En el bucle principal se configura el sensor para que lea en alta resolución, es decir, devolverá 19 bits para la presión y 16 bits para la temperatura. Para obtener la temperatura en grados centígrados, bastará con dividir los 16 bits entre 20
  • A continuación se lee la temperatura en 2 bytes
  • Finalmente, se lee la presión en dos partes: primero se leen los 3 bits más altos, y seguidamente los 16 bits más bajos. Estas dos partes se combinan en un long entero desplazando los bits más altos y realizando una OR bit a bit para combinarlos con los 16 más bajos. La humedad en pascales es el resultado de 19 bits dividido entre 4.

El código completo se muestra a continuación. Se han dejado los comentarios para simplificar la comprensión del mismo:



// Incluimos la librería SPI
#include <SPI.h>

//Direcciones de los registros de la memoria del sensor
const int PRESSURE = 0x1F;      //3 bits mas significativos de la presion
const int PRESSURE_LSB = 0x20;  //16 bits menos significativos de la presion
const int TEMPERATURE = 0x21;   //16 bits de la lectura de temperatura
const byte READ = 0b11111100;     // Instruccion de lectura del SCP1000
const byte WRITE = 0b00000010;   // Instruccion de escritura del SCP1000

// Pines usados para la conexion con el sensor
// El resto ya estan definidos en la libreria SPI
const int dataReadyPin = 30;
const int chipSelectPin = 31;

void setup() {
  Serial.begin(9600);

  // Inicializamos la libreria SPI
  SPI.begin();

  // Inicializamos pines dataReady y chipSelect
  pinMode(dataReadyPin, INPUT);
  pinMode(chipSelectPin, OUTPUT);

  //Configuramos el SCP1000 en config. de bajo ruido
  writeRegister(0x02, 0x2D);
  writeRegister(0x01, 0x03);
  writeRegister(0x03, 0x02);
  // Y le damos tiempo al sensor para que se prepare
  delay(100);
}

void loop() {
  //Seleccionamos el modo de alta resolucion
  writeRegister(0x03, 0x0A);

  // No hacemos nada hasta que el pin dataReady este alto
  if (digitalRead(dataReadyPin) == HIGH) {
    //Leemos la temperatura
    int tempData = readRegister(0x21, 2);

    // Convertimos la temp. a Celcius y la mostramos
    float realTemp = (float)tempData / 20.0;
    Serial.print("Temp[C]=");
    Serial.print(realTemp);

    // Leemos los 3 bits mas altos de la presion
    byte  pressure_data_high = readRegister(0x1F, 1);
    pressure_data_high &= 0b00000111; // Solo hacen falta los bits del 2 al 0

    //Se leen los 16 bits mas bajos de la presion
    unsigned int pressure_data_low = readRegister(0x20, 2);
    // Se combinan las dos partes en un solo numero de 19 bits:
    long pressure = ((pressure_data_high << 16) | pressure_data_low)/4;

    // Mostramos la presion:
    Serial.println("\tPressure [Pa]=" + String(pressure));
  }
}

//Lecturas desde o escrituras hacia los registros del SCP1000
unsigned int readRegister(byte thisRegister, int bytesToRead ) {
  byte inByte = 0;           // Byte entrante del SPI
  unsigned int result = 0;   // Resultado a devolver
  Serial.print(thisRegister, BIN);
  Serial.print("\t");
  // SCP1000 espera el nombre del registro en los 6 bits mas altos
  // del byte. Asi que desplazamos los bits hacia la izq. 2 posiciones
  thisRegister = thisRegister << 2;
  // Combinamos la direccion y la instruccion en un byte
  byte dataToSend = thisRegister & READ;
  Serial.println(thisRegister, BIN);
  // Bajamos el ChipSelct para seleccionar el dispositivo
  digitalWrite(chipSelectPin, LOW);
  // Mandamos al dispositivo el registro que queremos leer:
  SPI.transfer(dataToSend);
  // Mandamos un valor de 0 para leer el primer byte devuelto
  result = SPI.transfer(0x00);
  // Reducimos en uno el numero de bytes restantes por leer
  bytesToRead--;
  // Si quedan bytes por leer
  if (bytesToRead > 0) {
    // Desplazamos el primer byte hacia la izquierda, y obtenemos el 2º byte:
    result = result << 8;
    inByte = SPI.transfer(0x00);
    // Combinamos el byte que acabamos de obtener con el anterior:
    result = result | inByte;
    // Nos queda un byte menos por leer:
    bytesToRead--;
  }
  // Levantamos el chip-select
  digitalWrite(chipSelectPin, HIGH);
  // Devolvemos el resultado
  return(result);
}

//Mandamos ahora una escritura el dispositivo

void writeRegister(byte thisRegister, byte thisValue) {

  // SCP1000 espera la direccion del registo en los 6 bits mas altos
  // del byte. Asi que desplazamos en 2 posiciones hacia la izquierda
  thisRegister = thisRegister << 2;
  // Combinamos el registro de direccion y la instruccion en un solo byte:
  byte dataToSend = thisRegister | WRITE;

  // Bajamos el chip-select para seleccionar el sensor:
  digitalWrite(chipSelectPin, LOW);

  SPI.transfer(dataToSend); //Mandamos la localizacion del registro
  SPI.transfer(thisValue);  //Mandamos el valor a almacenar en el registro

  // Levantamos el chip-select
  digitalWrite(chipSelectPin, HIGH); }

Aquí os dejo una captura de la salida de datos, en la que se ve la presión en grados, la temperatura en pascales y el contenido de los registros leídos en bianrio (simplemente los he dejado como traza, para ver que todo se hace correctamente):


---------------------------------
Referencias:

- Sensor SCP1000: http://www.bricogeek.com/shop/150-sensor-de-presion-barometrica-scp1000.html

2 comentarios:

  1. Tengo una duda cuando se refieren a los pins 50, 51, 52 y 30 y 31. A que pines se refieren o equivalen en una placa arduino uno ya que no encuentro equivalencia.
    Gracias

    ResponderEliminar
    Respuestas
    1. Hola Jose,

      Efectivamente se trata de la placa Arduino UNO, tal y como puedes ver en este enlace: http://mindstormsyarduino.blogspot.com.es/2010/11/placa-usada-para-el-desarrollo-de-este.html

      Sin embargo, los pines 50, 51, 52, 30 y 31 no son más que entradas / salidas digitales de la placa, así que puedes escoger las que necesites según el modelo que estés usando.

      Un abrazo

      Eliminar