Está en la página 1de 22

1 de 22

Ultima actualizacin:
07/03/2007

Sistemas Operativos para


microcontroladores

RTOS
para

PIC

INTRODUCCIN:
Gracias a la labor del amigo Reinier Torres Labrada, del foro sobre
microcontroladores
TODOPIC,
ponemos
en
uControl
esta
Introduccin
a
los
Sistemas
Operativos
para
Microcontroladores.
Realmente, Reinier esta haciendo un muy buen trabajo con este
tema, y debido a que no hay demasiada informacin sobre RTOS para
PIC en espaol, es que vamos a ir recopilando en esta pagina sus post
sobre el tema. Como podrn ver, abundan los ejemplos, y sus
explicaciones son muy claras.

NDICE:
> Introduccin
> Presentacin de la gua
> Un poco de teora sobre los Sistemas Operativos (SO)
> Diferencias entre usar un SO o usar las libreras del compilador de turno
> Qu es un Sistema Operativo?
> Clasificacin de los SO
> Introduccin al RTOS de CCS
> Funciones del RTOS
> Controlando la ejecucin de las tareas
> Yield vs delay
> Coordinar para no daar
> En sus marcas, listos, FUERA!
> RTOS mail
> Datos de Contacto
> Bibliografa

> Presentacin de la gua:


Las siguientes son palabras de Reinier, presentando en el foro su idea de armar esta Introduccin a los
Sistemas Operativos para Microcontroladores:
"Hola amigos
He visto que en el hilo "RTOS para PIC GNU" ha aparecido una interesante controversia sobre los RTOS, sin
embargo lo que ms curioso me resulta es que muchos no conocen prcticamente nada sobre el tema, y como
aqu todos estamos para aprender y compartir lo poco que sabemos, quisiera comenzar por explicar algunos de
los principios bsicos de los SO y como podemos aplicarlos al campo de los microcontroladores.
Espero que esta nueva idea sea de utilidad y despierte el inters en muchos de ustedes. Yo soy muy nuevo en
este campo de los SO y los microcontroladores, pero con la ayuda de ustedes podremos hacer muchas cosas
interesantes y beneficiosas para todos.
De hecho todava no he comenzado a utilizar ningn RTOS o algo parecido para meter en un PIC, ni siquiera
me he metido con el cdigo de ningn SO, pero en la maestra que estoy cursando tengo los SO (desde la
ptica del diseo) como asignatura obligada y no quisiera que despus de un montn de horas delante de un
profesor que produce ms sueo que inters por su asignatura (aunque el tema es interesantsimo), todo ese
conocimiento se quedara en la nota al final del semestre.
Bueno amigos... sin ms muela (prembulo) comencemos a trabajar"
[Volver al ndice]

> Un poco de teora sobre los Sistemas Operativos (SO)


Haciendo un poco de historia, y los ms aejaditos lo saben mejor que yo que soy un nio de 26, los SO
aparecieron ms o menos por all por los 60.
Lo que ocurri por aquel entonces, cuando las computadoras, eran tan poderosas como nuestros PICs
(algunos de gama alta son hasta ms poderosos que aquellas computadoras), era que muchos programadores
(matemticos locos la mayora), no estaban interesados en conocer los detalles de las interfaces, controladores

2 de 22

(matemticos locos la mayora), no estaban interesados en conocer los detalles de las interfaces, controladores
y dems cacharros electrnicos que adornan a una computadora, y por otro lado algunos programadores ya
haban escrito controladores para esos dispositivos y por tanto los que venan detrs simplemente queran
utilizarlos y ya (algo parecido a lo que hacemos en el foro).
Pues bien, con el tiempo se acumularon programas tiles para manejar dispositivos y tareas complejas que
deban programar personas no interesadas en la electrnica, entonces la gente, que trabajaba en equipo,
organiz todo aquello de manera que los programadores, los programas y el hardware (HW) pudieran coexistir
sin que se produjera una guerra hubiteana (guerra en la que los hombres y los bits se pelean hasta que los
hombres se mueren de alguna clase de infarto o pierden a la mujer). Surgieron as los primeros intentos de
crear un SO y los hombres mantuvieron la Paz sobre la tierra y tambin la guerra fra, aunque las cosas se
calentaran a intervalos.
Pas el tiempo y lleg Bill Gates con DOS y luego Windows y Steve Jobs con su Mac, unos tipos ms listos y
cabrones que ingenieros o programadores. y despus tambin apareci Linus Torvalds con Linux, uno que
estaba ms loco que El Quijote y entonces las personas corrientes creyeron que en el mundo solo existen a lo
sumo tres SO (Windows, Mac, y Linux), pero no es as hay un montn de SO, algunos muy poderosos y otros
no tanto, dependiendo de en que lugar y para que se hayan diseado.
Como es lgico suponer, en la parte de la historia que les acabo de contar est el por qu los SO son tiles,
pero eso lo iremos viendo poco a poco porque hay muchas formas en las que un SO nos puede servir. Vamos a
ver algunas:
1) Un SO convierte a las computadoras en equipos tiles.
Pone una o varias capas de Software (SW) sobre el HW, y con eso podemos escribir programas y utilizar
programas ya escritos por otros para hacer otros programas escritos por nosotros mismos, sin tener que
meternos en detalles tales como bueno ahora mi procesador de textos ya trabaja y como guardo el
documento?. Seguramente si usted le dice al programador del procesador de texto que para guardar el
documento tiene que tirarse meses escribiendo las rutinas que guardan el doc. seguramente le da un ataque.
2) Un SO es una herramienta poderosa en la gestin de procesos.
Nosotros mismos cuando programamos los PICs tenemos que leer el puerto serie, escribir en una LCD,
controlar el motor y todas esas cosas las hacemos a la vez. Pero cada una de esas tareas podemos
considerarla un proceso, y un SO puede ayudarnos a gestionarlos eficientemente, aprovechando al mximo el
procesador. Por ejemplo en vez de poner al PIC a esperara a que el motor se mueva un poco poniendo una
demora, podemos utilizar ese tiempo en ir escribiendo un poco en la LCD y despus volver a donde nos
quedamos con el motor.
3) Un SO nos ayuda a disear ms rpido sistemas mas complejos.
Imagnense ahora una aplicacin donde tengamos que hacer clculos, encender y apagar cosas, comunicarnos
con otros dispositivos y otras tareas ms, y que adems tengamos que hacerlo rpido y trabajando con otras
personas. Entonces el concepto de divide y vencers nos pude ser til y un SO es el arma que podemos utilizar
para derrotar a nuestros enemigos: el tiempo y la complejidad. Pues s nos auxiliamos del SO para dividir y
gestionar los procesos, y con ello no eliminamos la complejidad pero le damos una vuelta elegante, y no
matamos al tiempo pero le damos menos oportunidad de que sea l el que nos mate y si no que el jefe nos
bote.
4) Un SO nos puede ayudar a hacer sistemas ms estables.
Ahora tenemos unas rutinas que demoran cierto tiempo en hacer unos clculos y como somos listos, hemos
activado el WatchDog (WD) para que si la cosa se cuelga en el campo se reinicie el sistema. Pero que pasa si
la rutina demora ms de lo debido y el WatchDog nos reinicia sin que haya ningn problema real?. Otra vez la
gestin de recursos nos puede ayudar en eso, ya que si nuestra tarea demora ms de lo debido el SO puede
quitarle el procesador para atender al WatchDog y darle el procesador a otra tarea que tambin lo necesita por
algn tiempo. Este caso tambin sirve cuando an sin el WD ponemos una llamada a una funcin que se queda
esperando indefinidamente por que ocurra algo que no ocurre y el cdigo que le sigue no se ejecuta en los
tiempos establecidos.
Bueno amigos, hasta aqu hemos visto algunas de las cosas en que puede ayudarnos un SO, y sera
maravilloso poder contar con esas herramientas para programar nuestros PIC. Ms adelante seguiremos
aprendiendo un poco sobre la teora de los SO, para despus meterle el cuerpo a los programas.
Hay algunos libros interesantes sobre los SO, les recomiendo uno que puede ayudarles mucho en esta primera
parte: Sistemas Operativos Diseo e Implementacin. Andrew S. Tanenbaum.
[Volver al ndice]

> Diferencias entre usar un SO o usar las libreras del compilador de turno.
Nocturno, un integrante del foro, le plantea a Reinier la siguiente pregunta, que es aprovechada para avanzar
en la explicacin de los SO:

3 de 22

en la explicacin de los SO:


"Por lo que leo en el captulo 1 de tu artculo, no veo diferencias entre usar un SO o usar las libreras del
lenguaje que ests utilizando en cada momento. No me cabe duda que un SO tendr muchas ms aportaciones
que las libreras, pero cul es la principal ventaja que los diferencia?"
Desde el punto de vista de la programacin no ests haciendo otra cosa que utilizar las libreras del lenguaje u
otras creadas por t o por un buen amigo que te las haya cedido. De hecho si revisamos, por ejemplo, el RTOS
de CCS y las funciones que brinda el lenguaje para desarrollar aplicaciones utilizando esta potencialidad del
lenguaje, nos damos cuenta, que por ejemplo, la directiva #use RTOS lo que hace es indicarle al compilador
que ponga en el programa final, creado por el compilador, el cdigo del dispatcher (luego vamos a ver que es)
del RTOS, y luego nos ofrece unas funciones de librera como por ejemplo RTOS_WAIT( ), RTOS_ENABLE( ),
RTOS_RUN( ), etc, que nos ayudan a gestionar nuestras tareas (tambin veremos el concepto y la
implementacin en el futuro). Bien hasta ahora nada nuevo, ninguna ventaja, y una desventaja: consumo de
memoria de programa para el dispatcher y complicaciones de la vida del programador.
Sin embargo la ventaja del SO radica en que le permite al programador contar con una herramienta para
gestionar varias cosas fundamentales en el sistema: el procesador, la memoria, y los perifricos, en nuestro
caso eso sera todo nuestro flamante PIC. De todos ellos el ms importante es el procesador, ya que es quin
hace la mayor parte del trabajo, el objetivo de nuestro SO es mantener ocupado al procesador con trabajo til,
por ejemplo una demora por SW es hacer trabajar al procesador con trabajo intil y ese tiempo que se la pasa
saltando de aqu para all lo podemos utilizar en hacer otras cosas y la memoria de programas tambin,
despus veremos como hacer eso.
Supongamos ahora que estamos atendiendo un teclado, que no est conectado a ninguna fuente de
interrupcin, no queda ms remedio que encuestar a nuestro teclado para saber si han oprimido o soltado una
tecla, si es as, entonces tenemos que hacernos cargo de los rebotes, etc. Hay muchas formas de hacer eso,
una de ellas sera:
1-Espera que se oprima o suelte una tecla
2-Espera un tiempo a que termine el rebote
3-Lee el teclado
4-Procesa la tecla
5-Hacer algo con el cdigo del teclado
6-Regresa al punto 1
Pero una forma sencilla utilizando un SO tendra la siguiente forma:
1-Espera que se oprima o suelte una tecla
2-Me dormir hasta que termine el rebote
3-Lee el teclado
4-Procesa la tecla
5-Manda un mensaje (el cdigo del teclado) a la funcin adecuada
6-Regresa al punto 1.
Ahora vemos que la cosa cambi ligeramente porque le hemos dicho a alguien, me voy a dormir un tiempo,
despirtame cuando pase ese tiempo, y cuando tengo el dato o cdigo de la tecla, le mando un mensaje a
alguien (una funcin), no llamo directamente a la funcin, pongo el dato en algn lugar e indico que hay un
dato, es asunto de ese alguien tomarlo, procesarlo y notificarlo. Esas dos acciones las hago sirvindome del SO
y le dejo a l el problema de despertarme, y poner el mensaje donde corresponde, sin embargo en este
problema el SO puede hacer algo ms que en principio no est bajo nuestro control.
Como vemos nuestro programa se queda siempre haciendo lo mismo en un lazo infinito, entonces podemos
decirle al SO: "Oye, este cdigo debe ejecutarse todo en tal tiempo". Entonces, cuando se cumpla el plazo
establecido, el SO le quita el procesador a ese que se lo quiere coger todo para l solo y se lo da a otra funcin
que hace algo parecido o para que se atienda una interrupcin, etc. cuando todo el mundo haya recibido su
poco de tiempo de procesador, le dice a la funcin que atiende el teclado: toma el procesador por el tiempo
que te corresponde y as todo el mundo puede tener el procesador para el solo durante un tiempo, es decir
ponemos a un vigilante a que reparta equitativamente el tiempo del procesador.
Hasta aqu hemos visto algunas de las ventajas, ms adelante veremos muchas ms, sin embargo todava no
hemos terminado con la introduccin terica a los SO, pero para los ms aventajados esto puede aclarar
algunas de sus dudas. Yo se que cosas como esta se pueden hacer blandiendo interrupciones a derecha e
izquierda, y con otras tcnicas, pero como veremos ms adelante los SO nos ayudan en otras cosas, mientras
aprovechamos al mximo nuestros preciados recursos del PIC.
[Volver al ndice]

> Qu es un Sistema Operativo?


Segn Tanenbaum, una de las personalidades ms reconocidas en el mundo acadmico de los SO, no es fcil

4 de 22

Segn Tanenbaum, una de las personalidades ms reconocidas en el mundo acadmico de los SO, no es fcil
dar una definicin definitiva de lo que es un SO. El problema consiste en que los SO tienen la caracterstica de
comportarse para el usuario (que puede ser una persona cualquiera, un programador, o un programa de
computadora), como un tipo con "doble personalidad".
Veamos esto con ms detenimiento:
1) El SO como mquina extendida:
En esta faceta de la personalidad del SO, la caracterstica destacable es simplificar al programador los detalles
del funcionamiento de los dispositivos conectados al sistema.
Esta caracterstica se pone tambin de manifiesto en aplicaciones donde no se usan los SO, un ejemplo tpico
son las funciones output_x() e input_x() del compilador CCS. Un programador puede utilizar estas funciones
sin conocer que para que los datos se pongan en los pines o se lean, hay que cambiar varios registros en el
uC. Se dice que estas funciones son una abstraccin del proceso de E/S en puerto. Esto es bueno porque
ayuda a los programadores a desarrollar soluciones ms rpidamente y con menor probabilidad de errores ya
que si la funcin est bien escrita es poco probable que falle.
La funcin de la mquina extendida es ofrecer al programador una "interfaz" gracias a la cual se utilizan los
recursos del sistema, sin tener que profundizar demasiado en los detalles del funcionamiento de sus diferentes
componentes. Esta interfaz que el SO ofrece al programador o el usuario, se conoce comnmente como
Llamadas al Sistema o API (Aplication Programmer Interface).
Sin embargo esta visin de los sistemas operativos es poco aplicable a nuestro entorno, en el sentido en que
hoy se clasifican a las llamadas al sistema, ya que en nuestro mundo todo es pequeo en cuanto a capacidad y
el crear una mquina extendida poderosa consume recursos que usualmente no tendremos. Entonces en este
caso la mquina extendida queda limitada a algunas llamadas a funciones del SO y al uso de las libreras que
hasta el momento hemos utilizado habitualmente.
2) El SO como administrador de recursos:
En este caso el SO, se comporta como un administrador de nuestros recursos. La ventaja de tener alguien que
administre eficientemente los recursos consiste en que el SO ofrezca al usuario un conjunto de reglas para
compartir y hacer uso de los recursos disponibles con eficacia y eficiencia.
Un ejemplo de administracin de los recursos es el uso de la CPU, en un sistema sin SO, el programador tiene
que estar muy pendiente de la implementacin de su sistema, porque puede que determinados requisitos
temporales en la ejecucin de algunas funciones tengan que cumplirse.
En nuestro caso lo usual es que nos rompamos el coco manipulando interrupciones, poniendo demoras,
cambiando contadores y chequeando banderas Uf solo de pensarlo me dan ganas de llorar! Sin embargo un
SO puede hacerse cargo de todos esos temas de manera eficaz y eficiente, incluso ahorrando memoria y
tiempo, y nosotros los programadores concentrarnos en la implementacin de la solucin, ms que en la
gestin eficiente de nuestros recursos.
Por supuesto que el SO no es mago ni adivino, para ello debe ofrecernos un conjunto de mecanismos,
relativamente sencillos, que nos ayuden a "indicarle" o "pedirle" que es lo que queremos hacer.
En el caso de los uC, las implementaciones de los SO, se caracterizan por potenciar la administracin de
recursos del SO, por lo que es esta la faceta de personalidad que ms a menudo encontraremos en los RTOS.
[Volver al ndice]

> Clasificacin de los SO.:


A continuacin veremos como se clasifican los SO en cuanto a dos caractersticas esenciales: la administracin
del recurso fundamental (el procesador) y el destino del SO.
Los SO se pueden clasificar de distintas maneras, pero para abreviar lo ms posible, solamente me voy a
referir a las ya mencionadas.
En cuanto a la administracin del procesador existen dos clasificaciones:
1) SO cooperativo (no preemptive):
En este caso es el programador quin tiene la responsabilidad de entregarle el procesador al ncleo del SO,
para que ste lo entregue a la prxima tarea que est solicitndolo o programada para ejecutarse. Es
entonces, muy importante, que las llamadas a funciones que ejecutemos nunca se queden esperando mucho
tiempo por determinados eventos, evitar los lazos infinitos y entregar el procesador cuando no lo necesitemos,
para que otra tarea o proceso pueda utilizarlo.
2) SO de tiempo compartido (preemptive):
En este caso el programador debe contar con los mismos mecanismos que en el anterior, pero el SO tiene la
facultad de quitarle el procesador y drselo a otro si usted se ha excedido en su tiempo o hay alguien que tiene

5 de 22

facultad de quitarle el procesador y drselo a otro si usted se ha excedido en su tiempo o hay alguien que tiene
mayor prioridad.
En cuanto al destino hay unas cuantas clasificaciones pero me voy a concentrar en los RTOS. Un RTOS
(Sistema Operativo de Tiempo Real) es un sistema operativo concebido para dispositivos pequeos como los
uC. Aunque el concepto de "tiempo real" es muy controversial, la idea es ejecutar determinadas tareas de
forma que parece que cada tarea se est ejecutando en un sistema independiente, donde el procesador y el
resto de los recursos son slo para ella.
Los RTOS pueden ser utilizados tambin para computadoras grandes, pero la idea sigue siendo la misma,
ejecutar las tareas cumpliendo estrictamente con los requisitos temporales de cada una, sin violaciones de
ninguna ndole. Otro caso de SO, son los de propsito general como UNIX, LINUX, Windows, en este caso a
diferencia de los RTOS, las tareas cambian de prioridades en funcin de satisfacer las exigencias de los
humanos que actan como usuarios, no importa si algunas cosas se ejecutan o no cumpliendo tiempos
estrictos.
En la prxima entrega ya tendremos cdigo para ejecutar y ver como funciona un RTOS.
[Volver al ndice]
> Introduccin al RTOS de CCS
Despus de teorizar un poco sobre los Sistemas Operativos, vamos a introducirnos en la programacin de
aplicaciones empleando un RTOS.
En nuestro caso, para comenzar, utilizaremos el RTOS que viene con el compilador de CCS. Las razones de mi
eleccin las expongo a continuacin:
-

Sencillez en la implementacin de aplicaciones.


