- Descripción del sistema
El AS5047P es un codificador magnético rotatorio de alta rseolución que proporciona información de posición angular absoluta de 14 bits (0–16383 correspondiente a 0–360°) a través de una interfaz SPI. Al leer estos datos con un microcontrolador STM32, es posible implementar control de lazo cerrado de posición del motor, medición de velocidad y otras funciones.
- Conexión del hardware
2.1 Asignación de pines
| Pin AS5047P |
Pin STM32 |
Función |
| VDD |
3.3V |
Alimentación (2.7–3.6V) |
| GND |
GND |
Tierra |
| MOSI |
PA7 |
SPI1_MOSI (salida maestro) |
| MISO |
PA6 |
SPI1_MISO (entrada maestro) |
| SCK |
PA5 |
SPI1_SCK (reloj) |
| CS |
PB0 |
Chip select (activo en bajo) |
2.2 Características eléctricas
- Voltaje de operación: 2.7–3.6V (típico 3.3V)
- Modo SPI: modo 1 (CPOL=0, CPHA=1) o modo 3 (CPOL=1, CPHA=1)
- Frecuencia máxima de reloj: 10 MHz
- Resolución angular: 14 bits (0.022°/LSB)
- Configuración SPI en STM32 (con HAL)
3.1 Configuración en CubeMX
- SPI: Modo Full-Duplex Master, NSS por software, Prescaler DIV8 (10.5 MHz con SYSCLK de 84 MHz), Polaridad baja (CPOL=0), Fase segundo flanco (CPHA=1) → modo 1, Tamaño de datos 16 bits, MSB primero.
- GPIO: PB0 como salida (CS).
3.2 Código de inicialización SPI
// spi.c
#include "spi.h"
SPI_HandleTypeDef hspi1;
void MX_SPI1_Init(void)
{
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
HAL_SPI_Init(&hspi1);
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(spiHandle->Instance == SPI1)
{
__HAL_RCC_SPI1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
}
- Controlador para AS5047P
4.1 Definición de registros
// as5047p.h
#define AS5047P_CMD_READ 0xFFFF
#define AS5047P_CLR_ERROR 0x0001
#define AS5047P_REG_AGC 0x3FFD
#define AS5047P_REG_MAG 0x3FFE
#define AS5047P_REG_ANGLE 0x3FFF
typedef struct {
uint16_t raw; // valor crudo (0–16383)
float grados; // ángulo en grados (0.0–359.9°)
uint16_t agc; // control automático de ganancia
uint16_t mag; // intensidad de campo magnético
uint8_t err; // bandera de error
} datos_codificador;
4.2 Funciones de lectura SPI
// as5047p.c
#include "as5047p.h"
#include "spi.h"
#include "gpio.h"
#define CS_BAJO() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET)
#define CS_ALTO() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET)
static uint16_t spi_intercambio(uint16_t dato)
{
uint16_t rx;
HAL_SPI_TransmitReceive(&hspi1, &dato, &rx, 1, HAL_MAX_DELAY);
return rx;
}
static uint16_t leer_registro(uint16_t dir)
{
uint16_t comando = (dir & 0x3FFF) | 0x4000;
CS_BAJO();
uint16_t valor = spi_intercambio(comando);
CS_ALTO();
return valor;
}
datos_codificador leer_angulo(void)
{
datos_codificador d = {0};
CS_BAJO();
uint16_t raw_data = spi_intercambio(AS5047P_CMD_READ);
CS_ALTO();
d.raw = (raw_data >> 2) & 0x3FFF;
d.grados = (d.raw * 360.0f) / 16384.0f;
uint16_t status = leer_registro(AS5047P_REG_ANGLE);
d.err = (status & 0x0002) ? 1 : 0;
d.agc = leer_registro(AS5047P_REG_AGC) & 0x00FF;
d.mag = leer_registro(AS5047P_REG_MAG) & 0x3FFF;
return d;
}
- Programa principal
// main.c
#include "main.h"
#include "spi.h"
#include "gpio.h"
#include "as5047p.h"
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI1_Init();
datos_codificador enc;
while (1)
{
enc = leer_angulo();
printf("Ángulo: %.2f° | Raw: %d | AGC: %d | Mag: %d | Error: %d\n",
enc.grados,
enc.raw,
enc.agc,
enc.mag,
enc.err);
// Ejemplo: control PID aquí
// control_motor(enc.grados);
HAL_Delay(50);
}
}
5.1 Manejo de errores
void verificar_errores(datos_codificador *d)
{
if(d->err)
{
CS_BAJO();
spi_intercambio(AS5047P_CLR_ERROR);
CS_ALTO();
HAL_SPI_DeInit(&hspi1);
MX_SPI1_Init();
Error_Handler();
}
if(d->mag < 100)
{
// Indicar pérdida de campo magnético
encender_led_error(1);
}
}
- Técnicas de optimización
6.1 Formato de datos devueltos
El AS5047P devuelve 16 bits:
Bits 15–2: valor de ángulo (14 bits)
Bit 1: error (S)
Bit 0: paridad (C)
6.2 Filtrado por software
#define TAM_FILTRO 5
static float buffer[TAM_FILTRO];
static uint8_t idx;
float angulo_filtrado(float nuevo)
{
buffer[idx] = nuevo;
idx = (idx + 1) % TAM_FILTRO;
float suma = 0;
for(uint8_t i = 0; i < TAM_FILTRO; i++)
suma += buffer[i];
return suma / TAM_FILTRO;
}
6.3 Manejo del cruce por cero
float angulo_continuo(float actual, float anterior)
{
float diff = actual - anterior;
if(diff > 180.0f)
return anterior + (diff - 360.0f);
else if(diff < -180.0f)
return anterior + (diff + 360.0f);
return actual;
}
- Rseultados de pruebas
| Parámetro |
Resultado |
| Periodo de lectura |
0.8 μs (SPI a 1.25 MHz) |
| Resolución angular |
0.022° (14 bits) |
| Precisión estática |
±0.1° |
| Respuesta dinámica a 1000 RPM |
< 1° de retardo |
| Rango de temperatura |
-40°C a +125°C |
- Aplicaciones típicas
8.1 Control FOC de motor
void control_posicion(float objetivo)
{
datos_codificador enc = leer_angulo();
float error = objetivo - enc.grados;
float salida = PID_actualizar(&pid, error);
fijar_velocidad_objetivo(salida);
}
8.2 Articulaciones de robot
void leer_articulaciones(float *angulos)
{
for(int i = 0; i < 6; i++)
{
seleccionar_articulacion(i);
datos_codificador d = leer_angulo();
angulos[i] = d.grados;
}
}
8.3 Extrusora de impresora 3D
void control_extrusora(float longitud_filamento)
{
float angulo_objetivo = (longitud_filamento / (3.1416f * 0.5f)) * 360.0f;
mover_a_angulo(angulo_objetivo);
}
- Solución de problemas comunes
| Síntoma |
Causa posible |
Solución |
| Datos siempre cero |
CS no activo |
Verificar GPIO y nivel |
| Saltos aleatorios en datos |
Fase de reloj incorrecta |
Probar modo 0 o modo 3 |
| Ángulo no se actualiza |
Imán muy lejano |
Ajustar entrehierro a 0.5–1 mm |
| Lecturas aómalas a alta temperatura |
Alimentación ruidosa |
Mejorar filtrado de alimentación |
| Timeouts de comunicación |
Reloj SPI demasiado rápido |
Reducir prescaler |