Autor Tema: PIC 18F2550 y comunicación RS485  (Leído 2560 veces)

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

Desconectado claudiovega

  • PIC10
  • *
  • Mensajes: 31
PIC 18F2550 y comunicación RS485
« en: 20 de Octubre de 2015, 21:59:56 »
PIC: 18F2550
Compilador: CCS 4

El proyecto cuenta con 3 tarjetas con el chip max485 y un pic 18F2550 en cada una de ellas. El código es el siguiente:

Código: [Seleccionar]
#include <18F2550.h>
#DEVICE ADC  = 10
#include <stdlib.h>

#fuses INTRC,MCLR,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP,NOCPD
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, STREAM=COM_A, parity=N, bits=8)

#define TX_485_ENABLE PIN_C0

char p, term[2], command[66] = "", action[10] = "", values[45] = "";//, picid[10] = "";
char permited[9] = "";
int k = 0, contador1  = 0, distance[2], newdistance = 0, winche = 0, dir = 0;
int cmxcheck = 11, meters = 0, mdif = 0;
int32 seconds[14], times[14], epoch = 0, timeon = 0;
int16 checks = 0, cms = 0, oldchecks = 0;
int1 newcommand = 0, newsecond = 0, readsensor = 0, count = 0;
float value = 0;
unsigned int16 pic, picsaved;

//funciones 485
void USART_activa_tx(void){
  output_high(TX_485_ENABLE);
  delay_ms(5);
}
void USART_activa_rx(void){
  delay_ms(5);
  output_low(TX_485_ENABLE);
  delay_ms(1);
}
// subrutina de interrupción del timer1
#int_TIMER1                               
void TIMER1_isr(){             
contador1++;
if(contador1 == 2){
newsecond = 1;
contador1 = 0;
}          
set_timer1(3036);
}
//interrupcion por usart del pic
#INT_RDA
void usart_modem(void)

