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:
#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)
#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!