Autor Tema: Implementar yield() en un PIC16F1829  (Leído 4678 veces)

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

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5462
Implementar yield() en un PIC16F1829
« en: 20 de Agosto de 2014, 14:26:33 »
Estoy buscando la manera más sencilla de hacer un programa multitarea en un micro PIC16F1829

Un RTOS como SALVO es bastante completo, pero caro y, aunque ocupa poco, sigue siendo grande para lo que quiero hacer.

La función que busco es sencilla.
Sólo quiero implementar yield() manejando el stack para pasar el turno de ejecución a tres funciones diferentes de manera alternativa.
No necesito prioridades, semáforos ni nada por el estilo.

¿Alguien tiene idea de cómo hacerlo?

Un saludo.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5462
Re: Implementar yield() en un PIC16F1829
« Respuesta #1 en: 20 de Agosto de 2014, 15:15:00 »
El stack del PIC16F1829 es accesible por programa.
Este es un micro avanzado de la familia PIC16F y tiene características propias de la familia PIC18F.

Esto facilita las cosas para comenzar.

yield()  se puede implementar como una función normal:
   La función puede leer del stack la última dirección de salto y la guardarla en un buffer.
   A continuación puede leer la siguiente dirección del buffer  y escribirla en el stack
   Por último, al retornar de la función, salta automáticamente a la siguiente tarea.

Esto es simple y efectivo.

Las dudas que me quedan son:


1.- Al comienzo del programa ¿Cómo inicio el buffer con las diferentes direcciones de salto?
¿Las escribo directamente en el buffer?
¿Implemento una función fork() que llene automáticamente el buffer y devuelva varias veces la ejecución?



2.- ¿Que tipo de task switcher hacer?  cooperativo o preeventivo.
El preeventivo elimina la necesidad de utilizar yield() y cambia de tarea sin que ninguna pueda bloquear el programa, pero es menos eficiente en las esperas.
El cooperativo me parece más efectivo para eliminar tiempos inactivos, pero es más engorroso porque es obligatorio utilizar yield() y porque una tarea mal escrita puede bloquear todo el programa.
¿Alguien puede contarme más argumentos a favor o en contra de los dos métodos?


Saludos.
« Última modificación: 20 de Agosto de 2014, 15:17:53 por Picuino »

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5462
Re: Implementar yield() en un PIC16F1829
« Respuesta #2 en: 20 de Agosto de 2014, 15:23:15 »

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5462
Re: Implementar yield() en un PIC16F1829
« Respuesta #3 en: 20 de Agosto de 2014, 16:17:09 »
Pros y Contras de un sistema preemptive o de Multitarea apropiativa frente a un sistema de multitarea cooperativa:


Preemptive:
Pros:
 - Respuesta en tiempo real de las tareas (sólo depende de la latencia de las interrupciones).

Contras:
 - En cada cada tarea hay que salvar todo el contexto (los valores de los registros principales como W y STATE)
   Esto complica el programa y ocupa más memoria.
 - Existen muchos problemas con el código reentrante.




Cooperativo:
Pros:
 - Es más sencillo programar el sistema operativo (scheduler)
 - Para sistemas sencillos donde el programador tiene todo el control sobre las tareas, es igual o más eficiente que el sistema preemptive.
 - Se simplifican los problemas con las funciones reentrantes, porque estas son interrumpidas sólo en las posiciones permitidas por el programador.
 - Esta multitarea puede funcionar junto con código por interrupciones.
   Este código manejado por interrupciones trabaja en tiempo real y su rendimiento es igual que en el sistema preemptive.

Contras:
 - El tiempo de respuesta de una tarea depende mucho del tiempo de ejecución de las demás tareas.
   Es responsabilidad del programador hacer tareas que ocupen poco tiempo entre llamadas al kernel, para no quitar tiempo a las demás tareas.



Saludos.
« Última modificación: 20 de Agosto de 2014, 16:31:50 por Picuino »

Desconectado jeremylf

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1341
Re: Implementar yield() en un PIC16F1829
« Respuesta #4 en: 22 de Agosto de 2014, 18:48:58 »
No te sirve el RTOS OSA?

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5462
Re: Implementar yield() en un PIC16F1829
« Respuesta #5 en: 22 de Agosto de 2014, 19:20:13 »
No he encontrado el port para el compilador xc8 que estoy utilizando.
En otra ocasión intenté compilarle con otro compilador y me daba problemas.

