|
|
View previous topic :: View next topic |
Author |
Message |
Orcino
Joined: 07 Sep 2003 Posts: 56
|
Modbus slave with PIC24FJ128GA204 |
Posted: Tue Dec 27, 2016 12:03 pm |
|
|
Hello Guys,
I made some modifications in the example modbus_slave, to use the PIC24FJ128GA204, but it's not working.
Tested hardware with a program for RS485 network and is running.
I put a break point, below the while (! modbus_kbhit ());, but the program gets stuck in while (! modbus_kbhit ());
To test I'm using the program ModbusMAT 1.1
Can anyone help?
Thank you
Code: | #include <24FJ128GA204.h>
#device ICD=TRUE
#FUSES NOOSCIO
#FUSES PR
#FUSES HS
#FUSES NOWDT // No Watch Dog Timer
#FUSES NOJTAG // JTAG disabled
#FUSES NOCKSNOFSM // Clock Switching is disabled, fail Safe clock monitor is disabled
#FUSES NOIESO // Internal External Switch Over mode disabled
#FUSES NOWPFP // Write/Erase Protect Page Start/End Location, set to page 0
#FUSES NOBROWNOUT // No brownout reset
#FUSES NODSBOR // BOR disabled in Deep Sleep
#FUSES NODSWDT // Deep Sleep Watchdog Timer disabled
#FUSES NODS // Deep Sleep operation is always disabled
#use delay(clock=20MHz, crystal)
#pin_select U2TX=PIN_C0
#pin_select U2RX=PIN_C2
//#use rs232(UART2, baud=9600,enable=PIN_C1,errors, stream=RS485)
#define MODBUS_TYPE MODBUS_TYPE_SLAVE
#define MODBUS_SERIAL_TYPE MODBUS_RTU
#define MODBUS_SERIAL_RX_BUFFER_SIZE 64
#define MODBUS_SERIAL_BAUD 9600 // 9600
#define MODBUS_SERIAL_INT_SOURCE MODBUS_INT_RDA2 // Uses hardware UART
#define MODBUS_SERIAL_ENABLE_PIN PIN_C1 // Controls DE pin for RS485
#define MODBUS_ADDRESS 0x01
#define MODBUS_TIMER_USED MODBUS_TIMER_T2
#define MODBUS_TIMER_UPDATE MODBUS_TIMER_ISR
#include <modbus.c>
int8 swap_bits(int8 c)
{
return ((c&1)?128:0)|((c&2)?64:0)|((c&4)?32:0)|((c&8)?16:0)|((c&16)?8:0)
|((c&32)?4:0)|((c&64)?2:0)|((c&128)?1:0);
}
void main()
{
int8 coils = 0b00000101;
int8 inputs = 0b00001001;
int16 hold_regs[] = {0x8800,0x7700,0x6600,0x5500,0x4400,0x3300,0x2200,0x1100};
int16 input_regs[] = {0x1100,0x2200,0x3300,0x4400,0x5500,0x6600,0x7700,0x8800};
int16 event_count = 0;
setup_adc_ports(NO_ANALOGS);
modbus_init();
while(TRUE)
{
while(!modbus_kbhit());
delay_us(50);
//check address against our address, 0 is broadcast
if((modbus_rx.address == MODBUS_ADDRESS) || modbus_rx.address == 0)
{
switch(modbus_rx.func)
{
case FUNC_READ_COILS: //read coils
case FUNC_READ_DISCRETE_INPUT: //read inputs
if(modbus_rx.data[0] || modbus_rx.data[2] ||
modbus_rx.data[1] >= 8 || modbus_rx.data[3]+modbus_rx.data[1] > 8)
modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
else
{
int8 data;
if(modbus_rx.func == FUNC_READ_COILS)
data = coils>>(modbus_rx.data[1]); //move to the starting coil
else
data = inputs>>(modbus_rx.data[1]); //move to the starting input
data = data & (0xFF>>(8-modbus_rx.data[3])); //0 out values after quantity
if(modbus_rx.func == FUNC_READ_COILS)
modbus_read_coils_rsp(MODBUS_ADDRESS, 0x01, &data);
else
modbus_read_discrete_input_rsp(MODBUS_ADDRESS, 0x01, &data);
event_count++;
}
break;
case FUNC_READ_HOLDING_REGISTERS:
case FUNC_READ_INPUT_REGISTERS:
if(modbus_rx.data[0] || modbus_rx.data[2] ||
modbus_rx.data[1] >= 8 || modbus_rx.data[3]+modbus_rx.data[1] > 8)
modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
else
{
if(modbus_rx.func == FUNC_READ_HOLDING_REGISTERS)
modbus_read_holding_registers_rsp(MODBUS_ADDRESS,(modbus_rx.data[3]*2),hold_regs+modbus_rx.data[1]);
else
modbus_read_input_registers_rsp(MODBUS_ADDRESS,(modbus_rx.data[3]*2),input_regs+modbus_rx.data[1]);
event_count++;
}
break;
case FUNC_WRITE_SINGLE_COIL: //write coil
if(modbus_rx.data[0] || modbus_rx.data[3] || modbus_rx.data[1] > 8)
modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
else if(modbus_rx.data[2] != 0xFF && modbus_rx.data[2] != 0x00)
modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_VALUE);
else
{
if(modbus_rx.data[2] == 0xFF)
bit_set(coils,modbus_rx.data[1]);
else
bit_clear(coils,modbus_rx.data[1]);
modbus_write_single_coil_rsp(MODBUS_ADDRESS,modbus_rx.data[1],((int16)(modbus_rx.data[2]))<<8);
event_count++;
}
break;
case FUNC_WRITE_SINGLE_REGISTER:
if(modbus_rx.data[0] || modbus_rx.data[1] >= 8)
modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
else
{
hold_regs[modbus_rx.data[1]] = make16(modbus_rx.data[2],modbus_rx.data[3]);
modbus_write_single_register_rsp(MODBUS_ADDRESS,
make16(modbus_rx.data[0],modbus_rx.data[1]),
make16(modbus_rx.data[2],modbus_rx.data[3]));
}
break;
case FUNC_WRITE_MULTIPLE_COILS:
if(modbus_rx.data[0] || modbus_rx.data[2] ||
modbus_rx.data[1] >= 8 || modbus_rx.data[3]+modbus_rx.data[1] > 8)
modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
else
{
int i,j;
modbus_rx.data[5] = swap_bits(modbus_rx.data[5]);
for(i=modbus_rx.data[1],j=0; i < modbus_rx.data[1]+modbus_rx.data[3]; ++i,++j)
{
if(bit_test(modbus_rx.data[5],j))
bit_set(coils,7-i);
else
bit_clear(coils,7-i);
}
modbus_write_multiple_coils_rsp(MODBUS_ADDRESS,
make16(modbus_rx.data[0],modbus_rx.data[1]),
make16(modbus_rx.data[2],modbus_rx.data[3]));
event_count++;
}
break;
case FUNC_WRITE_MULTIPLE_REGISTERS:
if(modbus_rx.data[0] || modbus_rx.data[2] ||
modbus_rx.data[1] >= 8 || modbus_rx.data[3]+modbus_rx.data[1] > 8)
modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
else
{
int i,j;
for(i=0,j=5; i < modbus_rx.data[4]/2; ++i,j+=2)
hold_regs[i] = make16(modbus_rx.data[j],modbus_rx.data[j+1]);
modbus_write_multiple_registers_rsp(MODBUS_ADDRESS,
make16(modbus_rx.data[0],modbus_rx.data[1]),
make16(modbus_rx.data[2],modbus_rx.data[3]));
event_count++;
}
break;
default: //We don't support the function, so return exception
modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_FUNCTION);
}
}
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Dec 27, 2016 12:53 pm |
|
|
Go into the file that has the modbus_kbhit() function in it and put
breakpoints in it. Find out what line of code is causing the problem.
Quote: | c:\program files\picc\drivers\modbus_app_layer.c
|
It calls modbus_check_timeout(), in this file:
Quote: | c:\program files\picc\drivers\modbus_phy_layer_rtu.c |
That routine calls get_ticks() and modbus_timeout_now().
Anyway, you can keep placing breakpoints farther inside (if necessary)
until you find the line of code that's causing the problem. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Tue Dec 27, 2016 1:08 pm |
|
|
I think you may find this is your problem:
#define MODBUS_SERIAL_ENABLE_PIN PIN_C1 // Controls DE pin for RS485
The CCS driver has two defines controlling the buffer. The comment in the file is not very clear.
The MODBUS_SERIAL_ENABLE_PIN is used to control the buffer on/off pin.
MODBUS_SERIAL_RX_ENABLE, is the line used to control the buffer direction.
Normally you don't need MODBUS_SERIAL_ENABLE_PIN, however you must have MODBUS_SERIAL_RX_ENABLE to control the bus direction. Obviously if the bus is not being set to receive, then your receive interrupt will never see anything..... |
|
|
Orcino
Joined: 07 Sep 2003 Posts: 56
|
|
Posted: Tue Dec 27, 2016 4:07 pm |
|
|
Hi Ttelmah,
I changed the lines you mentioned, but not solved.
When the program is compiled, shows the following messages.
--- Info 300 "C:\Program Files (x86)\PICC\Drivers\modbus_phy_layer_rtu.c" Line 25(1,1): More info: Timer 1 tick time is 102,40 us
>>> Warning 216 "exemplo_modbus_slave.c" Line 251(1,2): Interrupts disabled during call to prevent re-entrancy: (modbus_enable_timeout)
>>> Warning 216 "exemplo_modbus_slave.c" Line 251(1,2): Interrupts disabled during call to prevent re-entrancy: (modbus_calc_crc)
Is that why does not work ? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Wed Dec 28, 2016 4:11 am |
|
|
No. They use the CRC routine both inside and outside the interrupt (silly, they should just duplicate it), and the enable is a tiny routine, so 'fair enough'.
I'd be going through your hardware really carefully. How is the RS485 buffer actually wired?. The 'standard' way is to have the buffer permanently enabled (hence not needing the DE line), and setup so it receives all the time it is not transmitting. Then the RX enable controls the actual direction it is working. You should also have a pull-up resistor on the RX line out of the buffer (otherwise you can get spurious 'garbage' received when it is not receiving). Similarly, have you got the bus properly biased when idle?. This wouldn't cause a problem sending simple messages each way, but will with Modbus.
Do you have a logic analyser or scope?. You need to verify that your PIC is receiving data when the PC program sends. Then you will know that the buffer is setup the correct way for this driver.
Once you are sure that data is actually arriving at the PIC, step into PCM_programmer's suggestion and debug deeper into the routine that hangs. |
|
|
Orcino
Joined: 07 Sep 2003 Posts: 56
|
|
Posted: Wed Dec 28, 2016 12:04 pm |
|
|
Thanks Ttelmah.
The problem was in the configuration of the communication. Parity was disabled on the MASTER.
I'm with a doubt. How to write the records ? I want to use the function 3 -HOLDING_REGISTERS.
I need to send 4 variables to the PLC. |
|
|
Orcino
Joined: 07 Sep 2003 Posts: 56
|
|
Posted: Wed Dec 28, 2016 1:42 pm |
|
|
I found out just put the values in the hold_regs[].
Thanks |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Thu Dec 29, 2016 2:34 am |
|
|
Well spotted.
Sounds as if you have moved nicely forwards. |
|
|
|
|
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
|