View previous topic :: View next topic |
Author |
Message |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
Modbus kbhit() not triggering |
Posted: Fri Feb 19, 2021 1:39 pm |
|
|
Hi,
I have a breadboard setup with a PIC16F1788 (Modbus slave) and MAX485.
Wiring was tested with simple printf().
Hardware serial port pins (C6 Tx, C7 Rx, B5 RE/DE).
On the computer (master) the program QModMaster.
At uC boot the LED blinks for 2 seconds. Ok, program is running with internal oscillator.
Then I would expect it to toggle every time there are incoming data, but it does not and the master says "timeout".
RX and REDE have 10 kOhm pull up.
REDE is low, therefore I see the data sent from the PC, with the oscilloscope, at the RX pin.
All good so far, but modbus_kbhit() isn't going to 1, and no response is sent.
Code: |
////modbus slave example
#include <16F1788.h>
#fuses INTRC_IO, PUT, NOWDT, NOLVP, PROTECT, NODEBUG
#use delay(clock=8000000)
#define STATUS_LED PIN_B3
#define MODBUS_SERIAL_INT_SOURCE MODBUS_INT_RDA
#define MODBUS_TYPE MODBUS_TYPE_SLAVE
#define MODBUS_SERIAL_TYPE MODBUS_RTU //use MODBUS_ASCII for ASCII mode
#define MODBUS_SERIAL_BAUD 9600
#define MODBUS_SERIAL_ENABLE_PIN PIN_B5 // Controls DE pin for RS485
//#define MODBUS_SERIAL_RX_ENABLE PIN_B5 // Controls RE pin for RS485
#include <modbus.c>
#define MODBUS_ADDRESS 31
void main()
{
setup_adc_ports(NO_ANALOGS);
//flash a few times the LED
for(int i=0; i<20; i++){
output_toggle(STATUS_LED);
delay_ms(100);
}
modbus_init();
while(TRUE) {
if(modbus_kbhit()){
output_toggle(STATUS_LED);
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)
{
//////////////ex_modbus_slave.c
}
}
}
}
} |
|
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9200 Location: Greensville,Ontario
|
|
Posted: Fri Feb 19, 2021 1:42 pm |
|
|
Have you the proper terminations? pullup, bias, pulldown ?
Haven't got AB flipped to BA ?? |
|
![](templates/subSilver/images/spacer.gif) |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Fri Feb 19, 2021 1:59 pm |
|
|
No, because with printf I receive on the computer, so, the hardware is ok.
Modbus is such a bad protocol.
For some other things I used a string in JSON format...so easy to parse, and send floating point and large numbers without splitting them in bytes. |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9200 Location: Greensville,Ontario
|
|
Posted: Fri Feb 19, 2021 6:29 pm |
|
|
Hmm. the program you posted doesn't enable the RDA interrupt !
Also no ISR. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Feb 19, 2021 7:46 pm |
|
|
temtronic,
It does those things in modbus_phy_layer_rtu.c
Code: |
#if (MODBUS_SERIAL_INT_SOURCE==MODBUS_INT_RDA)
#int_rda
.
.
.
void incomming_modbus_serial()
{
char c;
c=fgetc(MODBUS_SERIAL);
.
.
.
|
Code: | void RCV_ON(void)
{
.
.
.
#if(MODBUS_SERIAL_INT_SOURCE==MODBUS_INT_RDA)
enable_interrupts(INT_RDA);
.
.
} |
|
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
Re: Modbus kbhit() not triggering |
Posted: Sat Feb 20, 2021 1:31 am |
|
|
What happens if you increase the timeout number by 10x as shown
below in bold ? Try it, just as a test.
Quote: | #define MODBUS_SERIAL_TIMEOUT 100000 // was 10000 for RTU
#define MODBUS_SERIAL_INT_SOURCE MODBUS_INT_RDA
#define MODBUS_TYPE MODBUS_TYPE_SLAVE
#define MODBUS_SERIAL_TYPE MODBUS_RTU //use MODBUS_ASCII for ASCII mode
#define MODBUS_SERIAL_BAUD 9600
#define MODBUS_SERIAL_ENABLE_PIN PIN_B5 // Controls DE pin for RS485
//#define MODBUS_SERIAL_RX_ENABLE PIN_B5 // Controls RE pin for RS485
#include <modbus.c>
#define MODBUS_ADDRESS 31
|
|
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19446
|
|
Posted: Sat Feb 20, 2021 1:58 am |
|
|
Yes, it does enable the interrupt in the physical layer, but only if he has
it defined. He is not telling the driver where the interrupt is to come
from or even what serial to use, |
|
![](templates/subSilver/images/spacer.gif) |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Sat Feb 20, 2021 3:53 am |
|
|
I agree that the symptom is that the PIC is missing to interrupt upon serial receive.
Isn't this like enough to tell the modbus library to use the first hardware serial port?
Code: |
#define MODBUS_SERIAL_INT_SOURCE MODBUS_INT_RDA |
To make sure the hardware is ok I made a simple test program that toggle a led when there is a serial interrupt.
Code: |
#use rs232(baud=.........);
#int_rda
void serial_isr(){
output_toggle(STATUSLED);
}
void main(){
enable_interrupts(int_rda);
enable_interrupts(global);
while(true){}
}
|
and the led flashes when in the QmodMaster program I click the button to read a register.
My compiler version is 5.034 |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19446
|
|
Posted: Sat Feb 20, 2021 4:19 am |
|
|
Yes.
The thing that worries me, is that 'as shown', you have nothing defined to
turn the RS485 bus round. You have remmed out the RE define, so it
can only work with a full duplex connection. If the bus is not being set to
receive, how can it receive anything?...
You do realise that the kbhit does not go 'true' when a character is received?.
It only goes TRUE when a modbus packet is seen. |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9200 Location: Greensville,Ontario
|
|
Posted: Sat Feb 20, 2021 6:02 am |
|
|
More curiousness...
Am I to 'assume' that the included file 'modbus.c' is from CCS and NOT been modified in any way ???
It'd be nice to see a comment at the end of the line saying WHERE it came from and the version(date) of it !
If it is the CCS version, I 'assume' it's pretty 'solid' code otherwise someone would have reported it ?? I know that CCS will update a 'driver' or 'EX_ample code, so it might be important to know the 'version'. |
|
![](templates/subSilver/images/spacer.gif) |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Sat Feb 20, 2021 7:31 am |
|
|
The bus and the MAX485 is set to receive because I see on the RX pin of the uC the serial data sent from QmodMaster.
Even if I hard wire the RE-DE pins to have it always in receive, I should see the PIC responding something on the TX pin following something on the RX, but it does not.
Somewhere in the forum I read that is not good to have two #define for the same pin. I read that in case RE-DE are connected together, I should only define MODBUS_SERIAL_ENABLE_PIN.
Anyway defining also MODBUS_SERIAL_RX_ENABLE does not work either.
The example that came with the compiler is from 2013, apparently. I haven't modified it.
Quote: | You do realise that the kbhit does not go 'true' when a character is received?. It only goes TRUE when a modbus packet is seen. |
Ahhh ok. I misunderstood that.
I am wondering if the packet from the PC is a valid modbus packet now... |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19446
|
|
Posted: Sat Feb 20, 2021 8:19 am |
|
|
Yes, that is the critical question... |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9200 Location: Greensville,Ontario
|
|
Posted: Sat Feb 20, 2021 8:23 am |
|
|
OK, silly question...
You have the PIC set for modbus adrs #31.
Does the PC send data to adres #31 ??
I don't use MODbus and don't have time to decode what it's doing perhaps others have. I would not expect anything from the PIC if you're not sending #31 with the 'data packet' or whatever it's called.... |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19446
|
|
Posted: Mon Feb 22, 2021 8:08 am |
|
|
and one little extra 'caveat' on that. Some of the PC packages default to using
hex for address. |
|
![](templates/subSilver/images/spacer.gif) |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Mon Feb 22, 2021 11:29 am |
|
|
Yes the address is correct.
So, I've tied both Re and DE to GND so the MAX485 is always on receive.
I've hooked the scope with signal decoding to the RX pin (inverted).
I see a packed that is correct (haven't checked the CRC).
I've changed the address to 2 on both C program and QmodMaster.
So, my QModMaster program is set to read 1 holding register (FC=3) starting at 1, from slave 2, at 9600 bps.
On the oscilloscope's decoder I get:
02 - 03 - 00 01 - 00 01 - D5 F9
Address - FunctionCode - start address - how many bytes to read - CRC
https://www.modbustools.com/modbus.html#function03
It seems all right.
On the TX pin however I see no answer from the uC.
Do I have a buggy library? At this point probably CCS knows what to do.
Here is my program, which is basically the CCS example with minimal changes. I removed some proprietary CCS code in the switch-case statements.
Code: |
////modbus slave example
#include <16F1788.h>
#fuses INTRC_IO, PUT, NOWDT, NOLVP, PROTECT, NODEBUG //INTRC_IO to be able to use A7 and A6 as GPIO
#use delay(clock=8000000)
#define STATUS_LED PIN_B3
#define MODBUS_SERIAL_TIMEOUT 100000
#define MODBUS_SERIAL_INT_SOURCE MODBUS_INT_RDA
#define MODBUS_TYPE MODBUS_TYPE_SLAVE
#define MODBUS_SERIAL_TYPE MODBUS_RTU //use MODBUS_ASCII for ASCII mode
#define MODBUS_SERIAL_BAUD 9600
#define MODBUS_SERIAL_ENABLE_PIN PIN_B4 // Controls DE pin for RS485
#define MODBUS_SERIAL_RX_ENABLE PIN_B5 // Controls RE pin for RS485
#include <modbus.c>
#define MODBUS_ADDRESS 2
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);
for(int i=0; i<20; i++){
output_toggle(STATUS_LED);
delay_ms(100);
}
modbus_init();
while(TRUE)
{
if(modbus_kbhit()){
output_toggle(STATUS_LED);
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
break;
case FUNC_READ_HOLDING_REGISTERS:
case FUNC_READ_INPUT_REGISTERS:
break;
case FUNC_WRITE_SINGLE_COIL: //write coil
break;
case FUNC_WRITE_SINGLE_REGISTER:
break;
case FUNC_WRITE_MULTIPLE_COILS:
break;
case FUNC_WRITE_MULTIPLE_REGISTERS:
break;
default: //We don't support the function, so return exception
modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_FUNCTION);
}
}
}//end of if modbus_kbhit()
}
} |
|
|
![](templates/subSilver/images/spacer.gif) |
|