disable_interrupts(INT_RDA);
newcommand = 0;
if (kbhit(COM_A))
{
p = fgetc(COM_A);
if(p == '#') {
command[k] = '\0';
newcommand = 1;
k = 0;
}else{
command[k] = p;
k++;
}
}
enable_interrupts(INT_RDA);
}
//comparar 2 cadenas
int is_equal(char *p1, char *p2)
{
int *p3;
p3 = strstr(p1,p2);
return (p3);
}
//variables a cero
void to_zero()
{
readsensor = 0;
meters = 0;
checks = 0;
cms = 0;
}
//encendido manual de pines segun comando
void open(void)
{
int i, j=0;
char numbers[3] = "", letter;
unsigned char number;

for(i = 0; i < strlen(values); i += 3){
numbers[0] = values[i];
numbers[1] = values[i+1];
numbers[2] = '\0';
letter     = values[i+2];
number     = atoi(numbers);
if(letter == 77) number *= 60;
seconds[j] = number;
times[j]   = epoch;
j++;
}
if(seconds[0]  > 0) output_bit(PIN_C0, 1);
if(seconds[1]  > 0) output_bit(PIN_C1, 1);
if(seconds[2]  > 0) output_bit(PIN_C2, 1);
if(seconds[3]  > 0) output_bit(PIN_C3, 1);
if(seconds[4]  > 0) output_bit(PIN_B7, 1);
if(seconds[5]  > 0) output_bit(PIN_B6, 1);
if(seconds[6]  > 0) output_bit(PIN_B5, 1);
if(seconds[7]  > 0) output_bit(PIN_B4, 1);
if(seconds[8]  > 0) output_bit(PIN_B3, 1);
if(seconds[9]  > 0) output_bit(PIN_B2, 1);
if(seconds[10] > 0) output_bit(PIN_B1, 1);
if(seconds[11] > 0) output_bit(PIN_B0, 1);
if(seconds[12] > 0) output_bit(PIN_C5, 1);
if(seconds[13] > 0) output_bit(PIN_C4, 1);
}
//apagado manual de pines segun comando close
void close(void)
{
if(values[0]  > 0) output_bit(PIN_C0, 0);
if(values[1]  > 0) output_bit(PIN_C1, 0);
if(values[2]  > 0) output_bit(PIN_C2, 0);
if(values[3]  > 0) output_bit(PIN_C3, 0);
if(values[4]  > 0) output_bit(PIN_B7, 0);
if(values[5]  > 0) output_bit(PIN_B6, 0);
if(values[6]  > 0) output_bit(PIN_B5, 0);
if(values[7]  > 0) output_bit(PIN_B4, 0);
if(values[8]  > 0) output_bit(PIN_B3, 0);
if(values[9]  > 0) output_bit(PIN_B2, 0);
if(values[10] > 0) output_bit(PIN_B1, 0);
if(values[11] > 0) output_bit(PIN_B0, 0);
if(values[12] > 0) output_bit(PIN_C5, 0);
if(values[13] > 0) output_bit(PIN_C4, 0);
}
//auto apagado de pines segun paso del tiempo
void auto_off(void)
{
if(seconds[0]  > 0 && (epoch - times[0])  > seconds[0])  output_bit(PIN_C0, 0);
if(seconds[1]  > 0 && (epoch - times[1])  > seconds[1])  output_bit(PIN_C1, 0);
if(seconds[2]  > 0 && (epoch - times[2])  > seconds[2])  output_bit(PIN_C2, 0);
if(seconds[3]  > 0 && (epoch - times[3])  > seconds[3])  output_bit(PIN_C3, 0);
if(seconds[4]  > 0 && (epoch - times[4])  > seconds[4])  output_bit(PIN_B7, 0);
if(seconds[5]  > 0 && (epoch - times[5])  > seconds[5])  output_bit(PIN_B6, 0);
if(seconds[6]  > 0 && (epoch - times[6])  > seconds[6])  output_bit(PIN_B5, 0);
if(seconds[7]  > 0 && (epoch - times[7])  > seconds[7])  output_bit(PIN_B4, 0);
if(seconds[8]  > 0 && (epoch - times[8])  > seconds[8])  output_bit(PIN_B3, 0);
if(seconds[9]  > 0 && (epoch - times[9])  > seconds[9])  output_bit(PIN_B2, 0);
if(seconds[10] > 0 && (epoch - times[10]) > seconds[10]) output_bit(PIN_B1, 0);
if(seconds[11] > 0 && (epoch - times[11]) > seconds[11]) output_bit(PIN_B0, 0);
if(seconds[12] > 0 && (epoch - times[12]) > seconds[12]) output_bit(PIN_C5, 0);
if(seconds[13] > 0 && (epoch - times[13]) > seconds[13]) output_bit(PIN_C4, 0);
}
//mueve el winche
void move()
{
to_zero();
if(winche == 0)
{
if(dir == 0)
{
output_bit(PIN_B7, 1);
output_bit(PIN_B5, 1);
readsensor = 1;
}
if(dir == 1)
{
output_bit(PIN_B6, 1);
output_bit(PIN_B4, 1);
readsensor = 1;
}
}
if(winche == 1)
{
if(dir == 0)
{
output_bit(PIN_B3, 1);
output_bit(PIN_B1, 1);
readsensor = 1;
}
if(dir == 1)
{
output_bit(PIN_B2, 1);
output_bit(PIN_B0, 1);
readsensor = 1;
}
}
}
//detiene el winche
void stop()
{
to_zero();
if(winche == 0)
{
if(dir == 0)
{
output_bit(PIN_B7, 0);
output_bit(PIN_B5, 0);
}
if(dir == 1)
{
output_bit(PIN_B6, 0);
output_bit(PIN_B4, 0);
}
}
if(winche == 1)
{
if(dir == 0)
{
output_bit(PIN_B3, 0);
output_bit(PIN_B1, 0);
}
if(dir == 1)
{
output_bit(PIN_B2, 0);
output_bit(PIN_B0, 0);
}
}
}
//cuenta vueltas y calcula distancia recorrida ITG0001|MOVE|0$2$|#
void check_distance()
{
value = read_adc();
if(value < 500)
{
if(count == 1)
{
checks++;
count = 0;
timeon = epoch;

USART_activa_tx();
printf("cms:%ld\r\n", (checks * cmxcheck));
USART_activa_rx();
}
cms = checks * cmxcheck;
meters = cms / 100;
count = 0;
}else{
count = 1;
}
if(meters == mdif)
{
distance[winche] = newdistance;
stop();

USART_activa_tx();
printf("OK\r\n");
USART_activa_rx();
}
if(checks == oldchecks && readsensor == 1 && (epoch - timeon) > 3)
{
stop();
distance[winche] = meters;
USART_activa_tx();
printf("STOP\r\n");
USART_activa_rx();
}
oldchecks = checks;
}
//lleva el winche a la posicion cero
void reset()
{
if(winche == 0)
{
output_bit(PIN_B6, 1);
output_bit(PIN_B4, 1);
}
if(winche == 1)
{
output_bit(PIN_B2, 1);
output_bit(PIN_B0, 1);
}
newdistance = 0;
readsensor = 1;
mdif = distance[winche] + 5;
}
/********* Programa Principal *********/
void main(void)
{
//activo lectura entrada analógica
setup_port_A(ALL_ANALOG);
setup_adc(ADC_CLOCK_INTERNAL);
//activo todos los pines A como entradas
set_tris_a(0xFF);
//activo todos los pines B como salidas
set_tris_b(0b00000000);
//activo PIN_C7 como entrada
set_tris_c(0b10000000);
//pines C0 a C5 apagados, C6 y C7 no se tocan
output_B(0b00000000);
//output_bit(PIN_C0, 0);
output_bit(PIN_C1, 0);
output_bit(PIN_C2, 0);
output_bit(PIN_C3, 0);
output_bit(PIN_C4, 0);
output_bit(PIN_C5, 0);
//configuración reloj interno del pic     
setup_oscillator(OSC_4MHZ);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_4);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
port_b_pullups(False);
USART_activa_rx();
//activo interrupciones
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);
enable_interrupts(INT_TIMER1);
set_timer1(3036);
//grabo id del pic. En este caso se compila usando el 3, pero se cambia por otro numero y se vuelve a compilar para otra tarjeta
picsaved = 3;
//distancias en cero
distance[0] = 0;
distance[1] = 0;
while(TRUE)
{
//llamo a autoapagado cada 1 segundo
if(newsecond)
{
epoch++;
if(!readsensor) auto_off();
newsecond = 0;
}
//chequeo de distancia recorrida
if(readsensor && distance[winche] != newdistance)
check_distance();
//si hay un nuevo comando lo analizo y ejecuto
if(newcommand)
{
newcommand = 0;
strcpy(term, "|");
//strcpy(picid, strtok(command, term));
pic = atoi(strtok(command, term));
strcpy(action, strtok(0, term));
strcpy(values, strtok(0, term));
if(pic == picsaved)
{
strcpy(permited, "OPEN");
if(is_equal(permited, action))
{
open();
USART_activa_tx();
printf("OK\r\n");
USART_activa_rx();
}
strcpy(permited, "RESET");
if(is_equal(permited, action))
{
winche = atoi(values);
set_adc_channel(winche);
reset();
USART_activa_tx();
printf("OK\r\n");
USART_activa_rx();
}
strcpy(permited, "SET");
if(is_equal(permited, action))
{
strcpy(term, "$");
winche = atoi(strtok(values, term));
distance[winche] = atoi(strtok(0, term));
USART_activa_tx();
printf("OK\r\n");
USART_activa_rx();
}
strcpy(permited, "SHOW");
if(is_equal(permited, action))
{
USART_activa_tx();
printf("D0:%d-D1:%d\r\n", distance[0], distance[1]);
USART_activa_rx();
}
strcpy(permited, "MOVE");
if(is_equal(permited, action))
{
stop();
strcpy(term, "$");
winche = atoi(strtok(values, term));
set_adc_channel(winche);
newdistance = atoi(strtok(0, term));
mdif = newdistance - distance[winche];
dir = 0;
if(newdistance > distance[winche]) mdif = newdistance - distance[winche];
if(newdistance < distance[winche]){
mdif = distance[winche] - newdistance;
dir = 1;
}
timeon = epoch;
if(newdistance != distance[winche]){
move();
}else{
USART_activa_tx();
printf("OK\r\n");
USART_activa_rx();
}
}
strcpy(permited, "CLOSE");
if(is_equal(permited, action))
{
readsensor = 0;
close();
USART_activa_tx();
printf("OK\r\n");
USART_activa_rx();
}
strcpy(permited, "STOP");
if(is_equal(permited, action))
{
stop();
USART_activa_tx();
printf("OK\r\n");
USART_activa_rx();
}
}
}
}
}

