Autor Tema: Sistemas operativos en PIC  (Leído 101489 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado reiniertl

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 1187
Re: Sistemas operativos en PIC
« Respuesta #60 en: 28 de Febrero de 2007, 16:04:20 »
Lo que más me sorprende es lo rápido que han contestado a este post, pareciera que me estaban esperando, realmente no estoy muy contento con la entrega de hoy, porque estoy un poco cansado del esfuerzo de estos últimos días, pero me gusta cumplir mis promesas así que por eso publiqué hoy.

Las gracias son bienvenidas, el esfuerzo no será en vano y yo mismo estoy aprendiendo mucho para poder escribir estos "articulillos".

Gracias a ustedes por prestar un poco de atención.

Desconectado LABmouse

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3574
    • Juntos es mejor
Re: Sistemas operativos en PIC
« Respuesta #61 en: 28 de Febrero de 2007, 20:12:07 »
Gracias reiniert. Esto es como tener a un perrito esperando por la proxima galletita. !! es muy bueno lo que estas haciendo y te agradezco nuevamente.

Saludos!

Desconectado reiniertl

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 1187
Re: Sistemas operativos en PIC
« Respuesta #62 en: 02 de Marzo de 2007, 14:28:18 »
RTOS mail

Hasta el momento solamente hemos visto mecanismos que nos permiten simplificar el diseño de nuestros programas, pero hoy vamos a ver una nueva potencialidad de los RTOS que es una cuestión realmente novedosa en cuanto la visión de la programación para uC a la cual estamos acostumbrados.

Cuando hacemos una llamada a una función, es frecuente pasarle algún parámetro para que esta pueda hacer su tarea, mientras la función trabaja, nuestro programa espera pacientemente a que la función retorne y nos devuelva el resultado, que puede ser un valor de retorno, un arreglo cambiado o simplemente el cambio en el estado de algún periférico o salidas del uC.

El párrafo anterior describe lo que hace nuestro programa cuando llamamos a una función, sin embargo nunca hemos visto que una función le envíe un dato a otra (no en la llamada a la función, sino fuera de ésta) para que cuando le toque ejecutarse tome esos valores y los procese, y si hay que devolver algún resultado entonces que nos envíe un acuse de recibo. Es lógico que un mecanismo como el que acabo de describir no se utilice en las técnicas de programación anterior porque la ejecución secuencial del código presupone que no se requiera de un mecanismo como este.

Lo más cercano al método descrito en el poner datos en algún lugar para que una función lo procese es el uso de las interrupciones, éstas deben procesar rápidamente el evento de interrupción y pude que pongamos el dato en algún lugar y levantemos una bandera para que cuando a la función 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 función sino para notificárselo 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 algún lugar del programa lo mandamos a convertir; una vez hecha la conversión se produce una interrupción que es atendida en la correspondiente subrutina de atención a esa interrupción; leemos el dato lo ponemos en una variable e incrementamos un contador. Posteriormente le toca ejecutarse a la función que promedia los resultados, ésta comprueba si hay, digamos 200 muestras, si las hay hace el cálculo 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 solución elegante para hacer esto en el contexto de la ejecución de tareas.

Estos mecanismos pueden funcionar también entre funciones pero tendremos el problema de tratar con un montón de estructuras de datos, banderas y contadores, complejas expresiones lógicas a procesar… ¿se acuerdan de eso?

Ahora imagínense hacer todo lo anterior cuando, en vez de llamadas a funciones metidas dentro de un código que se ejecuta más o menos estructuradamente, lo que tenemos es unas cuantas tareas de las que no tenemos un control de cuando ni como se ejecutarán. 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 también es relativamente simple.

Para hacer lo anterior los RTOS implementan un mecanismo de mensajes. Sí, amigos míos, un RTOS implementa una función similar a la de los correos.

El funcionamiento de ese mecanismo es simple, cuando una tarea o subrutina de atención a interrupciones necesita notificarle algo a otra tarea llama a una función que pone el dato en la cola de la tarea en cuestión, cuando a la tarea que recibió el mensaje le toca ejecutarse debe, en algún 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, este post por ejemplo:
  • 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 tratarán de leerlo y poner en práctica los nuevos conocimientos
  • si se sienten impresionados, me escribirán un mensaje a mi correo privado, dándome 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 más 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 código y ejemplos de verdad. :5] :5] :5]
Vale no nos ofusquemos, primero entender bien el concepto, luego ponerlo en práctica. :wink: :wink: :wink:

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 parámetro queue, dentro de la directiva #task, con este parámetro le indicamos al RTOS que reserve memoria y cree una cola de mensajes para la tarea, la declaración de una tarea con cola de mensajes sería como sigue:
Código: C++
  1. #task(rate = 1s, max=20ms, queue=5)
  2. void Tarea1(void);

En la declaración de la tarea el parámetro queue = 5, le dice al compilador que cree una cola de 5 bytes para la Tarea1.

Para el envío y recepción de mensajes tenemos las siguientes funciones:
RTOS_MSG_SEND( )
RTOS_MSG_POLL( )
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 función del RTOS de CCS que puede llamarse desde fuera de una tarea, lo que permite que desde una subrutina de atención a interrupción se le envíen mensajes a una tarea. El parámetro 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 leída.

int RTOS_MSG_POLL(); es la función 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 función 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 función 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 rápido, esta tarea se encargará de inhabilitar los robots llenadores de cajas, si se está llenando muy rápido 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, después explico por que hacen falta dos) donde se reflejará la última escritura realizada por cualquiera de los tres robots. Además, delegaremos en esta tarea la transmisión de la cantidad de botellas que hay en la cinta. La cantidad media de botellas a tener en la cinta es 50.