Al final me he programado un task switcher sencillo con las funciones yield y delay que son las que necesito.

Un saludo.

Desconectado manutek

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 555
Re: Implementar yield() en un PIC16F1829
« Respuesta #6 en: 22 de Agosto de 2014, 20:39:24 »
ni el osa ni el salvo soportan los nuevos compiladores de microchip.....lo que queda como algo parecido para la linea 16F1xxx y para los nuevos compiladores son las corrutinas .

En el link siguiente el MAESTRO jgpeiro06 lo comparte

http://www.todopic.com.ar/foros/index.php?topic=32948.0

Saludos a todos
No es la conciencia del hombre la que determina su ser, sino, por el contrario, es su ser social el que determina su conciencia

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5462
Re: Implementar yield() en un PIC16F1829
« Respuesta #7 en: 23 de Agosto de 2014, 16:35:38 »
Muchas gracias.
Por ahora puedo seguir adelante con el switcher que me he hecho, pero hace tiempo que vengo estudiando el tema de los RTOS y en cuanto pueda volveré a intentar poner en marcha el OSA o las corrutinas (había oído hablar de ellas, pero no las conocía)

Saludos.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5462
Re: Implementar yield() en un PIC16F1829
« Respuesta #8 en: 23 de Agosto de 2014, 19:52:28 »
Dejo aquí el código del switcher con un pequeño ejemplo.

Archivos:

main.c
Código: [Seleccionar]
/****************************************************************************
     Ejemplo de switcher multitarea

 Licencia del código: GNU
 http://www.gnu.org/copyleft/gpl.html
 ****************************************************************************/
#include "xc.h"
#include "stdio.h"
#include "rtos.h"
void init(void);


/****************************************************************************
     Tareas simultaneas y función principal
 ****************************************************************************/

void fa(void) {
   rtos_add_function();    // Añade esta función al planificador de tareas y retorna

   // Bucle principal de la función A
   for(;;) {
      rtos_set_delay(3000);     // Establece el tiempo de espera en milisegundos
      rtos_yield();             // Devuelve la ejecucion al switcher
      printf("fa time=\t%u\r\n", rtos_timer); // Imprime el tiempo actual de la función A
   }
}


void fb(void) {
   rtos_add_function();    // Añade esta función al planificador de tareas y retorna

   // Bucle principal de la función B
   for(;;) {
      rtos_set_delay(5000);     // Establece el tiempo de espera en milisegundos
      rtos_yield();             // Devuelve la ejecucion al switcher
      printf("\tfb time=\t%u\r\n", rtos_timer); // Imprime el tiempo actual de la función A
   }
}


void main(void) {
   init();
   printf("Sistema OK\r\n");

   // Inicializa el planificador de tareas
   rtos_init();

   // Inicia las tareas simultaneas
   fa();
   fb();

   // Ejecuta el planificador de tareas
   rtos_run();  
}


/****************************************************************************
     Configuration Word
 ****************************************************************************/
#pragma config FOSC = INTOSC
#pragma config PLLEN = ON
#pragma config WDTE = OFF
#pragma config LVP = OFF
#pragma config MCLRE = ON


/****************************************************************************
     Rutina de atención a interrupciones
 ****************************************************************************/
void interrupt isr(void) {

   // Interrupciones del Timer 4
   if (PIR1bits.TMR2IF == 1) {
      PIR1bits.TMR2IF = 0;    

      // Contador de tiempo por interrupciones
      rtos_timer++;      
   }

}


/****************************************************************************
     Inicializa el microcontrolador (PIC16F1829)
 ****************************************************************************/
void init(void) {

   // Oscilador interno
   OSCCON = 0b11110000;    // PLL enabled, 8MHz, Internal oscillator

   // Configura el Timer2 para que genere una interrupción cada milisegundo
   // Esta interrupción es necesaria para la función Delay()
   T2CON =  0b00000111;    // Timer2: 1/1 Postcaler, Timer2 ON, 1/64 Prescaler
   PR2   =  124;           // Una interrupción cada milisegundo.
   PIE1bits.TMR2IE = 1;

   // Configura las comunicaciones por UART
   SPBRGL = 207;           // 9600 baud @ 32 MHz
   BAUDCON = 0b01000000;   // 8-bit Baud Rate Generator
   RCSTA = 0b10000000;     // Serial port enable
   TXSTA = 0b00100100;     // 8bits, Transmit Enabled, Async, High speed
   TXREG = 0;
   TRISBbits.TRISB7 = 0;   // TX = out

   // Activa las Interrupciones
   INTCONbits.GIE = 1;     // Enable Global Interrupts
   INTCONbits.PEIE = 1;    // Enable Peripheral Interrupts
}