El problema es que cuando envío un comando desde el PC a una tarjeta, esta no responde al primer intento, si vuelvo a enviar el comando este se ejecuta correctamente. Pasa lo mismo al enviar el comando a cualquier otra tarjeta, siempre el primer comando no es ejecutado, los siguientes comandos si se ejecutan correctamente.

Desconectado Byron

  • PIC10
  • *
  • Mensajes: 7
Re:PIC 18F2550 y comunicación RS485
« Respuesta #1 en: 22 de Octubre de 2015, 02:25:49 »
He trabajado conexión 485, por ahora puedo darte un par de recomendaciones mientras me queda algo de tiempo para revisar el codigo y entenderlo un poco mejor:
1. utiliza el fuse INTRC_IO en lugar de INTRC.
2. el bus 485 nunca debe estar libre, esto es, siempre debe haber un dispositivo que se "adueñe" del bus, normalmente siempre es el maestro, pero si este espera una respuesta, el esclavo que debe trasmitir debe "adueñarse" del bus (TXENABLE) antes de que el maestro lo libere, hay que tener eso muy en cuenta para el manejo de los tiempos...

Desconectado claudiovega

  • PIC10
  • *
  • Mensajes: 31
Re:PIC 18F2550 y comunicación RS485
« Respuesta #2 en: 22 de Octubre de 2015, 13:04:12 »
Gracias Byron.
¿Podrías indicarme como es eso de "adueñarse" del bus? En mi código sólo activo tx o rx según corresponda. ¿Que debería hacer para "adueñarme" del bus?
¿Qué diferencia hay entre INTRC e INTRC_IO?

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:PIC 18F2550 y comunicación RS485
« Respuesta #3 en: 22 de Octubre de 2015, 13:21:47 »
Citar
¿Qué diferencia hay entre INTRC e INTRC_IO?

INTRC - Oscilador interno, salida de CLK por el pin de OSC2
INTRC_IO - Oscilador interno, OSC2 como I/O, un pin mas de entrada salida

(Creo que era OSC2 .. )

Citar
¿Podrías indicarme como es eso de "adueñarse" del bus? En mi código sólo activo tx o rx según corresponda. ¿Que debería hacer para "adueñarme" del bus?