Código: C++
  1. #include "D:\Documentos\Projects\RTOS\RTOS.h"
  2. #use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)
  3. #use RTOS(timer=0, minor_cycle=10ms)
  4. int8 semaphore; //Este es nuestro semáforo
  5. int8 iCantidad; //Esta es la cantidad de botellas en la estera
  6.                  //constituye nuestro recurso compartido
  7.  
  8.  
  9. #task (rate=50ms, max=10ms)
  10. void R_Despachador();
  11.  
  12. #task (rate=50ms, max=10ms)
  13. void R_Llenador1();
  14.  
  15. #task (rate=50ms, max=10ms)
  16. void R_Llenador2();
  17.  
  18. #task (rate=1s, max=10ms, queue=2) //la cola tiene 2 byte aunque solamente necesitamos 1
  19. void Supervisor();
  20.  
  21. void main()
  22. {
  23.    semaphore = 1; //Solo una tarea puede utilizar el recurso cada vez
  24.    iCantidad = 120; //Inicializamos esta variable para tener algunas botellas en
  25.                     //la estera, normalmente deberiamos tener un sensor que nos reporte
  26.                     //en algun momento el total de botellas en la cinta, ya que un
  27.                     //robot revisor de llenado o una persona puede retirar botellas
  28.                     //de la cinta
  29.  
  30.    //Al comenzar todos los robots estan deshabilitados
  31.    output_bit( PIN_B3, 0);
  32.    output_bit( PIN_B4, 0);
  33.    output_bit( PIN_B5, 0);
  34.  
  35.    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
  36.    rtos_run();
  37.  
  38. }
  39.  
  40.  
  41. void R_Despachador()
  42. {
  43.  //Note como hacemos la sincronizacion fuera de la seccion critica, mas adelante veremos
  44.  //que esto no siempre es posible hacerlo o que las cosas se complican un poco mas
  45.  //de lo que hemos visto hasta ahora.
  46.  rtos_await(iCantidad<100); //Esperemos a que se vacie un poco la cinta
  47.  
  48.  output_bit( PIN_B3, 1); //A partir de aqui, si no se podia antes,  poner botellas
  49.  
  50.  rtos_wait(semaphore); //Reclamamos el recurso y aquí comienza la secc crítica
  51.  
  52.    if(input(PIN_B0)==1)
  53.         iCantidad++;  //sí es didáctico y por eso lo he utilizado así.
  54.  
  55.    if(iCantidad >= 100)
  56.        output_bit( PIN_B3, 0); //Le decimos al robot despachador que no ponga mas botellas
  57.  
  58.  rtos_msg_send(Supervisor, iCantidad); //Enviamos un mensaje con la cant de botellas
  59.  
  60.  rtos_signal(semaphore); //Liberamos el semáforo y aquí se acaba la sec crítica
  61.  
  62.  rtos_yield(); // A dormir por otros 50ms para evitar poner dos veces la misma botella
  63. }
  64.  
  65.  
  66. void R_Llenador1()
  67. {
  68.   //El robot debe esperar a que la cinta tenga suficientes botellas para sacar antes
  69.   //de comenzar a trabajar.
  70.   rtos_await(iCantidad>24); //Esperemos a que se llene un poco la cinta
  71.   output_bit( PIN_B4, 1); //A partir de aqui, si no se podia antes, sacar botellas
  72.  
  73.  rtos_wait(semaphore);
  74.  
  75.  if(input(PIN_B1)==1)
  76.     iCantidad -= 12;
  77.  
  78.  if(iCantidad <= 24)
  79.     output_bit( PIN_B4, 0); //Le decimos al robot que no saque mas botellas
  80.  
  81.  rtos_msg_send(Supervisor, iCantidad);  //Enviamos un mensaje con la cant de botellas
  82.  
  83.  rtos_signal(semaphore);
  84.  
  85.  rtos_yield(); // A dormir por otros 50ms para evitar poner dos veces la misma botella
  86.  
  87. }
  88.  
  89. void R_Llenador2()
  90. {
  91.  rtos_await(iCantidad>24); //Esperemos a que se llene un poco la cinta
  92.  output_bit( PIN_B5, 1); //A partir de aqui, si no se podia antes, sacar botellas
  93.  
  94.  rtos_wait(semaphore);
  95.  
  96.  if(input(PIN_B2)==1)
  97.      iCantidad -= 12;
  98.  
  99.  if(iCantidad <= 24)
  100.     output_bit( PIN_B5, 0); //Le decimos al robot que no saque mas botellas
  101.  
  102.  rtos_msg_send(Supervisor, iCantidad); //Enviamos un mensaje con la cant de botellas
  103.  
  104.  rtos_signal(semaphore);
  105.  
  106.  rtos_yield();
  107. }
  108.  
  109. void Supervisor()
  110. {
  111.  int8 iBotellas;
  112.   rtos_await(rtos_msg_poll()>0);  //Esperamos a que haya algun mensaje en la cola
  113.  
  114.  
  115.  iBotellas = rtos_msg_read(); //Leemos el mensaje
  116.  
  117.  //Lo que hacemos ahora es comprobar la cantidad de botellas que hay en la estera
  118.  //y en funcion de eso habilitamos y deshabilitamos las tareas y los robots que hacen falta
  119.  //para controlar la cantidad de botellas en la estera
  120.  if(iBotellas > 50)
  121.    {
  122.  
  123.      output_bit( PIN_B3, 0); //No despachar mas botellas
  124.      rtos_disable(R_Despachador);
  125.  
  126.      rtos_enable(R_Llenador1);
  127.      rtos_enable(R_Llenador2);
  128.  
  129.    }
  130.   else
  131.    {
  132.     rtos_enable(R_Despachador);  //No llenar mas cajas
  133.  
  134.     output_bit( PIN_B4, 0);
  135.     rtos_disable(R_Llenador1);
  136.  
  137.     output_bit( PIN_B5, 0);
  138.     rtos_disable(R_Llenador2);
  139.    }
  140.  
  141.  
  142.  printf("%3.0w \r",iBotellas);  //Transmitir la cantidad de botellas
  143.  
  144. }
  145.  
  146.  
  147.  

Este programa se puede simular con el mismo fichero de Proteus que publiqué en el post anterior, 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 razón no la conozco pero con 1 byte no funciona, debe ser algún problema de la implementación de CCS o alguna limitación de los PIC que obliga a ello.

Bueno espero que les sirva.

Un saludo Reinier

PD: Lo de esta embotelladora es un invento, en ningún 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 redacción y programación.
« Última modificación: 02 de Marzo de 2007, 15:28:49 por reiniertl »

Desconectado LABmouse

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3574
    • Juntos es mejor
Re: Sistemas operativos en PIC
« Respuesta #63 en: 02 de Marzo de 2007, 15:14:55 »
:-/ :-/ :-/ Impresionante reinirtl, que nivel,.. Que nivel. Esto realmente te abre puertas a la hora de programar. Te parecerá lo mismo de siempre lo que yo digo pero Muchísimas gracias y siempre diré lo mismo MUCHISIMAS GRACIAS por compartirlo. :mrgreen:

Desconectado reiniertl

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 1187
Re: Sistemas operativos en PIC
« Respuesta #64 en: 02 de Marzo de 2007, 15:32:55 »
En la próxima entrega, que espero tenerla para el lunes, veremos como mezclar las interrupciones con el servicio de mensajes para hacer funciones mucho más poderosas que las que implementa CCS para atender a unos cuanto de esos periféricos que tienen servicio de interrupción.

Se llamará: ¡Interrupciones...! ¡A MÍ!

Estoy apurandome un poco porque pronto salgo de vacaciones y estaré ausente unos 15 días.

Reinier

Desconectado micro_cadaver

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2102
    • blog microembebidos
Re: Sistemas operativos en PIC
« Respuesta #65 en: 04 de Marzo de 2007, 05:40:34 »
sigo leyendo tus post y estan muy bien redactados reiniertl  :-), esperamos ansiosos tus siguientes temas  :-/
a cosechar!!!... :P
pic32... ahi voy....
aguante el micro 16f84  !!!!

visita mi pagina: http://www.microembebidos.wordpress.com

Desconectado Y@el

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 415
Re: Sistemas operativos en PIC
« Respuesta #66 en: 04 de Marzo de 2007, 13:34:36 »
WOW... cada vez, me sorprendo mas, aprendo mas,  y me dan ganas de conocer mas. Es que este mundo del RTOS, nuevo para mi hasta hace poco.  Abre la imaginacion a la gran cantidad de cosas que se pueden hacer, y ni que decir de la metodologia q usas. Es como decian por ahi... enseñar a sumar con manzanitas.... Muy buena por cierto....

Saludos, y gracias por tu bien preciado tiempo.

Yoel

Desconectado Darukur

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 464
    • Informacion, recursos y ejemplos para desarrollos con microcontroladores
Re: Sistemas operativos en PIC
« Respuesta #67 en: 05 de Marzo de 2007, 10:45:10 »
Gente, empece a ver el RTOS uCOS-II de micrium.
Seguramente reiniertl lo debes conocer, es un sistema operativo en tiempo real muy bien documentado y con ports para todos los microcontroladores y compiladores conocidos.
Lo mas importante, se ofrece libremente para su uso académico y estudiantil. Su pagina www.micrium.com
Es un sistema operativo preemptivo excelente, entre otras cosas tien certificaciones tan importantes como el aval para uso en aviones, tal vez deberiamos enfocarnos en el para los ejemplos e informacion de este post.

Saludos
« Última modificación: 05 de Marzo de 2007, 10:46:45 por Darukur »
El que no sabe lo que busca no entiende lo que encuentra.
Mi Pagina Web:  http://www.sistemasembebidos.com.ar
Mi foro:             http://www.sistemasembebidos.com.ar/foro/

Desconectado Zaphyrus

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 323
    • Mi blog: Es cuestión de actitud
Re: Sistemas operativos en PIC
« Respuesta #68 en: 06 de Marzo de 2007, 17:34:06 »
Darukur, yo me prendo a la idea. Ya estoy por empezar a leer por segunda vez el libro de uCOS-II para poder usarlo en ARM. Sería bueno empezar un hilo para compartir ideas sobre el tema.

Saludos.
"¿Lo quiere rápido, barato, o bien hecho? Puede elegir dos de las tres cosas." Arthur C. Clarke.
Mi Proyecto Final de Carrera-Microprocesador RISC de 16 bits en HDL: http://martin.calveira.googlepages.com/home
Mi página web o blog: http://es-cuestion-de-actitud.blogspot.com/
Martín Calveira - Zárate - Argentina

Desconectado aitopes

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5102
    • uControl
Re: Sistemas operativos en PIC
« Respuesta #69 en: 07 de Marzo de 2007, 11:14:31 »
Hola amigos!
Es un PLACER contarles que Reinier me ha autorizado a darle forma de guia a todo lo posteado en el hilo (e iremos agregando las futuras entregas), y lo he publicado aquí.

