# Problema con CCS (Interrupción RDA)



## Wever20 (Abr 30, 2014)

Hola a todos. Estoy desarollando un programa el cual envia datos por puerto serie. Resulta que como no me enviaba los datos (por problemas del compilador seguramente) decidí desinstalarlo y volverlo a instalar. Ahora tengo el MPLAB 8.87, con la ultima version de plugins para utilizar ccs y el compilador CCS V4.140. 

El programa sigue sin limpiar la interrupcion serie se queda colgado en cuanto envia un primer dato por el puero serie. He probado en utilizar cleaner_interrupt(INT_RDA) pero sigue igual... En otros foros no me dan solucion.

Con ésta version de CCS no debería tener problemas no? Como puedo limpiar manualmente el bit RCIF del PIC16F88 para que el flag del puerto serie vuelva a 0?


```
#include <16f88.h>
#device ADC=10 //INDICO EL NÚMERO DE BITS DEL ADC

#include <stdio.h>
#include <string.h>


#fuses HS, NOWDT, NOLVP, NOBROWNOUT, NOPROTECT, PUT
#use delay(clock=8000000)
#use rs232(baud=9600, xmit=PIN_B5, rcv=PIN_B2) //CONFIGURO PUERTO SERIE


//**VARIABLES PARA GESTIONAR LA TRAMA RECIBIDA Y LA TRAMA A ENVIAR POR PUERTO SERIE**//

long valor_adc=0; //Variable para lectura ADC

int P_W=0; //puntero escritura
int P_R=0; //puntero lectura

int i=0; //puntero bucle for
int j=0;

int inicio=0;
int final=0;

char string_valor_adc[]=",0000";//Cadena de caracteres para guardar valor ADC en Carcteres
char trama_entrada[91]={0}; //String para guardar el dato de entrada por UART
char direccion_pic[]="P01";
char tipo_dato[]="$ADQ";
char canal[]="CH0";
//char dato_salida[]="$ADQ,P01,CH0,0000\r\n"; //String para guardar lo que envio por UART
char dato[]="$ADQ,P01,CH0\r";


char midireccion[]="P01";
char micabecera[]="$ADQ";
char miretorno[]="\r";
char misimbolo[]="$";
char micanal0[]="CH0";
char micanal1[]="CH1";
char mitest[]="$TST";


short flag_final=0;
short flag_permiso=0;
short flag_tst=0;
short flag_envio=0;


void lectura(){

 for(P_R=0; P_R<91; P_R++){

  if(trama_entrada[P_R]==misimbolo[0]){

  inicio=P_R;
  
  for(P_R=inicio; P_R<91; P_R++){
 
   if(trama_entrada[P_R]==miretorno[0]){

   P_W=0;
   final=P_R;
   flag_permiso=1;
   break;

    }
 
   }
   break;
  }

 }

}


void escritura(){

for(i=inicio; i<=final; i++){ 
  
dato[j]=trama_entrada[i];
j++;

  }

for(i=0;i<91;i++){
trama_entrada[i]='\0';
}
i=0;
j=0;

return;
}


void procesamiento(){

for(i=0; i<3; i++){

direccion_pic[i]=dato[i+5];

}

direccion_pic[3]='\0';


if(strcmp(direccion_pic, midireccion)==0){

for(i=0; i<4; i++){

tipo_dato[i]=dato[i];

}

tipo_dato[4]='\0';


if(strcmp(tipo_dato, micabecera)==0){

flag_tst=0;

for(i=0; i<3; i++){

canal[i]=dato[i+9];

}

canal[3]='\0';


if(strcmp(canal,micanal0)==0){
 set_adc_channel(0);  
   }
  
  
   else if(strcmp(canal,micanal1)==0){
      set_adc_channel(1);
   }

  
delay_us(20);//retardo para leer ADC
valor_adc=read_adc();//lectura ADC

 }

else if(strcmp(tipo_dato, mitest)==0){

flag_tst=1;

}
flag_envio=1;
}
return;
}


void enviar(){

switch(flag_tst){

case 0:

    sprintf(string_valor_adc,",%04ld",valor_adc);

    output_high(PIN_B0);

    printf("$ADQ,P01,%s,%s\r", canal,string_valor_adc); //Envio un solo String con la direccion, canal CHX y el resutado del PIC por UART.

    output_high(PIN_B0);


    break;


case 1:


    output_high(PIN_B0);

    printf("$TST,P01\r"); //Envio un solo String con la direccion, canal CHX y el resutado del PIC por UART.

    output_high(PIN_B0);
    
    

    break;

}
return;
}


#INT_RDA

void INT_UART() {
if(kbhit()){
trama_entrada[P_W]=getc();

if(trama_entrada[P_W]=='\r'){
P_W=0;
flag_final=1;
}

else{
P_W++;
}

} 

}
void main(){

output_low(PIN_B0);

enable_interrupts(GLOBAL); //HABIlLITO TODAS LAS INTERRUPCIONES GLOBALES
enable_interrupts(INT_RDA); //HABILITO LA INTERRUPCIÓN UART
setup_adc_ports(sAN0|sAN1|sAN2|sAN3|sAN4|sAN5); //INDICO EL PIN A0/A1/A2/A3/A4/A5 COMO ENTRADA ANALÓGICA 
setup_adc(ADC_CLOCK_INTERNAL); //CLOCK INTERNO PARA CONVERSIÓN ADC

 while(1){
if(flag_final==1){
flag_final=0;
 lectura();

if(flag_permiso==1){
 flag_permiso=0;
 escritura();
 procesamiento();
if(flag_envio==1){
flag_envio=0;
enviar();
}
  }
 }
}

}
```


----------



## luis30 (Abr 30, 2014)

Wever20 dijo:


> Hola a todos. Estoy desarollando un programa el cual envia datos por puerto serie. Resulta que como no me enviaba los datos (por problemas del compilador seguramente) decidí desinstalarlo y volverlo a instalar. Ahora tengo el MPLAB 8.87, con la ultima version de plugins para utilizar ccs y el compilador CCS V4.140.
> 
> El programa sigue sin limpiar la interrupcion serie se queda colgado en cuanto envia un primer dato por el puero serie. He probado en utilizar cleaner_interrupt(INT_RDA) pero sigue igual... En otros foros no me dan solucion.
> 
> ...



Yo también estuve batallando con eso, y no hay otra forma que hacer un getc después de la interrupción para que se limpie la interrupción!, no has intentado asi?


```
#include <16f88.h>
#device ADC=10 //INDICO EL NÚMERO DE BITS DEL ADC

#include <stdio.h>
#include <string.h>


#fuses HS, NOWDT, NOLVP, NOBROWNOUT, NOPROTECT, PUT
#use delay(clock=8000000)
#use rs232(baud=9600, xmit=PIN_B5, rcv=PIN_B2) //CONFIGURO PUERTO SERIE


//**VARIABLES PARA GESTIONAR LA TRAMA RECIBIDA Y LA TRAMA A ENVIAR POR PUERTO SERIE**//

long valor_adc=0; //Variable para lectura ADC

int P_W=0; //puntero escritura
int P_R=0; //puntero lectura

int i=0; //puntero bucle for
int j=0;
int1 hay_dato;
int inicio=0;
int final=0;

char string_valor_adc[]=",0000";//Cadena de caracteres para guardar valor ADC en Carcteres
char trama_entrada[91]={0}; //String para guardar el dato de entrada por UART
char direccion_pic[]="P01";
char tipo_dato[]="$ADQ";
char canal[]="CH0";
//char dato_salida[]="$ADQ,P01,CH0,0000\r\n"; //String para guardar lo que envio por UART
char dato[]="$ADQ,P01,CH0\r";


char midireccion[]="P01";
char micabecera[]="$ADQ";
char miretorno[]="\r";
char misimbolo[]="$";
char micanal0[]="CH0";
char micanal1[]="CH1";
char mitest[]="$TST";


short flag_final=0;
short flag_permiso=0;
short flag_tst=0;
short flag_envio=0;


void lectura(){

 for(P_R=0; P_R<91; P_R++){

  if(trama_entrada[P_R]==misimbolo[0]){

  inicio=P_R;
  
  for(P_R=inicio; P_R<91; P_R++){
 
   if(trama_entrada[P_R]==miretorno[0]){

   P_W=0;
   final=P_R;
   flag_permiso=1;
   break;

    }
 
   }
   break;
  }

 }

}


void escritura(){

for(i=inicio; i<=final; i++){ 
  
dato[j]=trama_entrada[i];
j++;

  }

for(i=0;i<91;i++){
trama_entrada[i]='\0';
}
i=0;
j=0;

return;
}


void procesamiento(){

for(i=0; i<3; i++){

direccion_pic[i]=dato[i+5];

}

direccion_pic[3]='\0';


if(strcmp(direccion_pic, midireccion)==0){

for(i=0; i<4; i++){

tipo_dato[i]=dato[i];

}

tipo_dato[4]='\0';


if(strcmp(tipo_dato, micabecera)==0){

flag_tst=0;

for(i=0; i<3; i++){

canal[i]=dato[i+9];

}

canal[3]='\0';


if(strcmp(canal,micanal0)==0){
 set_adc_channel(0);  
   }
  
  
   else if(strcmp(canal,micanal1)==0){
      set_adc_channel(1);
   }

  
delay_us(20);//retardo para leer ADC
valor_adc=read_adc();//lectura ADC

 }

else if(strcmp(tipo_dato, mitest)==0){

flag_tst=1;

}
flag_envio=1;
}
return;
}


void enviar(){

switch(flag_tst){

case 0:

    sprintf(string_valor_adc,",%04ld",valor_adc);

    output_high(PIN_B0);

    printf("$ADQ,P01,%s,%s\r", canal,string_valor_adc); //Envio un solo String con la direccion, canal CHX y el resutado del PIC por UART.

    output_high(PIN_B0);


    break;


case 1:


    output_high(PIN_B0);

    printf("$TST,P01\r"); //Envio un solo String con la direccion, canal CHX y el resutado del PIC por UART.

    output_high(PIN_B0);
    
    

    break;

}
return;
}


#INT_RDA

void INT_UART() {
trama_entrada[P_W]=getc();
hay_dato=1;
}

void main(){

output_low(PIN_B0);

enable_interrupts(GLOBAL); //HABIlLITO TODAS LAS INTERRUPCIONES GLOBALES
enable_interrupts(INT_RDA); //HABILITO LA INTERRUPCIÓN UART
setup_adc_ports(sAN0|sAN1|sAN2|sAN3|sAN4|sAN5); //INDICO EL PIN A0/A1/A2/A3/A4/A5 COMO ENTRADA ANALÓGICA 
setup_adc(ADC_CLOCK_INTERNAL); //CLOCK INTERNO PARA CONVERSIÓN ADC

while(1){
if (hay_dato==1){
hay_dato=0;

if(trama_entrada[P_W]=='\r'){
P_W=0;
flag_final=1;
}

else{
P_W++;
}
}

if(flag_final==1){
flag_final=0;
 lectura();

if(flag_permiso==1){
 flag_permiso=0;
 escritura();
 procesamiento();
if(flag_envio==1){
flag_envio=0;
enviar();
}
  }
 }
}

}
```


----------



## D@rkbytes (Abr 30, 2014)

Wever20 dijo:


> ¿Cómo puedo limpiar manualmente el bit RCIF del PIC16F88 para que el flag del puerto serie vuelva a 0?


No uses KBHIT, ya estás usando la interrupción por AUSART y KBHIT ya no es necesario.
Toma únicamente los datos con GETC o GETS.

Como comentario:
Tu programa corre perfectamente, no se traba dentro de la interrupción.
Usa un LED testigo dentro del bucle while para darte cuenta si sigue corriendo el programa principal.

Puedes usar clear_interrupt (INT_RDA); pero no es necesario.
También puedes declarar el bit RCIF usando esto:
#byte PIR1 = getenv ("SFRIR1")
#bit RCIF = PIR1.5

Pero como te menciono, durante debug el bit RCIF permanece en 0 y siempre sale de la interrupción.

Suerte.


----------



## Wever20 (Abr 30, 2014)

¿¿Cuando fuerzas otra interrupción sigue entrando bien??


----------



## D@rkbytes (Abr 30, 2014)

Wever20 dijo:


> ¿¿Cuando fuerzas otra interrupción sigue entrando bien??


Sip, no existe problema, el programa siempre sigue corriendo tras una interrupción.
De hecho el flag RCIF se limpia cuando se lee el registro RCREG y el flag TXIF cuando se escribe TXREG.

Prueba con este sencillo programa y verás que no existe problema durante la interrupción.

```
#include <16f88.h>
#fuses   NOBROWNOUT
#use     delay (internal = 8MHz)
#use     RS232(UART1)         // AUSART a 9600bps por defecto.

#INT_RDA
void AUSART_ISR (void)
{char b_data;
   
   b_data = getc();           // Guardar el dato de recepción en b_data
   putc(b_data);              // Se reenvía como eco.
   
   if (b_data == 'a')         // Si b_data es la letra "a"...
      output_high(pin_b3);    // RB3 = 1
      
   else                       // Cualquier otro dato diferente a "a"
      output_low(pin_b3);     // RB3 = 0
}


void main (void)
{
   setup_oscillator(OSC_8MHz | OSC_STATE_STABLE);  // oscilador interno estable a 8MHz.
   enable_interrupts(INT_RDA);   // Configurar interrupción por AUSART
   enable_interrupts(GLOBAL);    // Habilitar interrupciones.
   
   output_low(pin_a1);           // RA1 en 0
   output_low(pin_b3);           // RB3 en 0
   
   while (true)
   {
      output_toggle(pin_a1);  // Hacer parpadear un LED por RA1 (LED testigo)
      delay_ms(500);
   }
}
```
Si llegas a tener problemas por no salir de la interrupción, entonces si tienes problemas con el PCWHD.

Suerte.


----------



## Wever20 (May 1, 2014)

Una pregunta de arduino sabes algo? es que quizás el problema sea este ya que comuniqué más de una vez el pic con el arduino DUE que funciona a 3,3v y el pic da 5v quizás he roto algo del chip del arduino DUE que hace que no pueda recibir bien los datos o no pueda enviarlos bien no?

Luego depsués de un reset para un PIC16F88 debería éste ejecutar la rutina de atención a la interrupción serie? Yo tengo puesto que se encienda un led cuando entra en la interrupcion serie (inicialemnte en el void main lo puse en apagado) y justo despues de un reset entra en ella. sé que entra en la interrupcion serie porque el led realiza el delay que le indico. Puede ser que el pic ande mal?


----------



## D@rkbytes (May 1, 2014)

Wever20 dijo:


> Una pregunta de arduino sabes algo? es que quizás el problema sea este ya que comuniqué más de una vez el pic con el arduino DUE que funciona a 3,3v y el pic da 5v quizás he roto algo del chip del arduino DUE que hace que no pueda recibir bien los datos o no pueda enviarlos bien no?


Nop, nunca he pensado trabajar con algún tipo de arduino.


Wever20 dijo:


> quizás  el problema sea este ya que comuniqué más de una vez el pic con el  arduino DUE que funciona a 3,3v y el pic da 5v


El PIC16F88 puede trabajar en un rango de voltajes desde 2.0V hasta 5.5V.
Si alimentas ambos a 3.3V todo debe funcionar sin problemas.



Wever20 dijo:


> Luego después de un reset para un PIC16F88 debería éste ejecutar la  rutina de atención a la interrupción serie?


Sip, un reset reinicia el programa, lo que no se reinicia son los valores de las variables, por eso se deben cargar con un valor inicial al principio del programa.


Wever20 dijo:


> Yo tengo puesto que se  encienda un led cuando entra en la interrupción serie (inicialmente en  el void main lo puse en apagado) y justo después de un reset entra en  ella.
> Sé que entra en la interrupción serie porque el led realiza el  delay que le indico.
> ¿Puede ser que el pic ande mal?


Puede ser que estés teniendo un problema con la frecuencia de trabajo del oscilador.
Este PIC tiene varias frecuencias de trabajo para el oscilador interno.

En tu programa estás usando el oscilador HS para trabajar a 8MHz y esa frecuencia también se puede alcanzar con el oscilador interno.
Pero este PIC cuenta con un sistema llamado Fail Safe Clock Monitor.
Este se encarga de detectar posibles fallas en el oscilador externo, y si está activo por medio del fuse FCMEN entonces cuando el oscilador externo falla, se activa el oscilador interno.
Entonces el programa seguirá corriendo pero a otra frecuencia dependiendo de la configuración del registro OSCCON o de los valores que tome en el POR (Power On Reset)

Dices que el tiempo de encendido del LED es el que tú le estás dando, pero a veces te puedes confundir.
Verifica bien que en realidad el PIC esté trabajando a la velocidad de 8MHz que requieres.
Si puedes utiliza otro PIC para que salgas de dudas en el caso que el PIC esté dañado.

Suerte.


----------



## Wever20 (May 1, 2014)

Es que estoy sospechando que puede ser que el pic esté dañado ya que algunas veces cominiqué dos PIC entre ellos pero me equivoqué y puse el RX de uno en el RX del otro y el TX de uno en el TX del otro. Quizás esto sea un posible mal para el PIC.

Luego le he puesto un oscilador externo de 8Mhz pero los condensadores son de 20pF (no los 27pF que pide el datasheet..) Así que quizás sea una de éstas dos cosas.

Muchas gracias por tu respuesta.


----------



## D@rkbytes (May 1, 2014)

Wever20 dijo:


> Es que estoy sospechando que puede ser que el pic esté dañado ya que algunas veces comuniqué dos PIC entre ellos pero me equivoqué y puse el RX de uno en el RX del otro y el TX de uno en el TX del otro. Quizás esto sea un posible mal para el PIC.


Por eso te puse ese programa de prueba para que vieras físicamente el funcionamiento del PIC.
Esa prueba con el hyperterminal es muy sencilla y puedes verificar recepción y transmisión.

No creo que el PIC se haya dañado por conectar inversamente Tx y Rx, pero con ese programa lo sabrás.


Wever20 dijo:


> Luego le he puesto un oscilador externo de 8Mhz pero los condensadores  son de 20pF (no los 27pF que pide el datasheet.) Así que quizás sea una  de éstas dos cosas.


Ese valor no es muy critico, son 7pF de diferencia por rama que te darán una ligera desviación de la frecuencia.
Lo que si tienes que verificar es que realmente sí esté funcionando el oscilador a cristal.
En todo caso prueba con el interno a 8MHz.


----------



## Wever20 (May 1, 2014)

Bueno amigo la interrupción cuando le envío un caracter sí funciona. Creo que puede ser problema de la placa arduino que no envía correctamente los datos o del micro porque cuando le envío una frase de más de un byte (14 bytes) se queda como "colgado".

Por cierto sabes el MPLAB 8.87 junto con el compilador CCS 4.140 es buena opción para programar pics?

Muchas gracias por tu ayuda D@arkbytes!!


----------



## D@rkbytes (May 1, 2014)

Wever20 dijo:


> Bueno amigo la interrupción cuando le envío un caracter sí funciona. Creo que puede ser problema de la placa arduino que no envía correctamente los datos o del micro porque cuando le envío una frase de más de un byte (14 bytes) se queda como "colgado".


Si tienes problemas cuando envías muchos bytes, entonces debes aumentar la frecuencia de reloj para que puedas también aumentar la velocidad transmisión.
Por ejemplo, a 16 o 20MHz con 19200 o 28800Bps.


Wever20 dijo:


> Por cierto sabes el MPLAB 8.87 junto con el compilador CCS 4.140 es buena opción para programar pics?


Yo prefiero usar el entorno de desarrollo que viene con cada lenguaje de programación.
El MPLAB lo uso únicamente para los lenguajes de programación de Microchip.
A muchos le gusta usar los plug-ins para usar MPLAB con otros lenguajes, yo en lo personal, no.
Tal vez para hacer uso de los debuggers, pero cada entorno tiene el suyo también.
A final de cuentas al compilar un programa de CCS con MPLAB se usa el PCM Compiler, no el MPASM.


Wever20 dijo:


> Muchas gracias por tu ayuda D@rkbytes!!


De nada, suerte.


----------



## felipeduarte1088 (May 4, 2014)

Pasa que estoy haciendo una alarma para una materia de la universidad que se llama Sistemas Digitales 3 y la alarma funciona bien, pero cuando le agrego la rutina de de servicio de la interrupcion del puerto serie simulada funciona bien pero cuando la implemento no funciona se traba y sin esa rutina funciona perfectamente tanto implementada como simulada, les agrego el codigo para ver si me pueden apoyar:




```
#include <16F887.h>                                          
 #FUSES INTRC_IO,NOWDT,NOBROWNOUT
   //Internal RC Osc, no CLKOUT
 #use delay(clock=4000000)
 #use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
 #include <input.c>
 #include <stdlib.h>
 #include <string.h>
 //#INCLUDE<TONES.C>
 #include <flex_lcd.c>  
#include <kbd2.c> 
#USE FAST_IO(B)
#USE FAST_IO(D)
#rom 0x2100={\'1\',\'2\',\'3\',\'4\'}
#define CRISTAL  4000000 
#define FRECUENCIA_TIMER1 (CRISTAL / 4)  // 1 tick = frecuencia del cristal/4
#DEFINE TIEMPO 0X00
int l=0,b;
unsigned int zone=0;
char zonas[8];
INT1 FLAGR=0;
INT J=0;                //CONTADORES PARA EL AREA DE PASSWORD
INT i=0;
//int fc=0;
int8 Timesirena=0;

INT ESTADO,PASSOK;
int time;
CHAR K;
CHAR DATO[4],CLAVE[4],CADENA[7];
ENUM ESTADOS{DESARMADO,ARMANDO,CAMPASS,ARMADO,DISPARADA,DESARMANDO};
CONST CHAR NUMEROS[10]={\'0\',\'1\',\'2\',\'3\',\'4\',\'5\',\'6\',\'7\',\'8\',\'9\'};
VOID PTOB();
//////////////////////////////////////////////////////////////////////////////
//          INTERRUPCION TMR0                                     //
/////////////////////////////////////////////////////////////////////////////
#INT_TIMER0
VOID TIMER0_ISR()
{


OUTPUT_TOGGLE(PIN_E1);
SET_TIMER0(170);

}





//////////////////////////////////////////////////////////////////////////////
//           TERMINA ISR TMR0                                      //
/////////////////////////////////////////////////////////////////////////////

#INT_RDA
ISR_SERIE()
{

GET_STRING(CADENA,7);
IF(CADENA[0]==\'N\' && CADENA[1]==\'P\' && CADENA[2]!=0 && CADENA[3]!=0 && CADENA[4]!=0 && CADENA[5]!=0 )
 {
 WRITE_EEPROM(0X2100,CADENA[2]);
 WRITE_EEPROM(0X2101,CADENA[3]);
 WRITE_EEPROM(0X2102,CADENA[4]);
 WRITE_EEPROM(0X2103,CADENA[5]);
 LCD_PUTC("\\fPASS CAMB /SERIE");
 PRINTF("CONTRASEÑA CAMBIADA\\n\\r");
 DELAY_MS(1000);
 //OUTPUT_A(0XFF);
 }
 IF(ESTADO==DESARMADO && CADENA[0]==\'A\' && CADENA[1]==\'R\' && CADENA[2]==\'M\' && CADENA[3]==\'A\' && CADENA[4]==\'R\'  )
 {
 
 LCD_PUTC("\\f ARMANDO");
 FLAGR=1;

 }
 IF((ESTADO==DISPARADA || ESTADO==ARMADO) && CADENA[0]==\'D\' && CADENA[1]==\'E\' && CADENA[2]==\'S\' && CADENA[3]==\'A\' && CADENA[4]==\'R\' && CADENA[5]==\'M\'&& CADENA[6]==\'A\'  )
 {
 
 LCD_PUTC("\\f DESARMANDO");
 FLAGR=1;

 }
 IF(ESTADO==DESARMADO && CADENA[0]==\'E\' && CADENA[1]==\'N\' && CADENA[2]==\'T\' && CADENA[3]==\'R\' && CADENA[4]==\'A\' && CADENA[5]==\'D\'&& CADENA[6]==\'A\'  )
 {
 
 
 FLAGR=1;
 PTOB();

 }
 }
 //////////////////////////////////////////////////////////////////////////////
//           TERMINA ISR PTO SERIE                                           //
/////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
//           CONFIG TMR1                                                    //
/////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//           TERMINA CONFIG TMR1                                            //
/////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//           CONFIFURACION                                                  //
/////////////////////////////////////////////////////////////////////////////
 void configuracion()
 {
 lcd_init();
 kbd_init();
 SET_TRIS_B(0XFF);
 SET_TRIS_E(0X00);
 OUTPUT_LOW(PIN_E1);
ENABLE_INTERRUPTS(GLOBAL);
ENABLE_INTERRUPTS(INT_RDA);
SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_16);
SET_TIMER0(TIEMPO);

 
 }
 //////////////////////////////////////////////////////////////////////////////
//           TERMINA CONFIGURACION                                      //
/////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
//           INICIO                                                         //
/////////////////////////////////////////////////////////////////////////////
void inicio()
{
lcd_putc("INICIANDO");
//delay_ms(1000);
lcd_putc("\\fINICIANDO.");
//delay_ms(1000);
lcd_putc("\\fINICIANDO..");
//delay_ms(1000);
lcd_putc("\\fINICIANDO...");
//delay_ms(1000);
lcd_putc("\\fINICIANDO....");
//delay_ms(1000);
}
//////////////////////////////////////////////////////////////////////////////
//           TERMINA INICIO                                                 //
/////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//           ESCANEO PUERTO B                                              //
/////////////////////////////////////////////////////////////////////////////
VOID PTOB()
{
















  IF(INPUT(PIN_B0)==0 )
   {

   LCD_GOTOXY(1,2);
   PRINTF(LCD_PUTC,"%C",NUMEROS[1]);
   IF(ESTADO==DISPARADA || ESTADO==ARMADO)
   PRINTF("ZONA %C ABIERTA\\n\\r",NUMEROS[1]);

   }
    else
   {
   LCD_GOTOXY(1,2);
   LCD_PUTC(" ");
   }

   IF(INPUT(PIN_B1)==0)
   {
   LCD_GOTOXY(3,2);
   PRINTF(LCD_PUTC,"%C",NUMEROS[2]);
   IF(ESTADO==DISPARADA || ESTADO==ARMADO)
   PRINTF("ZONA %C ABIERTA\\n\\r",NUMEROS[2]);
   }
   else
   {
   LCD_GOTOXY(3,2);
   LCD_PUTC(" ");
   }
   IF(INPUT(PIN_B2)==0)
   {
   LCD_GOTOXY(5,2);
   PRINTF(LCD_PUTC,"%C",NUMEROS[3]);
   IF(ESTADO==DISPARADA || ESTADO==ARMADO)
   PRINTF("ZONA %C ABIERTA \\n\\r",NUMEROS[3]);
   }
    else
   {
   LCD_GOTOXY(5,2);
   LCD_PUTC(" ");
   }
   IF(INPUT(PIN_B3)==0)
   {
   LCD_GOTOXY(7,2);
   PRINTF(LCD_PUTC,"%C",NUMEROS[4]);
   IF(ESTADO==DISPARADA || ESTADO==ARMADO)
   PRINTF("ZONA %C ABIERTA\\n\\r",NUMEROS[4]);
   }
    else
   {
   LCD_GOTOXY(7,2);
   LCD_PUTC(" ");
   }
   IF(INPUT(PIN_B4)==0)
   {
   LCD_GOTOXY(9,2);
   PRINTF(LCD_PUTC,"%C",NUMEROS[5]);
   IF(ESTADO==DISPARADA || ESTADO==ARMADO)
   PRINTF("ZONA %C ABIERTA\\n\\r",NUMEROS[5]);
   }
    else
   {
   LCD_GOTOXY(9,2);
   LCD_PUTC(" ");
   }
   IF(INPUT(PIN_B5)==0)
   {
   LCD_GOTOXY(11,2);
   PRINTF(LCD_PUTC,"%C",NUMEROS[6]);
   IF(ESTADO==DISPARADA || ESTADO==ARMADO)
   PRINTF("ZONA %C ABIERTA\\n\\r",NUMEROS[6]);
   }
    else
   {
   LCD_GOTOXY(11,2);
   LCD_PUTC(" ");
   }
   IF(INPUT(PIN_B6)==0)
   {
   LCD_GOTOXY(13,2); 
   PRINTF(LCD_PUTC,"%C",NUMEROS[7]);
   IF(ESTADO==DISPARADA || ESTADO==ARMADO)
   PRINTF("ZONA %C ABIERTA\\n\\r",NUMEROS[7]);
   }
    else
   {
   LCD_GOTOXY(13,2);
   LCD_PUTC(" ");
   }
   IF(INPUT(PIN_E2)==0)
   {
   LCD_GOTOXY(15,2);
   PRINTF(LCD_PUTC,"%C",NUMEROS[8]);
   IF(ESTADO==DISPARADA || ESTADO==ARMADO)
   PRINTF("ZONA %C ABIERTA\\n\\r",NUMEROS[8]);
   }
    else
   {
   LCD_GOTOXY(15,2);
   LCD_PUTC(" ");
   }
}

//////////////////////////////////////////////////////////////////////////////
//           TERMINA ESCANEO PUERTO B                                     //
/////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//          SISTEMA DESARMADO                                              //
/////////////////////////////////////////////////////////////////////////////
VOID SISTEMADESARMADO()
{
while(1)
{
lcd_gotoxy(1,2);
   IF(INPUT(PIN_B0) && INPUT(PIN_B1) && INPUT(PIN_B2) && INPUT(PIN_B3) && INPUT(PIN_B4) && INPUT(PIN_B5) && INPUT(PIN_B6) && INPUT(PIN_E2))
   {
   lcd_putc("             ");
   lcd_command(cursor_home);
   LCD_PUTC("PUEDE ARMAR");
   
      DO
      {
      
      K=kbd_getc();
         IF(k==\'A\')
         {  
         ESTADO=ARMANDO;
         
         RETURN;
         } 
         ELSE IF (K==\'B\')
         {
         ESTADO=CAMPASS;
        
         return;
         }
      }  WHILE(K==0 && INPUT(PIN_B0) && INPUT(PIN_B1) && INPUT(PIN_B2) && INPUT(PIN_B3) && INPUT(PIN_B4) && INPUT(PIN_B5) && INPUT(PIN_B6) && INPUT(PIN_E2) && FLAGR==0);
      IF(FLAGR==1)
      {
      ESTADO=ARMADO;
      FLAGR=0;
      RETURN;
      }
   RETURN;
   }
   ELSE
   {
   PTOB();
   lcd_putc("               ");
   lcd_command(cursor_home);
   }
}
}

//////////////////////////////////////////////////////////////////////////////
//           TERMINA SISTEMA DESARMADO                                      //
/////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//           CONTRASEÑA                                      //
/////////////////////////////////////////////////////////////////////////////
void pass()
{

lcd_putc("\\fINGRESE CLAVE");


while(i<4)
         {
            k=kbd_getc(); // leer la tecla presiono 
            if(k!=0)
            {
                     dato[i]=k; 
                     i++;
                     lcd_gotoxy(i,2); // posicion i de la segunda linea 
                     lcd_putc(\'*\');
            }
         }
         
 for(i=0;i<4;i++)
 clave[i]=read_eeprom(i); //guarda la constraseña  en el vector clave 
   
if( dato[0]==clave[0] &&  dato[1]==clave[1] && dato[2]==clave[2] && dato[3]==clave[3])
{  
      lcd_putc("\\fClave Correcta! ");
      lcd_putc("\\nAdelante!!  ");
      PASSOK=1;
      i=0;
      return;
}
   else
   {
   
     lcd_putc("\\fClave incorecta ");
     lcd_putc("\\nINTENTELO DE NUEVO");
     delay_ms(500);
     lcd_putc("\\f");
     i=0;
     j++;
     PASSOK=0;
      
      if(j==3)
      {
        lcd_putc("\\fTecladoBloqueado ");
        lcd_putc("\\n      -_-  ");
        delay_ms(60000);
        j=0;
      }
    }
}
//////////////////////////////////////////////////////////////////////////////
//           TERMINA COMPROBACION CONTRASEÑA                                //
/////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//           CAMBIO CONTRASEÑA                                              //
/////////////////////////////////////////////////////////////////////////////
void cambiopass()
{
if(i!=0)
i=0;
if(J!=0)
{
 j=0;
 return;
}

lcd_putc("\\fINGRESE NUEVO PASS");
while(i<4){

            k=kbd_getc(); // leer la tecla presiono 
            if(k!=0){
                     dato[i]=k; 
                     i++;
                     lcd_gotoxy(i,2); // posicion i de la segunda linea 
                     lcd_putc(\'*\');
                    }
         }
 for(i=0;i<4;i++)
   write_eeprom(0x2100+i,dato[i]);
   i=0;
   return;
}
VOID ESCANEO()
{
   LCD_PUTC("\\fSISTEMA ARMADO");
      DO
      {
      
      K=kbd_getc();
       IF(K==\'A\')
         {
         ESTADO=DESARMANDO;
         }
         ELSE
         {
         ESTADO=DISPARADA;
         }
      }WHILE(K==0 && INPUT(PIN_B0) && INPUT(PIN_B1) && INPUT(PIN_B2) && INPUT(PIN_B3) && INPUT(PIN_B4) && INPUT(PIN_B5) && INPUT(PIN_B6) && INPUT(PIN_E2) && FLAGR==0);
    IF(FLAGR==1)
    {
    FLAGR=0;
    ESTADO=DESARMADO;
    }
      
}
//////////////////////////////////////////////////////////////////////////////
//           TERMINA CAMBIO CONTRASEÑA                                      //
/////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//           INICIA SIRENA                                                  //
/////////////////////////////////////////////////////////////////////////////
VOID SIRENA ()                //LISTO //EN ESTA FUNCION SIEMPRE SE ESTAN MONITOREANDO LAS ENTRADAS 
{           
   
   ENABLE_INTERRUPTS(INT_TIMER0);             
   LCD_PUTC("\\fDISPARADA");         
   LCD_GOTOXY(1,2);
      DO
      {
       
      
       K=kbd_getc();
       PTOB();
       
      
      
       
         }WHILE(k!=\'A\' && FLAGR==0);
         IF(FLAGR==1)
         {
         
         ESTADO=DESARMADO;
         FLAGR=0;
         RETURN;
         }
         
         ESTADO=DESARMANDO;
         
         
} 
     
  //////////////////////////////////////////////////////////////////////////////
//           TERMINA SIRENA                                                  //
/////////////////////////////////////////////////////////////////////////////

void main()
{


PRINTF("INICIANDO \\n");
configuracion();
inicio();
ESTADO=DESARMADO;
WHILE(1)
      {
               switch(ESTADO)
               {
                  case DESARMADO:    
                     OUTPUT_LOW(PIN_E1);
                     disable_interrupts(int_timer0);
                     lcd_command(CURSOR_HOME);
                     lcd_putc("DESARMADO        ");
                     //delay_ms(50);
                     SISTEMADESARMADO();
                     BREAK;
                  case ARMANDO:
                     PASS();
                     IF(PASSOK==1)
                     {
                     ESTADO=ARMADO;
                     PASSOK=0;
                     }
                     ELSE
                     
                     BREAK;
                  case ARMADO:
                       PRINTF("ARMADA\\n\\r");
                       ESCANEO();
                       BREAK;
                  case DISPARADA:
                       SIRENA();
                       BREAK;
                  case DESARMANDO:
                       
                        PASS();
                        IF(PASSOK==1)
                        {
                        
                        
                        ESTADO=DESARMADO;
                        PRINTF("DESARMADA\\n\\r");
                        LCD_GOTOXY(1,2);
                         LCD_PUTC("SISTEMA DESARMADO");  
                         DELAY_MS(1500);
                          LCD_GOTOXY(1,2);
                        LCD_PUTC("                    "); 
                        PASSOK=0;
                        }
                        BREAK;
                  case CAMPASS:
                        pass();                       
                        IF(PASSOK==1)
                        {
                        CAMBIOPASS();
                        ESTADO=DESARMADO;
                         }
                        ELSE
                        ESTADO=DESARMADO;
                        BREAK;                    
               }
               
      }


}
```
 ...


----------



## D@rkbytes (May 5, 2014)

felipeduarte1088 dijo:


> les agrego el codigo para ver si me pueden apoyar


Es mejor que adjuntes tu programa incluyendo librerías, dentro de un archivo comprimido, porque contiene código basura que agrega el navegador y lo hace casi incompresible.
Si tienes la simulación también es necesario que la incluyas.

Saludos.


----------



## Wever20 (May 5, 2014)

D@rkbytes me resulta muy extraño que el pic NUEVO (recien comprado) cuando lo programo solo entra una sola vez a la interrupción! Es que me ocurre exactamente lo mismo... Hay alguna manera de saber si se trata del CCS que tengo o el MPLAB o alguna configuracion que no estoy haciendo bien?? Es que me estoy volviendo absoltamente loco... debería funcionar y no lo hace! ((((


----------



## D@rkbytes (May 5, 2014)

Wever20 dijo:


> D@rkbytes me resulta muy extraño que el pic NUEVO  (recién comprado) cuando lo programo solo entra una sola vez a la  interrupción! Es que me ocurre exactamente lo mismo. ¿Hay alguna manera  de saber si se trata del CCS que tengo o el MPLAB o alguna configuración  que no estoy haciendo bien? Es que me estoy volviendo absolutamente  loco.
> Debería funcionar y no lo hace! ((((


Pues podrías realizar un programa sencillo en otro lenguaje.
¿Ya probaste con el programa que puse?


----------



## Wever20 (May 5, 2014)

D@rkbytes dijo:


> Pues podrías realizar un programa sencillo en otro lenguaje.
> ¿Ya probaste con el programa que puse?



Tu programa en un pic me funcionó pero en éste ya no me funciona es curioso. También debo decirte que el pic lo acabo de conectar unos segundos al revés porque me he confundido... quizás lo he roto.

Otra pregunta, qué otro lengaje puedo utilizar? yo el entorno de trabajo que domino es MPLAB y el programador utilizo el ICD2


----------



## D@rkbytes (May 6, 2014)

Wever20 dijo:


> Tu programa en un pic me funcionó pero en éste ya no me funciona es curioso.


¿Lo probaste con otro PIC16F88 o en otro PIC diferente?



Wever20 dijo:


> También debo decirte que el pic lo acabo de  conectar unos segundos al revés porque me he confundido... Quizás lo he  roto.


Probablemente. 
Puedes realizar una secuencia de comprobación de todos los pines para probar su funcionamiento.
Por hardware puedes verificar el estado con LED's o una punta lógica.


Wever20 dijo:


> Otra pregunta, ¿qué otro lenguaje puedo utilizar? Yo el entorno de trabajo  que domino es MPLAB y el programador utilizo el ICD2


Está bien que uses C, pero debes utilizar el lenguaje del que más tengas conocimientos.
Si conoces PICBasic te recomiendo Proton IDE.
Todos los lenguajes de alto nivel tienen sus pros y sus contras, programando en ensamblador tardarás más en hacer un programa, pero entenderás muchas cosas y sobre todo, cómo funcionan los registros del PIC.
Mira este sencillo ejemplo adjunto en ensamblador para que te des una idea.
El programa está 100% garantizado de que funciona físicamente.
También con este programa puedes comprobar el funcionamiento del AUSART.

Suerte.


----------



## Wever20 (May 7, 2014)

D@rkbytes he probado tu programa y todo anda OK. Mi programa ahora utilizando las funciones PRINTF, SPRINTF y STRCAT anda bien. Resulta que el problema era la version del CCS. La versión en la que han arreglado todo ésto es a partir de la 5.013.

Tengo otro pequeño o gran problema. Resulta que cuando envio primeramente un dato de solicitud del estilo "$ADQ,P01,CH0\r" o "$ADQ,P01,CH1\r" y luego un dato de solicitud del estilo "$TST,P01\r" SOLO ME RESPONDE SIEMPRE al primer dato. Y si lo hago al revés primero le envio "$TST,P01\r" y luego "$ADQ,P01,CHx\r" solo me hace el primero. Y siempre responde solo al primer tipo de dato que le envio. Si luego le envio otro tipo de dato ya no responde.

A qué puede ser debido? Si te vuelvo a dar el código podrías ayudarme a solucionar ésto? Yo ya no  veo cual es el fallo amigo...

La solucion que he probado es meterle un reset_cpu() una vez envio los datos y entonces va bien. Pero no es la mejor solucion esta...


----------



## luis30 (May 7, 2014)

Tal ves se satura el buffer de recepcion y se queda trabado el Pic no has probado limpiarlo despues de recibir algunos caracteres?


----------



## Wever20 (May 7, 2014)

luis30 dijo:


> Tal ves se satura el buffer de recepcion y se queda trabado el Pic no has probado limpiarlo despues de recibir algunos caracteres?



El buffer de recepcion siempre lo estoy leyendo. En principio cuando leo caracteres el buffer se limpia no? Hay alguna intruccion que permite limpiarlo cuando se desee? Hay algo raro porque cuando hago un reset todo anda OK.


----------



## D@rkbytes (May 7, 2014)

Wever20 dijo:


> D@rkbytes he probado tu programa y todo anda OK.
> Mi programa ahora utilizando las funciones PRINTF, SPRINTF y STRCAT anda bien. Resulta que el problema era la versión del CCS. La versión en la que han arreglado todo ésto es a partir de la 5.013.


Sip, cada vez solucionan los bugs que tiene el compilador de CCS.
Ya tiene tiempo que no lo actualizo, ahora tengo la versión 5.021


Wever20 dijo:


> Tengo otro pequeño o gran problema. Resulta que cuando envío  primeramente un dato de solicitud del estilo "$ADQ,P01,CH0\r" o  "$ADQ,P01,CH1\r" y luego un dato de solicitud del estilo "$TST,P01\r"  SOLO ME RESPONDE SIEMPRE al primer dato.
> Y si lo hago al revés primero  le envío "$TST,P01\r" y luego "$ADQ,P01,CHx\r" solo me hace el primero.
> Y siempre responde solo al primer tipo de dato que le envío.
> Si luego le envío otro tipo de dato ya no responde.


Yo tuve un problema similar al trabajar con recepción de cadenas.
Utilice un buffer y las instrucciones gets y strcat.
El resultado fue que al recibir los datos, funcionaba inversamente.
Es decir, si yo mandaba "prender" se activaba la sentencia apagar. 
Hasta ahora no lo he podido resolver.


Wever20 dijo:


> ¿Si te vuelvo a dar el código podrías ayudarme a solucionar ésto?
> Yo ya no  veo cual es el fallo, amigo.
> 
> La solución que he probado es meterle un reset_cpu() una vez envío los  datos y entonces va bien. Pero no es la mejor solución esta.


Pues si quieres lo podría revisar para ver si encuentro algo raro.
Cuando comentan el código es más fácil entender que es lo que quieren hacer. 
Espero que tengas comentados los bloques del programa.


----------



## Wever20 (May 7, 2014)

Bueno YA HE LOGRADO solucionarlo. Resulta que al copilador en CCS no le gusta a veces éste tipo de definiciones *variable[]="hola"*. Sustituyendo ese tipo de definiciones ahora el programa anda perfecto. 

Conclusión, si alguien tiene muchos problemas con un programa que aparentemente está bien, primero que revise todo por si acaso y luego si siguen los problemas que cambie de compilador a una versión más reciente y definir en el programa las variables y demás de forma que el compilador sepa exactamente con que se está trabajando.

Tengo una duda respecto a la conexión de pics con MAX485 te podría consultar?

Quiero conectar tres pics. El pic principal interroga a los otros dos enviandoles una direccion y estos responden si esa direccion coincide con la suya. 

Yo he conectado estos tres pics tal cual dice en las especificaciones. Pero solo me responde uno de ellos, el otro no me responde. Si vuelvo a conectar y desconectar todo a veces me responde el segundo pic pero el primero ya no.

¿Hay que elaborar algún tipo de protocolo para que cada MAX485 sepa cual es su función? o simplemente cambiando el estado de los pines RE/DE ya hay suficiente (porque ésto es lo que realizo en función de si escribo o escucho)?


----------



## felipeduarte1088 (May 15, 2014)

D@rkbytes dijo:


> Es mejor que adjuntes tu programa incluyendo librerías, dentro de un archivo comprimido, porque contiene código basura que agrega el navegador y lo hace casi incompresible.
> Si tienes la simulación también es necesario que la incluyas.
> 
> Saludos.



te agrego todo el codigo, lo raro es que simulado funciona bien pero al momento de implementar no funciona correctamente la comunicacion por el puerto serie, en el archivo adjunto creo que va  hasta la simulacion


----------



## D@rkbytes (May 15, 2014)

felipeduarte1088 dijo:


> lo raro es que simulado funciona bien pero al momento de implementar no funciona correctamente la comunicación por el puerto serie.


No pude compilar bien el código por falta de la librería lcd_flex.c, y las que hay por la red no tienen esta función: lcd_command();  "tuve que omitir la llamada a esas funciones."

Por lo que vi, estás tratando de usar una velocidad de 9600bps a 4MHz con el oscilador interno.
Te recomiendo que subas la frecuencia a 8MHz si piensas usar los 9600bps.


----------



## Psyke (Ago 4, 2015)

Hola, no quise abrir otro hilo porque me pareció mejor publicar acá. Disculpen si hice lo incorrecto.
Estoy trabajando con dos PICs, un 16f877a y un 18f4550. Los estoy comunicando por USART, y el primero es el emisor, y el 18f es el receptor. Bien, en el emisor hice una pequeña estructura para enviar datos constantemente, un while con un putc cada 250 ms, detallado a continuación.
Lo que deseo hacer es un protocolo de comunicación. No sé si se hacen así, pero es lo que se me ocurrió. La idea es tener un arreglo de 5 enteros en el emisor, y el 4 entero tiene el dato que utilizo para realizar acciones.


```
while(true)
{
   for(i=0;i<5;i++)
   {
   putc(DATOS[i]);
   delay_ms(250);
   }
}
```

El emisor ya comprobé que envía bien los datos.
El problema viene con el receptor. He hecho otros programas sencillos y recibía bien, pero con este no quiere funcionar, y lo necesito para continuar con el desarrollo. Lo dejo a continuación.


```
#include <18f4550.h> 
#fuses INTRC_IO,NOWDT,PLL1,CPUDIV1,NOFCMEN,NOPUT,BROWNOUT,NOLVP,NOMCLR,NOWRT,NOCPD
#use delay(clock=8000000) 
#use rs232(baud=9600, xmit=pin_c6, rcv=pin_c7, bits=8, ERRORS)

int DATOS[5]; //0=SINCRO, 1=INICIO, 2=DIREC, 3=DATO, 4=CHECKSUM
int i,j;

#int_RDA
void RDA_isr()
{
   if (i<5)
   {
      DATOS[i] = getc();
      if (DATOS[0] == 0xAA)
      { 
         output_toggle(pin_b7);
         i++;
      }
      else
      {  
         output_toggle(pin_b6);
         i=0;
      }
      //printf("%u",DATOS[i]);
   }
}


void main()
{  
   setup_oscillator(OSC_8MHZ|OSC_INTRC|OSC_PLL_OFF);
   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);
   while(1)
   {
   }
}
```

Poniendo además un output_toggle(pin_b7) dentro de la interrupcion, tampoco producía nada. Lo que me llamaba la atención es que al alimentar el circuito, el LED comenzaba encendido. Así que presumo que entra a la interrupción por una vez y no sale. Y ya estoy tomando el dato que llega, por lo que descarto que el error sea que no se quita el flag de la interrupción. Tambien probé con clear_interrupt(int_rda) y nada.



EDITO: 
Si quito el if(i<5) en la interrupcion, funcionan los LEDs. Pero obviamente deja de cumplir la función que quiero que haga. Resumiendo, se ve que el if(i<5) "no le gusta", pero ya probe con un while(i<5) y tampoco. así que ya no se. Quedaría así


```
#int_RDA
void RDA_isr()
{
      DATOS[i] = getc();
      if (DATOS[0] == 0xAA)
      { 
         output_toggle(pin_b7);
         i++;
      }
      else
      {  
         output_toggle(pin_b6);
         i=0;
      }
      //printf("%u",DATOS[i]);
   clear_interrupt(INT_RDA);
}
```


----------



## D@rkbytes (Ago 4, 2015)

Psyke dijo:


> La idea es tener un arreglo de 5 enteros en el emisor, y el 4 entero tiene el dato que utilizo para realizar acciones.


Es mejor que adquieras los datos con* gets()* y después separes el valor del búfer.

Por ejemplo:

```
[B][COLOR=Red]#INT_RDA[/COLOR]
[COLOR=Blue]void[/COLOR] SDI_RS232 ([COLOR=Blue]void[/COLOR])
{
[COLOR=Purple]// La instrucción gets() retorna hasta que se reciba un Car Return (\r o el ASCCI 13)[/COLOR]
   gets(buffer);            [COLOR=Purple]// Se guardan los datos recibidos en el arreglo.[/COLOR]
   
   flag_rx = [COLOR=SeaGreen]1[/COLOR];             [COLOR=Purple]// Indicar recepción (Búfer leído)[/COLOR][/B]
}
```
Y después obtienes el valor que te interesa: *var_main = buffer[3];    // Cuarta posición del buffer.*


----------



## Psyke (Ago 4, 2015)

Si pongo 
	
	



```
#int_RDA
void RDA_isr()
{
      gets(DATOS);
      if (DATOS[0] == 0xAA && i<5)
      { 
         output_toggle(pin_b7);
         i++;
      }
      else
      {  
         output_toggle(pin_b6);
         i=0;
      }
}
```

Deja de funcionar


----------



## D@rkbytes (Ago 5, 2015)

Para que la instrucción *gets() *retorne, debe recibir la cadena con un \*r* al final.
Esto es lo que le indica a la instrucción el final de la cadena, si no se recibe permanece en un bucle de espera.



			
				CCS Help dijo:
			
		

> Reads characters (using getc()) into the string *until a RETURN  (value 13) is encountered.*



Esto lo comenté en el fragmento de código de ejemplo.


D@rkbytes dijo:


> *// La instrucción gets() retorna hasta que se reciba un Car Return (\r o el ASCII 13)*


----------



## Psyke (Ago 5, 2015)

D@rkbytes dijo:


> Para que la instrucción *gets() *retorne, debe recibir la cadena con un \*r* al final.
> Esto es lo que le indica a la instrucción el final de la cadena, si no se recibe permanece en un bucle de espera.
> 
> 
> ...



Acabo de hacerlo, poniendo un además un "putc(13);" en el emisor, luego de cada dato que envío, pero funciona más feo jajaja, con el getc no he tenido problemas. De todos modos, cuando pueda solucionar el problema que planteé al principio, tendré en cuenta este consejo que me has dado y lo implementaré! Gracias D@rk


----------



## D@rkbytes (Ago 5, 2015)

Pues debe funcionar, ya que no tiene por qué no hacerlo.

Lo que no entiendo es, ¿por qué esperas el valor 170 (0xAA) si sólo mandas valores del 0 al 5?


----------



## Psyke (Ago 5, 2015)

No,no, estoy mandando los valores del arreglo en la posicion del 0 al 4.


```
#include <16f877a.h>
#fuses XT,NOWDT,NOPUT,NOLVP,NOBROWNOUT,NOWRT,NOPROTECT
#use delay(clock=4000000)
#use rs232(baud=9600, xmit= pin_c6, rcv=pin_c7, bits=8)

#define SINCRO    0
#define INICIO    1
#define DIREC     2
#define DATO      3
#define CHECKSUM  4

//int8 DATOS[5] 0=SINCRO, 1=INICIO, 2=DIREC, 3=DATOS, 4=CHECKSUM

int DATOS[5] = {0xAA, 0x7E, 0x66, 0x66};

void main()
{

int i;
DATOS[CHECKSUM] = DATOS[DIREC] + DATOS[DATO];

while(true)
{
   for(i=0;i<5;i++)
   {
   putc(DATOS[i]);
   putc(13);
   delay_ms(250);
   }
}
}
```


----------



## D@rkbytes (Ago 5, 2015)

OK. Me faltó ver esa estructura.

Mira este sencillo ejemplo para que veas que si funciona lo que te menciono.
Tal vez viéndolo puedas encontrar lo que te hace falta.


----------



## Psyke (Ago 5, 2015)

D@rkbytes dijo:


> OK. Me faltó ver esa estructura.
> 
> Mira este sencillo ejemplo para que veas que si funciona lo que te menciono.
> Tal vez viéndolo puedas encontrar lo que te hace falta.



Me parece bastante fácil ese método D@rk. Ahora quiero explicarte algo. Quiero hacer una especie de protocolo (nunca vi como se hace uno, pero me parece que así debería funcionar). La idea es que el emisor envie un 5 enteros, en un arreglo de enteros localizado en el. 
Los tres primeros enteros contienen un valor fijo.

//int8 DATOS[5] 0=SINCRO, 1=INICIO, 2=DIREC, 3=DATOS, 4=CHECKSUM

El primer dato y segundo dato es para indicar que se comenzará el envío. El tercer dato es el de dirección, que si existieran mas PICs recibiendo, cada uno se identificaría por un código diferente. El 4 dato contiene la info, es decir, si recibo (por ejemplo) un "0x56", que el receptor encienda tal cosa, si recibo otra cosa, que haga otra cosa. Y el 5 dato, el checksum, que me permite verificar que se haya recibido bien el arreglo, este lo obtengo haciendo la suma entre el entero de DIRECCION y el de DATOS. 
En cualquier instancia, cuando se reciba un valor que no corresponde con los que deberían llegar, se descarta la cadena entera. Y para no recibir datos de gusto, en el receptor coloco


```
...
void RDA_isr()
{
      gets(DATOS);
      if ([B][COLOR=Red]DATOS[0] == 0xAA [/COLOR][/B]&& i<5)
...
```
para que esté esperando datos hasta recibir un OxAA y ahí continuar la recepción de más datos.

Escribo esto para comentarte, que hasta este momento no quiero cambiar las estructuras que utilizo, porque creo que debería funcionar con un getch, o al menos así lo hizo. Como comentaba anteriormente, solo aparece el problema cuando pongo el if(i<5) dentro de la interrupción. Parezco medio tonto solicitando ayuda y rechazando tu solicitud, pero te agradezco de todas formas, y en caso de que no quede otra solución, haré lo que tú me dices. Lo que no me convence es que debe recibir todo el buffer de una, y si se llega a colar algun dato de alguna interferencia ahi, pierdo toda la cadena de gusto.

---------- Actualizado después de 1 hora ----------

*Asunto solucionado.* La interrupción no entraba en la  estructura if(i<5).... El poco inteligente no inicializó i! Ahora  aprendí qué tan importante es hacerlo. Gracias D@rk por tu apoyo. Como  te comenté, ahora procederé a intentar utilizar la estructura que  propones para continuar el proyecto


----------



## luis30 (Ago 20, 2015)

Podrias intentar con esto

```
#include <18f4550.h> 
#fuses INTRC_IO,NOWDT,PLL1,CPUDIV1,NOFCMEN,NOPUT,BROWNOUT,NOLVP,NOMCLR,NOWRT,NOCPD
#use delay(clock=8000000) 
#use rs232(baud=9600, xmit=pin_c6, rcv=pin_c7, bits=8, ERRORS)

int DATOS[5]; //0=SINCRO, 1=INICIO, 2=DIREC, 3=DATO, 4=CHECKSUM
int j;
int8 i;
int1 hay_dato;

#int_RDA
void RDA_isr()
{
   DATOS[i++]=getc();
   if(i==5){
      i=0;
      hay_dato=1;
   }
}

void main()
{  
  // setup_oscillator(OSC_8MHZ|OSC_INTRC|OSC_PLL_OFF);
   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);
   while(1)
   {
   if(hay_dato==1){
      hay_dato=0;
      
      if (DATOS[0] == 0xAA)
      { 
        //se sigue la comparacion de los demas caracteres esperados
      }
      else
      {  
         output_toggle(pin_b6);
      }
   }
   }
}
```

Leyendo bien seria algo asi, solo cambias por los valores que quieres


```
#include <18f4550.h> 
#fuses INTRC_IO,NOWDT,PLL1,CPUDIV1,NOFCMEN,NOPUT,BROWNOUT,NOLVP,NOMCLR,NOWRT,NOCPD
#use delay(clock=8000000) 
#use rs232(baud=9600, xmit=pin_c6, rcv=pin_c7, bits=8, ERRORS)

int DATOS[5]; //0=SINCRO, 1=INICIO, 2=DIREC, 3=DATO, 4=CHECKSUM
int j;
int8 i;
int1 hay_dato;

#int_RDA
void RDA_isr()
{
   DATOS[i++]=getc();
   output_toggle(pin_b7);
   if(i==5){
      i=0;
      hay_dato=1;
   }
}

void main()
{  
  // setup_oscillator(OSC_8MHZ|OSC_INTRC|OSC_PLL_OFF);
   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);
   while(1)
   {
   if(hay_dato==1){
      hay_dato=0;
      
      if (DATOS[0] == 0xAA && DATOS[1] == INICIO &&  DATOS[2] == DIREC && DATOS[3] == DATO && DATOS[4] == CHECKSUM )
      { 
        //Ejecutar accion1
      }
      else if (DATOS[0] == 0xAA && DATOS[1] == INICIO &&  DATOS[2] == DIREC && DATOS[3] == DATO2 && DATOS[4] == CHECKSUM2 )
      { 
        //Ejecutar accion2
      }
      else
      {  
         output_toggle(pin_b6);
      }
   }
   }
}
```

Pero veo mal tu trasmisor



> #include <16f877a.h>
> #fuses XT,NOWDT,NOPUT,NOLVP,NOBROWNOUT,NOWRT,NOPROTECT
> #use delay(clock=4000000)
> #use rs232(baud=9600, xmit= pin_c6, rcv=pin_c7, bits=8)
> ...


_

Segun yo..

Saludos!!_


----------



## D@rkbytes (Ago 20, 2015)

Si miras el tema anterior, el problema ya fue solucionado.


Psyke dijo:


> *Asunto solucionado.* La interrupción  no entraba en la  estructura if(i<5).... El poco inteligente no  inicializó i! Ahora  aprendí qué tan importante es hacerlo.


Pero te explico lo siguiente...

int DATOS[5] = {0xAA, 0x7E, 0x66, 0x66}; //Solo tienes 4 valores

Aquí mencionas que sólo existen 4 valores.
En los arreglos siempre se debe declarar uno más.
Si declaras 4, el compilador dará la advertencia 229: (Subscript out of range) "Subíndice fuera de rango".

DATOS[CHECKSUM] = DATOS[DIREC] + DATOS[DATO];//Este arreglo no lo usas

Esto no es un arreglo. Es una adquisición de datos sobre una variable que forma parte de un arreglo.
DATOS[CHECKSUM] tendrá la suma de DATOS[DIREC] + DATOS[DATO]

for(i=0;i<5;i++) //Mandas 5 datos Pero solo le diste valor a los primeros 4 no hay un quinto

Esto es debido a la primer explicación.
El valor máximo del bucle "For" debe ser igual a la dimensión del arreglo para que se procesen todos los datos.

putc(13); //Con getc no seria necesario enviarlo

En esto tienes razón, al parecer es algo que a Psyke no le quedó muy claro. 

Saludos.


----------



## luis30 (Ago 20, 2015)

D@rkbytes dijo:


> Si miras el tema anterior, el problema ya fue solucionado.
> 
> Pero te explico lo siguiente...


 Una disculpa la verdad no lei el tema completo, al igual solo es una respuesta con el fin de ayudar.




> int DATOS[5] = {0xAA, 0x7E, 0x66, 0x66}; //Solo tienes 4 valores
> Aquí mencionas que sólo existen 4 valores.
> En los arreglos siempre se debe declarar uno más.
> Si declaras 4, el compilador dará la advertencia 229: (Subscript out of range) "Subíndice fuera de rango".




a lo que me referia no es al tema de la advertencia 229 si no que solo le da valor a los 4 primeros, es decir dato0,dato1,dato2,dato3, pero en el for hace un conteo de 
for(i=0;i<5;i++)  es decir de dato0 a dato4, manda 5 valores pero en la declaracion solo tiene 4 es decir que la condicion del receptor recibia 5 datos no 4 por eso i<5 no se cumple, segun mi logica, enviaria 4datos que el tiene mas uno extraño o repetido al final. 


DATOS[CHECKSUM] = DATOS[DIREC] + DATOS[DATO];//Este arreglo no lo usas



> Esto no es un arreglo. Es una adquisición de datos sobre una variable que forma parte de un arreglo.
> DATOS[CHECKSUM] tendrá la suma de





> DATOS[DIREC] + DATOS[DATO]




si esto ya lo se pero a lo que me refiero es que el envia, dato_ en el for que es la cadena de 5 datos que discutimos anteriormente, no envia datos[checksum], es verdad que me pude haber equivocado tambien.

Saludos Master D@RKbytes._


----------



## D@rkbytes (Ago 20, 2015)

Nop. No prestaste atención a lo que expliqué.
Si existen 4 valores, el arreglo debe tener uno más, o sea; 5 locaciones.
Y si en el bucle "For" no se coloca el valor de la dimensión del arreglo, el 4 valor no será procesado.

En C, la terminación de un arreglo o cadena debe terminar con "Null" ('\0') y este carácter debe ser considerado dentro del arreglo.
Por lo tanto, cuando se declara un arreglo, siempre se debe considerar ese carácter extra.


----------



## unifim (Oct 16, 2015)

hola, una consulta yo tengo implementado el siguiente codigo, pero al simular en proteus, el do while de la interrupcion RDA solo me esta capturando el valor del caracter que llega, la variable data se esta actualizando pero no se adiciona a la variable cadena, es decir no se esta juntando los caracteres en el array cadena. podrian ayuarme con esta duda por favor, lo probe en proteus simulando paso a paso y se ve el array cadena nunca se llena de algun valor. adjunto el codigo y el diagrama en proteus. por fa ayuda. 


```
#include <16f877a.h>
#include <string.h>
#include <stdlib.h>
#fuses NOWDT,HS,NOLVP
#use delay(clock=10M)

#use RS232(baud=9600,XMIT=PIN_C6,RCV=PIN_C7,stream=receptor)

#bit RB0=0x06.0
#bit RB1=0x06.1
#bit RC3=0x07.3
#bit RC4=0x07.4
#bit RC7=0x07.7

int i;
int const length=10;
char data;
char cadena[length];
short flagcomand=0;
signed int16 p=0;

#int_RDA
void  RDA_isr(void) 
{
   do
   {
    data=fgetc(receptor);
    if(data=='\0')
      {
       break;
      }
    else
      {
       cadena[i]=data;
       i++;
      }
   }while(kbhit(receptor));
  flagcomand=1; 
}


void limpiar_buffer()
 {
  int j;
  for(j=0;j<length;j++)
   {
    cadena[j]=0x00;
   }
 }

#INT_EXT                    // directiva de interrupcion por cambio de estado en RB0
void interrupcion_RB0()
{
 if(RB0==1)
   {
    ext_int_edge(H_TO_L);
    if(RB1==1)
      {
       p=p+1;
      }
   }
 else
   {
    ext_int_edge(L_TO_H);
    if(RB1==1)
      {
       p=p-1;
      }
   }
 //putc(p);
 //puts(p);
 printf("\r%Ld",p);
}

void main()
{
  //char valorRec[4];          //variable donde se recibira desde la cadena
  char c;
  int d;
 
 set_tris_b(0xFF);               //configuro portb=in
 set_tris_c(0x80);               //solo el Rx esta como entrada
 RC3=0;
 RC4=0;
 //configuracion pwm
 setup_ccp1(CCP_PWM);
 setup_timer_2(T2_DIV_BY_16,255,1);      //Tpwm=1.63ms--->el ciclo de trabajo sera de 0-255
 set_timer2(0);
 set_pwm1_duty(0);
 enable_interrupts(INT_RDA);
 enable_interrupts(INT_EXT);     //habilito interrupcion RB0
 ext_int_edge(L_TO_H);           //configuro interrupcion por flanco de subida
 enable_interrupts(GLOBAL);      // habilito interrupcion global
 
 
 while(TRUE)
  {
   //gets(valorRec);
   c=cadena[0];
   if(flagcomand==1)
    {
    flagcomand=0;
   switch(c)
     {
      case 's':
        {
         //printf("%3Lu",p);
         //putc(p);
         //printf("%3u",pv);
         //delay_ms(500);
         break;
        }
      case 'i':
         {
          RC3=0;
          RC4=1;
          break;
         }
      case 'd':
         {
          RC3=1;
          RC4=0;
          break;
         }
      default:
         {
          d=atoi(cadena);
          set_pwm1_duty(d);
          //putc(p);
          //printf("%3Lu",p);
          break;
         } 
     }
   limpiar_buffer();
   } 
 }

}
```


----------



## Saint_ (Oct 17, 2015)

Hola unifim, lo que pasa es que cuando la interrupción RDA se activa el dato llegado por el puerto serie se guarda en el vector _cadena_, luego sale de la interrupción y antes de que llegue el o los nuevos datos la subrutina _limpiar_buffer()_ limpia el dato almacenado en el vector _cadena_. Esto sucede para cada uno de los datos que llegan al puerto serie y por eso sucede el problema que comentas.
Una solución al problema sin hacer mucho parche es usar un fin de cadena, por ejemplo '\r'(0x0d):


```
#include <16f877a.h>
#include <string.h>
#include <stdlib.h>
#fuses NOWDT,HS,NOLVP
#use delay(clock=10M)

#use RS232(baud=9600,XMIT=PIN_C6,RCV=PIN_C7,stream=receptor)

#bit RB0=0x06.0
#bit RB1=0x06.1
#bit RC3=0x07.3
#bit RC4=0x07.4
#bit RC7=0x07.7


int const length=10;
char data;
char cadena[length];
short flagcomand=0;
signed int16 p=0;

#int_RDA
void  RDA_isr(void) 
{
   static unsigned int8 i;
   data=fgetc(receptor);
   if(data=='\r')
   {
      cadena[i]=0; //fin de cadena de texto
      i=0;
      flagcomand=1;
   }
   else
   {
      cadena[i++]=data;
   }
}


void limpiar_buffer()
{
   int j;
   for(j=0;j<length;j++)
   {
      cadena[j]=0x00;
   }
}

#INT_EXT                    // directiva de interrupcion por cambio de estado en RB0
void interrupcion_RB0()
{
   if(RB0==1)
   {
      ext_int_edge(H_TO_L);
      if(RB1==1)
      {
         p=p+1;
      }
   }
   else
   {
      ext_int_edge(L_TO_H);
      if(RB1==1)
      {
         p=p-1;
      }
   }
 //putc(p);
 //puts(p);
 printf("\r%Ld",p);
}

void main()
{
  //char valorRec[4];          //variable donde se recibira desde la cadena
   char c;
   int d;
 
   set_tris_b(0xFF);               //configuro portb=in
   set_tris_c(0x80);               //solo el Rx esta como entrada
   RC3=0;
   RC4=0;
   //configuracion pwm
   setup_ccp1(CCP_PWM);
   setup_timer_2(T2_DIV_BY_16,255,1);      //Tpwm=1.63ms--->el ciclo de trabajo sera de 0-255
   set_timer2(0);
   set_pwm1_duty(0);
   enable_interrupts(INT_RDA);
   enable_interrupts(INT_EXT);     //habilito interrupcion RB0
   ext_int_edge(L_TO_H);           //configuro interrupcion por flanco de subida
   enable_interrupts(GLOBAL);      // habilito interrupcion global
  
   while(TRUE)
   {
      //gets(valorRec);
      c=cadena[0];
      if(flagcomand==1)
      {
         flagcomand=0;
         switch(c)
         {
            case 's':
            {
            //printf("%3Lu",p);
            //putc(p);
            //printf("%3u",pv);
            //delay_ms(500);
               break;
            }
            case 'i':
            {
               RC3=0;
               RC4=1;
               break;
            }
            case 'd':
            {
               RC3=1;
               RC4=0;
               break;
            }
            default:
            {
               d=atoi(cadena);
               set_pwm1_duty(d);
             //putc(p);
             //printf("%3Lu",p);
               break;
            } 
         }
         limpiar_buffer();
      } 
   }
}
```


----------



## unifim (Nov 10, 2015)

hola Saint_, muchas gracias por responder. estara atareado con otras cosas y recien me di tiempo para probarlo con lo que mencionas, es correcto tal como indicas, funciona bien muchas gracias por la ayuda. una consulta has hecho comunicacion bluetooth con android studio y el modulo HC-05?? yo realice una app en app inventor y me logro comunicar con mi modulo bluetooth y controlo un pwm y envio de datos, pero ahora intento hacerlo con android studio pero no se bien como hacerlo. adjunto la imagen que hice en app inventor y pretendo hacer la misma funcionalidad pero en android studio, agradeceria si pudieras ayudarme.


----------



## Saint_ (Nov 13, 2015)

Lamentablemente hasta ahora no trabaje con android studio asi que no puedo aconsejarte repecto de ese tema, solamente trabaje con programas bajo windows.


----------



## unifim (Nov 13, 2015)

Ok. comprendo, gracias por las observaciones de la interrupción.


----------

