Slave modbus RTU

General discussion on mikroBasic PRO for PIC.
Post Reply
Author
Message
California
Posts: 361
Joined: 14 Dec 2005 20:56
Location: Slovenia

Slave modbus RTU

#1 Post by California » 10 Mar 2023 10:07

Hello, I manage to modify UART example code to recive 8 bytes from master correctly. Now I need to send some bytes back to master. The question is how to pack all bytes together into slave's message and then send this message to master. Your help would be verry appreciated.

Regards, Vlado

Slave message contain bytes in this order:

Code: Select all

address = 0x01
function_code = 0x03
no_bytes = 0x06
up_reg_1 = 0xAE
low_reg_1 = 0x41
up_reg_2 = 0x56
low_reg_2 = 0x52
up_reg_3 = 0x43
low_reg_3 = 0x40
crc_up_reg = 0x49
crc_low_reg = 0xAD
Slave code:

Code: Select all

program UART_1


'     MCU:             PIC18F458


dim LCD_RS as sbit  at RB2_bit
    LCD_EN as sbit  at RB3_bit
    LCD_D4 as sbit  at RB4_bit
    LCD_D5 as sbit  at RB5_bit
    LCD_D6 as sbit  at RB6_bit
    LCD_D7 as sbit  at RB7_bit

    LCD_RS_Direction as sbit at TRISB2_bit
    LCD_EN_Direction as sbit at TRISB3_bit
    LCD_D4_Direction as sbit at TRISB4_bit
    LCD_D5_Direction as sbit at TRISB5_bit
    LCD_D6_Direction as sbit at TRISB6_bit
    LCD_D7_Direction as sbit at TRISB7_bit

dim uart_rd        as byte
dim uart_rd_flag   as byte
dim buffer         as string[13]
dim counter        as byte
dim i              as byte
dim text                        as string[20]
dim uart_rd_buff                as byte [8]

sub procedure interrupt()
  if RCIF_bit then         'UART1 receive interrupt                             RC1IF_bit
     uart_rd = UART1_Read()
     uart_rd_flag = 1
     counter = counter + 1
     uart_rd_buff[i] = uart_rd
     inc(i)
     RCIF_bit = 0      'clear INT flag                                          RC1IF_bit
  end if
end sub

Sub procedure HW_Init_California()

    TRISA = %11111111
    TRISE = %00000111
    PORTA = 0
    ADCON1 = 7
    CMCON = 7
    PORTB  = 0
    PORTD  = 0
    TRISB  = 0
    TRISD  = 0
    
    RCIE_bit = 1     'enable interrupt on UART1 receive                           RC1IE_bit
    RCIF_bit = 0     'clear interrupt flag UART1                                  RC1IF_bit
 '  PIR3.RC1IF = 0
    PEIE_bit = 1      'Peripheral Interrupt Enable bit
    GIE_bit = 1       'Global Interrupt Enable bit

    Lcd_Init()                     ' Initialize Lcd
    Lcd_Cmd(_LCD_CLEAR)            ' Clear display
    Lcd_Cmd(_LCD_CURSOR_OFF)       ' Cursor off
    lcd_out(1,1,"UART            ")
    lcd_out(2,1,"7.6.0_09.03.2023")
    
    UART1_Init(19200)                     ' Initialize UART module at 9600 bps
    Delay_ms(100)                        ' Wait for UART module to stabilize
    uart_rd_flag = 0
    counter = 0 ' -1
End Sub

Sub procedure Display_var()
    Lcd_Cmd(_LCD_CLEAR)
    i = 0

    while i < 8
          ByteToStr(uart_rd_buff[i], text)
          if i = 0 then
              Lcd_Out(1, 1, text)
          end if
          if ((i > 0) and (i < 4)) then
              Lcd_Out(1, ((4 * i) + 1), text)
          end if
          if i = 4 then
              Lcd_Out(2, 1, text)
          end if
          if i > 4 then
              Lcd_Out(2, (4 * ((i - 4) + 1)), text)
          end if
          inc(i)
    wend

    
    IntToStr(counter, text)
    Lcd_Out(4, 1, text)
    i = 0
    counter = 0