El RTOS est integrado en el propio compilador de CCS.
Abundante experiencia en el foro con este compilador.
Gran cantidad de dispositivos soportados por el compilador de CCS.

La versin del compilador que tengo instalada en estos momentos es la 3.249, as que si en versiones
posteriores han aparecido nuevas caractersticas, les ruego que lo informen para tomar las debidas
providencias en el momento oportuno, y comenzar a utilizar esas nuevas caractersticas.
El RTOS de CCS es un Sistema Operativo de Tiempo Real que implementa la tcnica de multiprocesamiento
cooperativo (non preemptive), por lo que es responsabilidad del programador asegurarse de que el control del
procesador retorna al planificador de tareas en algn momento. As que cuando programemos nuestra
aplicacin, tenemos que asegurarnos de que no llamamos a una funcin que se queda esperando por algn
evento largo como es el caso de gets(), o dentro de un lazo infinito o demasiado extenso.
Planificador de tareas
Uno de los elementos fundamentales de cualquier SO es el planificador de tareas, ste seor es el
administrador de nuestros recursos. Su misin fundamental es determinar dentro de las tareas que estn listas
para ejecutarse, a cul de ellas le entrega el procesador. La poltica de planificacin empleada por CCS no la
conozco, pero eso no importa porque el RTOS funciona y para lo que queremos hacer, nos sirve bien.
Directivas del preprocesador
Existen dos directivas del preprocesador para el uso del RTOS, ellas son:
#USE RTOS: Se utiliza para indicarle al compilador que se va a utilizar el RTOS
#TASK: Se utiliza para indicarle al compilador se la funcin definida a continuacin es una tarea a ejecutar por
el RTOS
Vamos a ver ms detenidamente cada una de las directivas, as como sus parmetros de configuracin:
#USE RTOS : Opciones del RTOS:
timer: especifica que temporizador, de los disponibles, es el que se utilizar para la ejecucin de las tareas.
Este temporizador solamente debe ser utilizado por el RTOS y tpicamente se escoge Timer0.
minor_cycle: especifica la cantidad de tiempo mnima que una tarea tendr para ejecutarse, y los tiempos de
ejecucin de cada tarea deben ser mltiplos de esta cantidad. Si por ejemplo decimos que el tiempo mnimo de
ejecucin para todas las tareas es de 1ms, debemos conocer que cada tarea se ejecutar, en menos tiempo
que este. Lo realmente importante de este dato es que ayuda a establecer la frecuencia con que se ejecutan
las tareas, luego veremos un ejemplo de esto. Este parmetro, si no se especifica, es calculado por el
compilador en el momento de la compilacin.
statistics: le indica al compilador que lleve las estadsticas de las tareas, esto sirve para conocer que tiempo

6 de 22

statistics: le indica al compilador que lleve las estadsticas de las tareas, esto sirve para conocer que tiempo
consume cada tarea en ejecutarse, sin embargo como veremos ms adelante, la estadstica realmente
importante es la que nos indica si nuestra tarea se ha sobrepasado en su tiempo mnimo de ejecucin.
#TASK: Opciones para las tareas:
rate: especifica con que frecuencia se ejecuta la tarea, este parmetro debe ser igual a minor_cycle de
#use_rtos o un mltiplo de este valor.
max: especifica que cantidad de tiempo debe consumir esta tarea en su ejecucin, si se sobrepasa este tiempo
y estn activadas las estadsticas, entonces esta tarea es marcada con el valor overrun. Este parmetro es til
para informar al programador que una tarea se ha pasado de su tiempo de ejecucin, y si el RTOS fuera de
tiempo compartido seguramente especificara el tiempo en que el planificador le retira el procesador para
drselo a otra tarea.
queue: especifica el tamao de la cola de mensajes de la tarea. Si la tarea no recibe mensajes, entonces debe
dejarse en blanco para no consumir memoria RAM innecesariamente.
Hasta aqu hemos visto una pequea explicacin de las directivas para utilizar el RTOS. Sin embargo, la
utilidad de esto es mejor verla con un ejemplo.
[Volver al ndice]

> Funciones del RTOS


EL RTOS de CCS ofrece un conjunto de funciones que veremos cada una en su momento y con sus debidos
ejemplos. Sin embargo hoy utilizaremos solamente la funcin rtos_run(), que le indica al planificador que
comience a ejecutar las tareas.
El ejemplo:
Se quiere implementar una aplicacin en un PIC16F877, donde se utilice el RTOS para transmitir por el puerto
serie de este uC, tres cadenas de caracteres. Cada cadena ser transmitida desde dentro de una tarea del
RTOS y tendrn el formato Ejecutada tarea #. Las especificaciones de tiempo del sistema y de cada tarea
son las siguientes:
Temporizador para el RTOS: Timer0
Tiempo mnimo en que debe ejecutarse una tarea: 10ms
Frecuencia de ejecucin de la Tarea 1: 1seg, tiempo para ejecutar: 10ms
Frecuencia de ejecucin de la Tarea 2: 2seg, tiempo para ejecutar: 5ms
Frecuencia de ejecucin de la Tarea 3: 3seg, tiempo para ejecutar: 250us
El cdigo lo pongo a continuacin y posteriormente les doy una explicacin:
Cdigo:
#include "D:\Documentos\Projects\RTOS\RTOS.h"
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)
#use RTOS(timer=0, minor_cycle=10ms) //temporizador Timer0, tiempo mnimo de ejecucin de cada tarea 10ms
int8 test;
//Definicin de las prototipos de funcin de las tareas
#task (rate=1s, max=10ms) //Ejecutar cada 1 segundo y consumir como mximo 10ms
void Tarea1();
#task (rate=2s, max=5ms) //Ejecutar cada 2 segundos y consumir como mximo 5ms
void Tarea2();
#task (rate=3s, max=250us) //Ejecutar cada 3 segundo y consumir como mximo 250us
void Tarea3();
void main()
{
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
rtos_run(); //A partir de aqu comenzar la ejecucin de las tareas
}
//Implementacin de las tareas
void Tarea1()
{
printf("Ejecutada tarea 1\r");
}

7 de 22

void Tarea2()
{
printf("Ejecutada tarea 2\r");
}
void Tarea3()
{
printf("Ejecutada tarea 3\r");
}

Este cdigo funciona y si lo simulan con el Proteus comprobarn que las cadenas salen por el puerto serie.
Como pueden ver es un ejemplo sencillo pero que muestra el funcionamiento del RTOS. Al ejecutarlo pueden
comprobar que primero se ejecuta la Tarea 1, pero despus comprobarn que las tareas no se ejecutan en
orden secuencial porque la Tarea 2 se ejecutar cada 2 segundos y la Tarea 3 cada 3 segundos.
La no ejecucin secuencial de cada tarea se debe al parmetro rate de la directiva #task, que le dice al
planificador con que frecuencia ejecutar cada tarea. Este programa puede ser fcilmente modificado para
cualquier aplicacin especfica, un ejemplo que se me ocurre es la lectura de teclados y eliminacin de rebotes.
[Volver al ndice]

> Controlando la ejecucin de las tareas


En la pasada entrega sobre programacin con el RTOS de CCS vimos como es que el planificador programaba
la ejecucin de las tareas que estaban activas para ser ejecutadas. Pero como es lgico en todo momento las
tareas no tienen por que encontrarse en condiciones de ser ejecutadas, a veces hace falta poner a dormir
una tarea y despertarla cuando hace falta que se ejecute.
Para lograr este objetivo el RTOS de CCS nos ofrece dos funciones: RTOS_DISABLE( ) y RTOS_ENABLE( )
Al crear una tarea el RTOS la marca como activa (enable), y cuando comienza a ejecutarse el planificador de
tareas la pondr en la cola de ejecucin para ejecutarla cuando le llega su turno. Sin embargo en muchas
ocasiones notaremos que no hace falta ejecutar la tarea hasta que se cumplan ciertas condiciones.
Este es un mecanismo simple, que sin el uso del RTOS controlaramos mediante una bandera (flag), y la
implementacin de una funcin a la cual llamaremos si se cumple la condicin de su ejecucin.
Hasta el momento el RTOS no nos ofrece ninguna ventaja respecto al mtodo tradicional, sin embargo
combinemos esta caracterstica con lo aprendido en el ejemplo de la entrega anterior y comprobaremos que si
hay ventajas, y por cierto nada despreciables.
La ventaja principal con respecto al mtodo tradicional consiste en que usted hace la consulta para comprobar
si hay que ejecutar la funcin, sin embargo ahora solamente le dice al RTOS, habilita a la tarea tal y ponla a
ejecutarse cuando le corresponda y se olvida de todos los problemas asociados respecto al tema de cuando le
corresponde ejecutarse la tarea y dems.
Alguien se acuerda de los molestos temporizadores, banderas, registros y Dios sabe cuantos engendros de
control de ejecucin condicional para una funcin estndar?
De forma similar a como se le dice al planificador que la tarea tal debe ser ejecutada, podemos avisarle para
que no la ejecute.
Veamos esto con un ejemplo:
Tenemos una aplicacin en la que hemos colocado tres LEDs uno rojo en RB0, uno verde en RB1 y otro
amarillo en RB2. Vamos a encender y apagar los LEDs con una frecuencia determinada y a intervalos regulares
segn el siguiente esquema:
-

Led Rojo parpadea con una frecuencia de 250ms por un perodo de 5s, el resto apagado.
Led Verde parpadea con una frecuencia de 350ms por un perodo de 10s, el resto apagado.
Led Amarillo parpadea con una frecuencia de 450ms por un perodo de 15s, el resto apagado.
Todos los LED parpadean, cada uno con su frecuencia correspondiente durante 5s.
Comenzamos por el LED rojo nuevamente y repetimos el ciclo.