/****************************************************************************
     Rutina put char, necesaria para que funcione la función printf
 ****************************************************************************/
void putch(char c) {
   while (PIR1bits.TXIF == 0);
   TXREG = c;
}




rtos.c
Código: [Seleccionar]
/****************************************************************************
      SWITCHER MULTITAREA

 Licencia del código: GNU
 http://www.gnu.org/copyleft/gpl.html
 ****************************************************************************/
#include "xc.h"
#include "rtos.h"


/****************************************************************************
     VARIABLES GLOBALES
 ****************************************************************************/
unsigned int rtos_taskbuff_stack[RTOS_MAX_TASK];
unsigned char rtos_taskbuff_state[RTOS_MAX_TASK];
unsigned int rtos_taskbuff_time[RTOS_MAX_TASK];
unsigned char rtos_current_task;
unsigned char rtos_max_task;
unsigned char rtos_intcon;
dir_t dir;
unsigned int rtos_timer;


enum {TASK_RUN, TASK_DELAY};



/****************************************************************************
     DEFINICIÓN DE FUNCIONES
 ****************************************************************************/

void rtos_init(void) {
   rtos_current_task = 0;
   rtos_max_task = 0;
}


void rtos_add_function(void) {
   // Guarda el estado actual de las interrupciones
   rtos_intcon = INTCON;

   // Extraer la dirección de la última llamada (POP)
   INTCONbits.GIE = 0;
   dir.byte[0] = TOSL;
   dir.byte[1] = TOSH;
   STKPTR--;
   INTCON = rtos_intcon;

   // Crea una nueva rutina en el task switcher
   rtos_taskbuff_stack[rtos_max_task] = dir.word;
   rtos_taskbuff_state[rtos_max_task] = TASK_RUN;
   rtos_max_task++;

   return;
}


void rtos_set_delay(unsigned int time) {
   rtos_taskbuff_time[rtos_current_task] = rtos_timer + time;
   rtos_taskbuff_state[rtos_current_task] = TASK_DELAY;
}


void rtos_run(void) {
   // Salta a la función actual guardada en el buffer
   rtos_intcon = INTCON;
   dir.word = rtos_taskbuff_stack[rtos_current_task];
   INTCONbits.GIE = 0;
   TOSL = dir.byte[0];
   TOSH = dir.byte[1];
   INTCON = rtos_intcon;
   return;
}


void rtos_yield(void) {
   // Guarda el estado actual de las interrupciones
   rtos_intcon = INTCON;

   // Salva la dirección de la última llamada
   INTCONbits.GIE = 0;
   dir.byte[0] = TOSL;
   dir.byte[1] = TOSH;
   INTCON = rtos_intcon;
   rtos_taskbuff_stack[rtos_current_task] = dir.word;

   // Busca la siguiente tarea activa
   for(;;) {
      rtos_current_task++;
      if (rtos_current_task >= rtos_max_task)
         rtos_current_task = 0;
      if (rtos_taskbuff_state[rtos_current_task] == TASK_DELAY) {
         if (rtos_taskbuff_time[rtos_current_task] - rtos_timer > 0xEFFF) {
            rtos_taskbuff_state[rtos_current_task] == TASK_RUN;
            break;
         }
      }
      if (rtos_taskbuff_state[rtos_current_task] == TASK_RUN)
         break;
   };

   // Lee la siguiente llamada correcta
   dir.word = rtos_taskbuff_stack[rtos_current_task];

   // Guarda en el stack la dirección de la siguiente rutina
   INTCONbits.GIE = 0;
   TOSL = dir.byte[0];
   TOSH = dir.byte[1];
   INTCON = rtos_intcon;

   // Salta a la siguiente rutina
   return;
}


rtos.h
Código: [Seleccionar]
#ifndef RTOS_H
#define RTOS_H

