Conceptos Esenciales de Programación en C: Parámetros, Almacenamiento y Gestión de Interrupciones

Clasificado en Informática

Escrito el en español con un tamaño de 9,09 KB

Paso de Parámetros a Funciones en C

El paso de parámetros a funciones en C es fundamental para la comunicación entre diferentes partes de un programa. Existen dos mecanismos principales:

  • Paso por Valor

    En el paso por valor, se crea una copia de los valores de los parámetros en la pila de la función. Esto significa que cualquier modificación realizada a los parámetros dentro de la función no afectará a las variables originales fuera de ella. Las funciones solo pueden devolver un resultado simple a través de la instrucción return.

    int doble(int dato) {
      int resultado;
      resultado = 2 * dato;
      return resultado;
    }
    
    void main() {
      int x, y;
      x = 3;
      y = doble(x); // 'y' será 6, 'x' sigue siendo 3
    }
  • Paso por Dirección o Referencia

    En el paso por dirección (o referencia), se utilizan punteros para acceder y modificar directamente las variables originales que se encuentran fuera del ámbito de la función. Esto permite que la función altere el valor de las variables pasadas como argumento.

    void duplicar(int* pDato) {
      *pDato = *pDato * 2;
    }
    
    void main() {
      int x;
      x = 3;
      duplicar(&x); // Se pasa la dirección de 'x'. Tras esta sentencia, 'x' tendrá el valor 6.
    }

Clases de Almacenamiento en C

En C, las clases de almacenamiento determinan el ámbito, la duración y la ubicación de las variables en la memoria. Las principales clases son:

  • extern

    Se utiliza para declarar una variable global que ha sido definida en otro módulo fuente. Permite que una variable sea accesible desde múltiples archivos de código fuente, promoviendo la compartición de datos entre módulos.

  • static

    El modificador static tiene diferentes comportamientos según el contexto:

    • Si es una variable global, su ámbito se restringe al módulo fuente donde está definida. Solo puede accederse desde instrucciones dentro de ese mismo archivo.
    • Si es una variable local a una función, solo es visible dentro de esa función. Sin embargo, a diferencia de las variables locales automáticas, tiene almacenamiento estático, lo que significa que no se destruye al finalizar la función y mantiene su valor entre llamadas sucesivas a la función. Por defecto, las variables estáticas se inicializan a 0.
  • register

    Se sugiere al compilador que almacene la variable en un registro de la CPU en lugar de la memoria principal. Esto puede acelerar significativamente las operaciones de lectura y escritura, ya que el acceso a los registros es mucho más rápido. Es una sugerencia, y el compilador puede ignorarla si no hay registros disponibles o si considera que no es óptimo.

  • volatile

    Indica al compilador que el valor de la variable puede ser modificado por causas ajenas al programa (por ejemplo, por hardware, interrupciones o hilos concurrentes). Esto evita que el compilador realice optimizaciones que podrían asumir que el valor de la variable no cambia entre accesos, asegurando que cada lectura de la variable se realice directamente desde la memoria.

Comunicaciones: Interrupción vs. Consulta (Polling)

Existen dos enfoques principales para gestionar la comunicación con periféricos o eventos externos en un microcontrolador:

  • Comunicación por Consulta (Polling)

    En el modelo de consulta (o polling), el microcontrolador debe verificar repetidamente el estado de un periférico o un "flag" para determinar si un evento ha ocurrido (por ejemplo, si un byte ha sido enviado o recibido). Esto implica que, cada vez que se quiera enviar un byte, el microcontrolador debe esperar a que el envío anterior finalice. De manera similar, para recibir un byte, debe consultar constantemente un indicador de llegada, bloqueando el programa en esta comprobación y sin poder realizar otras tareas. Estas esperas activas conllevan una pérdida de tiempo significativa, durante la cual el microcontrolador podría estar ejecutando otras operaciones útiles.

  • Comunicación por Interrupción

    La programación de comunicaciones mediante interrupciones ofrece una alternativa más eficiente. Permite iniciar el envío de un byte en cualquier momento y, acto seguido, el microcontrolador puede continuar realizando otras tareas. Cuando el periférico está listo para el siguiente envío o ha recibido un byte, genera una interrupción. Esta señal detiene temporalmente la ejecución del programa principal y transfiere el control a una rutina de atención a la interrupción (ISR) específica. Solo entonces se ejecuta el código necesario para atender el evento (enviar el siguiente byte o procesar el recibido), y una vez finalizada la ISR, el programa principal reanuda su ejecución desde donde se quedó. Esto optimiza el uso del tiempo del microcontrolador, permitiendo la ejecución concurrente de tareas.

Orden de Bytes en Memoria: Big-Endian y Little-Endian

Cuando un tipo de variable (como un entero de 16 o 32 bits) requiere más de un byte para su almacenamiento en memoria, es crucial definir cómo se organizarán estos bytes. Los diferentes bytes que componen la variable se almacenarán en posiciones consecutivas de la memoria, y a la variable se le asignará la dirección del primer byte.

Existen dos esquemas principales para esta organización:

  • Little-Endian

    En la organización Little-Endian, el primer byte (la dirección de memoria más baja) almacena el byte menos significativo (LSB) de la variable completa, y los bytes subsiguientes almacenan los bytes de mayor significancia, hasta que el último byte (la dirección de memoria más alta) contiene el byte más significativo (MSB).

  • Big-Endian

    Por el contrario, en la organización Big-Endian, el primer byte (la dirección de memoria más baja) almacena el byte más significativo (MSB) de la variable, y los bytes subsiguientes almacenan los bytes de menor significancia, hasta que el último byte (la dirección de memoria más alta) contiene el byte menos significativo (LSB).

Uso de overlay en Compiladores (MPLAB C18 para PIC)

El modificador overlay, específico de algunos compiladores como MPLAB C18 para microcontroladores PIC, se utiliza para indicar al compilador que comparta la misma región de memoria para almacenar variables declaradas con este modificador. Esta técnica es una forma de optimización del uso de memoria, lo cual es particularmente crítico y necesario en arquitecturas con recursos de memoria muy limitados, como los microcontroladores.

Las variables declaradas con el modificador overlay tendrán un almacenamiento estático, lo que significa que su espacio en memoria se asigna una vez y persiste durante toda la ejecución del programa, pero ese espacio puede ser reutilizado por otras variables overlay en diferentes momentos de la ejecución, siempre y cuando no se necesiten simultáneamente.

Prioridad de Rutinas de Interrupción en C (Ejemplo PIC18F452)

En microcontroladores como el PIC18F452, se implementan sistemas de interrupción con diferentes niveles de prioridad para gestionar eficientemente múltiples eventos asíncronos. Específicamente, existen dos tipos de interrupciones:

  • Interrupciones de Alta Prioridad

    Cuando ocurre una interrupción de alta prioridad, el control del programa se traslada automáticamente a la dirección de memoria de programa 0x0008.

  • Interrupciones de Baja Prioridad

    Si se produce una interrupción de baja prioridad, el control se transfiere a la dirección de memoria de programa 0x0018.

Para gestionar estas interrupciones de manera organizada, se utiliza la directiva de compilación #pragma code. Esta directiva permite crear una nueva sección de código y especificar la dirección física exacta en la memoria de programa donde se desea almacenar ese código. De esta forma, es posible insertar un pequeño fragmento de código (un "salto" o jump) en las direcciones a las que el microcontrolador salta automáticamente al producirse una interrupción. Este código de salto, a su vez, redirige la ejecución a la rutina de atención a la interrupción (ISR) específica y más extensa que manejará el evento particular.

Entradas relacionadas: