¿Como Utilizar un Sensor AS5048a con Arduino?

¿Como Utilizar un Sensor AS5048a con Arduino?

En la siguiente guía vamos a explicar como puedes utilizar con Arduino un Encoder AS5048a y leer los datos que se están recibiendo fácilmente en un LCD 16×2

Materiales Necesarios:

 

  1. Encoder AS5048a.
  2. Arduino Nano, Uno, Mega.
  3. Jumpers.

Pasos a Seguir:

  1. Realizaremos al siguiente conexión electrónica entre nuestro Arduino y Encoder AS5048a.
  2. Ahora procedemos a descargar y importar la librería que controla nuestra LCD, la encontraras en el siguiente link:https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-libraryTambién puedes descargarla desde nuestros servidores en el siguiente link:

  3. Ahora procedemos a cargar el siguiente código a nuestro Arduino:
    #include <SPI.h>
    /*PINS
       Pines Arduino SPI
       MOSI = 11, MISO = 12, SCK = 13, CS = 10
       Pines STM32 SPI
       MOSI = PA7, MISO = PA6, SCK = PA5, CS = PA4
    */
    
    //16x2 LCD
    #include <LiquidCrystal_I2C.h>
    /*PINS
    
       Pines Arduino i2C
       SDA = A4, SCL = A5
    
       Pines STM32 i2C
       SDA = PB7, SCL = PB6
    */
    
    LiquidCrystal_I2C lcd(0x27, 16, 2);
    
    const byte CS_pin = 10; //Pin de selección de chip para conmutación manual
    
    uint16_t rawData = 0; //Pin de selección de chip para conmutación manual
    float degAngle = 0; //Ángulo en grados
    float startAngle = 0; //ángulo de inicio para referencia
    float correctedAngle = 0; //valor del ángulo tarado (degAngle-startAngle)
    float totalAngle = 0; //desplazamiento angular acumulado total
    float numberofTurns = 0;
    float rpmCounter = 0; //cuenta el número de turnos durante un período determinado
    float revsPerMin = 0; //RPM
    int quadrantNumber = 0;
    int previousquadrantNumber = 0;
    
    uint16_t command = 0b1111111111111111; //comando de lectura (0xFFF)
    
    float timer = 0; //temporizador para actualizar la pantalla LCD y enviar los datos a través del puerto serie
    float rpmTimer = 0; //temporizador para estimar las RPM
    
    void setup()
    {
      SPI.begin();
      Serial.begin(9600);
      Serial.println("AS5048A - Codificador de posición magnetico");
      pinMode(CS_pin, OUTPUT); //Pin CS - salida
    
      //------------------------------------------------------
      lcd.begin();                      //inicializar la pantalla lcd
      lcd.backlight();
      //------------------------------------------------------
      lcd.setCursor(0, 0); //Definición de posición para escribir desde la primera fila, primera columna.
      lcd.print("AS5048A Encoder");
      lcd.setCursor(0, 1); //2da fila, 1er bloque
      lcd.print("SPI Demo");
      delay(2000); //espera 2 seg
      printLCD(); //Imprimir Valores
      //------------------------------------------------------
    
      //Comprobando el ángulo inicial
      readRegister();
      startAngle = degAngle;
    }
    
    void loop()
    {
      readRegister(); //leer la posición del imán
      correctAngle(); //normalizar la lectura anterior
      checkQuadrant(); //comprobar el sentido de giro y calcular el desplazamiento final
      if (millis() - timer > 250)
      {
        Serial.print("Giros: ");
        Serial.println(numberofTurns);
    
        Serial.print("Angulo Total: ");
        Serial.println(totalAngle, 2);
    
        updateLCD(); //imprima el nuevo contenido en la pantalla LCD (solo los números)
        timer = millis();
      }
    
      if (millis() - rpmTimer > 15000) //comprobar y calcular las RPM cada 15 segundos
      {
        revsPerMin = 4 * rpmCounter; //60000/15000 = 4 (asumimos la misma velocidad durante todo el minuto)
    
        rpmCounter = 0; //Reinicio
        rpmTimer = millis();
      }
    }
    
    void readRegister()
    {
      SPI.beginTransaction(SPISettings(3000000, MSBFIRST, SPI_MODE1));
    
      //--enviando el comando
      digitalWrite(CS_pin, LOW);
      SPI.transfer16(command);
      digitalWrite(CS_pin, HIGH);
    
      delay(10);
    
      //--recibiendo la lectura
      digitalWrite(CS_pin, LOW);
      rawData = SPI.transfer16(command);
      digitalWrite(CS_pin, HIGH);
    
      SPI.endTransaction();
    
      rawData = rawData & 0b0011111111111111; //quitar los 2 bits superiores (PAR y EF)
    
      degAngle = (float)rawData / 16384.0 * 360.0; //16384 = 2^14, 360 = 360 grados
    
      //Serial.print("Gra: ");
      //Serial.println(degAngle);
    }
    
    void correctAngle()
    {
      //recalcular el ángulo
      correctedAngle = degAngle - startAngle; //esto tara la posición
    
      if (correctedAngle < 0) //si el ángulo calculado es negativo, necesitamos "normalizarlo"
      {
        correctedAngle = correctedAngle + 360; //corrección para números negativos (es decir, -15 se convierte en +345)
      }
      else
      {
        //hacer nada
      }
      //Serial.print("Ángulo corregido: ");
      //Serial.println(correctedAngle, 2); //imprimir el ángulo corregido / tarado
    }
    
    void checkQuadrant()
    {
      /*
        //Cuadrantes:
        4  |  1
        ---|---
        3  |  2
      */
    
      //cuadrante 1
      if (correctedAngle >= 0 && correctedAngle <= 90)
      {
        quadrantNumber = 1;
      }
    
      //Cuadrante 2
      if (correctedAngle > 90 && correctedAngle <= 180)
      {
        quadrantNumber = 2;
      }
    
      //Cuadrante 3
      if (correctedAngle > 180 && correctedAngle <= 270)
      {
        quadrantNumber = 3;
      }
    
      //Cuadrante 4
      if (correctedAngle > 270 && correctedAngle < 360)
      {
        quadrantNumber = 4;
      }
      //Serial.print("Cuadrante: ");
      //Serial.println(quadrantNumber); //imprime nuestra posición "en cuadrante"
    
      if (quadrantNumber != previousquadrantNumber) //si cambiamos de cuadrante
      {
        if (quadrantNumber == 1 && previousquadrantNumber == 4)
        {
          numberofTurns++; // 4 --> 1 transición: rotación CW
          rpmCounter++;
        }
    
        if (quadrantNumber == 4 && previousquadrantNumber == 1)
        {
          numberofTurns--; // 1 --> 4 transición: rotación CCW
          rpmCounter--;
        }
        //esto podría hacerse entre cada cuadrante para que se pueda contar cada 1/4 de transición
    
        previousquadrantNumber = quadrantNumber;  //actualizar al cuadrante actual
    
      }
      //Serial.print("Vueltas: ");
      //Serial.println(numberofTurns); //número de vueltas en términos absolutos (puede ser negativo, lo que indica vueltas en sentido antihorario)
    
      //después de tener el ángulo corregido y los giros, podemos calcular la posición absoluta total 
    
      totalAngle = (numberofTurns * 360) + correctedAngle; //número de vueltas (+/-) más el ángulo real dentro del rango 0-360
      //Serial.print("Angulo total: ");
      //Serial.println(totalAngle, 2); //posición absoluta del motor expresada en ángulos de grado, 2 dígitos
    }
    
    void printLCD()
    {
      //imprimiendo las partes permanentes
      lcd.setCursor(0, 0); // primera linea
      lcd.print("RPM: ");
      lcd.setCursor(5, 0);
      lcd.print("           ");
      lcd.setCursor(5, 0);
      lcd.print(revsPerMin,0);
    
      lcd.setCursor(0, 1); // segunda linea
      lcd.print("Total: ");
      lcd.setCursor(7, 1);
      lcd.print("         ");
      lcd.setCursor(7, 1);
      lcd.print(totalAngle,1);
    }
    
    void updateLCD()
    {
      //imprimiendo las partes variables
      lcd.setCursor(5, 0); // primera linea
      lcd.print("     ");
      lcd.setCursor(5, 0);
      lcd.print(revsPerMin,0);
    
      lcd.setCursor(7, 1); // segunda linea
      lcd.print("            ");
      lcd.setCursor(7, 1);
      lcd.print(totalAngle,1);
    }

     

  4. Por ultimo procedemos a cargar el código y podremos verificar en nuestro Encoder que pasos estamos teniendo y el sentido de giro.