Ademas, el documento esta disponible en formato PDF, son 220Kb y unas 22 paginas de informacion sin desperdicio. Lo pueden bajar desde un link en el mismo lugar que mencione.

Saludos!
Si cualquier habilidad que aprende un niño será obsoleta antes de que la use, entonces, ¿qué es lo que tiene que aprender? La respuesta es obvia:
La única habilidad competitiva a largo plazo es la habilidad para aprender
“. Seymour Papert

Desconectado reiniertl

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 1187
Re: Sistemas operativos en PIC
« Respuesta #70 en: 07 de Marzo de 2007, 16:56:11 »
Hola. Lamento no haber posteado el mensaje sobre las interrupciones y los mensajes

Le problema es que me he complicado un poco con el trabajo y además este viernes me voy de vacaciones y tengo que dejar unas cuantas cosas arregaldas.

Ya casi tengo listo el post, pero es probable que no lo pueda poner hasta mañana. Voy a hacer el mayor esfuerzo posible para poner ese post antes de irme durante una semana completa lejos de la PC, los programas, etc.


Un saludo Reinier

Desconectado reiniertl

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 1187
Lo prometido es deuda: ¡Interrupciones! ¡A MÍ!
« Respuesta #71 en: 08 de Marzo de 2007, 14:17:31 »
¡Interrupciones! ¡A MÍ!

La oración anterior me hace parecer súper héroe. Aunque yo no lo sea, pero con un RTOS y la técnica que veremos hoy, puedo considerarme uno de ellos, al menos en la programación de microcontroladores, y después de hoy, todos podemos aspirar a ser un RTOS PIC SÚPER-HÉROE.

En la entrega anterior estudiamos el paso de mensajes, pero solamente vimos el paso de mensajes entre tareas, esta posibilidad de los RTOS es poderosa y además es el mejor método para pasar información de una tarea a otra, por su sencillez. El paso de mensajes es una necesidad de los SO, porque como expliqué, las tareas no son como las funciones, a las cuales un segmento de código llama y se queda esperando hasta que la función retorna. Entonces como no sabemos en que momento una tarea entrará en su contexto, hay que crear un mecanismo eficiente para que trabaje con los datos que debe servir otra parte del código.

Además de lo anterior, durante todo el cursillo, no hemos visto ni utilizado ninguna interrupción y eso, desde mi punto de vista, no es nada bueno. Los procesos de interrupción nos permiten atender con eficiencia procesos asincrónicos como la conversión analógica, la escritura en memorias EEPROM, las interrupciones externas, la recepción de datos por la USAR, el PSP o el MSSP y también procesos sincrónicos como los que producen los temporizadores.

Pero el uso de un RTOS, nos plantea un dilema con el uso de las interrupciones, ya que en principio cuando utilizamos un RTOS estamos imponiendo que las tareas se van a ejecutar más o menos cada cierto tiempo o que estarán bloqueadas en espera de algo. Por lo tanto, si deseamos que una tarea atienda un proceso asincrónico, ésta debe hacerlo por encuesta, es decir cuando le toque ejecutarse debe comprobar si hay información que procesar. Por otro lado, las interrupciones cuando ocurren, deben ser atendidas en el instante y no cuando al RTOS considere que deben ser atendidas.

Ahora tenemos por un lado una herramienta que nos obliga a utilizar los mecanismos de encuesta, el RTOS, pero que nos ayuda a crear código robusto, eficiente y con velocidad, ventajas nada despreciables. Por otro tenemos un mecanismo para atender procesos que no pueden esperar mucho tiempo en ser atendidos o se corre el riesgo de perder la información, y perder datos es inaceptable para un sistema embebido. Entonces: ¿cómo hacer para aprovechar de las ventajas de ambos?

Para solucionar este problema los RTOS deben permitir que desde una ISR (subrutina de atención a interrupción) podamos pasarle mensajes a cualquier tarea que lo requiera. Vamos a ver esta ventaja con un ejemplito simple.

