Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Ernesto Tolocka
www.mundomicro.com.ar
Introducción
Veremos en este artículo un ejemplo sencillo de cómo utilizar punteros a funciones instalando
un callback en la rutina de atención de interrupciones del Módulo Timebase de un GP32.
Punteros a funciones
Algunas personas afirman que existen dos tipos de lenguajes de programación: los que
permiten el uso de punteros y los que sirven para jugar a programar.
Sin ir hasta ese extremo, debemos coincidir en que la habilidad de manejar punteros es una de
las características del lenguaje C que lo hacen tan versátil y tan poderoso, sobre todo en las
aplicaciones con microcontroladores, y al mismo tiempo una de las fuentes de errores mas
comunes cuando no se manejan cuidadosamente.
Sin pretender dar una explicación exhaustiva sobre el tema de los punteros, diremos sólo que
son variables que no contienen directamente un valor (como puede ser una variable de tipo
char) si no que generalmente contienen la dirección donde vive otra variable. Se dice que un
puntero “apunta” a una variable. Esta otra variable puede ser de cualquier tipo: char, int, float,
hasta puede ser otro puntero.
Además de apuntar a variables, se puede hacer que un puntero apunte a una función. Un
puntero a una función contiene la dirección donde reside esa función y por su intermedio, esa
función puede ser llamada o invocada. Esto tiene muchas aplicaciones. Por ejemplo, se puede
tener un array de punteros a funciones y llamar a una función en particular en base a un valor
numérico que se utiliza como índice de dicho array, sin tener que apelar a una estructura de
tipo switch.
Callbacks
Un callback es un recurso muy utilizado por los desarrolladores de kernels, sistemas operativos
o librerías de uso específico que permite que el programador de aplicaciones realice un
llamado a una función de su propiedad cuando es ejecutada un función del kernel, sistema
operativo o librería. Es el equivalente de un “gancho” que se deja disponible en el sistema
asociado a una determinada función y que puede ser usado o no. Si queremos llamar a una
función de nuestra propiedad cuando se active la función del sistema, simplemente la
“enganchamos” a ella. El gancho es el callback.
Por ejemplo, si escribimos una librería para manejar el módulo SCI de un GP32, con funciones
para recibir y transmitir caracteres con un buffer, sería conveniente dejar disponible un callback
en la función que recibe un carácter para darle la posibilidad al usuario de nuestra librería de
llamar a una función suya cada vez que llega un carácter por el SCI.
Implementación
El siguiente es un ejemplo que aprovecha el módulo Timebase del GP32 para generar
interrupciones periódicas. El aspecto de la ISR es el siguiente:
(*TBMCallBack)();
}
Como puede verse, además de borrar el pedido de interrupción, se llama a la función apuntada
por la variable TBMCallBack, que es un puntero definido de la siguiente forma:
Este puntero inicialmente no está inicializado. Para que apunte a una función cualquiera,
simplemente debemos cargarle la dirección de dicha función, de la forma:
TBMCallBack=&MiFuncion;
En el programa que sigue a modo de ejemplo, se han definido dos funciones para controlar
esto. La primera, TBMInit, hace apuntar el Callback a una función dummy, es decir, que no
hace nada. Esto es por razones de seguridad, ya que una llamada a la ISR con el puntero sin
inicializar puede tener consecuencias impredecibles. Obviamente, esto también puede hacerse
directamente en la etapa de inicialización del código de la aplicación, sin necesidad de escribir
una función.
La otra, instala la función que nosotros deseamos llamar en el callback, por el mismo
procedimiento, esto es, cargando en el puntero su dirección:
TBMCallBack=mifuncion;
El resto de las funciones se emplean para controlar las funciones básicas del TBM, tales como
inicializarlo, prenderlo o apagarlo.
Código
//*****************************************************************//
#include "PE_Types.h"
#include "PE_Error.h"
#include "PE_Const.h"
#include "IOgp32.h"
#define TBON 2
#define TBIE 4 //Timebase Interrupt Enabled
#define TACK 8 //Ack del TBCR
(*TBMCallBack)();
}
TBMCallBack=&TBMDefault;
//Arranca el TBM
TBCR |= TBIE;
TBCR |= TBON; //Prende TBM
//Detiene el TBM
TBMCallBack=mifuncion;
}
void MiFuncion (void) {
PTA^=0x80;
//*********************************************************************************//
//*********************************************************************************//
Referencias