End sub

main:
    HW_Init_California




  'UART1_Write_Text("Ready")
  'UART1_Write(13)                      ' Line Feed
  'UART1_Write(10)                      ' Carriage Return

  while (TRUE)
    if (uart_rd_flag) then                    ' Endless loop
      if (counter < 11) then      ' If data is received,
        buffer[counter] = uart_rd
      else 
        if (counter = 11) then
          buffer[counter] = uart_rd
          counter = counter + 1
          buffer[counter] = 0        'end buffer
          'UART1_Write_Text(buffer)
          'UART1_Write(13)                      ' Line Feed
          'UART1_Write(10)                      ' Carriage Return
          counter = 0
        end if
      end if
      Display_var
      uart_rd_flag = 0
    end if
  wend
end.
Attachments
Slave_1.png
Slave_1.png (778.65 KiB) Viewed 475 times
Master.png
Master.png (34.02 KiB) Viewed 475 times
Vlado

California
Posts: 361
Joined: 14 Dec 2005 20:56
Location: Slovenia

Re: Slave modbus RTU

#2 Post by California » 13 Mar 2023 16:19

Ok, smal progress. I am able to get response from slave device, link of example data in the code below.
A lot of work still has to be done...converting: float to IEEE457 4 bytes, integers to 2 bytes: packing bytes into array preparred for UART1_Write...
Any participation is more then welcome...

Code: Select all

program UART_2A


'     MCU:             PIC18F458
' Library:   Conversions, LCD, String, UART


dim LCD_RS as sbit  at RB2_bit
    LCD_EN as sbit  at RB3_bit
    LCD_D4 as sbit  at RB4_bit
    LCD_D5 as sbit  at RB5_bit
    LCD_D6 as sbit  at RB6_bit
    LCD_D7 as sbit  at RB7_bit

    LCD_RS_Direction as sbit at TRISB2_bit
    LCD_EN_Direction as sbit at TRISB3_bit
    LCD_D4_Direction as sbit at TRISB4_bit
    LCD_D5_Direction as sbit at TRISB5_bit
    LCD_D6_Direction as sbit at TRISB6_bit
    LCD_D7_Direction as sbit at TRISB7_bit

dim uart_rd        as byte
dim uart_rd_flag   as byte
dim buffer         as string[13]
dim counter        as byte
dim i              as byte
dim text           as string[20]
dim uart_rd_buff   as byte[8]
dim uart_wr_buff   as byte[11]
dim hex_2_byte     as byte[11]

dim slave_address  as byte
dim function_code  as byte
dim n_bytes        as byte
dim up_reg_1       as byte
dim low_reg_1      as byte
dim up_reg_2       as byte
dim low_reg_2      as byte
dim up_reg_3       as byte
dim low_reg_3      as byte
dim crc_up_reg     as byte
dim crc_low_reg    as byte
'-------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
sub procedure interrupt()
  if RCIF_bit then         'UART1 receive interrupt
     uart_rd = UART1_Read()
     uart_rd_flag = 1
     counter = counter + 1
     uart_rd_buff[i] = uart_rd
     inc(i)
     RCIF_bit = 0      'clear INT flag
  end if