La solucin que les propongo es la siguiente:


- 3 tareas para controlar el parpadeo de cada LED y el tiempo que se ejecutan
- 1 tarea para controlar el tiempo en que todos los LEDs parpadean.
Tenemos un total de 4 tareas en la aplicacin y el control de la ejecucin ser el siguiente:

8 de 22

Tenemos un total de 4 tareas en la aplicacin y el control de la ejecucin ser el siguiente:


Al inicio solamente la tarea LED_R estar habilitada, una vez que LED_R ha concluido inicia la tarea LED_V y
se autodeshabilita.
Cuando LED_V concluye habilita LED_A y se autodeshabilita.
Cuando LED_V concluye habilita LEDS y se autodeshabilita.
Cuando LEDS se inicia por primera vez habilita LED_R, LED_V y LED_A cuando le toca de nuevo el turno se
autodeshabilita y deshabilita a LED_V y LED_A
Veamos el cdigo:
Cdigo:
#include "D:\Documentos\Projects\RTOS\RTOS.h"
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)
//Como el reloj de este micro se ha puesto a correr con 20MHz el Timer0 no tiene
//mayor resolucin que 10ms, es por eso que el tiempo mnimo de ejecucin es de 10ms
#use RTOS(timer=0, minor_cycle=10ms)
int1
int1
int8
int8
int8
int8

iB0, iB1, iB2;


iLEDS = 0;
iCountR = 0;
iCountV = 0;
iCountA = 0;
iCount = 0;

#task (rate=10ms, max=10ms)


void Task_Disabler();
#task (rate=250ms, max=10ms)
void LED_R();
#task (rate=350ms, max=10ms)
void LED_V();
#task (rate=450ms, max=10ms)
void LED_A();
#task (rate=5s, max=10ms)
void LEDS();
void main()
{
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
rtos_run();
}
//esta es una funcin truculenta porque las tareas no pueden crearse deshabilitadas
//y no se pueden deshabilitar hasta que el RTOS est funcionando. Lo considero una
//deficiencia sustancial de este RTOS
void Task_Disabler()
{
rtos_disable(LED_V);
rtos_disable(LED_A);
rtos_disable(LEDS);
rtos_disable(Task_Disabler);
}
//cada tarea tiene un contador para llevar la cantidad de veces que se pasa por la
//funcin y cuando se cumple el tiempo establecido entonces habilita y deshabilita
//las tareas correspondientes
void LED_R()
{
iB0 = !iB0;
output_bit( PIN_B0,
if (iCountR++==20)
{
iCountR = 0;
rtos_disable(LED_R);
rtos_enable(LED_V);
}
}

iB0);

9 de 22

}
void LED_V()
{
iB1 = !iB1;
output_bit( PIN_B1,
if (iCountV++==27)
{
iCountV = 0;
rtos_disable(LED_V);
rtos_enable(LED_A);
}
}
void LED_A()
{
iB2 = !iB2;
output_bit( PIN_B2,
if (iCountA++==33)
{
iCountA = 0;
rtos_disable(LED_A);
rtos_enable(LEDS);
}
}

iB1);

iB2);

void LEDS()
{
if(!iLEDS)
{
rtos_enable(LED_R);
rtos_enable(LED_V);
rtos_enable(LED_A);
iLEDS = 1;
}
else
{
rtos_disable(LED_V); //Hay que habilitar y deshabilitar explcitamente
rtos_disable(LED_A); //cada tarea sobre todo LED_R que debe continuar
rtos_disable(LEDS); //ejecutndose otros 5 segundos ms
rtos_enable(LED_R);
iCountR = 0;
iCountV = 0;
iCountA = 0;
iLEDS = 0;
}
}

Cuando corran y simulen el ejemplo vern que a veces los LEDs se quedan encendidos o apagados
indistintamente, este es un problema del programa, ya que lo deseable sera que los LEDs se quedaran
apagados cuando termina la funcin. Sin embargo lo he dejado as porque en el futuro vamos a ver cmo
podemos hacer esto con las propias funciones del RTOS.
Como la vez anterior, les dejo de tarea hacerlo sin RTOS para ver como les queda, a mi llev menos de dos
horas elaborar el texto y escribir el cdigo. Me imagino que sin RTOS me tardara ms de un da completo,
consumira un montn de pginas de explicacin y otro montn para el cdigo.
Este es un mtodo simple, pero hay otros mucho ms elaborados que iremos viendo poco a poco. La prxima
entrega ser yield() vs delay(), vamos a ver el mtodo de las esperas eficientes.
[Volver al ndice]

> Yield vs delay


Cuantas veces en nuestras aplicaciones tenemos que situar demoras para esperar la ocurrencia de un evento
determinado? Por ejemplo, para eliminar rebotes en un teclado, esperar a que el conversor AD termine y quin
sabe cuantas cosas ms.
Normalmente estas demoras se hacen poniendo al procesador a decrementar contadores y dar saltos
recursivos como si fuese un loco. Durante todo el tiempo de la demora, nuestro microcontrolador, estar
ocupado en perder el tiempo, y es por eso que a este mecanismo se le llama espera ocupada.

10 de 22

ocupado en perder el tiempo, y es por eso que a este mecanismo se le llama espera ocupada.
Sin embargo un RTOS nos ofrece un conjunto de herramientas para eliminar este molesto inconveniente, el
ms sencillo de ellos es aquel que le permite a una tarea decirle al RTOS: ponme a dormir hasta que me toque
de nuevo mi turno de ejecutarme. Para ese efecto el RTOS de CCS implementa la funcin rtos_yield().
Este mecanismo es muy bueno puesto que mientras la tarea se duerme nuestro microcontrolador puede
dedicarse a realizar otras tareas tiles y hacer de la espera ocupada una espera eficiente. Para la tarea que
est dormida esto no representa nada, a ella le da lo mismo ocupar al procesador en hacer nada que en hacer
algo productivo, sin embargo no ocurre lo mismo para el resto de las tareas que estn esperando que se les
entregue el procesador.
Otro caso en que yield() nos puede ser til es para entregar el procesador cuando nos hemos pasado de
tiempo en la ejecucin de alguna tarea. Ya sabemos que el RTOS de CCS es cooperativo, por lo que si una
tarea consume ms tiempo de la cuenta puede hacer que el sistema colapse, ya que hay que entregar
explcitamente el procesador al RTOS para que se lo de a otra tarea.
Sin embargo con la funcin de las estadsticas habilitadas, podemos comprobar si alguna tarea se ha pasado
de tiempo, y con ello implementar mecanismos adecuados para que la tarea en cuestin reajuste su dinmica
y ceda el procesador oportunamente, para ello podemos auxiliarnos de la funcin rtos_overrun(). Esta funcin
no tiene valor si se usa dentro de una tarea para comprobar si ella misma se ha pasado porque la actualizacin
de las estadsticas se hace despus de ceder el procesador, considero que esta es una de las debilidades de
este RTOS, en ese sentido.
El uso de rtos_overrun(), debera poderse utilizar dentro de una misma tarea para comprobar si desde que me
cedieron el procesador para ejecutar, me he pasado de tiempo o no y en consecuencia entregar el procesador
al RTOS.
En el ejemplo que les traigo hoy vamos a emplear rtos_yield() para ceder el procesador y rtos_overrun() para
conocer si una tarea se ha pasado de tiempo.
Sin embargo yield() no es una funcin realmente poderosa, al menos en este RTOS, porque pone a dormir a la
tarea durante un perodo completo del valor rate, que especificamos al declarar la funcin como una tarea del
RTOS, y eso en ocasiones no es lo que deseamos. An as es mejor que el procesador de nuestro PIC est
haciendo algo til y no perdiendo el tiempo.
En las entregas futuras veremos otras funciones que nos ofrece este RTOS para hacer esperas ms eficientes
vinculadas al uso de recursos compartidos en nuestras aplicaciones. El uso eficiente del procesador, los
recursos del sistema y la no linealidad en la ejecucin de las tareas en un sistema que emplea SO, ha obligado
a los diseadores de SO a crear mecanismos para proteger los datos y hacer uso de esos recursos de forma
ordenada y segura. Estos mecanismos se clasifican en dos grupos: La sincronizacin y la coordinacin que
comenzaremos a ver en la prxima entrega.
Ejemplo:
Implemente en un PIC16F877 una aplicacin en la que se ejecuten tres tareas, con las siguientes
caractersticas:
- La tarea No. 1 Tendr un contador el cual se incrementa en un lazo hasta que alcanza el valor de 1000.
Cuando llegue a ese valor imprime el siguiente mensaje: Tarea contadora completada y adems pone una
bandera a 1, para indicar que ha concluido. Debe colocar en esta tarea cdigo para que la tarea ceda el
procesador en algn momento al RTOS. El tiempo mximo de ejecucin de esta tarea es de 10ms y debe
ejecutarse cada 30ms.
- La tarea No. 2 debe esperar a que la tarea No. 1 termine para enviar por el puerto serie un mensaje similar
al de la tarea No. 1, sin embargo, esta tarea tambin enviar, por el puerto serie, un mensaje cada vez que le
cede el procesador al RTOS. Esta debe ejecutarse en un tiempo de 10ms y debe ejecutarse cada 40ms.
- Por ltimo, existe una tarea que se encarga de hacer parpadear un LED conectado en RB0, cada 100ms y
enviar un menaje por el puerto serie en caso de que la Tarea 1 o la Tarea 2 se hayan pasado en algn
momento de su tiempo de ejecucin. El tiempo de procesador para esta tarea debe ser de 10ms.
Cdigo:
#include "D:\Documentos\Projects\RTOS\RTOS.h"
#use rs232(baud=19200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)
#use RTOS(timer=0, minor_cycle=10ms, statistics) //se utilizan las estadsticas
//hace falta para usar rtos_overrun()
int32 iT1Counter = 0;
int1 bT1Flag = 0;
int1 bLed = 0;
#task (rate=30ms, max=10ms)