Necesitas alguien que controle el trafico, cuando tenes un unico bus, si todos transmiten en el mismo momento es imposible determinar el mensaje y quien lo transmitio.
Entonces lo mas simple es tener un maestro y un esclavo. El Maestro es quien maneja el bus y los esclavos no van a utilizar el bus a no ser que el maestro se los pida. Esto es "simple" si solo tenes 1 maestro y todos los demas son esclavos. Pero si por alguna extraña razon queres que cualquiera pueda ser el Maestro, deberias generar un protocolo el cual por ejemplo enviar un mensaje pidiendo el bus. Recibido todos acceden al pedido, transmitir, avisar que se termino de usar el bus para que otro pueda usarlo. Tambien tendrias otros problemas, como que los pedidos del bus salgan en el mismo momento, en ese caso procuras generar una delay aleatorio, el cual cuando se detecte la colision de los pedidos se espere X tiempo aleatorio y se envie de nuevo. Eso haria que los 2 que enviaron juntos , 1 envie primero y tome el bus. Obviamente en el caso de querer que todos sean "Maestros", sino lo simple como dije antes, 1 maestro y los demas esclavos, el unico que le puede decir a los esclavos que envien datos es el maestro. Incluso podes implementar un protocolo que el primer byte sea la direccion, el segundo byte comando y el tercero a enviar el dato (un ejemplo ) eso lo haces vos segun lo que necesite tu programa.

Creo que a eso se refirio Byron, es libre de postear, de paso amplio mis conocimientos :P

Desconectado claudiovega

  • PIC10
  • *
  • Mensajes: 31
Re:PIC 18F2550 y comunicación RS485
« Respuesta #4 en: 22 de Octubre de 2015, 14:50:34 »
Ok, entiendo.
Explico un poco el programa.
El código que pegué en el mensaje es el código de los esclavos. Todos son esclavos y el master es un programa del PC.
El PC envía a los esclavos un mensaje (protocolo), compuesto de: ID del esclavo, acción a realizar, valor.
El esclavo analiza el mensaje y decide si debe responder o no. Si debe responder activa la transmisión, responde, activa la recepción.
La respuesta puede ser un simple OK o un mensaje que va variando a medida que se ejecutan las acciones que el comando indicó (ejemplo: distancia recorrida).

Desconectado claudiovega

  • PIC10
  • *
  • Mensajes: 31
Re:PIC 18F2550 y comunicación RS485
« Respuesta #5 en: 30 de Octubre de 2015, 16:41:12 »
Bueno, continúo con esto.
He hecho cambios en el software y en el circuito y todo sigue igual.
Me parece curioso lo que sucede con RS485, pues al parecer no hay una forma correcta de implementar la red. Cada documentación que he leído entrega diversos consejos sobre el cable (se habla de colgar los dispositivos, no cortar el cable principal), las resistencias de termino, resistencias de polarización, etc. Sin embargo, tengo 12 cámaras domo (control de PTZ) y 6 sensores de nivel (entrega el dato de profundidad por rs485), conectados en una red 485, sin resistencias de termino, sin resistencias de polarización, con el cable con todos los cortes necesarios y no dan ningún error. Ahora, cuando conecto mi pcb, con el pic antes indicado y un integrado sp485 la comunicación entre el master (PC) y los esclavos (PCB's) presenta los problemas indicados en el primer mensaje.
¿Qué podría tener internamente el circuito de la cámara y de los sensores para no presentar problemas de comunicación?
« Última modificación: 30 de Octubre de 2015, 17:36:58 por claudiovega »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:PIC 18F2550 y comunicación RS485
« Respuesta #6 en: 30 de Octubre de 2015, 17:46:18 »
No se..
Aplicando un poco de logica:
La señal esta llegando, eso seguro por que cuando tenes el segundo o los siguientes datos lo recibe bien.
Asi que podriamos descartar el tema de un problema de cableado.

El problema ocurre solamente con la placa de los pics ?, O cuando conectas el PIC a la red con camaras y sensores de nivel tambien ocurre con lo mismo con los sensores y camaras, o sigue el PIC sin funcionar nomas ?.
( Luego veo el programa bien, no poseo mucho tiempo en este momento)

Desconectado claudiovega

  • PIC10
  • *
  • Mensajes: 31
Re:PIC 18F2550 y comunicación RS485
« Respuesta #7 en: 30 de Octubre de 2015, 18:12:17 »
Así es, los pic no se comunican bien con 485 solos en una red ni con los otros equipos. Los otros equipos funcionan bien en ambos casos.
La pcb también soporta usar xbee para la comunicación, con el mismo programa, y funciona correctamente, pero en este caso debo usar 485.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:PIC 18F2550 y comunicación RS485
« Respuesta #8 en: 30 de Octubre de 2015, 19:27:34 »
Bueno estuve mirando un poco mas... No veo en el programa problema.

Lo que si:

- Delays en la activacion, 2ms/5ms es mucho, son casi 2000 a 5000 instrucciones a 4Mhz, y el MAX485 solo necesita 2us como maximo.
- No necesitas el kbhit() ya que si entro ahi, es por que hay un dato.
- No necesitas desabilitar las interrupciones dentro de la interrupcion, ya se desabilitan solas cuando entra.
- Y algo que no tiene nada que ver con el problema es el timer.. deberias cargarlo antes o usar el CCP

Finalmente podrias probar haciendo un flush del buffer de recepcion al comienzo del programa por las dudas.

Desconectado claudiovega

  • PIC10
  • *
  • Mensajes: 31
Re:PIC 18F2550 y comunicación RS485
« Respuesta #9 en: 02 de Noviembre de 2015, 12:28:26 »
Hola, aquí el nuevo programa:

1) Bajé los delays a  1ms. ¿Podría se menos?
2) Quité deshabilitar de interrupciones.
3) Dejé el kbhit() por que no me funcionaba sin el.
4) El timer siempre lo cargaba, no se donde dices que falta.

