Autor Tema: TRANSMITIR STRING ENTRE 2 PIC18F4550 PARA MODIFICAR EL DUTY DEL MODULO CCP1  (Leído 8284 veces)

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

Desconectado nmz

  • PIC10
  • *
  • Mensajes: 4
Que tal compañeros del foro, este es el primer hilo que inicio para solicitar de su valiosa colaboración agradeciando por adelantado cualquier sugerencia para corregir lo que estoy tratando de hacer.

Lo que pretendo hacer es tener el mismo valor para el duty de 2 PIC18F4550, leyendo el valor del adc del primer pic e imprimirlo a un lcd y enviarlo al otro pic por rs-232, para recuperar el valor del adc y establecer el mismo valor del duty en el otro pic. Tengo entendido que para poder recibir datos con la interrupción int_rda es necesario que los datos lleguen en forma de cadena, y de acuerdo a que una cadena se imprime con %s  creo que la parte del transmisor ya esta bien, posteo el código aquí:
Código: [Seleccionar]
/////////////////////////////////////////////////////////////////////////////////
// TRANSMITIR STRING ENTRE 2 PIC18F4550 PARA MODIFICAR EL DUTY DEL MODULO CCP1 //
//              19/06/2012          Compilador CCS (v4.128)                    //
//                            Autor: nmz                                       //
//                  Para foro: www.todopic.com.ar                              //
/////////////////////////////////////////////////////////////////////////////////
   
#include <18F4550.h>            // Pic a utilizar
#priority ccp1                  // Prioridad al módulo CCP1
#device adc=10                  // ADC en 10 bits
#fuses PLL1,CPUDIV1,USBDIV,XTPLL,NOFCMEN,NOIESO,PUT,NOBROWNOUT,VREGEN,NOWDT,NOPBADEN,MCLR,NOSTVREN,NOLVP,NODEBUG,NOPROTECT,NOSTVREN,NOCPB,NOWRT   
#use delay(clock=48000000)     
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, PARITY=N, BITS=8, STOP=1, TIMEOUT=1000, ERRORS)  // Configuración del puerto RS-232
#include <stdlib.h> 
#byte use_portd_lcd=8           // Define el puerto_d para la lcd.
#include <lcd4x20d.c>           // Librería para el manejo del LCD
int16 j;                        // Variable global de 16 bits que almacena el valor del ADC y se convierte en el Duty del PWM
char duty_cadena[5];
void main(){                    // Inicio del Main
lcd_init();                     // Inicializa el LCD   
setup_adc_ports(AN0|VSS_VDD);   // Canal AN0 analógico para variar el Duty de 0-100% en proporcion a los 0-5V del ADC
setup_adc(ADC_CLOCK_INTERNAL);
setup_timer_2(T2_DIV_BY_4,249,1);
setup_ccp1(CCP_PWM);            // Módulo CCP1 como PWM
set_adc_channel(0);
while(true){                    // Bucle infinito
j = read_adc();                 // Captura del valor en el ADC y almacenado en la variable j
delay_ms(200);
set_pwm1_duty(j);               // Establecimiento del Duty del módulo CCP1 con la misma variable j
delay_ms(200);
sprintf(duty_cadena,"%4lu",j);  // Preparación de la variable j en cadena en la variable char duty_cadena
printf("%s\r",duty_cadena);     // Impresión del valor de j formateada a cadena por RS-232
lcd_gotoxy(1,1);                // Columna 1, Fila 1 del LCD
printf(lcd_putc,"\fADC:%4lu",j);// Impresión en LCD del valor del ADC
delay_ms(100);                  // \f para limpiar LCD cada que imprime el dato
}                               // Fin del While(true)
}                               // Fin del Main   

Ahora aquí dejo un video del transmisor simulado con el proteus:


En la parte que estoy atascado es en la recepción, ya que la variable no la puedo reimprimir en el lcd, por que necesito convertirla a entero nuevamente, los pines de la transmisión que son TX y RX muestran ligera actividad en la simulación,dejo el codigo del receptor aquí:

Código: [Seleccionar]
/////////////////////////////////////////////////////////////////////////////////
// TRANSMITIR STRING ENTRE 2 PIC18F4550 PARA MODIFICAR EL DUTY DEL MODULO CCP1 //
//              19/06/2012          Compilador CCS (v4.128)                    //
//                            Autor: nmz                                       //
//                  Para foro: www.todopic.com.ar                              //
/////////////////////////////////////////////////////////////////////////////////
#include <18F4550.h>                  // Pic a utilizar
#priority ccp1,rda                    // Prioridad a módulo ccp1 e interrupción rda
#device adc=10                        // ADC en 10 bits
#fuses PLL1,CPUDIV1,USBDIV,XTPLL,NOFCMEN,NOIESO,PUT,NOBROWNOUT,VREGEN,NOWDT,NOPBADEN,MCLR,NOSTVREN,NOLVP,NODEBUG,NOPROTECT,NOSTVREN,NOCPB,NOWRT   
#use delay(clock=48000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, PARITY=N, BITS=8, STOP=1, TIMEOUT=1000, ERRORS)  // Configuración del puerto RS-232
#include <stdlib.h> 
#byte use_portd_lcd=8                 // Define el puerto d para la lcd
#include <lcd4x20d.c>                 // Librería para el manejo del LCD
int16 j;                              // Variable global de 16 bits que almacena el valor del ADC y se convierte en el Duty del PWM
char duty_cadena[5];

#int_RDA                              // Interrupción por recepción de datos por RS-232
void RDA_isr(){                       
duty_cadena[5]=getch();               // En "duty_cadena" el dato recibido via RS232 mediante getch
lcd_gotoxy(1,1);//Columna 1, Fila 1
printf(lcd_putc,"\fDuty%s",duty_cadena); //Se muestra en pantalla información recibida
delay_ms(500);
   }

   
void main(){                         // Inicio del Main
lcd_init();                          // Inicializa el LCD   
enable_interrupts(int_rda);         
setup_timer_2(T2_DIV_BY_4,249,1);
setup_ccp1(CCP_PWM);                 // Módulo CCP1 como PWM

while(true){                         // Bucle infinito
set_pwm1_duty(j);
delay_ms(200);
}                                    // Fin del While(true)
}                                    // Fin del Main

Dejo un video del transmisor y receptor simulado con el proteus:


Un saludo a todos, y cualquier observación por parte de los administradores también es bienvenida.

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: TRANSMITIR STRING ENTRE 2 PIC18F4550 PARA MODIFICAR EL DUTY DEL MODULO CCP1
« Respuesta #1 en: 20 de Junio de 2012, 14:20:15 »
  Me parece que hay un error de concepto y no se si de tu parte o la mia. Hasta donde yo sé podés enviar cualquier información, ya que se estarían enviando paquetes de 8 bits (1 byte a la vez). Por lo tanto sería suficiente con enviar 2 bytes, ya que el ADC es de 10 bits.
  Lo que yo entiendo por string en cuanto al uso del RS232 es que si quiero enviar el texto "1" (el número 1 en ascii) no puedo enviar directamente el byte 0b00000001 ya que dicho byte no representa el número 1.

  Ya pasando a tu programa de recepción, uno de los errores está en la siguiente línea

Código: C
  1. duty_cadena[5] = getch();

  getch() devuelve sólo un caracter y si lo que necesitas es completar una cada, pues no te va a servir. Creo que CCS cuenta con la función getstr() que sí devuelve toda una cadena.

  A su vez, utilizar printf no es aconsejable dentro de una interrupción por el tiempo que insume. Y menos aún es dejar un delay tan largo como 500ms.
  Lo mejor sería activar algún flag (una variable que se ponga a 1) y luego en el programa principal procesar dicho flag.
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado nmz

  • PIC10
  • *
  • Mensajes: 4
Re: TRANSMITIR STRING ENTRE 2 PIC18F4550 PARA MODIFICAR EL DUTY DEL MODULO CCP1
« Respuesta #2 en: 20 de Junio de 2012, 19:07:38 »
Que tal AngelCris, gracias por tu tiempo para atender la pregunta :).

Respecto a lo que comentas acerca de la función getstr() busqué información en la ayuda del CCS C, y la función referente a ello es la funcion de gets (string), ya había intentado antes con esa función, pero al momento de compilar me marca error el compilador.

Y referente al uso de la función printf cual sería tu sugerencia para el envio de los datos por RS-232, ya que de acuerdo a lo que dices de que puede ser enviado cualquier dato por RS-232, entonces desde allí podría venir el problema.

Saludos.

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: TRANSMITIR STRING ENTRE 2 PIC18F4550 PARA MODIFICAR EL DUTY DEL MODULO CCP1
« Respuesta #3 en: 22 de Junio de 2012, 17:04:45 »
Que tal AngelCris, gracias por tu tiempo para atender la pregunta :).

Respecto a lo que comentas acerca de la función getstr() busqué información en la ayuda del CCS C, y la función referente a ello es la funcion de gets (string), ya había intentado antes con esa función, pero al momento de compilar me marca error el compilador.

Y referente al uso de la función printf cual sería tu sugerencia para el envio de los datos por RS-232, ya que de acuerdo a lo que dices de que puede ser enviado cualquier dato por RS-232, entonces desde allí podría venir el problema.

Saludos.

  Creo que existe la función putc o puch que manda un byte. Entonces deberías dividir el dato leído del ADC en dos byte y enviarlos de forma seguida. Y en la parte del receptor tocará reconstruir el dato luego de hacer dos lecturas sucesivas.

  También creo que sería conveniente que no estés enviando todo el tiempo el dato, ya sea enviarlo al RS232, o al LCD, o actualizando el duty del PWM.

  Yo haría algo como...

Código: C
  1. while (1)
  2. {
  3.   valor_actual = read_adc
  4.   if (valor_actual != valor anterior)
  5.   {
  6.     // setear el duty cicle
  7.     // actualizar el LCD
  8.     // descomponer lo leido en dos bytes
  9.     // enviar el primer byte
  10.     // enviar el segundo byte
  11.    valor_anterior = valor_catual;
  12.   }
  13. }
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: TRANSMITIR STRING ENTRE 2 PIC18F4550 PARA MODIFICAR EL DUTY DEL MODULO CCP1
« Respuesta #4 en: 25 de Junio de 2012, 22:09:12 »
Hola.

Para transmitir informacion en este caso, te conviene hacerlo en binario. No conviene realizarle conversiones para enviarlo. Como bien te dijo AngelGris, el tamaño original y más eficiente es de 10 bits, que son los que provienen directamente de la conversión ADC.

Para enviar 10 bits, sobre un puerto que acepta 8 bits por vez, como es el caso de tu configuración del puerto serie 8N1, el envío puede realizarse de esta manera sencilla:

Código: C
  1. void sendADC(uint16_t value){
  2.         putc(value>>7 | 0x80);          //MSB First
  3.         putc(value & 0x7F);                     //LSB Last
  4. }

Como puede observarse, es un método muy básico de empaquetamiento, en el cual se sacrifica el bit de mayor peso(MSB) de cada byte para indicar si el byte actual a enviar es un principio de paquete(bit 7 = 1) o la continuación del mísmo( bit 7 = 0). De esta manera aún cuando uno desconecte la comunicación entre dispositivos, el receptor será capaz de volver a resincronizarse detectando el principio del próximo paquete.

Entonces, si bien se envían 2 bytes por el puerto serie, dijimos que siempre el bit MSB no aporta información del dato en si, sino que aporta información de si el byte actual es el principio de paquete o una continuación del mísmo, quedando entonces 14 bits disponibles para dato máximo, y 2 bits para indicación de Begin Of Package(BOP).
Esto hace que entonces se envíen los 7 bits de mayor peso primero y luego los 7 de menor peso.

Del lado del receptor, hay una mínima máquina de estados que es la que irá detectando el BOP, llenando el contenido de a 7 bits por vez, y si es necesario, descartará el envío actual hasta poder resincronizarse si detecta que ha habido un problema de sincronismo durante la transacción.

Necesitamos declarar dos variables globales:

Código: C
  1. int16 j;                              // Variable global de 16 bits que almacena el valor del ADC y se convierte en el Duty del PWM
  2. uint8_t new_data = 0;                                   //flag para indicar si hay un nuevo dato arribado por puerto serie del ADC

Donde new_data será un flag que indica si hay un nuevo valor disponible para ser leído, y j el valor en sí.

La interrupción de recepción de la USART puede ser así:

Código: C
  1. #int_RDA                              // Interrupción por recepción de datos por RS-232
  2. void RDA_isr(){        
  3.         while(kbhit()) receiveADC(getc());
  4. }

y la subrutina que contiene la máquina de estados, la siguiente:

Código: C
  1. void receiveADC(uint8_t chunk){
  2.         static uint16_t value;
  3.         static uint8_t step = 0;
  4.  
  5.         if(chunk & 0x80){       //bit 7 set?
  6.                 chunk &= 0x7F;  //clear bit 7 of chunk
  7.                 value= chunk;   //Store MSB
  8.                 value<<= 7;             //make place for LSB to arrive
  9.                 if(!step) step++;
  10.         }else{
  11.                 if(!step) return;       //wrong. wait for re-sync
  12.                 value |= chunk;         //Store LSB
  13.                 step = 0;
  14.                 j = value;
  15.                 new_data = TRUE;
  16.         }
  17. }

Por último, adjunto el transmisor y receptor con las subrutinas incorporadas. Las mísmas requieren ser compiladas con el PICC antes de poder ser simuladas. Me gustaría que una vez que logres hacer andar en el LCD el ejemplo, compartas los archivos para que queden disponibles para otros usuarios que puedan necesitarlos a futuro.

Saludos.
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado nmz

  • PIC10
  • *
  • Mensajes: 4
Re: TRANSMITIR STRING ENTRE 2 PIC18F4550 PARA MODIFICAR EL DUTY DEL MODULO CCP1
« Respuesta #5 en: 03 de Julio de 2012, 16:32:48 »
Que tal compañeros, para ampliar un poco el entendimiento de las aportaciones de BrunoF y de AngelGris añado esta información:


Cuando el programa del transmisor se ejecuta enviando el máximo valor del ADC configurado en 10 bits, envia el 1023 en decimal o el 1111111111 en binario, el cual debe ser procesado con los Operadores de bits con la función sendADC, sin afectar el valor de la variable j. Durante el envio del máximo dato es necesario enviar información adicional en cada byte enviado para distinguir si es el primer byte o el segundo byte, en este caso un 1 en el inicio del primer byte y un cero en el inicio del segundo byte.

MSB                                                                      LSB
  0     0    0     0    0    0    1   1  1   1   1   1  1   1   1   1
b15 b14 b13 b12 b11 b10 b9 b8 b7 b6 b5 b4 b3 b2 b1 b0


1er byte:

MSB                              LSB
1 b13 b12 b11 b10 b9 b8 b7

2do byte:

MSB                       LSB
0 b6 b5 b4 b3 b2 b1 b0
 

Visualizando la configuración del envio de datos, 8 bits es la máxima salida, como podemos ver en la siguiente imagen:


Por lo cual nos damos cuenta que no es posible enviar los 16 bits a la vez, si no unicamente 8 bits o lo que correspondería  a un máximo de FF en hexadecimal o 255 en decimal.

El envio del dato máximo a traves del hyperteminal una vez que el dato fue procesado nos muestra lo siguiente:



Pero, ¿de donde salen este datos? El 87 es un valor en hexadecimal del primer byte enviado y el 7F también en hexadecimal es el segundo byte.

Sabemos que value en la función sendADC es una copia del valor de la variable j, pero que no afecta a j en el programa principal, entonces para entender de donde salió el 87 en hexadecimal que es el primer byte enviado, es necesario entender el desplazamiento siguiente:


El código:

Código: [Seleccionar]
putc(value>>7 | 0x80);
Le aplica un desplazamiento a la derecha a value, y depués el operador or le añade el uno como información adicional quedando lo siguiente:


Realizando la conversión de binario a hexadecimal nos queda:




El código:

Código: [Seleccionar]
putc(value & 0x7F);
Con el operador and le añade el cero como información, veamos como ocurre:


Realizando la conversión de binario a hexadecimal nos queda:


Saludos.
« Última modificación: 03 de Julio de 2012, 20:31:08 por nmz »

Desconectado erk2e212

  • PIC10
  • *
  • Mensajes: 1
Re:TRANSMITIR STRING ENTRE 2 PIC18F4550 PARA MODIFICAR EL DUTY DEL MODULO CCP1
« Respuesta #6 en: 24 de Marzo de 2021, 01:09:43 »
hola, como quedo el codigo? que me puedan ayudar por favor


 

anything