/****************************************************************************
     DECLARACIÓN DE FUNCIONES
 ****************************************************************************/

void rtos_add_function(void);
void rtos_init(void);
void rtos_run(void);
void rtos_yield(void);
void rtos_set_delay(unsigned int time);


/****************************************************************************
     VARIABLES EXTERNAS CONSTANTES Y TIPOS
 ****************************************************************************/
typedef union {
   unsigned int word;
   unsigned char byte[2];
} dir_t;


#define RTOS_MAX_TASK   8

extern unsigned int rtos_timer;

#endif


Salida por el puerto serie (UART) del programa de ejemplo:
Código: [Seleccionar]
Sistema OK
fa time= 3012
fb time= 5012
fa time= 6026
fa time= 9040
fb time= 10027
fa time= 12054
fb time= 15043
fa time= 15069
fa time= 18084
fb time= 20059
fa time= 21099
fa time= 24114
fb time= 25075
fa time= 27129
fb time= 30091
fa time= 30144
fa time= 33159
fb time= 35107
fa time= 36174
fa time= 39189
fb time= 40123
fa time= 42204
fb time= 45139
fa time= 45219
fa time= 48234
fb time= 50155
fa time= 51249
fa time= 54264
fb time= 55171
fa time= 57279
fb time= 60187
fa time= 60294
fa time= 63309
fb time= 65203
fa time= 788
fa time= 3801
fb time= 4683
fa time= 6815
fb time= 9698
fa time= 9829
fa time= 12843
fb time= 14713
fa time= 15858
fa time= 18873
fb time= 19729
fa time= 21888
fb time= 24745
fa time= 24903
fa time= 27918
fb time= 29761
fa time= 30933
fa time= 33948
fb time= 34777
fa time= 36864
fb time= 39793
fa time= 39879
fa time= 42894
fb time= 44809
fa time= 45909
fa time= 48924
fb time= 49825
fa time= 51939
fa time= 54784
fb time= 54841
fa time= 57799
fb time= 59857
fa time= 60814
fa time= 63829
fb time= 64873
fa time= 1308
fa time= 4322
fb time= 4353
fa time= 7336
fb time= 9368
fa time= 10350


Saludos.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5462
Re: Implementar yield() en un PIC16F1829
« Respuesta #9 en: 23 de Agosto de 2014, 19:57:01 »
Los tiempos extras aparecen por el tiempo que se tarda en imprimir el mensaje.
No es difícil definir una función que temporize un intervalo exacto de tiempo:

Código: [Seleccionar]
void rtos_add_delay(unsigned int time) {
   rtos_taskbuff_time[rtos_current_task] += time;
   rtos_taskbuff_state[rtos_current_task] = TASK_DELAY;
}

Saludos.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 17803
    • MicroPIC
Re: Implementar yield() en un PIC16F1829
« Respuesta #10 en: 24 de Agosto de 2014, 02:03:48 »
 ((:-)) ((:-)) ((:-))
Un saludo desde Sevilla, España.
Visita MicroPIC                                                                                        ɔ!doɹɔ!ɯ ɐʇ!s!ʌ

Desconectado leobianco

  • PIC10
  • *
  • Mensajes: 7
Re: Implementar yield() en un PIC16F1829
« Respuesta #11 en: 04 de Junio de 2015, 01:30:17 »
Hola amigo, les traigo una discusion, para ver si pueden ayudarme a encontrar la falla en el codigo que he planteado.

Resulta que comence a interiorisarme en el tema de los RTOS, siguiendo los hilos de Reiniertl.

La cuestion es que me he planteado los siguientes dos codigos con el fin de familiarizarme con el mecanismo del RTOS de CCS.
Codigo 1:
Código: [Seleccionar]
#include <18F46K20.h>
#device adc=10

#zero_ram

#FUSES noWDT                       //Usare el WDT
#FUSES WDT2048                   //Watch Dog Timer uses 1:2048 Postscale 2.048s
#FUSES INTRC_IO                  //Resistor/Capacitor Osc with CLKOUT
#FUSES PUT                       //Power Up Timer
#FUSES NOBROWNOUT                //No brownout reset
#FUSES NOMCLR                    //Master Clear pin used for I/O
#FUSES NOLVP                     //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST                   //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES PROTECT                   //Code protected from reads
#FUSES CPB                       //Boot Block Code Protected
#FUSES WRTC                      //configuration registers write protected
#FUSES EBTR                      //Memory protected from table reads