end sub
'-------------------------------------------------------------------------------
Sub procedure HW_Init_California()
    TRISA = %11111111
    TRISE = %00000111
    PORTA = 0
    ADCON1 = 7
    CMCON = 7
    PORTB  = 0
    PORTD  = 0
    TRISB  = 0
    TRISD  = 0

    RCIE_bit = 1     'enable interrupt on UART1 receive
    RCIF_bit = 0     'clear interrupt flag UART1
 '  PIR3.RC1IF = 0
    PEIE_bit = 1      'Peripheral Interrupt Enable bit
    GIE_bit = 1       'Global Interrupt Enable bit

    Lcd_Init()                     ' Initialize Lcd
    Lcd_Cmd(_LCD_CLEAR)            ' Clear display
    Lcd_Cmd(_LCD_CURSOR_OFF)       ' Cursor off
    lcd_out(1,1,"UART            ")
    lcd_out(2,1,"7.6.0_09.03.2023")

    UART1_Init(19200)                     ' Initialize UART module at 19200 bps
    Delay_ms(100)                        ' Wait for UART module to stabilize
    uart_rd_flag = 0
    counter = 0 ' -1
End Sub
'-------------------------------------------------------------------------------
sub procedure Write_bytes()
    ' https://ipc2u.com/articles/knowledge-base/modbus-rtu-made-simple-with-detailed-descriptions-and-examples/
    ' First example
    uart_wr_buff[0] = 0x11    ' device address
    uart_wr_buff[1] = 0x03    ' function code
    uart_wr_buff[2] = 0x06    ' The number of bytes further (6 bytes follow)
    uart_wr_buff[3] = 0xAE    ' The value of the upper register bit (AE hex)
    uart_wr_buff[4] = 0x41    ' The low-order bit of the register (41 hex)
    uart_wr_buff[5] = 0x56    ' The value of the upper register bit (56 hex)
    uart_wr_buff[6] = 0x52    ' The low-order bit of the register (52 hex)
    uart_wr_buff[7] = 0x43    ' The value of the upper register bit (43 hex)
    uart_wr_buff[8] = 0x40    ' The low-order bit of the register (40 hex)
    uart_wr_buff[9] = 0x49    ' Checksum
    uart_wr_buff[10] = 0xAD   ' Checksum
    
    ' https://minimalmodbus.readthedocs.io/en/stable/serialcommunication.html   ' 19200 bps
    delay_ms(2)    ' 3,5x character time
    PORTD.0 = 1    ' LED
    PORTD.1 = 1    ' LED
    PORTD.2 = 1    ' LED
    PORTD.4 = 1    ' Re/De controll pin
    delay_ms(2)    ' 3,5x character time

    i = 0
    while i < sizeof(uart_wr_buff)
          UART1_Write(uart_wr_buff[i])
          Delay_us(573)   ' 1x character time
          inc(i)
    wend
    
    delay_ms(2)    ' 3,5x character time
    PORTD.0 = 0    ' LED
    PORTD.1 = 0    ' LED
    PORTD.2 = 0    ' LED
    PORTD.4 = 0    ' Re/De controll pin
end sub
'-------------------------------------------------------------------------------
Sub procedure Display_var()
    Lcd_Cmd(_LCD_CLEAR)
    i = 0

    while i < 8
          ByteToStr(uart_rd_buff[i], text)
          if i = 0 then
              Lcd_Out(1, 1, text)
          end if
          if ((i > 0) and (i < 4)) then
              Lcd_Out(1, ((4 * i) + 1), text)
          end if
          if i = 4 then
              Lcd_Out(2, 1, text)
          end if
          if i > 4 then
              Lcd_Out(2, ((4 * (i - 4)) + 1), text)
          end if
          inc(i)
    wend
    i = 0

    counter = 0
End sub
'-------------------------------------------------------------------------------
main:
    HW_Init_California


  while (TRUE)
    if (uart_rd_flag) then                    ' Endless loop
      if (counter < 11) then      ' If data is received,
        buffer[counter] = uart_rd
        
        Write_bytes
        
      else
        if (counter = 11) then
          buffer[counter] = uart_rd
          counter = counter + 1
          buffer[counter] = 0        'end buffer
          counter = 0
        end if
      end if
      Display_var
      uart_rd_flag = 0
    end if
  wend
end.
Vlado

Post Reply

Return to “mikroBasic PRO for PIC General”