La generación y cálculo de tablas de búsqueda (LUT) para funciones trigonométricas implica varios pasos clave:
- Definición de la resolución (tamaño de la tabla)
- Para un número de micropasos deseado N, el tamaño típico de la tabla es N (aunque puede ser N+1 para facilitar la conexión circular).
- Por ejemplo, si se requieren 256 micropasos, se define
TABLE_SIZE = 256.
- Cálculo del incremento angular
El paso angular entre elementos de la tabla se determina con:
[ \Delta\theta = \frac{2\pi}{\text{TABLE_SIZE}} ]
- Cálculo de valores de seno y coseno en punto flotante
Para cada índice \(i = 0,1,\dots,\text{TABLE_SIZE}-1\), se calcula:
[ \theta_i = i \times \Delta\theta, \quad \text{sinTbl}[i] = \sin(\theta_i), \quad \text{cosTbl}[i] = \cos(\theta_i). ]
Ejemplo en pseudocódigo:
for (int i = 0; i < TABLE_SIZE; i++) {
float angle = 2.0f * M_PI * i / TABLE_SIZE;
sinTbl[i] = sinf(angle);
cosTbl[i] = cosf(angle);
}
- Conversión a valores de ciclo útil (duty cycle) para PWM
En microcontroladores, los ciclos útiles son enteros; por lo tanto, se mapea el rango −1 a +1 al intervalo 0 a PWM_MAX:
[ \text{CCR_value} = \bigl(\text{wave} + 1.0\bigr)\times \frac{\text{PWM_MAX}}{2} ]
Donde:
waverepresenta los valores desinTbl[i]ocosTbl[i];PWM_MAXes el valor de carga automática del temporizador (ARR), como 1000, 4095 o 65535.
uint16_t duty = (uint16_t)((sinTbl[i] + 1.0f) * 0.5f * PWM_MAX);
- Optimización de tipo de datos y almacenamiento
- Tabla en punto flotante: Si el MCU soporta operaciones en punto flotante, se pueden almacenar directamente como
float. - Tabla en punto fijo: Para ahorrar memoria flash, se multiplica cada valor por un factor fijo (por ejemplo, 32767) y se guarda como
int16_t:
[ \text{sinQ}[i] = \text{round}\bigl(\sin(\theta_i)\times 32767\bigr) ]
Posteriormente, durante la ejecución, se convierte mediante desplazamiento o multiplicación al ciclo útil.
- Conexión circular y interpolación
- La primera y última entrada suelen representar el mismo ángulo (0° o 360°), por lo que se puede almacenar solo una copia de las primeras N entradas.
- Para mayor precisión, se puede aplicar interpolación lineal en tiempo de ejecución, aunque en la mayoría de casos basta con acceso directo a la tabla.
- Ejemplo completo
// Declaración global o estática
#define TABLE_SIZE 256
#define PWM_MAX 4095
int16_t sinTblQ[TABLE_SIZE];
int16_t cosTblQ[TABLE_SIZE];
// Inicialización de la tabla de búsqueda
void InitLUT(void) {
for (int i = 0; i < TABLE_SIZE; i++) {
float angle = 2.0f * M_PI * i / TABLE_SIZE;
sinTblQ[i] = (int16_t)(sinf(angle) * 32767);
cosTblQ[i] = (int16_t)(cosf(angle) * 32767);
}
}
// Función para obtener el ciclo útil
uint16_t GetPWMDuty(int idx, int16_t *tblQ) {
return (uint16_t)(( (tblQ[idx] + 32767) / 65535.0f ) * PWM_MAX);
}
// Uso en salida:
uint16_t dutyA = GetPWMDuty(idx, sinTblQ); // Ciclo útil para fase A
uint16_t dutyB = GetPWMDuty(idx, cosTblQ); // Ciclo útil para fase B
Estos valores se escriben en los registros de comparación de los temporizadores (CCR) para controlar los puentes H del driver A4950, generando un vector de campo magnético correspondiente al ángulo θ = idx×(2π/TABLE_SIZE).
De esta forma, se puede generar dinámicamente una tabla de seno y coseno para cualquier nivel de细分 (microstepping) y mapearla a los ciclos útiles del temporizador para control preciso de motores paso a paso.
Recomendaciones prácticas
Selección de hardware:
- Utilizar temporizadores avanzados de STM32 (TIM1 o TIM8), que ofrecen:
- 4 salidas PWM independientes, o
- 2 salidas complementarias (útil para drivers con control de dead time).
- Capacidad suficiente para controlar los 4 puentes necesarios para un motor paso a paso bipolar.
Implementación de sfotware:
- Creación de la tabla de búsqueda
- Generar una tabla estándar de seno/coseno (punto flotante o punto fijo).
- Se puede usar una sola tabla con desplazamiento de fase para generar dos fases.
- Control de salida PWM
- Usar DMA o bucles de interrupción para escribir los ciclos útiles (
dutyA+,dutyA-,dutyB+,dutyB-) en los registros CCR del temporizador:``` TIMx->CCR1 = dutyA_plus; TIMx->CCR2 = dutyA_minus; TIMx->CCR3 = dutyB_plus; TIMx->CCR4 = dutyB_minus;
3. **Control del índice de paso**
- Actualizar el índice de forma sencilla para rotar la fase (ej. dirección de avance):```
idx = (idx ± 1) % TABLE_SIZE;
- El resto del proceso se maneja automáticamente mediante DMA, garantizando actualizaciones estables y eficientes.
Esta metodología permite implementar sistemas de control de motores paso a paso con alta precisión, gran细分 y bajo ruido, especialmente adecuados para aplicaciones de microstepping.