#use delay(clock=64000000, restart_wdt)

#use rs232(uart1,baud=9600)//,timeout=10)
//#use rs232(baud=9600, xmit=PIN_A2,rcv=PIN_A3, stream=uart_2)

#include <string.h>

//Constantes.
#define TAM_RDA   4           //Tamaño del Buffer del puerto serie.
#define TAM_CADENA 24
//Variables.
int8 hs, min, seg, iBuffer_RDA[TAM_RDA], iCont_Buffer_RDA, iSem_Port_ADC, iSem_Cadena_Put;
int16 Canal8, Canal9, Canal10, Canal11, mseg;
char cadena[TAM_CADENA];

//-----------------------------------------------------------------------------
//---------------------->Rutinas de RTOS<--------------------------------------
//-----------------------------------------------------------------------------
/* Para el RTOS se utiliza el timer 0 y las tareas tienen un minimo timepo de ejecucion de ...*/
#use RTOS(timer = 0, minor_cycle = 2ms)
//Declaracion de tareas.
#task (rate = 4ms, max = 2ms)
void envia_cadena();

#task (rate = 4ms, max = 1ms)
void reloj();

#task (rate = 10ms, max = 1ms)
void lectura_ADC_CH8();

#task (rate = 10ms, max = 1ms)
void lectura_ADC_CH9();

#task (rate = 10ms, max = 1ms)
void lectura_ADC_CH10();

#task (rate = 10ms, max = 1ms)
void lectura_ADC_CH11();

#task (rate = 10ms, max = 1ms, queue = 1)
void mensaje_disponible();

#task (rate = 500ms, max = 1ms)
void tiempo_max_espera_mensaje_RDA();

//Definicion de tareas.
void envia_cadena()
{  int8 cadena_put[150], longi_char_put = 0, cont_char_put = 0, cadena_put_now[7];
   rtos_wait(iSem_Cadena_Put);
   /*Se Genera la cadena que sera enviada por el puerto serie*/
   sprintf(cadena_put,"\rLa hora del sistemas es:\r%02u:%02u:%02u\rLas mediciones ADC son:\rCH08: %4Lu\rCH09: %4Lu\rCH10: %4Lu\rCH11: %4Lu %s", hs, min, seg, Canal8, Canal9, Canal10, Canal11, cadena);
   //Una vez cargados se borran para ver la frecuencia de lectura.
   Canal8  = 0;
   Canal9  = 0;
   Canal10 = 0;
   Canal11 = 0;
   cadena[0] = '\r';  //Retorno de carro.
   cadena[1] = '\r';  //Retorno de carro.
   cadena[2] = '\0';  //al hacer nulo ,'\0' = 0, este caracter, el printf lo concidera ultimo caracter.
   /*Seccion critica que envia 3 caracteres y devuelve el prosesador al administrador de tares, para regresar al punto de devolosion, llegado su proximo turno de ejecicion*/
   longi_char_put = strlen(cadena_put);
   while(cont_char_put < longi_char_put)
/*   {  sprintf(cadena_put_now,"%c%c%c", cadena_put[cont_char_put], cadena_put[++cont_char_put], cadena_put[++cont_char_put]);
      cont_char_put ++;
      printf(cadena_put_now);
      rtos_yield();
   }
   
 Esta no funciona adecuadamente, al volver luego del yield, se va de la tarea de manerailogica, hay algun error que no esta soportando adecuadamente el compilador.
*/   {  printf("%c%c%c", cadena_put[cont_char_put], cadena_put[++cont_char_put], cadena_put[++cont_char_put]);
      cont_char_put++;
      rtos_yield();
   }
/*
   Esta funciona bien pero es poco elegante.
   while(cont_char_put < longi_char_put)
   {  putc(cadena_put[cont_char_put]);
      cont_char_put++;
      tiem_char_put++;
      if(tiem_char_put >= 6)
      {  tiem_char_put = 0;
         rtos_yield();
      }
   }*/
   rtos_signal(iSem_Cadena_Put);
   rtos_disable(envia_cadena);
}

