Prueba01A.c
#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;
char cadena_mensaje_disponible[TAM_CADENA];
//-----------------------------------------------------------------------------
//---------------------->Rutinas de RTOS<--------------------------------------
//-----------------------------------------------------------------------------
#define RTOS_USAR_ESTADISTICAS
#define RTOS_TOMAR_ESTADISTICAS
#define RTOS_MINOR_CYCLE 100ms
/* Para el RTOS se utiliza el timer 0 y las tareas tienen un minimo timepo de ejecucion de ...*/
#IFDEF RTOS_USAR_ESTADISTICAS
#use RTOS(timer = 0, minor_cycle = RTOS_MINOR_CYCLE, statistics)
#ELSE
#use RTOS(timer = 0, minor_cycle = RTOS_MINOR_CYCLE)
#ENDIF
#IFDEF RTOS_TOMAR_ESTADISTICAS
//Definicion de estructura para la adquisicion de estadisticas.
struct rtos_estadisticas{
int32 total_ticks; //Numero de tics que la tarea ha tenido.
int16 min_ticks; //Minimo numero de ticks que demanda la tarea al ejecutarse
int16 max_ticks; //Maximo numero de ticks que demanda la tarea al ejecutarse.
int16 hns_per_tick; //???.
} estadisticas_envia_cadena, estadisticas_reloj;
int32 us_max_envia_cadena, us_min_envia_cadena, us_total_envia_cadena, us_max_reloj, us_min_reloj, us_total_reloj;
#ENDIF
//Prototipo de tareas.
#task (rate = 100ms, max = 80ms)
void envia_cadena();
#task (rate = 1s, max = 1ms)
void reloj();
#task (rate = 100ms, max = 1ms)
void lectura_ADC_CH8();
#task (rate = 100ms, max = 1ms)
void lectura_ADC_CH9();
#task (rate = 100ms, max = 1ms)
void lectura_ADC_CH10();
#task (rate = 100ms, max = 1ms)
void lectura_ADC_CH11();
#task (rate = 100ms, max = 1ms, queue = 1)
void mensaje_disponible();
#task (rate = 500ms, max = 1ms)
void tiempo_max_espera_mensaje_RDA();
//Definicion de tareas.
void envia_cadena()
{ /* Esta es habilitada por la tarea reloj, una ves la misma termina de enviar la cadena, se autodeshabilita. */
static char cadena_put[150];
static int longi_char_put, cont_char_put, div_longi_char_put;
rtos_wait(iSem_Cadena_Put);
longi_char_put = 0;
cont_char_put = 0;
div_longi_char_put = 2;
/*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_mensaje_disponible
); //Una vez cargados se borran para ver la frecuencia de lectura.
Canal8 = 0;
Canal9 = 0;
Canal10 = 0;
Canal11 = 0;
sprintf(cadena_mensaje_disponible
,"\r\rNo hay Mensajes"); /*Seccion que envia la mitad de los caracteres y devuelve el prosesador al administrador de tares, para regresar al punto de devolusion, llegado su proximo turno de ejecicion*/
longi_char_put
= strlen(cadena_put
); while(cont_char_put < longi_char_put)
{ putc(cadena_put
[cont_char_put
]); cont_char_put ++;
if(cont_char_put > (int)(longi_char_put / div_longi_char_put))
{ -- div_longi_char_put;
rtos_yield();
}
}
rtos_signal(iSem_Cadena_Put);
rtos_disable(envia_cadena);
}
void reloj()
{ if(++seg >= 60)
{ seg = 0;
if(++min >= 60)
{ min = 0;
if(++hs >= 24)
hs = 0;
}
}
if(iSem_Cadena_Put)
rtos_enable(envia_cadena);
#IFDEF RTOS_USAR_ESTADISTICAS
if(rtos_overrun(envia_cadena))
output_toggle(PIN_B7);
if(rtos_overrun(reloj))
output_toggle(PIN_B7);
#ENDIF
#IFDEF RTOS_TOMAR_ESTADISTICAS
rtos_stats(envia_cadena, &estadisticas_envia_cadena);
us_total_envia_cadena = (int32)(estadisticas_envia_cadena.total_ticks * estadisticas_envia_cadena.hns_per_tick)/10;
us_min_envia_cadena = (int32)(estadisticas_envia_cadena.min_ticks * estadisticas_envia_cadena.hns_per_tick)/10;
us_max_envia_cadena = (int32)(estadisticas_envia_cadena.max_ticks * estadisticas_envia_cadena.hns_per_tick)/10;
rtos_stats(reloj, &estadisticas_reloj);
us_total_reloj = (int32)(estadisticas_reloj.total_ticks * estadisticas_reloj.hns_per_tick)/10;
us_min_reloj = (int32)(estadisticas_reloj.min_ticks * estadisticas_reloj.hns_per_tick)/10;
us_max_reloj = (int32)(estadisticas_reloj.max_ticks * estadisticas_reloj.hns_per_tick)/10;
#ENDIF
}
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_mensaje_disponible,"\r\rMensaje: %u para %u\r\r", iBuffer_RDA[1], rtos_msg_read());
sprintf(cadena_mensaje_disponible
,"\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 mensaje.
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.
//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; //Indica que se esta transmitiendo una cadena.
rtos_run();
}