Código: C
  1. #include <18F2550.h>
  2. #DEVICE ADC  = 10
  3. #include <stdlib.h>
  4.  
  5. #fuses INTRC_IO,MCLR,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP,NOCPD
  6. #use delay(clock=4000000)
  7. #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, STREAM=COM_A, parity=N, bits=8)  
  8.  
  9. #define TX_485_ENABLE PIN_C0
  10.  
  11. char p, term[2], command[20] = "", values[10] = "";
  12. char action;
  13. int k = 0, contador1  = 0, newdistance = 0, winche = 0, dir = 0;
  14. int cmxcheck = 11, mdif = 0;
  15. int32 epoch = 0, timeon = 0, timeupd = 0, lastcmd = 0;
  16. int16 checks = 0, cms = 0, oldchecks = 0;
  17. int1 newcommand = 0, newsecond = 0, readsensor = 0, count = 0, checktime = 0;
  18. float value = 0, meters = 0, distance[2];
  19. int pic, picsaved;
  20.  
  21. //funciones 485
  22. void USART_activa_tx(void){
  23.   output_high(TX_485_ENABLE);
  24.   delay_ms(1);
  25. }
  26. void USART_activa_rx(void){
  27.   delay_ms(1);
  28.   output_low(TX_485_ENABLE);
  29.   delay_ms(1);
  30. }
  31. // subrutina de interrupción del timer1
  32. #int_TIMER1                                
  33. void TIMER1_isr(){              
  34.         contador1++;
  35.         if(contador1 == 2){
  36.                 newsecond = 1;
  37.                 contador1 = 0;
  38.         }                                
  39.         set_timer1(3036);
  40. }
  41. //interrupcion por usart del pic
  42. #INT_RDA
  43. void usart_modem(void)
  44. {  
  45.         newcommand = 0;
  46.         if (kbhit(COM_A))
  47.         {
  48.                 p = fgetc(COM_A);
  49.                 if(p == '#') {
  50.                         command[k] = '\0';
  51.                         newcommand = 1;
  52.                         k = 0;
  53.                 }else{
  54.                         command[k] = p;
  55.                         k++;
  56.                 }
  57.         }
  58. }
  59. //variables a cero
  60. void to_zero()
  61. {
  62.         readsensor = 0;
  63.         meters = 0;
  64.         checks = 0;
  65.         cms = 0;
  66. }
  67. //mueve el winche
  68. void move()
  69. {
  70.         to_zero();
  71.         if(winche == 0)
  72.         {
  73.                 if(dir == 0)
  74.                 {
  75.                         output_bit(PIN_B7, 1);
  76.                         output_bit(PIN_B5, 1);
  77.                         readsensor = 1;
  78.                 }
  79.                 if(dir == 1)
  80.                 {
  81.                         output_bit(PIN_B6, 1);
  82.                         output_bit(PIN_B4, 1);
  83.                         readsensor = 1;
  84.                 }
  85.         }
  86.         if(winche == 1)
  87.         {
  88.                 if(dir == 0)
  89.                 {
  90.                         output_bit(PIN_B3, 1);
  91.                         output_bit(PIN_B1, 1);
  92.                         readsensor = 1;
  93.                 }
  94.                 if(dir == 1)
  95.                 {
  96.                         output_bit(PIN_B2, 1);
  97.                         output_bit(PIN_B0, 1);
  98.                         readsensor = 1;
  99.                 }
  100.         }
  101. }
  102. //detiene todos los motores
  103. void stop_all()
  104. {
  105.         output_bit(PIN_B7, 0);
  106.         output_bit(PIN_B5, 0);
  107.         output_bit(PIN_B6, 0);
  108.         output_bit(PIN_B4, 0);
  109.         output_bit(PIN_B3, 0);
  110.         output_bit(PIN_B1, 0);
  111.         output_bit(PIN_B2, 0);
  112.         output_bit(PIN_B0, 0);
  113. }
  114. //detiene un winche
  115. void stop()
  116. {
  117.         to_zero();
  118.         if(winche == 0)
  119.         {
  120.                 if(dir == 0)
  121.                 {
  122.                         output_bit(PIN_B7, 0);
  123.                         output_bit(PIN_B5, 0);
  124.                 }
  125.                 if(dir == 1)
  126.                 {
  127.                         output_bit(PIN_B6, 0);
  128.                         output_bit(PIN_B4, 0);
  129.                 }
  130.         }
  131.         if(winche == 1)
  132.         {
  133.                 if(dir == 0)
  134.                 {
  135.                         output_bit(PIN_B3, 0);
  136.                         output_bit(PIN_B1, 0);
  137.                 }
  138.                 if(dir == 1)
  139.                 {
  140.                         output_bit(PIN_B2, 0);
  141.                         output_bit(PIN_B0, 0);
  142.                 }
  143.         }
  144. }
  145. //cuenta vueltas y calcula distancia recorrida 3|4|0$2$|#
  146. void check_distance()
  147. {
  148.         value = read_adc();
  149.         if(value < 500)
  150.         {
  151.                 if(count == 1)
  152.                 {
  153.                         checks++;
  154.                         count = 0;
  155.                         timeon = epoch;
  156.                         if(dir == 0){
  157.                                 USART_activa_tx();
  158.                                 printf("%f\r\n", (distance[winche] + meters));
  159.                                 USART_activa_rx();
  160.                         }
  161.                         else{
  162.                                 USART_activa_tx();
  163.                                 printf("%f\r\n", (distance[winche] - meters));
  164.                                 USART_activa_rx();
  165.                         }
  166.                                
  167.                 }
  168.                 cms = checks * cmxcheck;
  169.                 meters = cms / 100.0;
  170.                 count = 0;
  171.         }else{
  172.                 count = 1;
  173.         }
  174.         if(meters >= mdif)
  175.         {
  176.                 if(dir == 0){
  177.                         USART_activa_tx();
  178.                         printf("%f\r\n", (distance[winche] + meters));
  179.                         USART_activa_rx();
  180.                 }
  181.                 else{
  182.                         USART_activa_tx();
  183.                         printf("%f\r\n", (distance[winche] - meters));
  184.                         USART_activa_rx();
  185.                 }
  186.                        
  187.                 distance[winche] = newdistance;
  188.                 stop();
  189.                 USART_activa_tx();
  190.                 printf("OK\r\n");
  191.                 USART_activa_rx();
  192.                 lastcmd = epoch;
  193.         }
  194.         if(checks == oldchecks && readsensor == 1 && (epoch - timeon) > 2)
  195.         {
  196.                 if(action != 1){
  197.                         if(dir == 0){
  198.                                 USART_activa_tx();
  199.                                 printf("%f\r\n", (distance[winche] + meters));
  200.                                 USART_activa_rx();
  201.                                 distance[winche] = distance[winche] + meters;
  202.                         }else{
  203.                                 USART_activa_tx();
  204.                                 printf("%f\r\n", (distance[winche] - meters));
  205.                                 USART_activa_rx();
  206.                                 distance[winche] = distance[winche] - meters;
  207.                         }
  208.                 }else{
  209.                         distance[winche] = 0;
  210.                         USART_activa_tx();
  211.                         printf("%f\r\n", distance[winche]);
  212.                         USART_activa_rx();
  213.                 }
  214.                 stop();
  215.                 USART_activa_tx();
  216.                 printf("OK\r\n");
  217.                 USART_activa_rx();
  218.                 lastcmd = epoch;
  219.         }
  220.         oldchecks = checks;
  221. }
  222. //lleva el winche a la posicion cero
  223. void reset()
  224. {
  225.         to_zero();
  226.         if(winche == 0)
  227.         {
  228.                 output_bit(PIN_B6, 1);
  229.                 output_bit(PIN_B4, 1);
  230.         }
  231.         if(winche == 1)
  232.         {
  233.                 output_bit(PIN_B2, 1);
  234.                 output_bit(PIN_B0, 1);
  235.         }
  236.         dir = 1;
  237.         readsensor = 1;
  238. }
  239. //se apaga motor de subida/bajada despues de 30 segundos
  240. void check_time(){
  241.         if((epoch - timeupd) > 30){
  242.                 checktime = 0;
  243.                 if(winche == 0){
  244.                         output_bit(PIN_B4, 0);
  245.                         output_bit(PIN_B5, 0);
  246.                 }else{
  247.                         output_bit(PIN_B0, 0);
  248.                         output_bit(PIN_B1, 0);
  249.                 }
  250.                 USART_activa_tx();
  251.                 printf("OK\r\n");
  252.                 USART_activa_rx();
  253.                 lastcmd = epoch;
  254.         }
  255. }
  256. /********* Programa Principal *********/
  257. void main(void)                                                                                                                
  258. {
  259.         //activo lectura entrada analógica
  260.         setup_port_A(ALL_ANALOG);
  261.         setup_adc(ADC_CLOCK_INTERNAL);
  262.         //activo todos los pines A como entradas
  263.         set_tris_a(0xFF);
  264.         //activo todos los pines B como salidas
  265.         set_tris_b(0b00000000);
  266.         //activo PIN_C7 como entrada
  267.         set_tris_c(0b10000000);
  268.         //pines C0 a C5 apagados, C6 y C7 no se tocan
  269.         output_B(0b00000000);
  270.         output_bit(PIN_C0, 0);
  271.         output_bit(PIN_C1, 0);
  272.         output_bit(PIN_C2, 0);
  273.         output_bit(PIN_C3, 0);
  274.         output_bit(PIN_C4, 0);
  275.         output_bit(PIN_C5, 0);
  276.         //configuración reloj interno del pic      
  277.         setup_oscillator(OSC_4MHZ);
  278.         setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
  279.         setup_timer_1(T1_INTERNAL|T1_DIV_BY_4);
  280.         setup_timer_2(T2_DISABLED,0,1);
  281.         setup_comparator(NC_NC_NC_NC);
  282.         setup_vref(FALSE);
  283.         port_b_pullups(False);
  284.         //activo interrupciones
  285.         enable_interrupts(GLOBAL);
  286.         enable_interrupts(INT_RDA);
  287.         enable_interrupts(INT_TIMER1);
  288.         //cargo el timer
  289.         set_timer1(3036);
  290.         //grabo id del pic
  291.         picsaved = 4;
  292.         //aviso de conexión
  293.         USART_activa_tx();
  294.         printf("Conected %d\r\n", picsaved);
  295.         USART_activa_rx();
  296.         //distancias en cero
  297.         distance[0] = 0;
  298.         distance[1] = 0;
  299.         lastcmd = 0;
  300.         while(TRUE)
  301.         {
  302.                 //cuenta los segundos
  303.                 if(newsecond){
  304.                         epoch++;
  305.                         newsecond = 0;
  306.                 }
  307.                 //chequeo de distancia recorrida
  308.                 if(readsensor && distance[winche] != newdistance)
  309.                         check_distance();
  310.                 //chequeo tiempo de subida o bajada
  311.                 if(checktime == 1) check_time();
  312.                 //si hay un nuevo comando lo analizo y ejecuto
  313.                 if(newcommand)
  314.                 {
  315.                         newcommand = 0;
  316.                         strcpy(term, "|");
  317.                         pic = atoi(strtok(command, term));
  318.                         action = atoi(strtok(0, term));
  319.                         strcpy(values, strtok(0, term));
  320.                         if(pic == picsaved)
  321.                         {
  322.                                 if(action == 1) // reset
  323.                                 {
  324.                                         winche = atoi(values);
  325.                                         newdistance = 0;
  326.                                         mdif = 20 - newdistance;
  327.                                         timeon = epoch;
  328.                                         set_adc_channel(winche);
  329.                                         if(newdistance != distance[winche]){
  330.                                                 reset();
  331.                                         }else{
  332.                                                 USART_activa_tx();
  333.                                                 printf("OK\r\n");
  334.                                                 USART_activa_rx();
  335.                                         }
  336.                                 }
  337.                                 if(action == 2) // setear distancia
  338.                                 {
  339.                                         strcpy(term, "$");
  340.                                         winche = atoi(strtok(values, term));
  341.                                         set_adc_channel(winche);
  342.                                         distance[winche] = atoi(strtok(0, term));
  343.                                         USART_activa_tx();
  344.                                         printf("OK\r\n");
  345.                                         USART_activa_rx();
  346.                                         lastcmd = epoch;
  347.                                 }
  348.                                 if(action == 3) // obtener distancia
  349.                                 {
  350.                                         winche = atoi(values);
  351.                                         USART_activa_tx();
  352.                                         printf("%f\r\n", distance[winche]);
  353.                                         printf("OK\r\n");
  354.                                         USART_activa_rx();
  355.                                 }
  356.                                 if(action == 4) // mover un winche
  357.                                 {
  358.                                         strcpy(term, "$");
  359.                                         winche = atoi(strtok(values, term));
  360.                                         set_adc_channel(winche);
  361.                                         newdistance = atoi(strtok(0, term));
  362.                                         mdif = newdistance - distance[winche];
  363.                                         dir = 0;
  364.                                         if(newdistance > distance[winche]) mdif = newdistance - distance[winche];
  365.                                         if(newdistance < distance[winche]){
  366.                                                 mdif = distance[winche] - newdistance;
  367.                                                 dir = 1;
  368.                                         }
  369.                                         timeon = epoch;
  370.                                         if(newdistance != distance[winche]) {
  371.                                                 move();
  372.                                         }else{
  373.                                                 USART_activa_tx();
  374.                                                 printf("OK\r\n");
  375.                                                 USART_activa_rx();
  376.                                         }
  377.                                 }
  378.                                 if(action == 5) // apagar todos los motores
  379.                                 {
  380.                                         stop_all();
  381.                                         checktime = 0;
  382.                                         USART_activa_tx();
  383.                                         printf("OK\r\n");
  384.                                         USART_activa_rx();
  385.                                 }
  386.                                 if(action == 6) // subir camara
  387.                                 {
  388.                                         winche = atoi(values);
  389.                                         if(winche == 0){
  390.                                                 output_bit(PIN_B4, 1);
  391.                                         }else{
  392.                                                 output_bit(PIN_B0, 1);
  393.                                         }
  394.                                         timeupd = epoch;
  395.                                         checktime = 1;
  396.                                         USART_activa_tx();
  397.                                         printf("OK\r\n");
  398.                                         USART_activa_rx();
  399.                                 }
  400.                                 if(action == 7) // bajar camara
  401.                                 {
  402.                                         winche = atoi(values);
  403.                                         if(winche == 0){
  404.                                                 output_bit(PIN_B5, 1);
  405.                                         }else{
  406.                                                 output_bit(PIN_B1, 1);
  407.                                         }
  408.                                         timeupd = epoch;
  409.                                         checktime = 1;
  410.                                         USART_activa_tx();
  411.                                         printf("OK\r\n");
  412.                                         USART_activa_rx();
  413.                                 }
  414.                         }
  415.                 }
  416.         }
  417. }