Supongamos que tenemos una aplicación que tiene varias tareas, entre ellas hay una dedicada a atender la recepción de datos por el puerto serie, ésta tarea se ejecuta con una frecuencia que permite procesar los datos que llegan desde el puerto serie. Un método para hacerlo sería, que cada vez que a la tarea le toque ejecutarse, ésta compruebe si ha llegado un dato al puerto serie para tomarlo y procesarlo. Eso está bien, pero que pasa si mientras la tarea está esperando su turno de ejecutarse llega más de un dato al puerto serie, por supuesto que se perderán datos y esto si que no podemos permitirlo.

La solución al problema anterior es separar la atención de la llegada de datos al puerto serie del procesamiento de los datos recibidos, para ello dejamos en manos de una ISR la lectura del registro de datos y el control de los registros de estado del puerto serie y que la tarea se encargue, cada cierto tiempo, de procesar la información recibida.

El método anterior se puede implementar si el RTOS permite el paso de mensajes desde una ISR hacia una tarea del RTOS, invocando una función adecuada. De esta forma cuando se produzca la interrupción y nos vayamos hasta la ISR, lo que tenemos que hacer es leer el dato y mandarle un mensaje a la tarea, si llega otro dato lo leemos y lo mandamos y así sucesivamente, si la tarea tiene una cola de mensajes suficientemente larga, no debemos perder datos en la recepción por el puerto serie, aún cuando la tarea se ejecute con una frecuencia menor que la de recepción de datos en el puerto serie.

En el ejemplo de hoy vamos a hacer con RTOS algo parecido a lo que hace la función gets(), con la diferencia de que en vez de quedarnos como tontos esperando a que llegue el carácter de fin de línea o retorno de línea vamos a ceder el procesador cada vez que comprobemos que no ha llegado el carácter de terminación adecuado.

Para la implementación utilizaremos dos PIC16F877, en uno de ellos pondremos un programa que envía una cadena por el puerto serie hasta el otro PIC con una frecuencia de 3 segundos. El PIC que recibe los datos, implementa esta funcionalidad mediante la interrupción de la USART, los cuales pone en la cola de una tarea, la cual va reconstruyendo la cadena, hasta que esta está completa y entonces también la envía por su USART.

Este es el código del PIC que envía la cadena
Código: C++
  1. #include "D:\Documentos\Projects\RTOS\RTOS.h"
  2. #use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)
  3. #use RTOS(timer=0, minor_cycle=10ms)
  4.  
  5. int8 iBuffer; //Indice en el buffer para ir llenandolo
  6.  
  7. #task (rate=3s, max=10ms) //Creamos una cola con 10 bytes utiles
  8. void Serial();
  9.  
  10.  
  11. void main()
  12. {
  13.    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
  14.  
  15.    rtos_run();
  16. }
  17.  
  18.  
  19. void Serial()
  20. {
  21. printf("Prueba\n");
  22. }
  23.  
  24.  


y este el del PIC que recibe y retransmite la cadena
Código: C++
  1. #include "D:\Documentos\Projects\RTOS\RTOS.h"
  2. #use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)
  3. #use RTOS(timer=0, minor_cycle=10us)
  4.  
  5.  
  6.  
  7. char cBuffer[17] ; //Aqui guardamos el texto a enviar por el puerto serie
  8. int8 iBuffer; //Indice en el buffer para ir llenandolo
  9.  
  10.  
  11. #task (rate=100us, max=10us, queue = 3) //Creamos una cola con 2 bytes utiles
  12. void Serial();
  13.  
  14. void main()
  15. {
  16.    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
  17.    enable_interrupts(GLOBAL);
  18.    enable_interrupts(INT_RDA);
  19.  
  20.    rtos_run();
  21. }
  22.  
  23.  
  24. void Serial()
  25. {
  26.   char cDato;
  27.   rtos_await(rtos_msg_poll());  //Esperamos hasta que haya algun dato en cola
  28.  
  29.  
  30.   while(rtos_msg_poll())  //Procesamos la cola completa
  31.    {
  32.      cDato = rtos_msg_read();
  33.      cBuffer[iBuffer] = cDato;
  34.      iBuffer++;
  35.    }
  36.  
  37.  
  38.      if(iBuffer == 16 || cDato == '\n') //Si esta toda la cadena la enviamos
  39.         {
  40.          printf("%s\r", cBuffer);
  41.          iBuffer = 0;
  42.         }
  43. }
  44.  
  45.  
  46. #INT_RDA
  47. void fINT_RDA(void)
  48. {
  49.  rtos_msg_send(Serial, getc());  //Tomamos el dato del buffer y lo ponemos en la cola
  50. }
  51.  
  52.  