void reloj()
{  mseg += 4;
   if(mseg >= 1000)
   {  mseg -= 1000;
      if(++seg >= 60)
      {  seg = 0;
         if(++min >= 60)
         {  min = 0;
            if(++hs >= 24)
               hs = 0;
         }
      }
      if(iSem_Cadena_Put)
         rtos_enable(envia_cadena);
   }
}

void lectura_ADC_CH8()
{  rtos_wait(iSem_Port_ADC);    //Comiensa la seccion critica.
   set_adc_channel(8);
   delay_us(20);
   //rtos_yield();      No se justifica entregar el procesador por 20us.
   read_adc(ADC_START_ONLY);
   rtos_await(adc_done());       //devuelve el procesador hasta cuando se termine de realizar la convesion.
   Canal8 = read_adc(ADC_READ_ONLY);
   rtos_signal(iSem_Port_ADC);
}

void lectura_ADC_CH9()
{  rtos_wait(iSem_Port_ADC);    //Comiensa la seccion critica.
   set_adc_channel(9);
   delay_us(20);
   //rtos_yield();      No se justifica entregar el procesador por 20us.
   read_adc(ADC_START_ONLY);
   rtos_await(adc_done());       //devuelve el procesador hasta cuando se termine de realizar la convesion.
   Canal9 = read_adc(ADC_READ_ONLY);
   rtos_signal(iSem_Port_ADC);
}

void lectura_ADC_CH10()
{  rtos_wait(iSem_Port_ADC);    //Comiensa la seccion critica.
   set_adc_channel(10);
   delay_us(20);
   //rtos_yield();      No se justifica entregar el procesador por 20us.
   read_adc(ADC_START_ONLY);
   rtos_await(adc_done());       //devuelve el procesador hasta cuando se termine de realizar la convesion.
   Canal10 = read_adc(ADC_READ_ONLY);
   rtos_signal(iSem_Port_ADC);
}

void lectura_ADC_CH11()
{  rtos_wait(iSem_Port_ADC);    //Comiensa la seccion critica.
   set_adc_channel(11);
   delay_us(20);
   //rtos_yield();      No se justifica entregar el procesador por 20us.
   read_adc(ADC_START_ONLY);
   rtos_await(adc_done());       //devuelve el procesador hasta cuando se termine de realizar la convesion.
   Canal11 = read_adc(ADC_READ_ONLY);
   rtos_signal(iSem_Port_ADC);
}

void mensaje_disponible()
{  rtos_await(rtos_msg_poll());   //Espera a la llegada de un mensaje.
   //Control de checksum, complemento a 2, debe dar cero.
   //Si no da cero, hubo error de trama y se desecha el Mensaje.
   int g = 0, caracter = iBuffer_RDA[0], complementoA2 = 0;
   while(caracter != '\n')
   {  complementoA2 += caracter;
      caracter = iBuffer_RDA[++g];
   }
   if(complementoA2 == 0)
   {  //Carga el mensaje en la cadena, para ser impresa desde la tarea reloj.
//      sprintf(cadena,"\r\rMensaje: %u para %u\r\r", iBuffer_RDA[1], rtos_msg_read());
      sprintf(cadena,"\r\rMensaje: %c para %u", iBuffer_RDA[1], rtos_msg_read());
      //int i=0;
   }
}

void tiempo_max_espera_mensaje_RDA()
{  //Al cumplirse su tiempo, se supone que el mensaje por la UART llego incompleto y no se le pudo dar fin.
   iCont_Buffer_RDA = 0;   //Se reinicia su contador para un nuevo dato.
   rtos_disable(tiempo_max_espera_mensaje_RDA);
}

//---------------------->Fin Rutinas de RTOS<----------------------------------
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//--------------------------->Interrupciones<----------------------------------
//-----------------------------------------------------------------------------
#int_RDA
void RDA_isr(void)
{  //Toma el dato y lo almacena en la Buffer.
   int caracter = getc();
  //Control de Rango del Buffer antes de almacenar.
   if(iCont_Buffer_RDA < TAM_RDA)
   {  iBuffer_RDA[iCont_Buffer_RDA] = caracter;
      //Si es el primer caracter recivido, activa la tarea de tiempo maximo de espera por un mensaje.
      if(iCont_Buffer_RDA == 0)
         rtos_enable(tiempo_max_espera_mensaje_RDA);
      //Se incrementa para un proximo caracter.
      iCont_Buffer_RDA++;
   }
   else
      iCont_Buffer_RDA = 255;
   //Verifica si entro un caracter nueva linea '\n', con una longitud de mensaje valida.
   //Asegurando por lo menos el mensaje mas corto. De lo contrario se sigen esperando mas caracteres.
   if(caracter == '\n' && iCont_Buffer_RDA >= 3)
   {  //Al completarse el mensaje, desactiva la tarea de tiempo maximo de espera por un mensaje.
      rtos_disable(tiempo_max_espera_mensaje_RDA);
      iCont_Buffer_RDA = 0;
      //Envia el nobre del dispocitivo al que se llama indicando que hay un mensaje disponible.
      rtos_msg_send(mensaje_disponible, iBuffer_RDA[0]);
   }
}
//--------------------------->Fin Interrupciones<------------------------------
//-----------------------------------------------------------------------------