Como decía antes el programa funciona bien usando xbee (rs232).

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:PIC 18F2550 y comunicación RS485
« Respuesta #10 en: 02 de Noviembre de 2015, 12:40:52 »
Es que era lo unico que veia. Los delays no deberian existir casi mejor un delay_us(2); ( sino directamente comenta todos los delays)

Lo raro es que no funcione sin el kbhit(), parece absurdo, pero bueno, si funciona en RS232 deberia funcionar en RS485. Y la unica diferencia esta en la habilitacion
Asi que vamos ahora por el tema de los delays... intenta comentarlos (si es que lo tenes a 4Mhz) o bajarlos a 2us, Es lo unico que podria evitar la recepcion inicial rapida. Si ya esto no funciona. Agregale un

if(kbhit()) getc();

Antes de habilitar la recepcion. Asi haces un flush de lo que puede quedar

Código: C
  1. void USART_activa_tx(void){
  2.   output_high(TX_485_ENABLE);
  3.   //delay_ms(1);
  4. }
  5. void USART_activa_rx(void){
  6.   //delay_ms(1);
  7.   if(kbhit()) getc();   //opcional primero comentalo y luego si sigue sin andar ponelo
  8.   output_low(TX_485_ENABLE);
  9.   //delay_ms(1);
  10. }

Citar
4) El timer siempre lo cargaba, no se donde dices que falta.
No decia que falte.. sino esto:

Código: C
  1. #int_TIMER1                                
  2. void TIMER1_isr(){              
  3.         contador1++;
  4.         if(contador1 == 2){
  5.                 newsecond = 1;
  6.                 contador1 = 0;
  7.         }                                
  8.         set_timer1(3036);
  9. }

Contra esto:

Código: C
  1. #int_TIMER1                                
  2. void TIMER1_isr(){              
  3.         set_timer1(3036);
  4.         contador1++;
  5.         if(contador1 == 2){
  6.                 newsecond = 1;
  7.                 contador1 = 0;
  8.         }                                
  9. }
« Última modificación: 02 de Noviembre de 2015, 12:42:55 por KILLERJC »

Desconectado claudiovega

  • PIC10
  • *
  • Mensajes: 31
Re:PIC 18F2550 y comunicación RS485
« Respuesta #11 en: 02 de Noviembre de 2015, 13:11:18 »
Ok probaré gracias.
Una duda, en esta parte del código estoy siempre transmitiendo. ¿Ayudaría en algo dejar siempre activa la transmisión y desactivarla al terminar?
Esta función se llama desde el ciclo while principal. El programa sigue recibiendo comandos, pero no es estrictamente necesario que sea así.