11 de 22

#task (rate=30ms, max=10ms)


void Tarea1();
#task (rate=40ms, max=10ms)
void tarea2();
#task (rate=100ms, max=10ms)
void Tarea3();
void main()
{
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
rtos_run();
}
void Tarea1()
{
bT1Flag = 0;
for(iT1Counter = 0; iT1Counter <= 1000; iT1Counter++)
{ if(!(iT1Counter%100)) //mecanismo para ceder el procesador cada cierto tiempo
rtos_yield(); //cuando la tarea entra en contexto se comienza a ejecutar
//la lnea a continuacin de esta
}
printf("Tarea contadora completada\r");
bT1Flag = 1;
}
void tarea2()
{
//Aunque esta tarea no tiene que preocuparse mucho por ceder el procesador
//porque no tiene lazos infinitos o algo parecido puse de ejemplo tambien a
//rtos yield
if(bT1Flag)
printf("Espera por Tarea1 concluida\r");
else
{
printf("dormir T2\r");
rtos_yield();
}
}
void Tarea3()
{
bLed = !bLed;
output_bit( PIN_B0, bLed);
if(rtos_overrun(Tarea1)) //Si las tareas se pasaron de su tiempo de ejecucin
//se envan los mensajes por el pto serie
printf("Tarea 1 overrun\r");
if(rtos_overrun(Tarea2))
printf("Tarea 2 overrun\r");
}
Como pueden observar, este ejemplo realmente no se corresponde con una aplicacin que haga algo til, sin
embargo, me ha servido para ilustrar el uso de las funciones rtos_yield() y rtos_overrun() de la manera
ms sencilla que encontr. Las posibilidades de estas funciones estn ahora en sus manos y en lo que sus
cabezas puedan crear para ellas. Hay muchsimas aplicaciones en las que pueden ser tiles, sin embargo, ya el
tema de los RTOS es bastante complicado como para meternos a hacer programas complejos que demuestren
su uso.
El tiempo invertido para hacer el cdigo y el texto, fue de 2:30 hrs, la decisin de que ejemplo utilizar me tom
ms de un da.
[Volver al ndice]

> Coordinar para no daar


Hasta ahora hemos visto al RTOS como un elemento que nos ayuda a simplificar el cdigo de nuestra
aplicacin. Por una parte, dejndole parte de la temporizacin de las tareas que debe realizar nuestra
aplicacin y por otra utilizando el tiempo de las demoras ocupadas para hacer que otras tareas ejecuten su
cdigo en ese tiempo. Sin embargo esas ventajas no son nada comparado con dos herramientas

12 de 22

cdigo en ese tiempo. Sin embargo esas ventajas no son nada comparado con dos herramientas
fundamentales que nos ofrecen los SO: la coordinacin y la sincronizacin, de ellas hoy vamos a ver solamente
una de ellas: la coordinacin.
La coordinacin es un trmino en la programacin para SO, que se basa en la proteccin de recursos
compartidos, es un concepto orientado a evitar que diferentes tareas puedan acceder a los datos o recursos y
poner al sistema en un estado inestable o inseguro.
Ejemplos que ponen de manifiesto el problema de la coordinacin hay muchsimos pero en aras de mantener el
curso lo ms sencillo posible y adecuarlo un poco ms a las aplicaciones que normalmente se nos presentan yo
utilizar un problema ms cercano a nuestro entorno.
El problemas de la coordinacin tambin se conoce como el problema de la concurrencia o acceso concurrente
a recursos, a mi me gusta llamarlo coordinacin para establecer una mejor diferencia con respecto al otro
mecanismo; el de la sincronizacin que veremos en la prxima entrega.
Destripando un poco ms a la coordinacin diremos que: "la coordinacin es el mecanismo que debe
implementar un SO para asegurar el acceso seguro a recursos compartidos del sistema, y que no tiene en
cuenta restricciones temporales". Con esto queda claro que proteger a los recursos de un acceso no seguro es
lo ms importante en la coordinacin, no importa durante que tiempo alguien (una tarea) est utilizando el
recurso, hasta que no lo libere nadie ms podr utilizarlo.
Hay mecanismos de coordinacin que implementan tambin el problema de la sincronizacin, que si tiene en
cuenta el factor tiempo, pero el RTOS de CCS no los implementa. Esto puede considerarse una limitante o una
ventaja, segn el tipo de aplicacin en que se vaya a utilizar.
Un RTOS que implementa un mecanismo de coordinacin con sincronizacin es el LMOS de Darukur, que
veremos dentro de algn tiempo en este foro, debidamente documentado gracias a un proyecto que Darukur y
un servidor, llevaremos a ustedes. Por el momento este simple cursillo es un buen mtodo (no el nico) para
acercarse al mundo de los RTOS.
Veamos la coordinacin con un ejemplo sencillo pero bien claro:
"Supongamos que una madre ha comprado una camisa muy bonita, ella quera comprar dos, pero en la tienda
solo haba una as que decidi comprarla de todas formas. Cuando lleg a casa llama a sus hijos (ambos usan
la misma talla de camisa), y les dice: he comprado esta camisa, pero en la tienda solamente haba una, as
que deben compartirla como buenos hermanos.
Las palabras de la madre no son alentadoras porque a ambos les gusta mucho la camisa y sin embargo deben
compartirla, entonces la decisin de ambos es colocar la camisa en una percha, y cada vez que uno de los dos
decida utilizarla se la ponga (dejando el perchero vaco). Pero hay una regla adicional, si cuando uno de los dos
va a utilizar la camisa el otro ya se la llev dejar una marca para indicarle al otro hermano que no podr
utilizar la camisa hasta que el que la marc haya hecho uso de ella."
Este es un mecanismo en que los hermanos se han puesto de acuerdo para utilizar un recurso (la camisa), de
manera compartida (porque es la nica), de forma coordinada (para eso se pusieron de acuerdo e hicieron
unas reglas simples).
Para implementar las reglas mostradas en el ejemplo anterior, el RTOS de CCS tiene dos funciones
rtos_wait() y rtos_signal().
Para utilizar estas funciones primero hay que crear una variable entera que har las funciones de percha y, que
hablando con propiedad, se llama semforo. El semforo es el elemento que le permite a la tarea reclamar el
recurso compartido o esperar por l si ya est en uso. Las funciones rtos_wait() y rtos_signal() se utilizan
para marcar el momento de inicio y fin del cdigo que utiliza el recurso compartido. A la seccin de cdigo que
utiliza el recurso compartido se le conoce como seccin crtica.
Veamos como funciona esto en trminos de programacin:
Usted crea una variable entera que ser su semforo o marcador de uso del recurso compartido.
El recurso compartido puede ser una o varias variables del sistema, en este caso el recurso compartido es un
recurso de memoria. O puede ser un perifrico del sistema, como es el caso del puerto serie o la memoria
EEPROM, o cualquier otro.
rtos_wait() y rtos_signal() son los marcadores de inicio y fin del cdigo que hace uso de nuestro recurso
compartido.
Cuando se inicia el programa usted inicializa el semforo en algn valor positivo que determina la cantidad de
tareas que pueden utilizar el recurso al mismo tiempo, normalmente es uno para las tareas que modificarn el
recurso compartido, mientras que para tareas que solamente leen datos puede que no se usen secciones
crticas o se permita ms de una tarea que acceda simultneamente al recurso compartido.

13 de 22

