Bueno, quisiera consultar antes que nada si alguien tiene un ejemplo usando la librería RS485.C comunicando 2 pics.
A ver si alguien puede probar esto que posteo. Los hilos de RS485 ya me los leí a todos, también la norma RS485 y no puedo hacer funcionar esta bendita comunicación. Las librerías que andan por aquí desearía que tuvieran control de errores por eso uso esta que encontré por ahí y modifiqué un poquito. Ya habré escrito sin exagerar más de 100 códigos diferentes, algunos mejor otros peor funcionaron, pero nunca puedo hacer que funcione este ^#@*""%$"& protocolo para diferentes familias de PIC que es lo que quiero para que el próximo como yo que necesite RS485 no reniegue y sea como levantar el teléfono, discar y escuchar el interlocutor sin problemas, en fin ya estoy delirando.
Este es el último código de Maestro, Esclavo y Librería. Lo que no puedo hacer ahora es que el SLAVE se interrumpa por hard (INT_RDA)
Y el Proteus que vive diciendo Logic Contention aunque lo simule casi sin nada. Será Proteus el problema, habré puesto algo mal???
Ahora si, remito el código, pero por favor, si alguien quiere ayudar que lo simule, subo el archivito Proteus también. Lo digo porque se acostumbra a dar soluciones muy a priori en ocasiones que no ayudan mucho.
Gracias desde ya.
MASTER:
#include <16F876A.h>
#fuses HS, NOWDT, NOPROTECT, NOLVP, NOBROWNOUT, PUT
#use delay (clock=20000000)
//#define GREEN_LED PIN_C0
#define DATA_IN (ext_buffer_next_in != ext_buffer_next_out)
#define SEND_ADDRESS 0x02
#define MACHINE_ADDRESS 0x01
#include <RS485-mio.c>
void main() {
set_tris_c(0b00000000);
delay_ms(100);
while(1)
{
packet_buffer[0] = SEND_ADDRESS;
packet_buffer[1] = MACHINE_ADDRESS;
packet_buffer[2] = 0;
packet_buffer[3] = 0;
packet_buffer[4] = 9;
packet_buffer[5] = 'H';
packet_buffer[6] = 'i';
packet_buffer[7] = ' ';
packet_buffer[8] = 't';
packet_buffer[9] = 'h';
packet_buffer[10] = 'e';
packet_buffer[11] = 'r';
packet_buffer[12] = 'e';
packet_buffer[13] = '!';
send_packet(packet_buffer, 14);
}
}
SLAVE:
#include <16F876A.h>
#fuses HS, NOWDT, NOPROTECT, NOLVP, NOBROWNOUT, PUT
#use delay (clock=20000000)
#define DATA_IN (ext_buffer_next_in != ext_buffer_next_out)
#define SEND_ADDRESS 0x02
#define MACHINE_ADDRESS 0x01
#include <RS485-mio.c>
void main() {
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
setup_timer_2(T2_DIV_BY_16,255,16);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
set_tris_c(0b10000000);
while(TRUE)
get_packet(ext_buffer, TRUE);
}
LIBRERÍA:
#use rs232(baud=9600,bits=8,parity=N,xmit=PIN_C6,rcv=PIN_C7,stream=COM1)
#use rs232(baud=9600,bits=8,parity=N,xmit=PIN_C6,rcv=PIN_C7,force_sw,stream=COM2)
#define enable_rcv_max PIN_C5
#define ACK 0x01
#define NACK 0xFF
#define BUFFER_SIZE 20
int packet_buffer[BUFFER_SIZE];
char ext_buffer[BUFFER_SIZE];
////////////////////////////////////////////////////////////////////////////////
/// Estructura variables comunicacion serial ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
struct _comm{
int1 nuevo_paquete; //hay un nuevo paquete a analizar
int8 cuenta_rx; //caracteres recibidos en el ultimo paquete
BYTE trama[BUFFER_SIZE];
int1 ocupado; //flag que indica si estamos procesando un paquete
BYTE byt; //caracter dummy, para sacar del puerto serie
} comm;
////////////////////////////////////////////////////////////////////////////////
/// Interrupción timer1 para timeout tiempo para saber si hay datos nuevos /////
////////////////////////////////////////////////////////////////////////////////
#int_TIMER1
void TIMER1_isr(){
disable_interrupts(int_TIMER1);
comm.ocupado=1; // No mas recepción de mensajes..
comm.nuevo_paquete=1; // Paquete a la espera de ser analizado
}
////////////////////////////////////////////////////////////////////////////////
/// Interrupción serial para entrada de datos //////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#int_rda
void serial_isr(){
comm.byt=fgetc(COM1); // recoge dato byte entrante
if (!comm.ocupado){ // si estamos procesando un envió no se hace caso..
comm.trama[comm.cuenta_rx++]=comm.byt;
set_timer1(30000); // esperar el tiempo que deseemos como timeout
clear_interrupt(int_TIMER1); // limpiar el flag de overflow del timer1
enable_interrupts(int_TIMER1);
}
}
//#define CRC_CCITT 0x1021 //bit pattern (1)0001 0000 0010 0001
#include <CRC.C>
////////////////////////////////////////////////////////////////////////////////
/// Funcion que espera el bus para evitar colisiones ///////////////////////////
////////////////////////////////////////////////////////////////////////////////
void espera_bus(void){
int16 i;
setup_uart(FALSE); // Deshabilita UART para falsas recepciones
for(i=0; i <= 400; ++i){ // Espera aproximadamente 20 ms si el bus esta libre
if(!input(PIN_C7)) // sino se queda a la espera
i = 0;
else
delay_us(50);
}
}
// SEND_PACKET
// Función que envia paquete a otro dispositivo
void send_packet(int* packet_ptr, int16 packet_length)
{
int *ptr;
int16 CRC,i;
espera_bus(); // Espera el bus para evitar colisiones
output_high(enable_rcv_max); // Habilita salida datos max485
ptr = packet_ptr; // puntero a paquete
CRC = generate_16bit_crc(ptr, packet_length, CRC_CCITT); // crea CRC
for(i=0; i<packet_length; i++) // envia paquete
fputc(packet_ptr
,COM2);
fputc((int)(CRC>>,COM2); // envia CRC
fputc((int)(CRC),COM2);
delay_ms(10);
output_low(enable_rcv_max);
setup_uart(TRUE);
}
// GET_PACKET
// Función que procesa el paquete y analiza si es valido o no
// espera TRUE -> Espera paquete
// FALSE -> No espera paquete
short get_packet(int* packet_ptr, int1 espera)
{
short retval;
int16 length;
int16 CRC;
int16 i;
retval = TRUE;
if(espera){
while(!comm.nuevo_paquete); // Espera que halla nuevo paquete
}else{
if(!comm.nuevo_paquete){ // si no lo hay retorna cero
return(FALSE);
}
}
packet_ptr[0] = comm.trama[0]; // Direccion destino paquete
packet_ptr[1] = comm.trama[1]; // direccion de donde viene paquete
if(packet_ptr[0] != MACHINE_ADDRESS){
comm.ocupado=0; // Habilita recepción de nuevos datos
comm.nuevo_paquete=0; // ya no hay mas datos
comm.cuenta_rx=0; // Contador de index de datos a cero
return(FALSE);
}
packet_ptr[2] = comm.trama[2]; // Byte ACK o NACK
if(packet_ptr[2] == NACK){
comm.ocupado=0; // Habilita recepción de nuevos datos
comm.nuevo_paquete=0; // ya no hay mas datos
comm.cuenta_rx=0; // Contador de index de datos a cero
return(FALSE);
}
packet_ptr[3] = comm.trama[3]; // Tamaño de datos en el paquete
packet_ptr[4] = comm.trama[4];
length = make16(packet_ptr[3],packet_ptr[4]);
for(i=5; i<(length+5); i++) // recoje los datos
packet_ptr = comm.trama;
packet_ptr[length+5] = comm.trama[length+5]; // recoje CRC
packet_ptr[length+6] = comm.trama[length+6];
CRC = make16(packet_ptr[length+5],packet_ptr[length+6]);
if(CRC != generate_16bit_crc(packet_ptr, length+5, CRC_CCITT)){ // Analisis CRC
ext_buffer[0]=packet_buffer[1]; //En caso de CRC malo envia NACK
ext_buffer[1]=MACHINE_ADDRESS;
ext_buffer[2]=NACK;
ext_buffer[3]=0;
ext_buffer[4]=1;
ext_buffer[5]=NACK;
send_packet(ext_buffer,6);
retval = FALSE;
}
comm.ocupado=0; // Habilita recepción de nuevos datos
comm.nuevo_paquete=0; // ya no hay mas datos
comm.cuenta_rx=0; // Contador de index de datos a cero
return retval;
}