Código: C
  1. void check_distance()
  2. {
  3.         value = read_adc();
  4.         if(value < 500)
  5.         {
  6.                 if(count == 1)
  7.                 {
  8.                         checks++;
  9.                         count = 0;
  10.                         timeon = epoch;
  11.                         if(dir == 0){
  12.                                 USART_activa_tx();
  13.                                 printf("%f\r\n", (distance[winche] + meters));
  14.                                 USART_activa_rx();
  15.                         }
  16.                         else{
  17.                                 USART_activa_tx();
  18.                                 printf("%f\r\n", (distance[winche] - meters));
  19.                                 USART_activa_rx();
  20.                         }
  21.                                
  22.                 }
  23.                 cms = checks * cmxcheck;
  24.                 meters = cms / 100.0;
  25.                 count = 0;
  26.         }else{
  27.                 count = 1;
  28.         }
  29.         if(meters >= mdif)
  30.         {
  31.                 if(dir == 0){
  32.                         USART_activa_tx();
  33.                         printf("%f\r\n", (distance[winche] + meters));
  34.                         USART_activa_rx();
  35.                 }
  36.                 else{
  37.                         USART_activa_tx();
  38.                         printf("%f\r\n", (distance[winche] - meters));
  39.                         USART_activa_rx();
  40.                 }
  41.                        
  42.                 distance[winche] = newdistance;
  43.                 stop();
  44.                 USART_activa_tx();
  45.                 printf("OK\r\n");
  46.                 USART_activa_rx();
  47.                 lastcmd = epoch;
  48.         }
  49.         if(checks == oldchecks && readsensor == 1 && (epoch - timeon) > 2)
  50.         {
  51.                 if(action != 1){
  52.                         if(dir == 0){
  53.                                 USART_activa_tx();
  54.                                 printf("%f\r\n", (distance[winche] + meters));
  55.                                 USART_activa_rx();
  56.                                 distance[winche] = distance[winche] + meters;
  57.                         }else{
  58.                                 USART_activa_tx();
  59.                                 printf("%f\r\n", (distance[winche] - meters));
  60.                                 USART_activa_rx();
  61.                                 distance[winche] = distance[winche] - meters;
  62.                         }
  63.                 }else{
  64.                         distance[winche] = 0;
  65.                         USART_activa_tx();
  66.                         printf("%f\r\n", distance[winche]);
  67.                         USART_activa_rx();
  68.                 }
  69.                 stop();
  70.                 USART_activa_tx();
  71.                 printf("OK\r\n");
  72.                 USART_activa_rx();
  73.                 lastcmd = epoch;
  74.         }
  75.         oldchecks = checks;
  76. }

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:PIC 18F2550 y comunicación RS485
« Respuesta #12 en: 02 de Noviembre de 2015, 13:25:09 »
Si no vas a recibir nada , me refiero a que el maestro no envie nada en ese momento y lo unico que espera es recibir, entonces no tiene sentido deshabilitar al transmision.