Microcontroladores PIC => * PROYECTOS * => Mensaje iniciado por: escobedov en 26 de Febrero de 2016, 17:46:25
Título: Comunicación Serial entre Pics 18F4550 (Tx) y 16F887 (Rx).
Publicado por: escobedov en 26 de Febrero de 2016, 17:46:25
Hola! Soy nuevo en el foro, estoy desarrollando un proyecto de tableros LED. La idea es cambiar el número desplegado en el tablero de manera inalámbrica. En el control de mano, estoy usando un Pic 18F4550, con su LCD y teclado 4x4. y en el receptor tengo un 16F887. Tengo varios inconvenientes, espero estar en el tema correcto, y sobre todo, espero que me puedan brindar su valiosa ayuda.
1. En el pic de transmisión tenemos el problema que no es estable con la oscilación. Ya sea que le conectemos un oscilador de cristal o lo usemos con el oscilador interno del PIC, al encenderlo, es necesario tocar el pic varias veces para que pueda encender. Esto lo notamos con los mensajes del LCD. Mi pregunta aquí es, ¿Es falta de estabilidad? ¿Si es así, como lo puedo hacer estable?
2. No sé si sea derivado del problema anterior, que si tratamos de comunicar los PIC conectado Tx con Rx y viceversa entre ellos, a veces funciona y a veces no. Los firmwares ya los simulamos en Proteus y funcionan bien.
3. Cuando usamos el oscilador interno, la comunicación no funciona ni en simulación, ni en físico. y si lo ponemos a 8 MHz, el programa corre mas lento que a 4 MHz.
Y ya que no hemos podido hacer funcionar la transmisión alámbricamente, no hemos podido hacer pruebas con los Xbee. Así que las preguntas de ello las guardaré para cuando podamos hacerlo funcionar directo.
Espero que me puedan orientar con esto. Estuve leyendo algunos temas, pero en ninguno vi algo que me orientara con esto. De antemano se los agradezco!
Título: Re:Comunicación Serial entre Pics 18F4550 (Tx) y 16F887 (Rx).
Publicado por: elreypic2 en 26 de Febrero de 2016, 18:41:31
Que tal escobedov,
Podrias subir el codigo que estas usando y los esquemáticos de tu proyecto? De esa manera nos será más fácil ayudarte.
Elreypic.
Título: Re:Comunicación Serial entre Pics 18F4550 (Tx) y 16F887 (Rx).
Publicado por: KILLERJC en 26 de Febrero de 2016, 19:20:54
Citar
3. Cuando usamos el oscilador interno, la comunicación no funciona ni en simulación, ni en físico. y si lo ponemos a 8 MHz, el programa corre mas lento que a 4 MHz.
Eso parece ser mas problema del programa.
Título: Re:Comunicación Serial entre Pics 18F4550 (Tx) y 16F887 (Rx).
Publicado por: escobedov en 26 de Febrero de 2016, 19:44:44
Este es el del transmisor
/*Teclado controlador de tableta de precios /
// ESTADOS Enumeraciones para etiquetas de cada estado. enum tipoEdos{ INICIO=1, DIESEL, MAGNA, MENU, PREMIUM, ILUM};
//Declaración del puerto para el teclado 4x4 char keypadPort at PORTD; // LCD module connections sbit LCD_RS at LATB4_bit; sbit LCD_EN at LATB5_bit; sbit LCD_D4 at LATB0_bit; sbit LCD_D5 at LATB1_bit; sbit LCD_D6 at LATB2_bit; sbit LCD_D7 at LATB3_bit;
sbit LCD_RS_Direction at TRISB4_bit; sbit LCD_EN_Direction at TRISB5_bit; sbit LCD_D4_Direction at TRISB0_bit; sbit LCD_D5_Direction at TRISB1_bit; sbit LCD_D6_Direction at TRISB2_bit; sbit LCD_D7_Direction at TRISB3_bit; // End LCD module connections
///////////////////////////////////////////////////////////////////////////////// //Constantes //Tabla para dexcodificar teclado // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 //const char tablaKB[18]= { 0,'1','2','3','A','4','5','6','B','7','8','9','C','*','0','#','D' }; const char tablaKB[18]= { 0,'D','#','0','*','C','9','8','7','B','6','5','4','A','3','2','1' }; //Declaracion de funciones void pruebas(); //Para hacer pruebas parciales mientras se desarrolla el sistema.
void inic_UART(){ //Inicializa puerto serie Tx y Rx UART1_Init(9600); // Inicializa módulo UART at 9600 bps Delay_ms(1000); // Espera para que el UART se estabilice. PIR1.RCIF=0; //Borra solicitud de interrupción de RX. PIE1.RCIE=1; // Interrupción por RX habilitada. }
void inicPuertos(){
TRISA=0;TRISB=0; // Puertos A y B Digitales TRISE=0; // Bits 0,1,2 de PORTE como salidas PORTE=0; PORTA=0XFF; TRISC=0X80; //DECLARACIÓN DE PUERTO SERIE// Lcd_Init(); //Inicializa el LCD. Keypad_Init(); // Inicia Teclado . inic_UART(); //Inicializa Comunicacion RS232.
}
//Función para LimpiarPantalla. void limpiaLCD(void){ Lcd_Cmd(_LCD_CLEAR); Lcd_Cmd(_LCD_RETURN_HOME); }
//Rutina que lee el teclado no bloqueante que entrega valor // decodificado de tecla de acuerdo a la tabla tablaKB. char leeTeclado(){ return tablaKB[Keypad_Key_Press()]; }
// Funciones correspondientes a los estados.///// enum tipoEdos inicio(){ limpiaLCD(); Lcd_Out(1, 4,"HALLTECH"); Lcd_Out(2, 4,"SOLUTION"); Delay_ms(500); return MENU; }
enum tipoEdos ilum(){
char i=0;
limpiaLCD(); Lcd_Out(1, 1, "NIV. ILUMINACION"); Delay_ms(500); ilumin[0]=0x04; ilumin[3]=0xFF; ilumin[4]=0xFF; ilumin[5]=0x04; for(i=1; i<3; i++){ while(!leeTeclado()) // Espera a que se presione una tecla.
if (leeTeclado()=='1'){ interpretanum=0x01; Lcd_Out(2, i,"1");} if (leeTeclado()=='2'){ interpretanum=0x02; Lcd_Out(2, i,"2");} if (leeTeclado()=='3'){ interpretanum=0x03; Lcd_Out(2, i,"3");} if (leeTeclado()=='4'){ interpretanum=0x04; Lcd_Out(2, i,"4");} if (leeTeclado()=='5'){ interpretanum=0x05; Lcd_Out(2, i,"5");} if (leeTeclado()=='6'){ interpretanum=0x06; Lcd_Out(2, i,"6");} if (leeTeclado()=='7'){ interpretanum=0x07; Lcd_Out(2, i,"7");} if (leeTeclado()=='8'){ interpretanum=0x08; Lcd_Out(2, i,"8");} if (leeTeclado()=='9'){ interpretanum=0x09; Lcd_Out(2, i,"9");} if (leeTeclado()=='0'){ interpretanum=0x00; Lcd_Out(2, i,"0");}
for(i=1; i<=4; i++){ while(!leeTeclado()) // Espera a que se presione una tecla.
if (leeTeclado()=='1'){ interpretanum=0x01; Lcd_Out(2, i,"1");} if (leeTeclado()=='2'){ interpretanum=0x02; Lcd_Out(2, i,"2");} if (leeTeclado()=='3'){ interpretanum=0x03; Lcd_Out(2, i,"3");} if (leeTeclado()=='4'){ interpretanum=0x04; Lcd_Out(2, i,"4");} if (leeTeclado()=='5'){ interpretanum=0x05; Lcd_Out(2, i,"5");} if (leeTeclado()=='6'){ interpretanum=0x06; Lcd_Out(2, i,"6");} if (leeTeclado()=='7'){ interpretanum=0x07; Lcd_Out(2, i,"7");} if (leeTeclado()=='8'){ interpretanum=0x08; Lcd_Out(2, i,"8");} if (leeTeclado()=='9'){ interpretanum=0x09; Lcd_Out(2, i,"9");} if (leeTeclado()=='0'){ interpretanum=0x00; Lcd_Out(2, i,"0");}
enum tipoEdos premium(){ char i; limpiaLCD(); Lcd_Out(1, 2, "PREC. PREMIUM"); Delay_ms(500); precio2[0]=0x02; precio2[5]=0x02; for(i=1; i<=4; i++){ while(!leeTeclado()) // Espera a que se presione una tecla.
if (leeTeclado()=='1'){ interpretanum=0x01; Lcd_Out(2, i,"1");} if (leeTeclado()=='2'){ interpretanum=0x02; Lcd_Out(2, i,"2");} if (leeTeclado()=='3'){ interpretanum=0x03; Lcd_Out(2, i,"3");} if (leeTeclado()=='4'){ interpretanum=0x04; Lcd_Out(2, i,"4");} if (leeTeclado()=='5'){ interpretanum=0x05; Lcd_Out(2, i,"5");} if (leeTeclado()=='6'){ interpretanum=0x06; Lcd_Out(2, i,"6");} if (leeTeclado()=='7'){ interpretanum=0x07; Lcd_Out(2, i,"7");} if (leeTeclado()=='8'){ interpretanum=0x08; Lcd_Out(2, i,"8");} if (leeTeclado()=='9'){ interpretanum=0x09; Lcd_Out(2, i,"9");} if (leeTeclado()=='0'){ interpretanum=0x00; Lcd_Out(2, i,"0");}
for(i=1; i<=4; i++){ while(!leeTeclado()) // Espera a que se presione una tecla.
if (leeTeclado()=='1'){ interpretanum=0x01; Lcd_Out(2, i,"1");} if (leeTeclado()=='2'){ interpretanum=0x02; Lcd_Out(2, i,"2");} if (leeTeclado()=='3'){ interpretanum=0x03; Lcd_Out(2, i,"3");} if (leeTeclado()=='4'){ interpretanum=0x04; Lcd_Out(2, i,"4");} if (leeTeclado()=='5'){ interpretanum=0x05; Lcd_Out(2, i,"5");} if (leeTeclado()=='6'){ interpretanum=0x06; Lcd_Out(2, i,"6");} if (leeTeclado()=='7'){ interpretanum=0x07; Lcd_Out(2, i,"7");} if (leeTeclado()=='8'){ interpretanum=0x08; Lcd_Out(2, i,"8");} if (leeTeclado()=='9'){ interpretanum=0x09; Lcd_Out(2, i,"9");} if (leeTeclado()=='0'){ interpretanum=0x00; Lcd_Out(2, i,"0");}
if(leeTeclado()=='A'){ //Comando para cambiar precio de magna return MAGNA; } if(leeTeclado()=='B'){ //Comando para cambiar precio de premium return PREMIUM; } if(leeTeclado()=='C'){ //Comando para cambiar precio de diesel return DIESEL; } if(leeTeclado()=='D'){ //Comando para cambiar ilumnación return ILUM; }
}
}
/////////////////////////////////////////////////////////////////////////// //Programa Principal //////////////////////////////////////////////////////
INTCON.GIE = 1; // Habilitador global de interrupciones INTCON.PEIE =1; // Habilitador de interrupciones de periféricos (UART) //pruebas(); estado = INICIO; while(1){
switch(estado){ case INICIO: estado=inicio(); break; case MENU: estado=menu(); break; case ILUM: estado=ilum(); break; case DIESEL: estado=diesel(); break; case MAGNA: estado=magna(); break; case PREMIUM: estado=premium();break; } } }
Título: Re:Comunicación Serial entre Pics 18F4550 (Tx) y 16F887 (Rx).
Publicado por: escobedov en 26 de Febrero de 2016, 19:46:05
Este es el receptor
/*Teclado controlador de tableta de precios PIC16F887 Interfaz LED multiplexada con transistores y con codificación BCD a 7 segmentos comunicación RS232 con teclado controlador Autores: Diego Alejandro Chavira Félix
char is_RS232=0; //Indica si hay un mensaje por el puerto serie cuando !=0. char auxTxt[17]; char buffRx[15]; //Buffer de recepcion de mensajes RS232 char contRx=0; //Cuenta el numero de bytes recibidos en buffRx[]. char precio1[10]; char precio2[10]; char precio3[10]; char ilumin[10]; int i; char precioCENT; char precioPES; char aux; char pwm; char pwmB;
void inic_UART(){ //Inicializa puerto serie Tx y Rx UART1_Init(9600); // Initialize UART module at 9600 bps Delay_ms(1000); // Espera para que el UART se estabilice. PIR1.RCIF=0; //Borra solicitud de interrupción de RX. PIE1.RCIE=1; // Interrupción por RX habilitada.
// Servicio a Interrupciones///////////////////////////////////// void interrupt(void){
//Servicio a Interrupcion Rx RS232. if (PIR1.RCIF) { /*RB6_bit=1; Delay_ms(250); RB6_bit=0; */ // if(is_RS232){ is_RS232=2; return; } // Verifica que no se encime el mensaje // If data is ready, read it:
if (UART1_Data_Ready() == 1) { buffRx[contRx] = RCREG;
}
//if(buffRx[contRx]!='K'){ // Si el dato recibido NO es "K"... contRx++; //}
if(contRx==6){ if(contRx==0)return; // Si no habia ningun caracter en el mensaje, no hace nada. is_RS232=1; // ...indica con is_RS232 que hay nuevo mensaje. // Indica fin de texto en buffer
contRx=0; //Prepara para otro mensaje }
} PIR1.RCIF=0; }
void main() {
int current_duty1=100; ANSEL=0; ANSELH=0; TRISB=0; TRISA=0; TRISD=0; PORTA=0; TRISC=0x80; RCSTA=0x90; TRISE=0; // Bits 0,1,2 de PORTE como salidas PORTE=0; inic_UART(); PIE1.RCIE = 1; //enable USART receiver interrupt bit INTCON.PEIE = 1; //enable peripheral interrupt bit INTCON.GIE = 1; PWM1_Init(10000); PWM1_Start(); PWM1_Set_Duty(255); RB4_bit=1; RB5_bit=1; RB6_bit=1; RB7_bit=1;
//Pone en "X" número todos los precios precio1[0]=4; precio1[1]=3; precio1[2]=2; precio1[3]=1; precio2[0]=8; precio2[1]=7; precio2[2]=6; precio2[3]=5; precio3[0]=9; precio3[1]=1; precio3[2]=2; precio3[3]=3;
//Llama a la función de desplegado despliegaprecio();
}
Título: Re:Comunicación Serial entre Pics 18F4550 (Tx) y 16F887 (Rx).
Publicado por: KILLERJC en 26 de Febrero de 2016, 20:06:40
En el transmisor:
1er problema: Faltan includes y definiciones para que funcionen los delays, imagino que los sacaste.
2do problema: Por que tenes las interrupciones de lectura habilitadas en el transmisor ¿?. Especialmente cuando:
- No recibis, solo envias - No tenes definido la funcion de interrupcion
3er problema: ( Mas que problema un mal uso ) No encuentro la funcion Keypad_Key_Press(). La cual estas llamando SIEMPRE, y con llamar una sola ves bastaria.
Código: C
while(!leeTeclado())// Espera a que se presione una tecla.
if(leeTeclado()=='1'){
interpretanum=0x01;
Lcd_Out(2, i,"1");}
if(leeTeclado()=='2'){
interpretanum=0x02;
Lcd_Out(2, i,"2");}
if(leeTeclado()=='3'){
interpretanum=0x03;
Lcd_Out(2, i,"3");}
if(leeTeclado()=='4'){
interpretanum=0x04;
Lcd_Out(2, i,"4");}
if(leeTeclado()=='5'){
interpretanum=0x05;
Lcd_Out(2, i,"5");}
if(leeTeclado()=='6'){
interpretanum=0x06;
Lcd_Out(2, i,"6");}
if(leeTeclado()=='7'){
interpretanum=0x07;
Lcd_Out(2, i,"7");}
if(leeTeclado()=='8'){
interpretanum=0x08;
Lcd_Out(2, i,"8");}
if(leeTeclado()=='9'){
interpretanum=0x09;
Lcd_Out(2, i,"9");}
if(leeTeclado()=='0'){
interpretanum=0x00;
Lcd_Out(2, i,"0");}
Y podias hacer:
Código: C
while(tecla!=0){tecla = leeTeclado();}
if( tecla >='0'&& tecla <='9')
{
Lcd_Out(2,i,tecla);
numero = tecla -48;
}
4to problema:
Código: C
while(!leeTeclado())// Espera a que se presione una tecla.
if(leeTeclado()=='1'){
interpretanum=0x01;
Lcd_Out(2, i,"1");}
Ese while al no tener un ";" o " { } ", va a ejecutar la primera instruccion siguiente, es decir que no es que este leyendo siempre si no que ademas va a estar preguntando por 1 siempre.
5to problema:
Código: C
precio3=interpretanum;
Cuando precio3 es un array, un ratito antes hacias:
Código: C
precio3[0]=0x03;
precio3[5]=0x03;
6to problema: Abuso de delays, en algunos lugares sin sentido como al momento de enviar los datos
Código: C
UART1_Write(precio3[0]);
Delay_ms(200);
UART1_Write(precio3[1]);
Delay_ms(200);
UART1_Write(precio3[2]);
Delay_ms(200);
UART1_Write(precio3[3]);
Delay_ms(200);
UART1_Write(precio3[4]);
Delay_ms(200);
UART1_Write(precio3[5]);
Delay_ms(200);
Si con esto bastaria:
Código: C
for( i =0; i <6;++i )
{
UART1_Write(precio3[i]);
}
1er Consejo Las funciones: magna / diesel / entre otras son identicas, seguro que podes hacer una sola funcion para todas.
2da mala aplicacion
Código: C
if(leeTeclado()=='A'){//Comando para cambiar precio de magna
return MAGNA;
}
if(leeTeclado()=='B'){//Comando para cambiar precio de premium
return PREMIUM;
}
if(leeTeclado()=='C'){//Comando para cambiar precio de diesel
return DIESEL;
}
if(leeTeclado()=='D'){//Comando para cambiar ilumnación
return ILUM;
Utiliza leeTeclado() 1 sola vez por ciclo del while.
En el receptor:
1er problema: No se si esto funciona o no:
Código: C
void interrupt(void)
ya que siempre lo vi ( supongamos que la funcion se llama UART_RX ):
Código: C
void interrupt UART_RX(void)
Es decir el interrupt es como un modificador a esa funcion. En tu caso parece ser el nombre con lo cual jamas va a entrar.
1er consejo: Y aunque es correcto el codigo del main, prefiero tener el while(1) en el main y no en la funcion.
2do consejo: Esto no es necesario:
Código: C
Delay_ms(1000);// Espera para que el UART se estabilice.
La UART no se tiene que estabilizar, aun peor esto haria que sea posible que se llene el buffer de recepcion ( esto va para el receptor, pero en el transmisor se lo podes quitar tambien ), teniendo luego que lidiar con limpiar los errores.
2do POSIBLE problema: Aunque no estoy muy seguro como se maneja XC8 en ese caso, desconfiaria con poner un return en la rutina de interurpcion:
Código: C
if(contRx==0)return;
Ya que puede ejecutar un RETURN y no un RETFIE, pero esto no estoy seguro si es asi, realmente jamas probe poner un return ahi. De todas formas JAMAS se va a ejecutar esa instruccion, por que entra alli cuando es 6, por lo tanto jamas va a ser 0, y ese if esta por demas.
Por ahora son algunas de las cosas que vi. Como que parece demasiado grande el programa como para lo que deberia hacer, hasta ahora.
-------------------------------------------------
Hardware, el receptor esta mal realizado, especialmente el manejo del comun de los displays. Ya que deberia tener el emisor a GND, si es que vas a usar NPN, esto si son catodo comun, si son anodo comun, entonces vas a tener que realizar otro circuito para hacerlo funcionar con el PIC