Advertisement
mikroavr

modbus_slave_to_float

Aug 24th, 2023
1,379
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <avr/wdt.h>
  2. #include <Wire.h>
  3. //#include <LiquidCrystal_I2C.h>
  4. #include <Adafruit_ADS1015.h>
  5.  
  6.  
  7. #include <SimpleModbusSlave.h>
  8. /* This example code has 9 holding registers. 6 analogue inputs, 1 button, 1 digital output
  9.    and 1 register to indicate errors encountered since started.
  10.    Function 5 (write single coil) is not implemented so I'm using a whole register
  11.    and function 16 to set the onboard Led on the Atmega328P.
  12.    
  13.    The modbus_update() method updates the holdingRegs register array and checks communication.
  14.  
  15.    Note:  
  16.    The Arduino serial ring buffer is 128 bytes or 64 registers.
  17.    Most of the time you will connect the arduino to a master via serial
  18.    using a MAX485 or similar.
  19.  
  20.    In a function 3 request the master will attempt to read from your
  21.    slave and since 5 bytes is already used for ID, FUNCTION, NO OF BYTES
  22.    and two BYTES CRC the master can only request 122 bytes or 61 registers.
  23.  
  24.    In a function 16 request the master will attempt to write to your
  25.    slave and since a 9 bytes is already used for ID, FUNCTION, ADDRESS,
  26.    NO OF REGISTERS, NO OF BYTES and two BYTES CRC the master can only write
  27.    118 bytes or 59 registers.
  28.  
  29.    Using the FTDI USB to Serial converter the maximum bytes you can send is limited
  30.    to its internal buffer which is 60 bytes or 30 unsigned int registers.
  31.  
  32.    Thus:
  33.  
  34.    In a function 3 request the master will attempt to read from your
  35.    slave and since 5 bytes is already used for ID, FUNCTION, NO OF BYTES
  36.    and two BYTES CRC the master can only request 54 bytes or 27 registers.
  37.  
  38.    In a function 16 request the master will attempt to write to your
  39.    slave and since a 9 bytes is already used for ID, FUNCTION, ADDRESS,
  40.    NO OF REGISTERS, NO OF BYTES and two BYTES CRC the master can only write
  41.    50 bytes or 25 registers.
  42.  
  43.    Since it is assumed that you will mostly use the Arduino to connect to a
  44.    master without using a USB to Serial converter the internal buffer is set
  45.    the same as the Arduino Serial ring buffer which is 128 bytes.
  46. */
  47.  
  48.  
  49. // Using the enum instruction allows for an easy method for adding and
  50. // removing registers. Doing it this way saves you #defining the size
  51. // of your slaves register array each time you want to add more registers
  52. // and at a glimpse informs you of your slaves register layout.
  53.  
  54. //////////////// registers of your slave ///////////////////
  55. enum
  56. {    
  57.   // just add or remove registers and your good to go...
  58.   // The first register starts at address 0
  59.   ADC0,    
  60.   ADC1,        
  61.   ADC2,
  62.   ADC3,
  63.   ADC4,
  64.   ADC5,
  65.   ADC6,
  66.   ADC7,
  67.   ADC8,
  68.   ADC9,
  69.   ADC10,
  70.   ADC11,
  71.   TOTAL_ERRORS,
  72.   // leave this one
  73.   TOTAL_REGS_SIZE
  74.   // total number of registers for function 3 and 16 share the same register array
  75. };
  76.  
  77. unsigned int holdingRegs[TOTAL_REGS_SIZE]; // function 3 and 16 register array
  78. ////////////////////////////////////////////////////////////
  79.  
  80. //LiquidCrystal_I2C lcd(20, 4);
  81. Adafruit_ADS1115 ads;  /* Use this for the 16-bit version */
  82. int16_t adc0, adc1, adc2, adc3;
  83. float v1, v2, v3, v4;
  84. //String line1, line2, line3, line4;
  85.  
  86. union Pun {
  87.   float f; uint32_t u;
  88. };
  89.  
  90. void setup()
  91. {
  92.   //pinMode(A0, OUTPUT);
  93.   wdt_enable(WDTO_8S);
  94.   //digitalWrite(A0, HIGH);
  95.   //delay(2000);
  96.   //digitalWrite(A0, LOW);
  97.   //lcd.autoAddress();
  98.   //lcd.begin();
  99.  
  100.   /* parameters(long baudrate,
  101.                 unsigned char ID,
  102.                 unsigned char transmit enable pin,
  103.                 unsigned int holding registers size,
  104.                 unsigned char low latency)
  105.                
  106.      The transmit enable pin is used in half duplex communication to activate a MAX485 or similar
  107.      to deactivate this mode use any value < 2 because 0 & 1 is reserved for Rx & Tx.
  108.      Low latency delays makes the implementation non-standard
  109.      but practically it works with all major modbus master implementations.
  110.   */
  111.   ads.setGain(GAIN_TWOTHIRDS);  
  112.   ads.begin();
  113.  
  114.   modbus_configure(9600, 1, 16, TOTAL_REGS_SIZE, 0);
  115.  
  116.  }
  117.  
  118. void loop()
  119. {
  120.   // modbus_update() is the only method used in loop(). It returns the total error
  121.   // count since the slave started. You don't have to use it but it's useful
  122.   // for fault finding by the modbus master.
  123.   wdt_reset();
  124.   holdingRegs[TOTAL_ERRORS] = modbus_update(holdingRegs);
  125.    
  126.   for ( int i = 0; i<4; i++){
  127.      holdingRegs[i] = ads.readADC_SingleEnded(i);
  128.      delayMicroseconds(50);  
  129.   }
  130.   v1 = (holdingRegs[0] * 0.1875)/1000;
  131.   v2 = (holdingRegs[1] * 0.1875)/1000;
  132.   v3 = (holdingRegs[2] * 0.1875)/1000;
  133.   v4 = (holdingRegs[3] * 0.1875)/1000;
  134.  
  135.   encodeFloat(&holdingRegs[4], v1);
  136.   delayMicroseconds(50);
  137.   encodeFloat(&holdingRegs[6], v2);
  138.   delayMicroseconds(50);
  139.   encodeFloat(&holdingRegs[8], v3);
  140.   delayMicroseconds(50);
  141.   encodeFloat(&holdingRegs[10], v4);
  142.   delayMicroseconds(50);
  143.  
  144.     //unsigned long teg = (unsigned long)holdingRegs[4] << 16 | holdingRegs[5];
  145.   /*
  146.   float dtTeg1 = decodeFloat(&holdingRegs[4]);
  147.   float dtTeg2 = decodeFloat(&holdingRegs[6]);
  148.   float dtTeg3 = decodeFloat(&holdingRegs[8]);
  149.   float dtTeg4 = decodeFloat(&holdingRegs[10]);
  150.  
  151.   line1 = String(holdingRegs[0]) + ", " + String(dtTeg1,5);
  152.   line2 = String(holdingRegs[1]) + ", " + String(dtTeg2,5);
  153.   line3 = String(holdingRegs[2]) + ", " + String(dtTeg3,5);
  154.   line4 = String(holdingRegs[3]) + ", " + String(dtTeg4,5);
  155.  
  156.   lcd.clear();
  157.   lcd.setCursor(0,0);
  158.   lcd.print(line1);
  159.  
  160.   lcd.setCursor(0,1);
  161.   lcd.print(line2);
  162.  
  163.   lcd.setCursor(0,2);
  164.   lcd.print(line3);
  165.  
  166.   lcd.setCursor(0,3);
  167.   lcd.print(line4);
  168.   delay(10);
  169.   */
  170. }
  171.  
  172. void encodeFloat(uint16_t *regs, float x){
  173.   union Pun pun;
  174.   pun.f = x;
  175.   regs[0] = (pun.u>>16) & 0xFFFFU;
  176.   regs[1] = pun.u & 0xFFFFU;
  177. }
  178.  
  179. /*float decodeFloat(const uint16_t *regs){
  180.  union Pun pun;
  181.  pun.u = ((uint32_t)regs[0] << 16) | regs[1];
  182.  return pun.f;
  183. }
  184. */
  185.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement