Volver al inicio

Preguntas de C para Microcontroladores

El artículo contiene preguntas clave sobre programación en C para microcontroladores, sistemas de construcción, interrupciones y RTOS. La selección se basa en entrevistas reales para especialistas de nivel medio/senior. Ejemplos de código y explicaciones de terminología.

C para Microcontroladores: 60+ Preguntas Clave
Advertisement 728x90

Esenciales de C embebido: Preguntas clave de programación de microcontroladores

Los programadores de microcontroladores deben dominar las particularidades del lenguaje C bajo restricciones estrictas de recursos. A continuación, una lista curada de preguntas prácticas centradas en compilación, memoria y optimización. Estos temas surgen con frecuencia en entrevistas de empresas de sistemas embebidos.

Palabras clave principales y su uso

Static limita la visibilidad de una variable al archivo o función actual, preservando valores entre llamadas para estáticos locales. Volatile impide que el compilador optimice variables modificadas externamente (registros, memoria, interrupciones).

Ejemplo de código problemático:

Google AdInline article slot
int square(volatile int *ptr) {
    return *ptr * *ptr;
}

Aquí, volatile solo aplica al primer desreferenciamiento; el segundo podría optimizarse. Solución: (ptr) (*ptr).

Const volatile es útil para datos externos de solo lectura como registros de estado. Register sugiere almacenar una variable en un registro de CPU (deprecado en C11). Restrict indica al compilador que los punteros no se solapan, permitiendo vectorización.

Gestión de memoria y estructuras

Las variables globales const van en memoria Flash. Para un array constante de 32 KB lleno de 0xFF, usa una sección en el script del enlazador con fill(0xFF).

Google AdInline article slot

Operaciones con bits: verifica bit con n & (1 << k), limpia con n & ~(1 << k). Comparación de flotantes: fabs(a - b) < EPSILON.

El tamaño de estructuras depende del alineamiento.

struct Foo {
    int iiii;
    char c;
};

el tamaño es 8 bytes (4 bytes de relleno). Empaquetado en GCC: __attribute__((packed)).

Google AdInline article slot

Ejemplos de declaración de cadenas:

char str5[]={'s','t','r','i','n','g'};  // tamaño:7 long:6
char *str1="string";                    // tamaño:4 long:6 (puntero)
char str3[]="string";                   // tamaño:7 long:6
char str4[10]="string";                 // tamaño:10 long:6

Sistemas de construcción y cadenas de herramientas

Los sistemas de construcción automatizan la compilación, enlace y dependencias. Make maneja cambios en archivos, mientras que Ninja es más rápido gracias al paralelismo y simplicidad.

VPATH en GNU Make busca fuentes en directorios especificados.

Pipeline de código: .c → .i (preprocesador) → .s (ensamblador) → .o → .elf → .bin/.hex.

Desactivar advertencia de GCC: #pragma GCC diagnostic ignored "-Wrestrict".

Reducir firmware: -ffunction-sections -fdata-sections, ld --gc-sections y optimización -Os.

Artefactos de construcción

  • .o — archivos objeto
  • .elf — ejecutable con símbolos
  • .hex/.bin — para flashear (hex incluye direcciones)

Binutils: objdump (desensamblador), objcopy (convertidor), readelf (analizador ELF).

Verificar construcción: make V=1 o -n (ejecución en seco).

Estructuras de datos y algoritmos

Buffer circular — array en anillo con índices cabeza/cola, a diferencia de FIFO que desplaza elementos.

Eliminación en lista enlazada: prev->next = node->next (necesita prev) o node->next->prev = node->prev (doble enlace).

Polimorfismo en C: punteros a funciones en structs (estilo vtable).

Tarea sin if/switch:

void print_num(int n) {
    const char *nums[] = {"","Uno","Dos"};
    printf("%s", nums[n]);
}

do-while(0) para macros — una iteración con múltiples sentencias.

Interrupciones y RTOS

Interrupción — mecanismo hardware que salta a un ISR ante un evento. La tabla de vectores contiene direcciones de ISR. Cortex-M4: 12–16 ciclos para entrada (guardado de contexto).

Flujo: hardware guarda PC/LR, carga vector, salta a ISR, retorna vía POP.

Función reentrante — segura para llamadas concurrentes (sin estáticos/locales sin sincronización).

En RTOS:

  • Thread — unidad de ejecución con su propio stack
  • Mutex — exclusión mutua
  • Semaphore — contador de eventos
  • Spinlock — bloqueo busy-wait

Problema de código: interbloqueo por orden de bloqueos (TareaA: ma→mb, TareaB: mb→mc→ma).

Inversión de prioridad: tarea de alta prioridad espera a baja. Solución: herencia de prioridad.

Operaciones atómicas

Ejemplo: __atomic_exchange_n(&x, &y, __ATOMIC_SEQ_CST).

Bit-banding — acceso directo a bits sin máscaras (Cortex-M3/4).

Cadena de herramientas y depuración

ABI — interfaz binaria (convención de llamada).

Segmentos: .text (código Flash), .data (RAM inicializada), .bss (RAM ceros), .rodata (constantes Flash).

Expandir preprocesador: gcc -E file.c > expanded.i.

Documentos clave: hoja de datos, manual de referencia, manual de programación, esquemáticos.

Lecciones clave

  • Volatile es esencial para registros periféricos
  • Estructuras empaquetadas ahorran RAM pero ralentizan acceso
  • RTOS requiere código seguro para hilos y protección de secciones críticas
  • Optimización de construcción: secciones + gc-sections
  • Interrupciones usan el stack del hilo actual

Para relleno 0xFF en structs: script del enlazador con fill o __attribute__((packed)) + relleno manual.

— Editorial Team

Advertisement 728x90

Leer después