Cuando una tarea llegue a la seccin de cdigo que hace uso del recurso compartido, debe, primero que nada,
ejecutar la funcin rtos_wait(sem). Si el semforo es mayor que cero, el RTOS decrementar la variable y
permitir que la tarea contine su ejecucin, sin embargo si el semforo est en cero, el RTOS le quitar el
procesador a la tarea y se lo ceder a otra que le toque ejecutarse. Cuando le corresponda nuevamente a la
tarea que pidi el acceso al recurso compartido, el RTOS comprobar el estado del semforo, si ste es mayor
que cero, lo decrementar y le dar el procesador a la tarea para que se siga ejecutando, si no, volver a
dormir a la tarea hasta el prximo turno y as sucesivamente.
Al final del cdigo de la seccin crtica hay que colocar un rtos_signal(sem) para que el RTOS incremente el
semforo permitiendo que otra tarea pueda utilizar el recurso compartido.
El ejemplo de hoy es el siguiente:
Elabore un programa para un PIC16F877 que permita mantener actualizada la cantidad de botellas que hay en
un tramo de cinta transportadora en una embotelladora. La cinta es alimentada desde un almacn de botellas
que tiene un robot que incrementa la variable Cantidad cada vez que coloca una botella en la cinta, mientras
que dos robots llenadores de cajas, decrementan en 12 la variable cantidad cada vez que toman 12 botellas de
la cinta transportadora.
Como es de suponer el robot despachador debe llenar la cinta ms rpido de lo que los robots llenadores la
vacan.
En la prxima entrega utilizaremos la sincronizacin para resolver el problema de que la cinta se quede vaca o
se llene demasiado rpido. Como datos adicionales suponga que el robot despachador despacha una botella
cada 250ms y que los robots llenadores llenan una caja cada 6 segundos. El robot despachador est conectado
a RB0 y cada vez que pone una botella en la cinta transportadora le da un pulso al microcontrolador para
indicrselo. Los robots llenadores estn conectados uno a RB1 y el otro a RB2 e igualmente dan un pulso al
microcontrolador cada vez que despachan una caja. La duracin del pulso es de 100ms.
Como es de suponer este problema lo podemos resolver de muchas maneras y lgicamente sin el uso de los
RTOS, pero eso se los dejo de tarea. Adems el mecanismo de notificacin de cada robot es un poco
deficiente, pero ese no es el tema de este curso, aunque en su momento pondremos un ejemplo mejor al
respecto, cuando rescatemos a las interrupciones del olvido.
Analicemos un poco en detalle el problema: Supongamos que la tarea asociada al robot despachador comienza
a ejecutarse, lee el valor de la variable Cantidad, 100 botellas, y se va adormir esperando que el robot le
notifique que ha puesto una botella en la cinta, en ese momento el RTOS le da permiso a la tarea del robot
llenador 1 para que ejecute su cdigo, sta se da cuenta que el robot llen una caja por lo que lee la variable
Cantidad y le resta 12 botellas, quedando Cantidad = 88 botellas. Ahora le toca de nuevo a la tarea del robot
despachador ejecutarse y como ya se despach una botella le suma uno al valor previamente ledo y actualiza
la variable Cantidad, quedando 101 botellas, lo cual es falso.
Este ejemplo puede mejorarse semnticamente y evitarnos el uso de la seccin crtica, todo ello gracias a que
nuestro RTOS es cooperativo y en este caso, mientras la tarea est ejecutndose tiene todos los recursos para
ella sola hasta que entregue el procesador.
Por lo tanto podemos escribir el cdigo de modo que no haya ningn rtos_yield() intercalado con el cdigo que
accede a un recurso compartido, de esta forma la tarea se asegura el uso exclusivo del recurso compartido a
no ser que aparezcan las interrupciones en la palestra y las cosa se complique. Sin embargo en un sistema de
tiempo compartido (los hay para PIC, ejemplo de ellos es el FreeRTOS), donde no sabemos cuando el RTOS
nos quitar el procesador el uso de secciones crticas es OBLIGATORIO, para evitar problemas como los
mostrados, y por eso es importante que dominemos esta tcnica.
Por otro lado el uso de Perifricos puede complicar ms las cosas que el uso simple de la memoria y puede
ocurrir que para ser eficientes estemos obligados a poner un rtos_yield() dentro del cdigo de la seccin
crtica. Moraleja: aprenda a programar con secciones crticas o no programe con RTOS.
El cdigo:
#include "D:\Documentos\Projects\RTOS\RTOS.h"
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)
#use RTOS(timer=0, minor_cycle=10ms)
int8 semaphore; //Este es nuestro semforo
int16 iCantidad; //Esta es la cantidad de botellas en la estera
//constituye nuestro recurso compartido
#task (rate=50ms, max=10ms)
void R_Despachador();
#task (rate=50ms, max=10ms)
void R_Llenador1();

14 de 22

#task (rate=50ms, max=10ms)


void R_Llenador2();
void main()
{
semaphore = 1; //Solo una tarea puede utilizar el recurso cada vez
iCantidad = 100; //Inicializamos esta variable para tener algunas botellas en
//la estera.
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
rtos_run();
}
void R_Despachador()
{
int Botellas;
rtos_wait(semaphore); //Reclamamos el recurso y aqu comienza la secc crtica
Botellas = iCantidad; //Leemos la cantidad de botellas a una variable temporal
if(input(PIN_B0)==1)
{
Botellas++; //Ya sabemos que este cdigo no es eficiente pero
iCantidad = Botellas; //s es didctico y por eso lo he utilizado as.
}
rtos_signal(semaphore); //Liberamos el semforo y aqu se acaba la sec crtica
rtos_yield(); // A dormir por otros 100ms para evitar poner dos veces la misma botella
}
void R_Llenador1()
{
rtos_wait(semaphore);
if(input(PIN_B1)==1)
iCantidad -= 12; //Este s es un cdigo lgico, pero entonces el despachador
//no nos dara problemas aunque nos vayamos a dormir dentro de
//la seccin crtica.
rtos_signal(semaphore);
rtos_yield();
}
void R_Llenador2()
{
rtos_wait(semaphore);
if(input(PIN_B2)==1)
iCantidad -= 12;
rtos_signal(semaphore);
rtos_yield();
}

Este programa lo simul en Proteus poniendo en RB0 una fuente digital de tipo pattern con los siguientes
parmetros:
First Edge at (Secs)=1
Desmarcar el check mark: Equal Mark/Space Timing?
Mark Time (Secs) = 100m
Sapce Time(Secs) = 150m
Marcar el check mark: Continuos Secuence of Pulses
Marcar el check mark: Standard Hig-Low Pulse Train
Para RB1 y RB2 se utiliza una fuente del mismo tipo con los siguientes parrametros cambiados
Para RB1:
First Edge at (Secs)=5
Mark Time (Secs) = 100m
Sapce Time(Secs) = 5.9
Para RB2:
First Edge at (Secs)=7
Mark Time (Secs) = 100m

15 de 22

Mark Time (Secs) = 100m


Sapce Time(Secs) = 5.9

Simulen y vean como cada vez que se pasa por rtos_wait() y si el semforo es mayor que cero, se decrementa
y se entra en la seccin crtica, si el semforo es 0 entonces la tarea espera a que est disponible el recurso
(semforo>0) para ejecutar el cdigo de la seccin crtica.
[Volver al ndice]

> En sus marcas, listos, FUERA!


Un momento, un momento, no tan rpido que, hay una salida en falso del corredor del carril No. 2.
En un caso como el anterior diramos que ha fallado la sincronizacin de los corredores en el arranque, y la
sincronizacin es el tema que vamos a tratar hoy en nuestro cursillo de los RTOS para uC.
En el mundo de los uC es frecuente la utilizacin de demoras para esperar a que ocurran ciertos hechos o
eventos, para en consecuencia hacer algo. La duracin de estas demoras puede ser conocida, como en el caso
de esperar a que una LCD coloque los datos en determinados registros antes de enviarle otro dato, o esperar a
que la USART saque un dato que est transmitiendo antes de poder escribir nuevamente en el registro de
transmisin; sin embargo tambin son frecuentes aquellas esperas en las que no sabemos cuanto podemos
demorarnos.
En los casos en que no conocemos cuanto debemos esperar se pueden utilizar las interrupciones, pero en los
uC no tenemos interrupciones ilimitadas ni tampoco existe una biblioteca de mecanismos de interrupcin
disponibles para todos los casos que se nos presentan. Es por estas razones que muchas veces esperamos a la
ocurrencia de estos eventos haciendo suposiciones y blandiendo demoras.
Para la implementacin de demoras existen varios mecanismos ms o menos eficientes, sin embargo un SO no
nos ofrece este tipo de mecanismos que podemos llamar un poco primitivos. Para la implementacin de
demoras eficientes los SO han creado los mecanismos de sincronizacin de procesos.
En la entrega anterior vimos la coordinacin, en realidad los autores de los libros ms reconocidos en el tema
de los SO, han llamado a estos mecanismos y al que veremos hoy, mecanismos de sincronizacin de
procesos, pero a mi me gusta distinguir entre aquellos que se dedican especialmente a implementar esperas
eficientes para la proteccin de recursos, de aquellos que se dedican a implementar esperas eficientes para
eventos por los cuales un proceso debe esperar antes de continuar su ejecucin. Notemos que en ambos casos
la tarea o proceso debe esperar, pero no en todos los casos la espera tiene la misma naturaleza, en uno
esperamos por un recurso fsico al que queremos acceder y que no est disponible, en el otro esperamos a que
se produzcan ciertos hechos que determinan el estado del sistema.
Vamos a utilizar como referencia el problema anterior para ver el mecanismo de la sincronizacin en ejecucin.
Supongamos ahora que le hemos colocado a nuestros robots una entrada que cuando est en nivel bajo le
indica al robot que no coloque o extraiga botellas de la cinta transportadora. Con este mecanismo simple
vamos a tratar, por un lado, de evitar que el robot despachador de botellas llene demasiado la cinta y por el
otro que los robots llenadores de cajas traten de llenar las cajas cuando no hay suficientes botellas en la cinta
transportadora. Es decir, vamos sincronizar el proceso de llenado/vaciado de la cinta transportadora. Las
ventajas de esto son evidentes, por ejemplo: si el robot llenador no tiene botellas que poner en la cinta los
robots llenadores trabajarn hasta que la cantidad de botellas se lo permita; si los robots llenadores dejan de
trabajar, entonces el robot despachador trabajar hasta que llene la cinta transportadora.
Para lograr lo anterior, vamos a poner que la cantidad mxima de botellas que pueden estar en la cinta es de
100 y que la cantidad mnima de botellas es 24, por lo que cada una de las tareas que atiende a los robots
deber, adems de llevar la actualizacin del total de botellas en la cinta, indicarle a los robots que se
detengan cuando la cantidad de botellas en la cinta est fuera del rango especificado. Adems vamos a utilizar
el puerto serie para Tx la cantidad de botellas que hay en la cinta en cada momento.
Las entradas a los robots (salidas de nuestro PIC) las hemos colocado en los pines RB3..RB5, en RB3 al robot
despachador, en RB4 al robot llenador1 y en RB5 al robot llenador2
Para hacer la sincronizacin de tareas el RTOS de CCS nos ofrece una sola funcin, aunque parezca poco esta
funcin es bien poderosa, vamos a verla con ms detenimiento. La funcin se llama rtos_await(expr) lo que
tienes que pasarle es una expresin lgica que la funcin evaluar, si esta resulta verdadera entonces
continas la ejecucin normal de tu programa, si te devuelve falso, entonces rtos_await() le ceder el
procesador al RTOS y la tarea quedar bloqueada hasta que exp se cumpla para entonces continuar en la lnea
siguiente a la llamada a la funcin.
Ahora bien, es cierto que esta funcin es poderosa y simple, pero eso implica que tenemos que saber donde
ponerla, ya que si no evaluamos bien nuestras expresiones o no colocamos la funcin en el lugar adecuado,
estaremos sometindonos a riesgos durante la ejecucin de nuestro cdigo. Por ejemplo puede ocurrir que