Aquí está el fichero con los programas y la simulación en proteus: RTOS_ISR

Como verán en la implementación de estos programas he puesto al PIC que retransmite los datos a ejecutar su tarea que procesa los datos recibidos por el puerto serie con una frecuencia mucho mayor que la del PIC que le envía los datos, incluso es mucho más rápida que la velocidad de transmisión recepción de los mensajes, esto me permite tener una cola muy pequeña y que los mensajes no se pierdan.

Yo les aconsejo que jueguen con la frecuencia de ejecución de la tarea, (parámetro rate en la declaración #task) en el PIC que retransmite, y el tamaño de la cola, verán como la cadena a veces se corta, en ocasiones el PIC no retransmite nada. Pero esto les dará una idea de cómo funciona el mecanismo.

Si por ejemplo aumentan la frecuencia de ejecución pueden poner una cola más pequeña, es el código del ejemplo. Si tienen una frecuencia menor, entonces tendrán que poner una cola más grande para que el mensaje quepa completo.

Otra solución a este problema es que la ISR escriba directamente en el Buffer y solamente le mande un mensaje a la tarea cuando se haya recibido el mensaje completo para que esta lo retransmita. Con esto ahorramos memoria RAM, ya que podemos poner una cola muy pequeña, además podemos transferirle a la tarea que atienda los mensajes de error, el procesamiento de comandos y cosas por el estilo. Todo depende de la aplicación y de la imaginación del programador.

Me tomó 1:30 horas escribir el programa y ponerlo a punto, otra hora para escribir el texto y varios días para pensar como enfocarles el problema. Ahora es tarea de ustedes poner todo esto en práctica.

Les propongo que hagan un programa para enviar datos por la USART, similar a printf(), pero más eficiente. Pueden por ejemplo utilizar sprintf(), para poner la cadena en RAM y después que la tarea configure el servicio de interrupciones, mande el primer byte y la ISR envíe el resto, cuando la ISR termine debe notificar a la tarea que ya está en condiciones de enviar más datos, de modo que la tarea le puede crear otra cadena y volver a mandar a transmitir. Notarán que hay que tener unas cuantas cosillas en cuenta, pero es un buen problema para practicar.

Un saludo Reinier.



Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 17654
    • MicroPIC
Re: Sistemas operativos en PIC
« Respuesta #72 en: 08 de Marzo de 2007, 17:21:26 »
Esa misma técnica que utilizas en tu programa la he usado cienes y cienes de veces en programas secuenciales. Lo ideal es que la interrupción esté muy poco tiempo ejecutándose, así que yo preparo los datos en la interrupción para que sean procesados en el bucle principal del programa, tal y como tú has hecho con RTOS.

¿Qué capítulos nos esperan a la vuelta de tus vacaciones?
Un saludo desde Sevilla, España.
Visita MicroPIC                                                                                        ɔ!doɹɔ!ɯ ɐʇ!s!ʌ

Desconectado reiniertl

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 1187
Re: Sistemas operativos en PIC
« Respuesta #73 en: 08 de Marzo de 2007, 18:11:10 »
Los capítulos a las vuelta no son los más alagüeños, voy a tratar la visita de la diosa del infortunio, Némesis.

Los Griegos creian que a los hombres (hablo en sentido genérico) afortunados había que ponerles un límite, por eso crearon a Némesis, la diosa de la fortuna, que podía hacer que los más afortunados conocieran el desasociego y la deseperación, y eso aparece un poco en la programación con SO, vamos a conocer a nuestro enemigo No. 1 el abrazo fatal, y algunas técnicas para salvarnos  de él.

Reinier

Desconectado LABmouse

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3574
    • Juntos es mejor
Re: Sistemas operativos en PIC
« Respuesta #74 en: 09 de Marzo de 2007, 11:31:49 »
Que buena forma de enseñar. Aplausos por ello  :D.