Hola vasco, mira, yo cada vez que tengo que utilizar algo en CCS que no conozco o bien algo no funciona como me gustaria me echo una pasadita por el
foro oficial de CCS (Sin animo de despreciar a todopic, por favor). Ahi seguramente alguien ha tenido la misma duda o bien una parecida, hay muchisimos ejemplos, y si realmente te parece que descubriste un bug, lo posteas y te responden si esto puede ser asi o si te has equivocado tu. Obviamente esta en el idioma anglosajón. Otra forma de descubrir como funciona CCS es agarrando MPLAB, tal como te lo ha dicho Fire. Otra forma es revisando la lista C/ASM (el archivo con el formato .lst) que genera el compilador junto al .hex. Es un archivo que puedes abrir en el mismo CCS y que contiene el ASM del programa para cada parte del mismo, verás primero el lenguaje en C en forma de comentario y luego las lineas de ASM que lo representa, es muy útil, sobre todo para optimización.
las directivas #separate y #inline no forman parte del programa en sí que se va a ejecutar en el PIC, sino que le indican al compilador como generar el .hex. Las funciones que tu escribes pueden compilarse en forma INLINE, es decir, dos o más funciones se ejecutan como una sola, solo se utiliza un nivel de stack, estas se ejecutan más rápido y si deben llamarse más de una vez durante el programa el compilador simplemente copia y pega el código de estas cuantas veces se necesite. Salta a la vista que aunque este método ahorra stack y tiempo, no hace lo mismo precisamente con la ROM.
La contraparte son las funciones separadas (Que se definen con la directiva #separate), que se ejecutan en niveles diferentes de stack, y por lo tanto se pueden lograr funciones más pesadas en código que si son inline, para que te des una idea, el código dentro de las interrupciones serían funciones #separate por defecto ya que el programa tiene que saltar hacia otro nivel de stack para ejecutarlas, una vez que termina de ejecutarse la interrupción, el contador del programa vuelve el mismo hacia la función donde estaba y sigue ejecutandose con normalidad.
Ahora bien, te preguntarás ¿Porque a mi CCS nunca jamas me pidio definir como se compilan las funciones? ¿Porque habria de interesarme si yo escribo solo las funciones y el código se compila correctamente? ¿Entonces el código se compila siempre inline, o siempre separate?
. Bueno, en realidad, por defecto, el compilador lo hace automáticamente, es decir, lo decide por él mismo. Supongamos dos funciones:
void Inicio() {
// Codigo.
}
void Main() {
Inicio();
// Sigue el codigo.
}
Si no incluimos en la linea anterior a la declaración de la función Inicio ni #separate ni #inline, el compilador se hace cargo de definir si la función será inline o separada, y como lo hace?, bueno, el algoritmo que decide esto lo desconozco, pero sé por experiencia que se rige bajo ciertas reglas básicas: Si la función Inicio solo se llama una vez durante todo el código es probable que el compilador decida hacerla inline, porque siendo separate no se hace más que desperdiciar tiempo y no se ahorra memoria.
Si la función se llama X veces durante el código, entonces es más factible que el compilador la defina separada, porque de lo contrario hay que utilizar aproximadamente X veces más ROM que la que necesita Inicio(), pues el compilador no hace más que repetir en memoria el código original.
En forma explícita, nosotros podemos indicarle si queremos compilar las funciones como inline (colocando #inline antes de la declaración de la función) o como separada (colocando #separate antes de la declaración de la función), con todos los riesgos que esto supone. Cuando yo definí una de las funciones en tu código como #separate, lo hice sabiendo que el compilador la estaba poniendo inline al procedimiento main y que ambas dos sumadas consumian una cantidad de ROM que te estaba desbordando la capacidad del PIC (Me di cuenta muy rapido mirando el call tree). Colocandola separadas, tendrías mucho mas margen antes de obtener el error al generar el .hex.
Entonces, porque ahora quitas el #separate y el programa sigue funcionando bien?, bueno, eso es porque has optimizado el código lo suficiente como para que ambas funciones sean inline y aun ási te sobre ROM. Dado el caso, entonces no hay razón alguna para dejarla #separate, quita esta directiva y ahorraras un nivel de pila.
Ojo con implementar los #separate por solo el gusto de utilizarlos cada vez que nos falta ROM. El compilador te va a separar las funciones por mas que no tengas stack para hacerlo, eso lo aclara CCS en una parte de su manual. Primero optimiza y si no queda más remedio ahi usas el #separate.
Sigo en otro post el tema de los archivo header. No me tardo.