16 de 22

estaremos sometindonos a riesgos durante la ejecucin de nuestro cdigo. Por ejemplo puede ocurrir que
alguna tarea se quede bloqueada esperando por siempre a que la expresin lgica se evale de verdadera y
esto nunca ocurra o que la expresin est mal diseada y la tarea no se bloquee cuando haga falta. Bien todos
esos problemas los veremos ms adelante cuando la seorita Nmesis (diosa griega de la venganza y la
fortuna) haga acto de presencia para echarnos a perder toda la dicha que los RTOS traen al mundo de la
programacin con uC.
Desde aqui puedes descargar el cdigo fuente y la simulacin con Proteus (57Kb, formato ZIP)

Cuando corran el ejemplo noten como la cantidad de botellas en la cinta va descendiendo hasta que al llegar a
las 24 botellas, despus la cantidad de botellas en la cinta se mantendr ms o menos sobre las 20 y nunca
por debajo de 12. Las compuertas AND de conjunto con las formas de onda hacen la funcin de los robots.
El cdigo:
#include "D:\Documentos\Projects\RTOS\RTOS.h"
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)
#use RTOS(timer=0, minor_cycle=10ms)
int8 semaphore; //Este es nuestro semforo
int16 iCantidad; //Esta es la cantidad de botellas en la estera
//constituye nuestro recurso compartido
#task (rate=50ms, max=10ms)
void R_Despachador();
#task (rate=50ms, max=10ms)
void R_Llenador1();
#task (rate=50ms, max=10ms)
void R_Llenador2();
void main()
{
semaphore = 1; //Solo una tarea puede utilizar el recurso cada vez
iCantidad = 120; //Inicializamos esta variable para tener algunas botellas en
//la estera, normalmente deberiamos tener un sensor que nos reporte
//en algun momento el total de botellas en la cinta, ya que un
//robot revisor de llenado o una persona puede retirar botellas
//de la cinta
//Al comenzar todos
output_bit( PIN_B3,
output_bit( PIN_B4,
output_bit( PIN_B5,

los robots estan deshabilitados


0);
0);
0);

setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
rtos_run();
}
void R_Despachador()
{
//Note como hacemos la sincronizacion fuera de la seccion critica, mas adelante veremos
//que esto no siempre es posible hacerlo o que las cosas se complican un poco mas
//de lo que hemos visto hasta ahora.
rtos_await(iCantidad<100); //Esperemos a que se vacie un poco la cinta
output_bit( PIN_B3, 1); //A partir de aqui, si no se podia antes,

poner botellas

rtos_wait(semaphore); //Reclamamos el recurso y aqu comienza la secc crtica


if(input(PIN_B0)==1)
iCantidad++; //s es didctico y por eso lo he utilizado as.
if(iCantidad >= 100)
output_bit( PIN_B3, 0); //Le decimos al robot despachador que no ponga mas botellas
rtos_signal(semaphore); //Liberamos el semforo y aqu se acaba la sec crtica
printf("%3.0w \r",iCantidad);
rtos_yield(); // A dormir por otros 50ms para evitar poner dos veces la misma botella
}

17 de 22

void R_Llenador1()
{
//El robot debe esperar a que la cinta tenga suficientes botellas para sacar antes
//de comenzar a trabajar.
rtos_await(iCantidad>24); //Esperemos a que se llene un poco la cinta
output_bit( PIN_B4, 1); //A partir de aqui, si no se podia antes, sacar botellas
rtos_wait(semaphore);
if(input(PIN_B1)==1)
iCantidad -= 12;
if(iCantidad <= 24)
output_bit( PIN_B4, 0); //Le decimos al robot que no saque mas botellas
rtos_signal(semaphore);
printf("%3.0w \r",iCantidad);
rtos_yield(); // A dormir por otros 50ms para evitar poner dos veces la misma botella
}
void R_Llenador2()
{
rtos_await(iCantidad>24); //Esperemos a que se llene un poco la cinta
output_bit( PIN_B5, 1); //A partir de aqui, si no se podia antes, sacar botellas
rtos_wait(semaphore);
if(input(PIN_B2)==1)
iCantidad -= 12;
if(iCantidad <= 24)
output_bit( PIN_B5, 0); //Le decimos al robot que no saque mas botellas
rtos_signal(semaphore);
printf("%3.0w \r",iCantidad);
rtos_yield();
}

Hasta ahora solamente hemos visto ventajas del uso de los RTOS, sin embargo el uso de estas herramientas
presupone un montn de complicaciones que he tratado de no mostrar hasta el momento, en aras de mostrar
lo til que puede ser un RTOS, pero an con esas complicaciones el uso de los RTOS sigue siendo una
bendicin para cualquier desarrollador de sistemas con uC. Simplemente tendremos que ser un poco ms
cuidadosos con la semntica de nuestros programas y pensar un poco ms en la concepcin y modelacin de
las soluciones a nuestros problemas.
En la prxima entrega vamos a ver el uso de las funciones para el paso de mensajes entre tareas, que es otra
de las ventajas que los RTOS traen al mundo de la programacin para uC y cuando terminemos de ver todas
esas cosas buenas comenzaremos a estudiar las desgracias y cmo enfrentarlas.
[Volver al ndice]

> RTOS mail


Hasta el momento solamente hemos visto mecanismos que nos permiten simplificar el diseo de nuestros
programas, pero hoy vamos a ver una nueva potencialidad de los RTOS que es una cuestin realmente
novedosa en cuanto la visin de la programacin para uC a la cual estamos acostumbrados.
Cuando hacemos una llamada a una funcin, es frecuente pasarle algn parmetro para que esta pueda hacer
su tarea, mientras la funcin trabaja, nuestro programa espera pacientemente a que la funcin retorne y nos
devuelva el resultado, que puede ser un valor de retorno, un arreglo cambiado o simplemente el cambio en el
estado de algn perifrico o salidas del uC.
El prrafo anterior describe lo que hace nuestro programa cuando llamamos a una funcin, sin embargo nunca
hemos visto que una funcin le enve un dato a otra (no en la llamada a la funcin, sino fuera de sta) para
que cuando le toque ejecutarse tome esos valores y los procese, y si hay que devolver algn resultado
entonces que nos enve un acuse de recibo. Es lgico que un mecanismo como el que acabo de describir no se
utilice en las tcnicas de programacin anterior porque la ejecucin secuencial del cdigo presupone que no se

18 de 22

utilice en las tcnicas de programacin anterior porque la ejecucin secuencial del cdigo presupone que no se
requiera de un mecanismo como este.
Lo ms cercano al mtodo descrito en el poner datos en algn lugar para que una funcin lo procese es el uso
de las interrupciones, stas deben procesar rpidamente el evento de interrupcin y pude que pongamos el
dato en algn lugar y levantemos una bandera para que cuando a la funcin encargada de procesar los datos
le toque ejecutarse lea la bandera, procese los datos y coloque la bandera en el estado que notifica que ya se
proces, no para notificar a otra funcin sino para notificrselo a ella misma, no vaya a ser que cuando le
toque ejecutarse nuevamente procese los mismos resultados nuevamente o haga algo indebido.
Un ejemplo de lo anterior puede se el uso del conversor AD, en algn lugar del programa lo mandamos a
convertir; una vez hecha la conversin se produce una interrupcin que es atendida en la correspondiente
subrutina de atencin a esa interrupcin; leemos el dato lo ponemos en una variable e incrementamos un
contador. Posteriormente le toca ejecutarse a la funcin que promedia los resultados, sta comprueba si hay,
digamos 200 muestras, si las hay hace el clculo que pone en otra variable y deja el contador en cero. Este
mecanismo es eficaz porque se ha utilizado durante mucho tiempo, pero los RTOS brindan una solucin
elegante para hacer esto en el contexto de la ejecucin de tareas.

Estos mecanismos pueden funcionar tambin entre funciones pero tendremos el problema de tratar con un montn de
estructuras de datos, banderas y contadores, complejas expresiones lgicas a procesar se acuerdan de eso?
Ahora imagnense hacer todo lo anterior cuando, en vez de llamadas a funciones metidas dentro de un cdigo
que se ejecuta ms o menos estructuradamente, lo que tenemos es unas cuantas tareas de las que no
tenemos un control de cuando ni como se ejecutarn. Realmente puede ser una verdadera pesadilla hacer un
programa productivo, y es por ello que los RTOS nos ofrecen un poderoso mecanismo para hacer eso, y como
siempre, este mecanismo tambin es relativamente simple.
Para hacer lo anterior los RTOS implementan un mecanismo de mensajes. S, amigos mos, un RTOS
implementa una funcin similar a la de los correos.
El funcionamiento de ese mecanismo es simple, cuando una tarea o subrutina de atencin a interrupciones
necesita notificarle algo a otra tarea llama a una funcin que pone el dato en la cola de la tarea en cuestin,
cuando a la tarea que recibi el mensaje le toca ejecutarse debe, en algn lugar consultar su cola de
mensajes, si hay mensajes debe leerlos y procesarlos, como pueden ver este mecanismo es bastante parecido
a lo que hacemos habitualmente.
Si yo quiero pasarles un mensaje, por ejemplo un post, hago lo siguiente:
- lo escribo, este es el equivalente a realizar una tarea
- lo mando al foro, este es el equivalente a ponerlo en la cola de mensajes del hilo sobre RTOS
- ustedes llegan y consultan si hay mensajes nuevos en el hilo, por supuesto llegan cuando su tarea de leer el
foro est activa
- si hay un mensaje nuevo, normalmente tratarn de leerlo y poner en prctica los nuevos conocimientos
- si se sienten impresionados, me escribirn un mensaje a mi correo privado, dndome un acuse de recibo (no
hagan esto si no es estrictamente necesario, no vaya a ser que me vuelvan loco)
Aqu se ha puesto de manifiesto un ejemplo del sistema de mensajes ms simple utilizado por un SO: elaborar
y enviar de una parte y consultar si hay un mensaje, procesar y enviar acuse de recibo si es necesario de la
otra parte.
(Todo esto est muy bien. Pero yo quiero cdigo y ejemplos de verdad.)
Vale, no nos ofusquemos, primero entender bien el concepto, luego ponerlo en prctica.
Lo primero que tenemos que hacer es decirle al compilador que le cree una cola de mensajes a aquella tarea a
la cual queremos pasarle mensajes, para eso tenemos el parmetro queue, dentro de la directiva #task, con
este parmetro le indicamos al RTOS que reserve memoria y cree una cola de mensajes para la tarea, la
declaracin de una tarea con cola de mensajes sera como sigue:

El cdigo:
#task(rate = 1s, max=20ms, queue=5)
void Tarea1(void);
En la declaracin de la tarea el parmetro queue = 5, le dice al compilador que cree una cola de 5 bytes para
la Tarea1.
Para el envo y recepcin de mensajes tenemos las siguientes funciones:
RTOS_MSG_SEND( )
RTOS_MSG_POLL( )
RTOS_MSG_READ( )

19 de 22

RTOS_MSG_READ( )
RTOS_MSG_SEND(task, byte); permite enviar un byte de datos a la cola de mensajes de una tarea. Esta es la
nica funcin del RTOS de CCS que puede llamarse desde fuera de una tarea, lo que permite que desde una
subrutina de atencin a interrupcin se le enven mensajes a una tarea. El parmetro task es para el nombre
de la tarea y byte es un dato de 8 bits (un char o un int8), as que si queremos enviar un float o una
estructura tendremos que descomponer antes ese dato en bytes y luego componerlos cuando la cola de
mensajes sea leda.
int RTOS_MSG_POLL(); es la funcin que permite a una tarea conocer si tiene mensajes en su cola de
mensajes, no se puede llamar desde otra tarea para conocer cuantos mensajes tiene la tarea fulana. Devuelve
en un entero la cantidad de bytes ocupados dentro de la cola de mensajes.
int8 RTOS_MSG_READ(); permite leer un byte de la cola de mensajes. Cuando se ejecuta esta funcin se lee el
byte y se saca de la cola, por lo que si el dato se pierde no se podr recuperar, si se llama a la funcin y no
hay mensajes en la cola se pueden obtener datos falsos.
En el ejemplo que hemos estado viendo sobre la embotelladora, vamos a incluir un servicio especial para
balancear la cantidad de botellas que hay dentro de la cinta transportadora, para ello pondremos una tarea
adicional que recibir de las otras tareas el estado de la cantidad de botellas dentro de la cinta. Si la cinta se
est vaciando demasiado rpido, esta tarea se encargar de inhabilitar los robots llenadores de cajas, si se
est llenando muy rpido pues entonces se deshabilita al robot que despacha botellas hacia la cinta.
Para lograr esto cada vez que un robot ejecuta la tarea de llenado de cajas o despacho de botellas le notifica a
la tarea reguladora la cantidad de botellas que hay en la cinta, con este mecanismo evitamos que la tarea
supervisora tenga que leer el recurso compartido iCantidad, y que tenga que sincronizarse con los robots. La
cola de mensajes tendr dos bytes (aunque solo se necesita uno, despus explico por que hacen falta dos)
donde se reflejar la ltima escritura realizada por cualquiera de los tres robots. Adems, delegaremos en esta
tarea la transmisin de la cantidad de botellas que hay en la cinta. La cantidad media de botellas a tener en la
cinta es 50.
El cdigo:
#include "D:\Documentos\Projects\RTOS\RTOS.h"
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)
#use RTOS(timer=0, minor_cycle=10ms)
int8 semaphore; //Este es nuestro semforo
int8 iCantidad; //Esta es la cantidad de botellas en la estera
//constituye nuestro recurso compartido
#task (rate=50ms, max=10ms)
void R_Despachador();
#task (rate=50ms, max=10ms)
void R_Llenador1();
#task (rate=50ms, max=10ms)
void R_Llenador2();
#task (rate=1s, max=10ms, queue=2) //la cola tiene 2 byte aunque solamente necesitamos 1
void Supervisor();
void main()
{
semaphore = 1; //Solo una tarea puede utilizar el recurso cada vez
iCantidad = 120; //Inicializamos esta variable para tener algunas botellas en
//la estera, normalmente deberiamos tener un sensor que nos reporte
//en algun momento el total de botellas en la cinta, ya que un
//robot revisor de llenado o una persona puede retirar botellas
//de la cinta
//Al comenzar todos
output_bit( PIN_B3,
output_bit( PIN_B4,
output_bit( PIN_B5,

los robots estan deshabilitados


0);
0);
0);

setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
rtos_run();
}
void R_Despachador()

20 de 22

void R_Despachador()
{
//Note como hacemos la sincronizacion fuera de la seccion critica, mas adelante veremos
//que esto no siempre es posible hacerlo o que las cosas se complican un poco mas
//de lo que hemos visto hasta ahora.
rtos_await(iCantidad<100); //Esperemos a que se vacie un poco la cinta
output_bit( PIN_B3, 1); //A partir de aqui, si no se podia antes,

poner botellas

rtos_wait(semaphore); //Reclamamos el recurso y aqu comienza la secc crtica


if(input(PIN_B0)==1)
iCantidad++; //s es didctico y por eso lo he utilizado as.
if(iCantidad >= 100)
output_bit( PIN_B3, 0); //Le decimos al robot despachador que no ponga mas botellas
rtos_msg_send(Supervisor, iCantidad); //Enviamos un mensaje con la cant de botellas
rtos_signal(semaphore); //Liberamos el semforo y aqu se acaba la sec crtica
rtos_yield(); // A dormir por otros 50ms para evitar poner dos veces la misma botella
}
void R_Llenador1()
{
//El robot debe esperar a que la cinta tenga suficientes botellas para sacar antes
//de comenzar a trabajar.
rtos_await(iCantidad>24); //Esperemos a que se llene un poco la cinta
output_bit( PIN_B4, 1); //A partir de aqui, si no se podia antes, sacar botellas
rtos_wait(semaphore);
if(input(PIN_B1)==1)
iCantidad -= 12;
if(iCantidad <= 24)
output_bit( PIN_B4, 0); //Le decimos al robot que no saque mas botellas
rtos_msg_send(Supervisor, iCantidad);

//Enviamos un mensaje con la cant de botellas

rtos_signal(semaphore);
rtos_yield(); // A dormir por otros 50ms para evitar poner dos veces la misma botella
}
void R_Llenador2()
{
rtos_await(iCantidad>24); //Esperemos a que se llene un poco la cinta
output_bit( PIN_B5, 1); //A partir de aqui, si no se podia antes, sacar botellas
rtos_wait(semaphore);
if(input(PIN_B2)==1)
iCantidad -= 12;
if(iCantidad <= 24)
output_bit( PIN_B5, 0); //Le decimos al robot que no saque mas botellas
rtos_msg_send(Supervisor, iCantidad); //Enviamos un mensaje con la cant de botellas
rtos_signal(semaphore);
rtos_yield();
}
void Supervisor()
{
int8 iBotellas;
rtos_await(rtos_msg_poll()>0);

//Esperamos a que haya algun mensaje en la cola

iBotellas = rtos_msg_read(); //Leemos el mensaje

21 de 22

iBotellas = rtos_msg_read(); //Leemos el mensaje


//Lo que hacemos ahora es comprobar la cantidad de botellas que hay en la estera
//y en funcion de eso habilitamos y deshabilitamos las tareas y los robots que hacen falta
//para controlar la cantidad de botellas en la estera
if(iBotellas > 50)
{
output_bit( PIN_B3, 0); //No despachar mas botellas
rtos_disable(R_Despachador);
rtos_enable(R_Llenador1);
rtos_enable(R_Llenador2);
}
else
{
rtos_enable(R_Despachador);

//No llenar mas cajas

output_bit( PIN_B4, 0);


rtos_disable(R_Llenador1);
output_bit( PIN_B5, 0);
rtos_disable(R_Llenador2);
}
printf("%3.0w \r",iBotellas);

//Transmitir la cantidad de botellas

}
Este programa se puede simular con el mismo fichero de Proteus que publiqu antes, noten como la cantidad
de botellas en la cinta transportadora se mantiene sobre las 50 botellas. En el caso de la cola de mensajes
deben especificar n+1 bytes de los que necesiten, la razn no la conozco pero con 1 byte no funciona, debe ser
algn problema de la implementacin de CCS o alguna limitacin de los PIC que obliga a ello.
Bueno espero que les sirva.
PD: Lo de esta embotelladora es un invento, en ningn momento esto se ha probado en una planta de ese
tipo.
El tiempo que utilic para este ejemplo fue de 3:30 horas, incluyendo la redaccin y programacin.
[Volver al ndice]

> Datos de Contacto:


Los datos de contacto de Reinier son los siguientes:
e-mail: reiniertl@gmail.com
Ciudad de La Habana, Cuba
WEB provisional: http://reinier-torres-labrada.neurona.com
[Volver al ndice]

> Bibliografa:
- Sistemas Operativos Diseo e Implementacin. Andrew S. Tanenbaum.
[Volver al ndice]

En construccin...permanentemente.
Pasa en unos das para ver las novedades.

22 de 22

Pasa en unos das para ver las novedades.

www.ucontrol.com.ar | Desarrollo de sistemas de automatizacin y control | Pehuaj - Buenos Aires - Argentina


e-mail: arielpalazzesi@gmail.com

También podría gustarte