Last year I was doing some research and i wanted to record the Temperature and humidity (DHT22) in 22 compartments. This was in a factory with lots of steel and concrete and noise spread over a 500 ft radius. Wifi didn't look real feasible. So I opted for a wired network, RS485 and modbus protocol. There are modbus simulators that you can check the slave with from a PC. http://www.modbustools.com/modbus_poll.html . I actually used php to write a program to gather the data into a MySQL database every 5 minutes. Never got implemented yet at the factory but I do have 7 stations running full time at home . Don't get bothered by the BME280 stuff, i am just recording some data and this demonstrates how to add data to the outbuffer.
' Modbus RTU Slave'Onlytwocommands3readregand16modreg' command 3 reads from the variable array "outbuffer(20)" which is ram with sensor data plugged in'command16writestoRAMandisgoingtobeusedforlimits'Adopted/severely modified from Andrzej Sokulski,'andrzej@modbus.pl-www.modbus.pl' All rights reserved.'RewrittenbyMikeotteDecember2016/2017' All rights reserved.'Thissoftwareisfreeyoucanredistributeitand/or' modify it under the terms of the GNU Lesser General Public'LicenseaspublishedbytheFreeSoftwareFoundation;either' version 2.1 of the License, or (at your option) any later version.'*' This software is distributed in the hope that it will be useful,'' but WITHOUT ANY WARRANTY;'Innoeventshalltheregentsorcontributorsbeliableforanydirect,' indirect, incidential, special, exemplary, or consequential damages.'ModbusslavebasedonPIC16F886PIC16F1705'This slave supports modbus function 3 (read holding registers) and 16 (preset multiple registers)'command3readsfromthevariablearray"outbuffer(20)"whichisram'command 16 writes to EEPROM and is going to be used for limits'TheRS232issettobaudrate-9600,databits-8,stopbits1,parity-none'The hardware USART and MSSP/I2C are defined below'TheTimer2isusedfordetectingendofmodbusframe'Master Query'readregisters40000–40008fromslavedevice17:'Example = $0A$03$00$00$00$08$45$77'FieldName(Hex)'Slave Address $0A'Function$03'Starting Address Hi $00'StartingAddressLo$00'No. of Points Hi $00'No.ofPointsLo$08'Error Check ( CRC) $45 –– 16bits = last two bytes of packet'$77'Slave RESPONSE'0A0310018300D1000567C0000804F0841BEFDF133E'Example ASCII RTU'FieldName(Hex)Characters8–BitField'Header : (colon) None'SlaveAddress$0A0A00001010'Function $03 0 3 0000 0011'ByteCount$101000010000'Data Hi $01 0 1 0000 0001'DataLo$838310000011'Data Hi $00 0 0 0000 0000'DataLo$D1D111010001'.....'DataHi$EFEF11101111'Data Lo $DF D F 1101 1111'ErrorCheck$131300010011LRC(2chars.)CRC(16bits)'CRC $3E 3 E 0011 1110'TrailerforasciiCRLF' Total Bytes: 25 11 ASCII mode takes many more chars'ThiscodeonlyimplementsRTU!' Preset Multiple Holding Registers'***********Function16Hex$10''FieldName(Hex)'Slave Address $10'Function$10'Starting Address Hi $00'StartingAddressLo$01'No. of Registers Hi $00'No.ofRegistersLo$02'Byte Count $04'DataHi$00'Data Lo $0A'DataHi$01'Data Lo $02'ErrorCheck$__(LRCorCRC)––twobytes' $__'Responsefromslave'Field Name (Hex)'SlaveAddress$11'Function $10'StartingAddressHi$00'Starting Address Lo $01'No.ofRegistersHi$00'No. of Registers Lo $02'ErrorCheck$__(LRCorCRC)––twobytes' $__; ----- Configuration #chip 16F1705,8 #option explicit #config WDT_OFF, LVP_OFF 'GeneratedbyPICPPSToolforGreatCowBasic'PPS Tool version: 0.0.5.11 'PinManagerdata:v1.55' 'Templatecommentatthestartoftheconfigfile' #startup InitPPS, 85 Sub InitPPS UNLOCKPPS 'Module:EUSARTRXPPS=0x0005'RA5 > RX RC5PPS = 0x0014 'TX>RC5'Module: MSSP RC0PPS = 0x0010 'SCL>RC0SSPCLKPPS=0x0010'RC0 > SCL (bi-directional) RC1PPS = 0x0011 'SDA>RC1SSPDATPPS=0x0011'RC1 > SDA (bi-directional) LOCKPPS End Sub 'Templatecommentattheendoftheconfigfile#include<BME280.h>#include<DHT.h>;----- Define Hardware settings' Define I2C settings - CHANGE PORTS if required #define HI2C_BAUD_RATE 400 #define HI2C_DATA PORTC.1 #define HI2C_CLOCK PORTC.0 'InitialiseI2CSlave'I2C pins need to be input for SSP module Dir HI2C_DATA in Dir HI2C_CLOCK in 'MASTERHI2CModeMaster'DHT 22 Humidity and Temperature #DEFINE DHT_TYPE 22 #DEFINE DHT_PIN PORTA.2 '#definesensorPortA.2'PortA.0 ;RH/Temp sensor on pin dir PORTA.2 in 'sensorin'InitUSART usuart is on a RS485 network #define USART_BAUD_RATE 9600 #define USART_BLOCKING #define MaxDir PortA.4 'RS485directionMax485chipdirPortA.4Out' MAX485 direction control'timer2determinestheendoftheframepr2=0Inittimer2PS2_16,0'Prescale 1:16 /Postscale 1:1 Starttimer 2 On Interrupt UsartRX1Ready Call SerialInterrupt On Interrupt Timer2Match Call Timer2Interrupt;----- VariablesDim SlaveAddress as byteSlaveAddress = 10 'Modbusslaveadress(1..255)dimDHT_rh,DHT_cels,DHT_fahrasintegerdimDHT_errorasByteDimbuffer(74)'Modbus frame buffer - change if want to get more than 32 registers in single frameDim outbuffer(50) 'buffertocollectdatatosendbackbeforetransferingtobufferDimADC_P,ADC_TasLong' variables used by BME280_Read_TPHDim ADC_H as WordDim mbB0 as byte 'VariablesdefinitionDimmbB1asbyte' transmit this byteDim mbW0 as word 'addresspointerDimMBFrameasbyteDimNewFrameasbyteDimLengthasbyteDimTMR2Ticksasbyte'used to determine end of RTU frameDim mbi as byte 'forloopindexDimcounter1asword' waste time counter to do nothingDim counter2 as word 'wastetimecountertodonothingDimGeneratorasword' CRC variable/constant 40961Dim Temp as wordDim CRC as word 'CRCresultDimmbjasbyte' forloop indexDim mbBit as bit 'tempbitvarTMR2Ticks=0Length=0wait500msmainloop:Forcounter2=0to5' The main programFor counter1 = 0 to 10000 'Writeyourcodeherenextcounter1nextcounter2'diagnostic - used for testing 'MaxDir=1'hserprint "I am here " 'MaxDir=0' MaxDir = 1 'hserprintLength'MaxDir = 0'ModbusprotocolfunctionIfNewFrame=1Then' Check if new modbus frame is in buffer NewFrame = 0 Gosub checkMB 'CheckthemodbusReceivedframeSelectCaseMBFramecase3'MaxDir = 1 'hserprint"case 3 "'MaxDir = 0 mbReadRegResponse 'Responseforfunction3case16mbwriteRegResponse' Response for function 16 case else mbwriteBadRequest 'ResponseforerrorendselectLength=0EndifGotomainloopSubcharoutxmty:' USART send single byte If TXIF = 0 Then goto xmty 'WaitfortransmitregisteremptyTXREG=mbB1' Send character to transmit registerEnd SubSub crc__16'crc__16:' Function to calculate CRC16 checksumCRC = 65535 'CRCiswordandissettoall1's to startGenerator = 40961For mbi = 1 To Length Temp = buffer(mbi) CRC = CRC # Temp ''XOR ed For mbj = 1 To 8 STATUS.C = 0 Rotate CRC right 'CRC=CRC>>1mbBit=STATUS.CIfmbBitThenCRC=CRC#Generator'XOR ed End If NextNext'crc16(2)=CRC/256' CRC16 high byte'crc16(1)=SysCalcTempX' CRC16 low byte'CRCcontainstheCRCword16bitEndSubSubcheckMB'checkMB:'Checkthemodbusframeif(buffer(1)<>SlaveAddress)then'Wrong Slave address MBFrame = 0 Exit Sub end if if (buffer(2) <> 3) AND (buffer(2) <> 16) then 'WrongModbusfunctionMBFrame=0x81ExitSubendif'hserprint "wrong" 'if((buffer(5)>0)OR(buffer(6)>32))then'Too many registers 'MBFrame=0x83'Exit Sub 'endif'hserprint "Toomanyreg" if (Length > 74) then 'ToomanybytesinframeMBFrame=0x82ExitSubendif'hserprint "len74" if (Length <9) then 'FrametooshortMBFrame=0x81ExitSubendif'Check CRC Length = Length - 3 crc__16 'diagnosticCRCvalues(1)'MaxDir = 1 'hserprintcrc'MaxDir = 0 if (buffer(Length+1) <> [byte]CRC) OR (buffer(Length+2) <> CRC_H) then 'BadCRC16checksumMBFrame=0elseMBFrame=buffer(2)' Frame OK ! End ifEnd SubSub mbReadRegResponse 'readRegResponse:' Response for modbus function 3 (Read Holding Registers) 'UPDATERegistersfirst' DHT22 fills outbuffer 1-4 are written in the DHT22 sub readDHT( DHT_rh , DHT_cels, DHT_fahr , DHT_error ) outbuffer(1)=DHT_rh_H 'Writedatatobufferoutbuffer(2)=DHT_rh'Remember Holding Registers asked byt the master are 16 bit outbuffer(3)=DHT_cels_H 'sothatistwobytesoutbuffer(4)=DHT_celsBME280_Read_TPHoutbuffer(5)=adc_P_E' Write data to buffer outbuffer(6)=adc_P_U outbuffer(7)=adc_P_H outbuffer(8)=adc_P outbuffer(9)=adc_T_E 'Writedatatobufferoutbuffer(10)=adc_T_Uoutbuffer(11)=adc_T_Houtbuffer(12)=adc_Toutbuffer(13)=adc_H_Houtbuffer(14)=adc_H' outbuffer is 50 bytes of which we only filled 14 so far mbW0 = buffer(3)*255 + buffer(4) 'Startingaddress'mbW0 = mbW0 * 2 mbW0 = mbW0 - 40000 '40000issecretMODBUSoffsetforholdingregistersbuffer(3)=buffer(6)*2' buffer(6) is num of points(words) LO which is getting buffer ready for Tx 'buffer(3)isthenumberofdatabytestoxfer' Header neads MBaddress byte, MBcommand byte, Number of bytes to Xfer in the header 'theyarealreadythereformbB0=1tobuffer(3)buffer(mbB0+3)=outbuffer(mbB0)' Put data in buffer from ram ,leave room for header Next Length = buffer(3) + 3 'Buffer(3)=Lengthcrc__16buffer(Length+1)=[byte]CRC'crc16(1) 'CalculatetheCRC16forresponseframebuffer(Length+2)=CRC_H'crc16(2) Length = Length + 4 MaxDir = 1 'MAX485directioncontrol=TxFormbB0=1ToLength' Send the response to Master mbB1 = buffer(mbB0) Gosub charout Next MaxDir = 0 'MAX485directioncontrol+RxEndsubSubmbwriteRegResponse'writeRegResponse 'Responseformodbus16function(PresetMultipleRegisters)''SlaveAddress$0A'buffer(1)'Function$10'buffer(2)'StartingAddressHi$00'buffer(3)'StartingAddressLo$01'buffer(4)'No.ofRegistersHi$00'buffer(5)'No.ofRegistersLo$02'buffer(6)'ByteCount$04'buffer(7)'DataHi$00'Data Lo $0A'DataHi$01'Data Lo $02'ErrorCheck$__(LRCorCRC)––twobytes' $__ mbW0 = buffer(3)*255 + buffer(4) 'Calculatethestartingaddressofregisters(Holdingregistersare16bit)mbW0=(mbW0*2)-1' Claculate starting memory byte to write to.... 2 bytes per holding register for mbB0 = 0 TO (buffer(7)-1) 'buffer(7)containsthebytecountmbB1=buffer(mbB0+8)' Get byte of data 'EPWritembW0,mbB1' Write data to EEPROM memory outbuffer(mbW0) = mbB1 'writedatatomemorymbW0=mbW0+1' increment memory pointer 'wait10msNEXT'Response from slave'FieldName(Hex)'Slave Address $0A all ready in buffer(1)'Function$10allreadyinbuffer(2)'Starting Address Hi $00 all ready in buffer(3)'StartingAddressLo$01allreadyinbuffer(4)'No. of Registers Hi $00 all ready in buffer(5)'No.ofRegistersLo$02allreadyinbuffer(6)'Error Check $__(LRC or CRC) –– two bytes'$__Length=6'Tell crc how many to calccrc__16 'CalculatetheCRC16forresponseframe'CRC field is appended to the message as the last field in the message.'thelow–orderbyteofthefieldisappendedfirst,followedbythe'high–order byte.buffer(length+1) = [byte]CRC 'crc16(1)buffer(length+2)=CRC_H'crc16(2)Length = Length + 4MaxDir = 1For mbB0 = 1 To Length 'SendtheresponsetoMastermbB1=buffer(mbB0)GosubcharoutNextMaxDir=0EndSubSubmbwriteBadRequest'writeBadRequest: 'Responseforerrorinmodbuspoll'the following message is sent as ascii and you can see what the crc of the master should be'putthedecimalvalueintheprogrammerscalculator,switchtohex,andreversethetwobytes' remember crc is low byte first, high byte second in the frame packetMaxDir =1hserprint "bad crc should be = "hserprint crcHSerPrintCRLFMaxDir =0if (MBFrame <> 0) then 'IfMBFrame=0thennoresponsebuffer(2)=buffer(1)+0x80' Set the error code in modbus frame buffer(3)=MBFrame - 0x80 'SettheerrornrLength=3crc__16buffer(length+1)=[byte]CRC'crc16(1) 'CalculatetheCRC16forresponseframebuffer(length+2)=CRC_H'crc16(2) Length = Length + 4 MaxDir = 1 For mbB0 = 1 To Length 'SendtheresponsetoMastermbB1=buffer(mbB0)GosubcharoutNextmbB0MaxDir=0EndifEndSub'readMB:Sub SerialInterrupt If OERR then 'OERRorFERRRC1STA.2IfUSARTerrorthencleartheerrorflagCREN=0'CREN end if If FERR then 'OERRorFERRRC1STA.2IfUSARTerrorthencleartheerrorflagCREN=0'CREN end if CREN = 1 if RCIF then 'RCIFUSARTRECInterrupt(PIR1.5=1)TMR2Ticks=0' reset time out which indicates end of MBFrame If (NewFrame = 1) OR (Length = 0) then 'NewmodbusframestartNewFrame=0T2CON.2=1' Enable Timer2 Length = 1 End If do while RCIF 'Writemodbusframetobuffer(PIR1.5=1)buffer(Length)=RCREGLength=Length+1ifLength=75thenLength=0EndIfloopEndIfEndsubSubTimer2Interruptif(TMR2IF=1)then' Timer2 interrupt flag TMR2IF = 0 TMR2ON = 0 'Timer2disableTMR2Ticks=TMR2Ticks+1IfTMR2Ticks>120then' ~ 10 ms without new char NewFrame = 1 'TherewasnonewcharonUSART=>endofmodbusframeelseTMR2ON=1'Enable timer End If End If 'ResumeEndSub
This is only RTU implementation not ascii. Only used HSer routines for developement and trouble shooting (some are left). It was easier to read and write to the USART. Modbus is a Master /Slave protocol. The Master asks for data or sends data and tells the slave where to put it. The commands sent to the slave and the data sent back from the slave are in packets starting with the slaves address and ending with a CRC16 check. I included some modbus documentation.
GL
Mike
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
about the code for modbus 3 and 16....I would like to use a PLC as master and a glcd as slave.....what modifications must do to above code modbus RTU slave, to work with PIC16F1939 ? the pic that work as slave is connected to a glcd, to diplay text that I send from PLC (modbus master)...so, what is the variable (Rx) that will checked for incoming data in above code ? the above code uses var outbuffer ....below is my first approach to slave code ....the code for writing to glcd is ok....just to setup pic uart for RS-485 and check for incoming ..
modbus slave ........initialize
glcd ......initialize
var( Rx)= modbus slave : check for incoming
locate glcd cursor ...... var ( Idx = total pixels of glcd ).....go to the begging of row
read holding register value.......var (pic_reg)=modbus slave: read holding reg (Idx)
print value to glcd......print (pic_reg)
modbus error loop .....if Rx=255 then output 1 to a pin .
an opinion for how to add the above code to glcd code...
thanks in advance,
Basil
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Basil,
First question is who is Master and who is slave. Who initiates the communication? Modbus Master sends the command and the slave sends the response. In my experience the slave was the PLC and my Distributed ControlSytem would send and receive from the Holding registers of the PLC thus making the DCS the master.
If you can make your PLC act as Master, then that is fine because everything you need is in the code for Modbus 3 and 16. Your PLC would send the command 16 (modbus 16 function (Preset Multiple Registers)) to the PIC with the data and you would simulate holding registers in the PIC . Remember the holing registers are 16bit words. Then you LCD part of the slave program would write it to the LCD.
Basil,
I tried to comment and answer your questions in the above message.
"what modifications must do to above code modbus RTU slave, to work with PIC16F1939 ?"
Change the #chip 16F1939 ,8
define port for max485 direction
define usart port pins
"the pic that work as slave is connected to a glcd, to diplay text that I send from PLC (modbus master)..."
I am assuming you know how and where to make the PLC Master
"so, what is the variable (Rx) that will checked for incoming data in above code ?"
The master will send a command and it will be received in the " buffer()", It comes in as a data packet and when
the TMR2 times out it says the "Frame" Is received, Then the frame(all the bytes are in the buffer) is checked for address,
command, number of bytes, crc16 and then the command is executed. In your case ,Command 16, you would put the bytes
where you can use them for LCD display, Then a packet is sent back confirming reception.
"the above code uses var outbuffer"
outbuffer has nothing to do with the Modbus code, It is part of my DHT22 code only
"....below is my first approach to slave code ....the code for writing to glcd is ok...."
"just to setup pic uart for RS-485 and check for incoming .. modbus slave ........initialize"
usart baud blocking
set up pins tx, rx, dir
setup interrupts
"glcd ......initialize"
yours
"var( Rx)= modbus slave : check for incoming"
automatically comes in when frame is received complete
"locate glcd cursor ...... var ( Idx = total pixels of glcd ).....go to the begging of row"
what are doing with pixels?
"read holding register value.......var (pic_reg)=modbus slave: read holding reg (Idx)"
Your data is in the buffer and will be sent to your buffer with "Sub mbwriteRegResponse"
which processes the command 16
"print value to glcd......print (pic_reg)"
Your displaying the data
"modbus error loop .....if Rx=255 then output 1 to a pin ."
If errors occur then Modbus sends error message back to the master.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Mike,
many thanks for your detailed answer...
The PLC is Schneider Modicon M221... PLC configured as master and the board with pic-glcd is the slave....from PLC we send a text that displayed to glcd...the communication starts from PLC that send commands and the slave responds.. .because my knowledge about GCB is limited , would you like to help me to merge the two codes?....Anobium has be done an excellent work to help me, and sends to me a code to write characters to a glcd with a pic(PIC16F1939)....I send you that demo code to add if it possible the part of modbus slave code....for now instead of master ( i'll get Modicon later ) I use ComTestPro as modbus master simulator to send commands to slave board.....is it possible to send larger characters to glcd, or ghraphics (bmp) ? for any other info please let me know...
thanks in advance.
Basil
Mike,
I made a modification to code , to display some text...just to test the code....I send you the modified code.... as glcd I use a 240x128 type AGM2412A ( DISPLAYTRONIC) with T6963C...for the hardware I use a PIC16F1939 , an RS-485 connector , an SN75176 as receiver/transmitter for modbus data, the glcd as above ....( If you need schematic please let me know), the connections pic-glcd are : port B to D0-D7 of glcd , RW to pin D.3 , RD to pin C.4, CE to pin C.5, CD to pin D.5, RESET to pin D.6 , FS to pin A.0........connections SN75176 to pic..: pin 1( R) to C.7 pin (RX)..pin 4(D) to pin C.6 (TX)...direction pin ( RE, DE) to pin A.1....
Basil,
This is what I had last night at 11pm.
It wouldn't compile for me because of LCD errors.... I am running 98.03GCB and don't have your GLCD in my library. There are more things I want to change in the interrupts but this is close to running.
Mike,
very good work ...it compile for me, so can I send some characters with ComTestPro to test? is not critical for me the same type of glcd or pic...any type of glcd 240x128 even and 240x64 can be used ...Anobium make the code pic-glcd using a glcd 240x64....with a modification easy can work with 240x128....only to have controller T6963 or similar....I'll make some tests at next hours and inform you about....
best regards
Basil
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Mike,
I made some tests to send characters with ComTestPro...I had no response...I send 10 chars with mb command 16...as it seems at log there is no response with time out error...I was checked hardware for errors...ok...
Basil,
I am working to put together a test board so I can get immediate feedback and trouble shoot.
What you sent looks correct. The time out could be the time out setting on comtestpro is 100 ms and had the scan really slow at 4sec
doForeverwait4s' Modbus protocol function
Try increasing the comtestprotime out to 5000ms Or turn the wait down to something much lower. This would not be a solution but a test.
I probably need to take the "' Modbus protocol function" out and trigger it by itself. When a frame is complete.
I will work on this as I get time. I have to go to town today.
BR
Mike
I moved the processing of the Frame out of the main loop! See attached. This is a severely revised Version that I was working on last night. Worth a try.
Last edit: mmotte 2019-02-15
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Basil,
The time out is beacuse of the setting on the comtestpro timeout in upper right corner 100ms and I had put the processing of the new fram in the display main loop which cycles at 4000ms.
I moved the processing of new frame to the interrupt of the mbtimer2match. this is not ideal but worth a try.
working at putting some hardware together so i can test here
Mike,
after change the mb slave address to 07 , I send 10 chars (ABCDEFGHIJ) , I had response error (time out) , but I had the chars on glcd as below ..
Last year I was doing some research and i wanted to record the Temperature and humidity (DHT22) in 22 compartments. This was in a factory with lots of steel and concrete and noise spread over a 500 ft radius. Wifi didn't look real feasible. So I opted for a wired network, RS485 and modbus protocol. There are modbus simulators that you can check the slave with from a PC. http://www.modbustools.com/modbus_poll.html . I actually used php to write a program to gather the data into a MySQL database every 5 minutes. Never got implemented yet at the factory but I do have 7 stations running full time at home . Don't get bothered by the BME280 stuff, i am just recording some data and this demonstrates how to add data to the outbuffer.
This is only RTU implementation not ascii. Only used HSer routines for developement and trouble shooting (some are left). It was easier to read and write to the USART. Modbus is a Master /Slave protocol. The Master asks for data or sends data and tells the slave where to put it. The commands sent to the slave and the data sent back from the slave are in packets starting with the slaves address and ending with a CRC16 check. I included some modbus documentation.
GL
Mike
Very nice code. Excellent work.
Do have any photos of the opertional solution?
I do have a few pics. Should I post them here or send them via other method? i will post one now
Wonderful - can you send to Bed? And, I can we publish on the WebSite with some nice words?
Took the challenge.
Thanks for sharing your work
Article is online, now.
http://gcbasic.sourceforge.net/Typesetter/index.php/Modbus-Slave
Mike,
about the code for modbus 3 and 16....I would like to use a PLC as master and a glcd as slave.....what modifications must do to above code modbus RTU slave, to work with PIC16F1939 ? the pic that work as slave is connected to a glcd, to diplay text that I send from PLC (modbus master)...so, what is the variable (Rx) that will checked for incoming data in above code ? the above code uses var outbuffer ....below is my first approach to slave code ....the code for writing to glcd is ok....just to setup pic uart for RS-485 and check for incoming ..
modbus slave ........initialize
glcd ......initialize
var( Rx)= modbus slave : check for incoming
locate glcd cursor ...... var ( Idx = total pixels of glcd ).....go to the begging of row
read holding register value.......var (pic_reg)=modbus slave: read holding reg (Idx)
print value to glcd......print (pic_reg)
modbus error loop .....if Rx=255 then output 1 to a pin .
an opinion for how to add the above code to glcd code...
thanks in advance,
Basil
Basil,
First question is who is Master and who is slave. Who initiates the communication? Modbus Master sends the command and the slave sends the response. In my experience the slave was the PLC and my Distributed ControlSytem would send and receive from the Holding registers of the PLC thus making the DCS the master.
If you can make your PLC act as Master, then that is fine because everything you need is in the code for Modbus 3 and 16. Your PLC would send the command 16 (modbus 16 function (Preset Multiple Registers)) to the PIC with the data and you would simulate holding registers in the PIC . Remember the holing registers are 16bit words. Then you LCD part of the slave program would write it to the LCD.
Then the slave sends back the response confirming the transaction.. Header +the number of bytes and CRC16.
What brand and model PLC are you using?
I will help you through this.
Mike
Basil,
I tried to comment and answer your questions in the above message.
"what modifications must do to above code modbus RTU slave, to work with PIC16F1939 ?"
Change the #chip 16F1939 ,8
define port for max485 direction
define usart port pins
"the pic that work as slave is connected to a glcd, to diplay text that I send from PLC (modbus master)..."
I am assuming you know how and where to make the PLC Master
"so, what is the variable (Rx) that will checked for incoming data in above code ?"
The master will send a command and it will be received in the " buffer()", It comes in as a data packet and when
the TMR2 times out it says the "Frame" Is received, Then the frame(all the bytes are in the buffer) is checked for address,
command, number of bytes, crc16 and then the command is executed. In your case ,Command 16, you would put the bytes
where you can use them for LCD display, Then a packet is sent back confirming reception.
"the above code uses var outbuffer"
outbuffer has nothing to do with the Modbus code, It is part of my DHT22 code only
"....below is my first approach to slave code ....the code for writing to glcd is ok...."
"just to setup pic uart for RS-485 and check for incoming .. modbus slave ........initialize"
usart baud blocking
set up pins tx, rx, dir
setup interrupts
"glcd ......initialize"
yours
"var( Rx)= modbus slave : check for incoming"
automatically comes in when frame is received complete
"locate glcd cursor ...... var ( Idx = total pixels of glcd ).....go to the begging of row"
what are doing with pixels?
"read holding register value.......var (pic_reg)=modbus slave: read holding reg (Idx)"
Your data is in the buffer and will be sent to your buffer with "Sub mbwriteRegResponse"
which processes the command 16
"print value to glcd......print (pic_reg)"
Your displaying the data
"modbus error loop .....if Rx=255 then output 1 to a pin ."
If errors occur then Modbus sends error message back to the master.
Mike,
many thanks for your detailed answer...
The PLC is Schneider Modicon M221... PLC configured as master and the board with pic-glcd is the slave....from PLC we send a text that displayed to glcd...the communication starts from PLC that send commands and the slave responds.. .because my knowledge about GCB is limited , would you like to help me to merge the two codes?....Anobium has be done an excellent work to help me, and sends to me a code to write characters to a glcd with a pic(PIC16F1939)....I send you that demo code to add if it possible the part of modbus slave code....for now instead of master ( i'll get Modicon later ) I use ComTestPro as modbus master simulator to send commands to slave board.....is it possible to send larger characters to glcd, or ghraphics (bmp) ? for any other info please let me know...
thanks in advance.
Basil
Basil,
Good information.
Are you making a message display or aiming for a HMI? Could you give a typical message?
I will look this over.
Mike,
I made a modification to code , to display some text...just to test the code....I send you the modified code.... as glcd I use a 240x128 type AGM2412A ( DISPLAYTRONIC) with T6963C...for the hardware I use a PIC16F1939 , an RS-485 connector , an SN75176 as receiver/transmitter for modbus data, the glcd as above ....( If you need schematic please let me know), the connections pic-glcd are : port B to D0-D7 of glcd , RW to pin D.3 , RD to pin C.4, CE to pin C.5, CD to pin D.5, RESET to pin D.6 , FS to pin A.0........connections SN75176 to pic..: pin 1( R) to C.7 pin (RX)..pin 4(D) to pin C.6 (TX)...direction pin ( RE, DE) to pin A.1....
Mike,
I send you a short video to see glcd with pcb that I was designed as modbus monitor....
Basil,
This is what I had last night at 11pm.
It wouldn't compile for me because of LCD errors.... I am running 98.03GCB and don't have your GLCD in my library. There are more things I want to change in the interrupts but this is close to running.
I don't have your GLCD nor the PIC for a test bed
GL
Mike
Mike,
very good work ...it compile for me, so can I send some characters with ComTestPro to test? is not critical for me the same type of glcd or pic...any type of glcd 240x128 even and 240x64 can be used ...Anobium make the code pic-glcd using a glcd 240x64....with a modification easy can work with 240x128....only to have controller T6963 or similar....I'll make some tests at next hours and inform you about....
best regards
Basil
Mike,
I made some tests to send characters with ComTestPro...I had no response...I send 10 chars with mb command 16...as it seems at log there is no response with time out error...I was checked hardware for errors...ok...
Mike,
the glcd screen after power on before send charcters..no change at tests...
Basil,
I am working to put together a test board so I can get immediate feedback and trouble shoot.
What you sent looks correct. The time out could be the time out setting on comtestpro is 100 ms and had the scan really slow at 4sec
Try increasing the comtestprotime out to 5000ms Or turn the wait down to something much lower. This would not be a solution but a test.
I probably need to take the "' Modbus protocol function" out and trigger it by itself. When a frame is complete.
I will work on this as I get time. I have to go to town today.
BR
Mike
I moved the processing of the Frame out of the main loop! See attached. This is a severely revised Version that I was working on last night. Worth a try.
Last edit: mmotte 2019-02-15
Mike,
I changed slave address to 07 to mb master according to code....the same ...no response...
Basil,
The time out is beacuse of the setting on the comtestpro timeout in upper right corner 100ms and I had put the processing of the new fram in the display main loop which cycles at 4000ms.
I moved the processing of new frame to the interrupt of the mbtimer2match. this is not ideal but worth a try.
working at putting some hardware together so i can test here
BR
Mike
Mike,
after change the mb slave address to 07 , I send 10 chars (ABCDEFGHIJ) , I had response error (time out) , but I had the chars on glcd as below ..
Mike,
but in the next cycles chars changed as below.... I will try the updated code in a few minutes...
That's exciting! We're close!
Mike,
test for V1.55....the same as previous...responce error (time out) , 10 chars ok, but the first 4 chars changed in the next cycles....
Mike,
hoping to help, I send you a code in C (for FC7), that works fine with a lcd 4x20 with modbus protocol...