CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Serial MODBUS supporting PDU03 and PDU16

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
Kevin Bloch



Joined: 18 Jan 2007
Posts: 1
Location: Western Australia

View user's profile Send private message

Serial MODBUS supporting PDU03 and PDU16
PostPosted: Thu Jan 18, 2007 6:08 pm     Reply with quote

//************************************************************************
//* MODBUS Slave Device *
//************************************************************************
//* *
//* MODBUS Slave Device, Accepts PDU 03 (read multiple reg's) *
//* and PDU 16 (write multiple reg's). *
//* *
//* The major constraint to this code is that only about 25 registers *
//* can be sent or received due to the lack of memory in the PIC and *
//* the large amount required for the receive and transmit buffer. *
//* - Ideally external memory should be added to increase this limit *
//* *
//* Note: If you need to read or write a large number of registers in *
//* one read/write request you may have to increase the buffer size. *
//* *
//* WARNING! use this code at your risk. *
//************************************************************************

#include <16F88.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_B2,rcv=PIN_B1, STREAM=PC) // --- TX = pin 10, RX = pin 11

#include <STDLIB>
#include <string.h>

#DEFINE LED PIN_B3 //DIAG LED
#DEFINE MAXREG 25

int SlaveAddress = 1;

unsigned int buffer[31];
unsigned int tx_buffer[35];

int16 registers[MAXREG];
int16 crc = 0;
int stop = 0;

int cal_crc(unsigned int dataLength,char check); //CRC 16 for modbus checksum
unsigned char mb_req_pdu();
void mb_rsp_pdu_16(void); //response for modbus 16 function preset multiple registers
void writeBadRequest(unsigned char error); //response for error in modbus poll
void mb_rsp_pdu_03(void); //response for modbus 3 function read multiple registers
void crc16(char value);
void split(unsigned int16 value);

typedef struct {
unsigned int high_byte;
unsigned int low_byte;
} s_word;

s_word split_word;

VOID MAIN()
{
int c = 0;

registers[0] = 10; //for read testing
registers[1] = 15; //for read testing

FOR(;;)
{

c = 0;
c = mb_req_pdu(); //MODBUS Request PDU

if (c == 3)
mb_rsp_pdu_03(); //MODBUS Response PDU (func 03)
else
{
if (c==16)
mb_rsp_pdu_16();
else
writeBadRequest(c);
}
}
}


unsigned char mb_req_pdu()
{
unsigned int counter = 0;
unsigned int16 aux;
long timeout = 0;
int temp;

stop = 0;

while ((++timeout < 32000)&&(stop == 0))
{
if(!kbhit(PC))
{
delay_us(1); //wait for keypress
}
else
{
timeout = 0;
if (counter<26> 0)&&(buffer[0] != SlaveAddress)||(counter > 25))
{
stop = 1;
counter = 0;
}
}
}

if(stop == 0)
{
if ((buffer[1] == 16)&(((unsigned int) buffer[6] + 9)!=counter)) return 2; //wrong nr of registers
if (counter > 25) return 2; //to many bytes in frame
if (counter <7>0)|( buffer[5] > 32)) return 2; // to many registers
if( cal_crc(counter - 2,1)) //(counter-2) = data received less the 2byte crc
{
return buffer[1]; //OK
}
else
return 0; //bad CRC
}
else
{
for(temp=0;temp<25>0;i--)
if((crc)&0x0001)
crc = (crc>>1)^0xa001;
else
crc>>=1;
}

int cal_crc(unsigned int dataLength,char check)
{
int j;
int i;
int ser_data;
unsigned char lowCRC;
unsigned char highCRC;

if(check != 2)
{
crc = 0xffff;
for (j=0; j<dataLength>>8;
crc<<8>>8;
}
else
{
crc = 0xffff;
for (j=0; j<dataLength>>8;
crc<<8>>8;
}

if (check==2)
{
tx_buffer[dataLength] = lowCRC;
tx_buffer[dataLength+1] = highCRC;
return 1;
}
else
if (check==1) //input crc checking
{
if ((buffer[dataLength+1] == highCRC) & (buffer[dataLength] == lowCRC ))
return 1;
else
return 0;
}
else
if (check == 0)
{
buffer[dataLength] = lowCRC;
buffer[dataLength+1] = highCRC;
return 1;
}
}

void mb_rsp_pdu_03(void) //response for modbus 03 function (read registers)
{
int16 start_addr = 0;
int16 number_points = 0;
int16 counter = 0;
unsigned int counter2 = 0;

int16 i; //buffer[x]: 0=address,1=function,2=start address high, 3=start address low

start_addr = (255*buffer[2]) + buffer[3];
number_points = (255*buffer[4]) + buffer[5];

tx_buffer[0] = buffer[0];
tx_buffer[1] = buffer[1];
tx_buffer[2] = 2*number_points;

counter2 = 3; //0=address,1=function,2=byte count, 3=first data val...

for(counter=start_addr;counter < (start_addr+number_points);counter++)
{
split(registers[counter]);
tx_buffer[counter2] = split_word.high_byte;
tx_buffer[counter2+1] = split_word.low_byte;
counter2 += 2;
}

i=cal_crc(counter2,2);

for(i=0;i<counter2>0)
{
buffer[1]+=0x80;
buffer[2]=error;
cal_crc(3,0);
for (i=0; i<5; i++)
putc(buffer[i]);
}
}

void mb_rsp_pdu_16(void) //response for modbus 16 function preset multiple registers
{
int16 start_addr = 0;
int16 number_points = 0;
int16 counter = 0;
unsigned int counter2 = 0;
int16 i;

start_addr = (255*buffer[2]) + buffer[3];
number_points = buffer[6]/2;

counter2 = 7; //0=address,1=function,2=start address hi, 3=start address lo, 4=no. registers hi
//5=no. registers lo, 6=byte count, (7=, 8=[register hi, register lo...])

for(counter=start_addr;counter < (start_addr+number_points);counter++)
{
registers[counter] = (255*buffer[counter2])+buffer[counter2+1];
counter2 += 2;
}

i=cal_crc(6,0);

for(i=0;i<8;i++)
{
printf("%C", buffer[i]);
}
}

//*****************************************************************************************
//* Program: Kevin Bloch *
//* Name: split *
//* Inputs: value - a 16bit unsigned integer *
//* Returns: the high and low byte of value, returned as .high_byte and .low_byte *
//* Function: Split an integer into a high and low byte *
//* Last update: 18th Jan 2004 *
//*****************************************************************************************
void split(unsigned int16 value)
{
int16 temp;

temp = (value & 65280) / 256;
split_word.high_byte = (unsigned int)temp;
temp= (unsigned int) value & 255;
split_word.low_byte = temp;
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Jan 20, 2007 2:26 pm     Reply with quote

There are several lines in your code that are garbled.
Here are a few examples:
Quote:

if (counter<26> 0)&&(buffer[0] != SlaveAddress)||(counter > 25))

if (counter <7>0)|( buffer[5] > 32)) return 2;

for (j=0; j<dataLength>>8;

Please see the following topic which explains the problem
and how to fix it.
http://www.ccsinfo.com/forum/viewtopic.php?t=29551


After you have fixed it, I will delete my post (this one).
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group