void main()
{  clear_interrupt(INT_RDA);
   enable_interrupts(INT_RDA);
   //enable_interrupts(INT_AD);
   enable_interrupts(GLOBAL);
   setup_adc_ports(sAN8|sAN9|sAN10|sAN11|VSS_VDD);
   setup_adc(ADC_CLOCK_INTERNAL|ADC_TAD_MUL_0);
   setup_oscillator(OSC_64MHZ);
   iSem_Port_ADC = 1;         //El recurso ADC, solo puede ser accedido por una tarea.
   iSem_Cadena_Put = 1;
   rtos_run();   
}
Este codigo implementa una tarea llamada reloj, otras 4 para leer los puertos ADC, recibe datos por el puerto serie, etc.

El error se presenta al momento de enviar datos por la UART, en la tarea "enviar_cadena", con la funcion printf, luego de aplicar la funcion rtos_yield(). Justa mente al regresar, para continuar con la ejecucion de la tarea, la misma se sale del bloque while.
He comentado dos secciones de codigo que funcionan, pero mi proposito es entender porque esta funcionando mal el bloque que estoy compilando.

El motivo por el cual estoy configurando "rate" tan altos es por que por un lado estoy exigiendo un poquito la herramienta RTOS para ver como responde y por el otro por que tengo en mente plantear un control de dispaly de 7 segmentos, los cuales necesito refrescarlos a una linda frecuencia, cada unos 4 ms.

El segundo codigo que le envia datos al primero es:
(este no me ha presentado dificultades)
Código: [Seleccionar]
#include <18F46K20.h>
#device adc=10

#zero_ram

#FUSES noWDT                       //Usare el WDT
#FUSES WDT2048                   //Watch Dog Timer uses 1:2048 Postscale 2.048s
#FUSES INTRC_IO                  //Resistor/Capacitor Osc with CLKOUT
#FUSES PUT                       //Power Up Timer
#FUSES NOBROWNOUT                //No brownout reset
#FUSES NOMCLR                    //Master Clear pin used for I/O
#FUSES NOLVP                     //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST                   //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES PROTECT                   //Code protected from reads
#FUSES CPB                       //Boot Block Code Protected
#FUSES WRTC                      //configuration registers write protected
#FUSES EBTR                      //Memory protected from table reads

#use delay(clock=16000000, restart_wdt)

#use rs232(uart1,baud=9600)//,timeout=10)
//#use rs232(baud=9600, xmit=PIN_A2,rcv=PIN_A3, stream=uart_2)

//Constantes.
#define TAM_RDA   4           //Tamaño del Buffer del puerto serie.
//Variables.
int8 i=32;

//---------------------->Rutinas de RTOS<--------------------------------------
/* Para el RTOS se utiliza el timer 0 y las tareas tienen un minimo timepo de ejecucion de 1us*/
#use RTOS(timer = 0, minor_cycle = 3ms)

#task (rate = 2001ms, max = 3ms)
void envia()
{  printf("%c%c%c\n",1,++i,~(int)(1+i)+1);
}

//---------------------->Fin Rutinas de RTOS<----------------------------------

//--------------------------->Interrupciones<----------------------------------
//--------------------------->Fin Interrupciones<------------------------------

void main()
{  setup_oscillator(OSC_16MHZ);
   rtos_run();
}

Espero puedan darme una mano para ver a que se debe que no pueda utilizar la funcion printf como lo estoy planteando.
Saludos y estamos en contacto!
« Última modificación: 04 de Junio de 2015, 01:35:46 por leobianco »