buenass:
por si os sirve de ayuda hace un par de años trabaje algo con modbus y pic......
///////////////////////////////////////////////////////////////////////////
//// pic_modbus.C ////
//// esclavo MODBUS para PIC ////
//// por Félix Sasián
WWW.PACALACONCURSO.COM ////
//// ////
//// rev0: enero 2004 ////
//// - implementados comandos 0x03, 0x04, 0x06 y 0x10 ////
//// rev1: febrero 2004 ////
//// - solucionado bug en rx gracias a los amigos ////
//// de foro
www.todopic.foro.st ////
//// -Escritura / lectura desde la eeprom via MODBUS DIR >100 ////
//// esta por terminar, solo usar 32 bytes ////
//// ////
//// ////
//// ////
//// ////
///////////////////////////////////////////////////////////////////////////
//// ////
//// ////
//// (C) Copyright 2004
www.pacalaconcurso.com ////
//// Este codigo puede ser usado, modificado y distribuido libremente ////
//// sin eliminar esta cabecera y sin garantía de ningún tipo. ////
//// ////
//// ////
///////////////////////////////////////////////////////////////////////////
//// usar de esta forma en la int_rda
////#int_rda
////void serial_isr()
//// {
//// while(kbhit())
//// {
//// analiza(getc());
//// }
//// }
////
///////////////////////////////////////////////////////////////////////////
//VARIABLES
//////////////////
//estructura para los datos modbus
struct _modbus
{
int8 address; //mi direccion modbus
char trama[30]; //espacio para almacenar datos del comando que se esta recibiendo
char datos[16]; //espacio para los datos de recibidos por modbus
char datostx[16]; //espacio para los datos a transmitir por modbus
int16 CRC ; // para calcular el CRC del paquete recibido
int16 comandos; //comandos mandados desde modbus
int1 nuevo_comando; // hay al menos un comando recibido desde modbus
} modbus;
int1 hay_modbus;
/* tenemos 32 bytes de intercambio con modbus.
dejo la primera word (dos primeros bytes para poder recibir 16 comandos desde
modbus */
//alias y defines para pruebas
int8 puntero; //puntero para la lectura de un nuevo comando modbus
int8 puntdatos; //puntero para los datos del comando 0x10
int16 num_datos; //numero de bytes de datos a guardar del comando 0x10
int1 timeout_error,pausa_rx;
//int1 led;
const int8 timeout_rx=5; //timeout para recepcion de mensaje modbus
///////////////
//rutinas
/************************************************************************************
Mb_test_crc : verifica si el CRC del paquete recibido es correcto
*************************************************************************************
entrada :
-------
trame : packet con el crc incluido
n : longitud del paquete sin el CRC
salida : 1 = crc erroneo
-------- 0 = crc ok
************************************************************************************/
int1 Mb_test_crc(CHAR trame[],int n)
{
unsigned int16 crc,i,j,carry_flag,a;
crc=0xffff;
for (i=0;i<n;i++)
{
crc=crc^trame
;
for (j=0;j<8;j++)
{
a=crc;
carry_flag=a&0x0001;
crc=crc>>1;
if (carry_flag==1)
crc=crc^0xa001;
}
}
if ((trame[n+1]!=(crc>>) || (trame[n]!=(crc&255)))
return 1;
else
return 0;
}
/************************************************************************************
Mb_calcul_crc : calcula el CRC de un paquete
*************************************************************************************
entrada :
-------
trame : packet con espacio para el crc
n : longitud del paquete sin el CRC
salida : CRC
--------
************************************************************************************/
int16 Mb_calcul_crc(CHAR trame[],int n)
{
int16 crc,carry_flag,a;
int8 i,j;
crc=0xffff;
for (i=0;i<n;i++)
{
crc=crc^trame;
for (j=0;j<8;j++)
{
a=crc;
carry_flag=a&0x0001;
crc=crc>>1;
if (carry_flag==1)
crc=crc^0xa001;
}
}
trame[n+1]=crc>>8;
trame[n]=crc&255;
return crc;
}
/************************************************************************************
comando : mira si se ha recibido algun comando desde modbus y activa el flag
*************************************************************************************
entrada :
-------
salida :
--------
************************************************************************************/
void comando()
{
int16 aux;
aux = (modbus.datos[0]<<+modbus.datos[1];
modbus.comandos ^= aux;
//se mantiene los comandos que pudieran estar a la espera de ejecutarse
//printf(lcd_putc, "\n %Lx",aux);
if (modbus.comandos >0) modbus.nuevo_comando = true;
{
//borramos el area de comandos
modbus.datos[0] = 0;
modbus.datos[1] = 0;
}
}
/************************************************************************************
modbus : Interpreta los paquetes válidos y envia ack al master
*************************************************************************************
usa la matrices de definicion global trama[] y datos[]
************************************************************************************/
void int_modbus()
{
int8 direccion; //direccion incicial del registro
int8 longitud,longitud1; //longitud en decimal de los datos
int8 i,bytes;
direccion =(int8)(modbus.trama[2]<<+modbus.trama[3];
longitud=(int8)(modbus.trama[4]<<+modbus.trama[5];
switch (modbus.trama[1])
{
case 0x03:
case 0x04:
for (i=0;i<longitud*2;i++)
{
if (direccion<100)
{
modbus.trama[3+i]=modbus.datostx[direccion*2+i];
// modbus.trama[4+i*2]=modbus.datostx[direccion*2+i+1];
}
else
{
modbus.trama[3+i]=read_ext_eeprom(direccion*2+i);
// modbus.trama[4+i*2]=read_ext_eeprom(direccion*2+i+1);
}
}
//calcular el CRC
modbus.trama[2]=longitud*2;//numero de bytes de datos a transmitir
Mb_calcul_crc(modbus.trama,longitud*2+3);
longitud1=longitud*2+5;
for (i=0;i<longitud1;i++)
{
printf("%c",modbus.trama);
}
break;
case 0x06:
//guardamos los registros a partir de la direccion indicada
for (i=0;i<2;i++)
{
if (direccion<100)
modbus.datos[direccion*2+i]=modbus.trama[4+i];
else
write_ext_eeprom(direccion*2+i,modbus.trama[4+i]);
}
//respuesta al master
for (i=0;i<8;i++)
{
printf("%c",modbus.trama);
}
//mirar si hay algun comando nuevo (en la primera word recibida)
comando() ;
break;
case 0x10:
bytes=modbus.trama[6];
//guardamos los registros a partir de la direccion indicada
for (i=0;i<bytes;i++)
{
if (direccion<100)
modbus.datos[direccion*2+I]=modbus.trama[7+i];
else
write_ext_eeprom(direccion*2+I,modbus.trama[7+i]);
}
//respuesta al master
//longitud1=num_datos+7;
//calcular el CRC para la respuesta
Mb_calcul_crc(modbus.trama,6);
//mandar la respuesta
for (i=0;i<8;i++)
{
printf("%c",modbus.trama);
}
//mirar si hay algun comando nuevo
comando() ;
break;
default:
}
}
/************************************************************************************
analiza : analiza los caracteres recibidos para montar un paquete
*************************************************************************************
entrada :
-------
c : caracter procedente de la usart
salida : ---
--------
************************************************************************************/
void analiza(char c)
{
switch (puntero)
{
case 0:// recibo el esclavo a quien va dirigido
if (c==modbus.address) //si el comando es para mi
{
modbus.trama[0]= c;
puntero+=1;
}
else
{
puntero =0;
pausa_rx=true;
}
break;
case 1:// recibo el comando
if (c == 0X03 ||c==0x04 ||c==0x06||c==0x10 ) //si es un comando conocido
{
modbus.trama[1]= c;
puntero+=1;
}
else
{
if (c==modbus.address) //si el comando es para mi
{
modbus.trama[0]=c;
puntero=1;
set_timer1(0);
}
else
{
puntero=0;
}
}
break;
case 2:
modbus.trama[2]=c; //direccion inicial (H)
puntero+=1;
break;
case 3:
modbus.trama[3]=c; //direccion inicial (L)
puntero+=1;
break;
case 4:
modbus.trama[4]=c; //Numero de registros (H)
puntero+=1;
break;
case 5:
modbus.trama[5]=c; //Numero de registros (L)
puntero+=1;
break;
case 6:
modbus.trama[6]=c; //CRC (H)
puntero+=1;
if (modbus.trama[1] == 0X10)//si se trata del comando 0x10
{
// num_datos = (modbus.trama[4]<<+modbus.trama[5];
// num_datos=num_datos*2+2;//datos que faltan por recibir incluido CRC
num_datos=(int)modbus.trama[6] + 2;
puntdatos=0;
}
break;
case 7:
if (modbus.trama[1] == 0X10)//si se trata del comando 0x10
{
modbus.trama[7+puntdatos]=c;
puntdatos+=1;
if (puntdatos>= num_datos) // si no se han recibido todos los datos
{
if (Mb_test_crc(modbus.trama,5+num_datos)==0)
{
int_modbus(); //rutina para interpretar el comando
hay_modbus=1;
}
puntero=0;
puntdatos=0; //
}
}
else // no se trata del comando 0x10
{
modbus.trama[7]=c; //CRC (L)
if (Mb_test_crc(modbus.trama,6)==0)
{
int_modbus(); //rutina para interpretar el comando
hay_modbus=1;
puntero=0;
}
else
{
puntero=0; //el CRC no es correcto
}
}
break;
default:
puntero =0;
}
}
saludossss