Администрация форума не несёт ответственности за достоверность информации и оставляет за собой право редактировать или в особых случаях даже удалять посты без предупреждения. Спасибо за понимание.

Программирование ATMEL в BASCOM.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.



MODBUS

Сообщений 1 страница 9 из 9

1

Как-то кто-то спрашивал, (Да и я тоже).
Тут основные ф-ции МОДБАС по прерыванию. Клиент.
Случайно попалось при разборе дисков с бэкапами, думал, ушло навсегда )
Автор Mladen Bruck , с моими изменениями.
Клиент рабочий, пару лет пашет в промышленном оборудовании, без глюков.

Код:
'*******************************************************************************

'
' read coil status  1
' read discrete inputs  2
' read holding registers  3
' read input registers  4
' write single coil  5
' write single register  6
' write multiple coils  15
' read single adc Alias 65                                  ' User function 65
'
'*******************************************************************************

'****************************************************************
' Compiler directives
'****************************************************************
$projecttime = 85
$regfile = "m32def.dat"                                     ' chip used
$hwstack = 48                                               ' default use 32 for the hardware stack
$swstack = 48                                               ' default use 10 for the SW stack
$framesize = 32                                             ' default use 40 for the frame space

'Const _crystal = 8000000
'Const _crystal = 11059200
'Const _crystal = 14745600
Const _crystal = 18432000
'Const _crystal = 22118400
$crystal = _crystal                                         ' xtal used

Const Baudrate = 9600
'Const Baudrate = 19200
'Const Baudrate = 38400
'Const Baudrate = 57600
'Const Baudrate = 115200
$baud = Baudrate                                            ' baud rate used

'modbus.lib contains the crcMB function
$lib "modbus.lbx"

'****************************************************************
' MCU hardware configuration
'****************************************************************

'****************************************************************
' TIMER1 should be configured for 3.5 character space based on baudrate speed
Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
Config Serialin = Buffered , Size = 16 , Bytematch = All
Config Timer1 = Timer , Prescale = 256
#if _crystal = 8000000
   #if Baudrate = 9600
      Const Load_timer = &H006C
   #endif
   #if Baudrate = 19200
      Const Load_timer = &H0031
   #endif
   #if Baudrate = 38400
      Const Load_timer = &H0018
   #endif
   #if Baudrate = 57600
      Const Load_timer = &H0011
   #endif
   #if Baudrate = 115200
      Const Load_timer = &H0008
   #endif
#endif

#if _crystal = 18432000
   #if Baudrate = 9600
      Const Load_timer = &H0106
   #endif
   #if Baudrate = 19200
      Const Load_timer = &H0083
   #endif
#endif


Load Timer1 , Load_timer                                    'cca 3.5 ms
On Timer1 Modbus_space

'***************************************************************
' I/O configuration
' This is user configurable.
' Config PORT'S pin's to match modbus client hardware
' Inputs must start with Input_
' Outputs must start with Coil_
Input_1 Alias Pina.0                                        ' Input 1
Input_2 Alias Pina.1                                        ' Input 2
Input_3 Alias Pina.2                                        ' Input 3
Input_4 Alias Pina.3                                        ' Input 4
Input_5 Alias Pina.4                                        ' Input 5
Input_6 Alias Pina.5                                        ' Input 6
Input_7 Alias Pina.6                                        ' Input 7
Input_8 Alias Pina.7                                        ' Input 8

Input_9 Alias Pinc.7                                        ' Input 9
Input_10 Alias Pinc.6                                       ' Input 10
Input_11 Alias Pinc.5                                       ' Input 11
Input_12 Alias Pinc.4                                       ' Input 12
Input_13 Alias Pind.2                                       ' Input 13
Input_14 Alias Pind.3                                       ' Input 14
Input_15 Alias Pinc.0                                       ' Input 15
Input_16 Alias Pinc.1                                       ' Input 16
'Input_17 Alias Pink.4                                       ' Input 17
'Input_18 Alias Pink.5                                       ' Input 18
'Input_19 Alias Pink.6                                       ' Input 19
'Input_20 Alias Pink.7                                       ' Input 20
'Input_21 Alias Pinj.7                                       ' Input 21
'Input_22 Alias Pina.0                                       ' Input 22
'Input_23 Alias Pina.1                                       ' Input 23
'Input_24 Alias Pina.2                                       ' Input 24
'Input_25 Alias Pina.3                                       ' Input 25
'Input_26 Alias Pina.4                                       ' Input 26
'Input_27 Alias Pina.5                                       ' Input 27
'Input_28 Alias Pina.6                                       ' Input 28
'Input_29 Alias Pina.7                                       ' Input 29
'Input_30 Alias Pinj.6                                       ' Input 30
'Input_31 Alias Pinj.5                                       ' Input 31
'Input_32 Alias Pinj.4                                       ' Input 32

Coil_1 Alias Portb.0                                        ' Coil 1
Coil_2 Alias Portb.1                                        ' Coil 2
Coil_3 Alias Portb.2                                        ' Coil 3
Coil_4 Alias Portb.3                                        ' Coil 4
Coil_5 Alias Portb.4                                        ' Coil 5
Coil_6 Alias Portc.2                                        ' Coil 6
Coil_7 Alias Portd.4                                        ' Coil 7
Coil_8 Alias Portd.5                                        ' Coil 8
Coil_9 Alias Portd.6                                        ' Coil 9
Coil_10 Alias Portd.7                                       ' Coil 10
'Coil_11 Alias Portb.6                                       ' Coil 11
'Coil_12 Alias Portb.7                                       ' Coil 12
'Coil_13 Alias Porth.7                                       ' Coil 13
'Coil_14 Alias Portg.4                                       ' Coil 14
'Coil_15 Alias Portg.3                                       ' Coil 15
'Coil_16 Alias Portl.0                                       ' Coil 16
'Coil_17 Alias Portl.1                                       ' Coil 17
'Coil_18 Alias Portl.2                                       ' Coil 18
'Coil_19 Alias Portl.3                                       ' Coil 19
'Coil_20 Alias Portl.4                                       ' Coil 20
'Coil_21 Alias Portl.5                                       ' Coil 21
'Coil_22 Alias Portl.6                                       ' Coil 22
'Coil_23 Alias Portl.7                                       ' Coil 23
'Coil_24 Alias Portd.4                                       ' Coil 24
'********************************************************************

'****** Remark putput lines which are not in modbus client
Config Coil_1 = Output                                      ' Coil 1
Config Coil_2 = Output                                      ' Coil 2
Config Coil_3 = Output                                      ' Coil 3
Config Coil_4 = Output                                      ' Coil 4
Config Coil_5 = Output                                      ' Coil 5
Config Coil_6 = Output                                      ' Coil 6
Config Coil_7 = Output                                      ' Coil 7
Config Coil_8 = Output                                      ' Coil 8
Config Coil_9 = Output                                      ' Coil 9
Config Coil_10 = Output                                     ' Coil 10
'Config Coil_11 = Output                                     ' Coil 11
'Config Coil_12 = Output                                     ' Coil 12
'Config Coil_13 = Output                                     ' Coil 13
'Config Coil_14 = Output                                     ' Coil 14
'Config Coil_15 = Output                                     ' Coil 15
'Config Coil_16 = Output                                     ' Coil 16
'Config Coil_17 = Output                                     ' Coil 17
'Config Coil_18 = Output                                     ' Coil 18
'Config Coil_19 = Output                                     ' Coil 19
'Config Coil_20 = Output                                     ' Coil 20
'Config Coil_21 = Output                                     ' Coil 21
'Config Coil_22 = Output                                     ' Coil 22
'Config Coil_23 = Output                                     ' Coil 23
'Config Coil_24 = Output                                     ' Coil 24
'**********************************************************************
' SUB and  function declarations
'**********************************************************************
Declare Function Bit_index_byte(byval Bit_index As Word , Lista As Byte) As Byte
Declare Sub Copy_inputs_to_table
Declare Sub Write_single_coil(byval Coil As Word , Byval Value As Byte)
Declare Sub Modbus_exec
Declare Sub Send_exception


'************************************************************
' Const definitions
'************************************************************
'********************************************************************
' This is user configurable.
' Config to match modbus client hardware
Const Modbus_slave_adress = 2
Const Maximum_coil_number = 10                              ' Keep in mind that modbus adress start at 0 so this is 16 coils !
Const Maximum_discrete_inputs = 16                          ' Keep in mind that modbus adress start at 0 so this is 16 inputs !
Const Maximum_holding_registers = 15                        ' Keep in mind that modbus adress start at 0 so this is 16 registers !
Const Maximum_input_registers = 15                          ' Keep in mind that modbus adress start at 0 so this is 16 registers !
Const Maximum_adc_channel = 7                               ' Keep in mind that modbus adress start at 0 so this is 8 channels !
'********************************************************************

F_read_coil_status Alias 1
F_read_discrete_inputs Alias 2
F_read_holding_registers Alias 3
F_read_input_registers Alias 4
F_write_single_coil Alias 5
F_write_single_register Alias 6
F_write_multiple_coils Alias 15
F_write_multiple_registers Alias 16                         ' Not implemented yet
F_read_single_adc Alias 65                                  ' Not defined in standard, user applicable

'Exception response codes
Illegal_function Alias 1
Illegal_data_address Alias 2
Illegal_data_value Alias 3

'************************************************************
' Variables definitions
'************************************************************
Dim Mbuf_rcv(16) As Byte
Dim Modbus_slave_adress_received As Byte At Mbuf_rcv(1) Overlay
Dim Modbus_function As Byte At Mbuf_rcv(2) Overlay
Dim Modbus_device_adress_hi As Byte At Mbuf_rcv(3) Overlay
Dim Modbus_device_adress_lo As Byte At Mbuf_rcv(4) Overlay
Dim Modbus_device_adress As Word
Dim Mb_number_of_devices_hi As Byte At Mbuf_rcv(5) Overlay
Dim Mb_number_of_devices_lo As Byte At Mbuf_rcv(6) Overlay
Dim Modbus_number_of_devices As Word
Dim Modbus_data_byte(8) As Byte At Mbuf_rcv(4) Overlay
Dim Modbus_register_read(maximum_holding_registers) As Word At Mbuf_rcv(4) Overlay
Dim Modbus_registers_write(maximum_holding_registers) As Word At Mbuf_rcv(5) Overlay
Dim Modbus_register_write_hi As Byte At Mbuf_rcv(5) Overlay
Dim Modbus_register_write_lo As Byte At Mbuf_rcv(6) Overlay
Dim Mb_f15_count As Byte At Mbuf_rcv(7) Overlay
Dim Mb_f15_data(8) As Byte At Mbuf_rcv(8) Overlay

Dim Coil_status_table(5) As Byte                            ' One more than number_of_coils/8
Dim Discrete_inputs_table(6) As Byte                        ' One more than number_of_inputs/8
Dim Holding_registers_table(16) As Word
Dim Input_registers_table(16) As Word

' Genereal program use
Dim For_loop As Byte

'************************************************************
' Program initialisation
'************************************************************
Coil_status_table(1) = 0
Coil_status_table(2) = 0
Coil_status_table(3) = 0
Coil_status_table(4) = 0
Coil_status_table(5) = 0

For For_loop = 1 To 16
   Holding_registers_table(for_loop) = 0
Next For_loop

'************************************************************
''  Program start
'************************************************************

Enable Timer1
Start Timer1
Enable Interrupts
Clear Serialin


' Coil_1 = 1                                      ' Coil 1
' Coil_2 = 1                                      ' Coil 2
' Coil_3 = 1                                      ' Coil 3
' Coil_4 = 1                                      ' Coil 4
' Coil_5 = 1                                      ' Coil 5
' Coil_6 = 1                                      ' Coil 6
' Coil_7 = 1                                      ' Coil 7
' Coil_8 = 1                                      ' Coil 8
' Coil_9 = 1                                      ' Coil 9
' Coil_10 = 1                                     ' Coil 10

'****************** User program start here ****************
Do
   NOP
Loop

End


'************************************************************
'----------------- SUBS and Functions ---------------------
'************************************************************

Sub Send_exception
Local Crc As Word
   Mbuf_rcv(2) = Mbuf_rcv(2) + &H80
   Crc = Crcmb(mbuf_rcv(1) , 3)                             ' create checksum
   Mbuf_rcv(4) = Low(crc)                                   'add to buffer
   Mbuf_rcv(5) = High(crc)                                  'add to buffer
   Printbin Mbuf_rcv(1) ; 5
End Sub

Sub Modbus_exec
 Local Chr_count As Byte
 Local Word_count As Byte
 Local Modbus_error As Byte
 Local Local_dummy_byte As Byte
 Local Local_dummy_byte_2 As Byte
 Local Local_dummy_word As Word
 Local Crc_received As Word
 Local Modbus_device_end_adress As Word
 Local No_bytes_to_send As Byte
 Local No_words_to_send As Byte
 Local Byte_to_send As Byte
 Local Word_to_send As Word

   ' Since this sub is executed after 3.5 character pause,
   ' all characters should be in receive buffer.
   ' Then let's put it in Modbus buffer
   Chr_count = 0
   While Ischarwaiting() = 1
     Incr Chr_count
     Inputbin Local_dummy_byte
     Mbuf_rcv(chr_count) = Local_dummy_byte
   Wend
   If Chr_count > 0 And Modbus_slave_adress_received = Modbus_slave_adress Then
         Local_dummy_byte = Chr_count - 1
         Crc_received = Makeint(mbuf_rcv(local_dummy_byte) , Mbuf_rcv(chr_count))       ' create word of received crc
         Decr Local_dummy_byte
         If Crc_received = Crcmb(mbuf_rcv(1) , Local_dummy_byte) Then
            Modbus_device_adress = Makeint(modbus_device_adress_lo , Modbus_device_adress_hi)
            Modbus_number_of_devices = Makeint(mb_number_of_devices_lo , Mb_number_of_devices_hi)
            Modbus_device_end_adress = Modbus_device_adress + Modbus_number_of_devices
            Modbus_error = 0
            ' First check if modbus packet is correct for this client
            Select Case Modbus_function
               Case F_read_coil_status :
                    If Modbus_device_end_adress > Maximum_coil_number Then
                        Mbuf_rcv(3) = Illegal_data_address
                        Modbus_error = 1
                    End If
               Case F_read_discrete_inputs :
                     If Modbus_device_end_adress > Maximum_discrete_inputs Then
                        Mbuf_rcv(3) = Illegal_data_address
                        Modbus_error = 1
                    End If
               Case F_read_holding_registers :
                     If Modbus_device_adress > Maximum_holding_registers Then
                        Mbuf_rcv(3) = Illegal_data_address
                        Modbus_error = 1
                    End If
               Case F_read_input_registers :
                     If Modbus_device_adress > Maximum_input_registers Then
                        Mbuf_rcv(3) = Illegal_data_address
                        Modbus_error = 1
                    End If
               Case F_write_single_coil :
                    If Modbus_device_adress > Maximum_coil_number Then
                        Mbuf_rcv(3) = Illegal_data_address
                        Modbus_error = 1
                    End If
               Case F_write_multiple_coils:
                    If Modbus_device_end_adress > Maximum_coil_number Then
                        Mbuf_rcv(3) = Illegal_data_address
                        Modbus_error = 1
                    End If
               Case F_write_single_register :
                     If Modbus_device_adress > Maximum_holding_registers Then
                        Mbuf_rcv(3) = Illegal_data_address
                        Modbus_error = 1
                     End If
               Case F_read_single_adc:
                     If Modbus_device_adress > Maximum_adc_channel Then
                        Mbuf_rcv(3) = Illegal_data_address
                        Modbus_error = 1
                     End If
               Case Else                                    ' Ilegal fuction
                  Mbuf_rcv(3) = Illegal_function
                  Modbus_error = 1
            End Select
            If Modbus_error = 1 Then
               Send_exception
               Modbus_function = 0
            End If
            ' If packet is  is correct for this client then Modbus_function is <> 0
            Select Case Modbus_function
               Case 1 To 2 :
                  If Modbus_function = F_read_discrete_inputs Then Copy_inputs_to_table
                  No_bytes_to_send = Modbus_number_of_devices / 8
                  Local_dummy_byte = Modbus_number_of_devices Mod 8
                  If Local_dummy_byte > 0 Then Incr No_bytes_to_send
                  Chr_count = 0
                  For Local_dummy_word = Modbus_device_adress To Modbus_device_end_adress Step 8
                     Incr Chr_count
                     If Chr_count > No_bytes_to_send Then
                       Byte_to_send = 0
                     Else
                       Select Case Modbus_function
                           Case F_read_coil_status : Byte_to_send = Bit_index_byte(local_dummy_word , Coil_status_table(1))
                           Case F_read_discrete_inputs : Byte_to_send = Bit_index_byte(local_dummy_word , Discrete_inputs_table(1))
                        End Select
                     End If
                     Modbus_data_byte(chr_count) = Byte_to_send
                  Next
                  Mbuf_rcv(3) = No_bytes_to_send            ' byte count
                  Chr_count = 3 + No_bytes_to_send
                  Crc_received = Crcmb(mbuf_rcv(1) , Chr_count)       ' create checksum
                  Incr Chr_count
                  Mbuf_rcv(chr_count) = Low(crc_received)   'add to buffer
                  Incr Chr_count
                  Mbuf_rcv(chr_count) = High(crc_received)  'add to buffer
                  For Local_dummy_byte = 1 To Chr_count
                    Printbin Mbuf_rcv(local_dummy_byte) ; 1
                  Next
               Case 3 To 4 :
                  No_words_to_send = Modbus_number_of_devices
                  Word_count = 0
                  Incr Modbus_device_adress                 ' ModBus start with adress 0, but table start with 1
                  Incr Modbus_device_end_adress
                  For Local_dummy_word = Modbus_device_adress To Modbus_device_end_adress
                     Incr Word_count
                     If Word_count > No_words_to_send Then
                       Word_to_send = 0
                     Else
                       Select Case Modbus_function
                           Case F_read_holding_registers : Word_to_send = Holding_registers_table(local_dummy_word)
                           Case F_read_input_registers : Word_to_send = Input_registers_table(local_dummy_word)
                        End Select
                     End If
                     Local_dummy_byte = High(word_to_send)
                     Local_dummy_byte_2 = Low(word_to_send)
                     Modbus_register_read(word_count) = Makeint(local_dummy_byte , Local_dummy_byte_2)
                  Next
                  Mbuf_rcv(3) = No_words_to_send * 2        ' byte count
                  Chr_count = Mbuf_rcv(3)
                  Chr_count = 3 + Chr_count
                  Crc_received = Crcmb(mbuf_rcv(1) , Chr_count)       ' create checksum
                  Incr Chr_count
                  Mbuf_rcv(chr_count) = Low(crc_received)   'add to buffer
                  Incr Chr_count
                  Mbuf_rcv(chr_count) = High(crc_received)  'add to buffer
                  For Local_dummy_byte = 1 To Chr_count
                    Printbin Mbuf_rcv(local_dummy_byte) ; 1
                  Next
               Case F_write_single_coil :
                     If Mb_number_of_devices_hi = 255 Then
                        Call Write_single_coil(modbus_device_adress , 1)
                        Printbin Mbuf_rcv(1) ; 8
                     Elseif Mb_number_of_devices_hi = 0 Then
                        Call Write_single_coil(modbus_device_adress , 0)
                        Printbin Mbuf_rcv(1) ; 8
                     Else
                        Mbuf_rcv(3) = Illegal_data_value
                        Send_exception
                     End If
               Case F_write_multiple_coils:
                     Local_dummy_word = Modbus_device_adress
                     For Chr_count = 1 To Mb_f15_count
                        For Local_dummy_byte = 0 To 7
                           If Local_dummy_word < Modbus_device_end_adress Then
                              Call Write_single_coil(local_dummy_word , Mb_f15_data(chr_count).local_dummy_byte)
                              Incr Local_dummy_word
                           Else
                              Exit For
                           End If
                        Next
                     Next Local_dummy_word
                     Crc_received = Crcmb(mbuf_rcv(1) , 6)  ' create checksum
                     Mbuf_rcv(7) = Low(crc_received)        ' add to buffer
                     Mbuf_rcv(8) = High(crc_received)       ' add to buffer
                     Printbin Mbuf_rcv(1) ; 8
               Case F_write_single_register:
                    Incr Modbus_device_adress               ' ModBus start with adress 0, but table start with 1
                    Holding_registers_table(modbus_device_adress) = Makeint(modbus_register_write_lo , Modbus_register_write_hi)
                    Printbin Mbuf_rcv(1) ; 8                ' Response is echo of query
               Case F_read_single_adc:
                     ' This function is implemented only for demonstration purpose !!! It does nothing !
                     ' User can select and implement a function code that is not supported by specification
                     ' The query message specifies the channel in word Modbus_device_adress (bytes 3 and 4)
                     ' where ADC=0 mean ADC channel number 1,  etc ADC=1 mean ADC channel number 2 etc                    '
                     ' Byte 1: Slave ID
                     ' Byze 2: Function ADC read
                     ' Byte 3: ADC channel HI byte
                     ' Byte 4: ADC channel LO byte
                     ' Byte 5: CRC LO
                     ' Byte 6: CRC HI
                     '
                     ' HERE IMPLEMENT ADC conversion code
                     '
                     Mbuf_rcv(3) = 0                        ' Sample data
                     Mbuf_rcv(4) = 0                        ' sample data
                     '                  '
                     ' The response message contain 16bit ADC vaule in format
                     ' Byte 1: Slave ID
                     ' Byze 2: Function
                     ' Byte 3: ADC conversion value HI byte
                     ' Byte 4: ADC conversion value LO byte
                     ' Byte 5: CRC LO
                     ' Byte 6: CRC HI
                       Crc_received = Crcmb(mbuf_rcv(1) , 4)       ' create checksum
                      Mbuf_rcv(5) = Low(crc_received)       ' add to buffer
                      Mbuf_rcv(6) = High(crc_received)      ' add to buffer
                      Printbin Mbuf_rcv(1) ; 6
            End Select
         End If
   End If
End Sub Modbus_exec

'*******************************************************************************
' This is user configurable.
' Remark lines which are not in modbus client
Sub Copy_inputs_to_table
   Discrete_inputs_table(1).0 = Input_1
   Discrete_inputs_table(1).1 = Input_2
   Discrete_inputs_table(1).2 = Input_3
   Discrete_inputs_table(1).3 = Input_4
   Discrete_inputs_table(1).4 = Input_5
   Discrete_inputs_table(1).5 = Input_6
   Discrete_inputs_table(1).6 = Input_7
   Discrete_inputs_table(1).7 = Input_8

   Discrete_inputs_table(2).0 = Input_9
   Discrete_inputs_table(2).1 = Input_10
   Discrete_inputs_table(2).2 = Input_11
   Discrete_inputs_table(2).3 = Input_12
   Discrete_inputs_table(2).4 = Input_13
   Discrete_inputs_table(2).5 = Input_14
   Discrete_inputs_table(2).6 = Input_15
   Discrete_inputs_table(2).7 = Input_16

'   Discrete_inputs_table(3).7 = Input_17
'   Discrete_inputs_table(3).6 = Input_18
'   Discrete_inputs_table(3).5 = Input_19
'   Discrete_inputs_table(3).4 = Input_20
'   Discrete_inputs_table(3).3 = Input_21
'   Discrete_inputs_table(3).2 = Input_22
'   Discrete_inputs_table(3).1 = Input_23
'   Discrete_inputs_table(3).0 = Input_24

'   Discrete_inputs_table(4).7 = Input_25
'   Discrete_inputs_table(4).6 = Input_26
'   Discrete_inputs_table(4).5 = Input_27
'   Discrete_inputs_table(4).4 = Input_28
'   Discrete_inputs_table(4).3 = Input_29
'   Discrete_inputs_table(4).2 = Input_30
'   Discrete_inputs_table(4).1 = Input_31
'   Discrete_inputs_table(4).0 = Input_32

'   Discrete_inputs_table(5).7 = Input_33
'   Discrete_inputs_table(5).6 = Input_34
'   Discrete_inputs_table(5).5 = Input_35
'   Discrete_inputs_table(5).4 = Input_36
'   Discrete_inputs_table(5).3 = Input_37
'   Discrete_inputs_table(5).2 = Input_38
'   Discrete_inputs_table(5).1 = Input_39
'   Discrete_inputs_table(5).0 = Input_40
End Sub

' This is user configurable.
' Drive outputs to match modbus client hardware
Sub Write_single_coil(byval Coil As Word , Byval Value As Byte)
   Select Case Coil
      Case 0 :
         Coil_1 = Value : Coil_status_table(1).0 = Value.0
      Case 1:
         Coil_2 = Value : Coil_status_table(1).1 = Value.0
      Case 2:
         Coil_3 = Value : Coil_status_table(1).2 = Value.0
      Case 3:
         Coil_4 = Value : Coil_status_table(1).3 = Value.0
      Case 4:
         Coil_5 = Value : Coil_status_table(1).4 = Value.0
      Case 5:
         Coil_6 = Value : Coil_status_table(1).5 = Value.0
      Case 6:
         Coil_7 = Value : Coil_status_table(1).6 = Value.0
      Case 7:
         Coil_8 = Value : Coil_status_table(1).7 = Value.0
      Case 8:
         Coil_9 = Value : Coil_status_table(2).0 = Value.0
      Case 9:
         Coil_10 = Value : Coil_status_table(2).1 = Value.0
'      Case 10:
'         Coil_11 = Value : Coil_status_table(2).2 = Value.0
'      Case 11:
'         Coil_12 = Value : Coil_status_table(2).3 = Value.0
'      Case 12:
'         Coil_13 = Value : Coil_status_table(2).4 = Value.0
'      Case 13:
'         Coil_14 = Value : Coil_status_table(2).5 = Value.0
'      Case 14:
'         Coil_15 = Value : Coil_status_table(2).6 = Value.0
'      Case 15:
'         Coil_16 = Value : Coil_status_table(2).7 = Value.0
'      Case 16:
'         Coil_17 = Value : Coil_status_table(3).0 = Value.0
'      Case 17:
'         Coil_18 = Value : Coil_status_table(3).1 = Value.0
'      Case 18:
'         Coil_19 = Value : Coil_status_table(3).2 = Value.0
'      Case 19:
'         Coil_20 = Value : Coil_status_table(3).3 = Value.0
'      Case 20:
'         Coil_21 = Value : Coil_status_table(3).4 = Value.0
'      Case 21:
'         Coil_22 = Value : Coil_status_table(3).5 = Value.0
'      Case 22:
'         Coil_23 = Value : Coil_status_table(3).6 = Value.0
'      Case 23:
'         Coil_24 = Value : Coil_status_table(3).7 = Value.0
   End Select
End Sub
'*******************************************************************************

' Return byte from array at adress of bit_index
Function Bit_index_byte(byval Bit_index As Word , Lista As Byte) As Byte
   Local Dummy_byte_sub As Byte
   Local Rest As Byte
   Local Index_byte As Byte
   Local Start_byte As Byte

   Dummy_byte_sub = 0
   Rest = 0
   Index_byte = 0
   Start_byte = 0

   Rest = Bit_index Mod 8
   Start_byte = Bit_index / 8
   Incr Start_byte
   Index_byte = Lista(start_byte)
   Shift Index_byte , Left , Rest
   Incr Start_byte
   Dummy_byte_sub = Lista(start_byte)
   Rest = 8 - Rest
   Shift Dummy_byte_sub , Right , Rest
   Bit_index_byte = Index_byte Or Dummy_byte_sub
End Function


'***********************************************************
' INTERUPTS !
'***********************************************************
Serial0bytereceived:
   Load Timer1 , Load_timer
   Start Timer1
Return

Modbus_space:
   Stop Timer1
   Call Modbus_exec
Return

Отредактировано Skull (2013-09-28 01:30:58)

0

2

Все повторяется. Тоже искал. Почему то здесь не нашел. Предложу свой вариант. В промышленности не испытывался. Реализованы функции 3 и 6. Другие, в принципе, особо и не нужны.

Код:
'modbus.lib contains the crcMB function
 $lib "modbus.lbx"


  $regfile = "m8def.dat"                                    ' chip used
 $crystal = 8000000                                         ' xtal used
 $baud = 19200                                              ' baudrate N,8,1




 Config Lcdpin = Pin , Db4 = Portd.5 , Db5 = Portd.6 , Db6 = Portd.7 , Db7 = Portb.0 , E = Portb.1 , Rs = Portb.2

 Dim Mbuf(255) As Byte , Modc As Byte , Modt As Byte , Modw As Word
 Dim Table_data(30) As Word                                 'таблица с данными (текущие значения измерений, слова входов выходов уставки, настройки )
 Dim Tmp As Word                                            'промежуточные переменные
 Dim Tmp_byte As Byte                                       'промежуточные переменные
 Dim Tmp_byte2 As Byte
 Dim Tmp_byte_modbus As Byte
 Dim N_word As Byte                                         'количество слов в посылке
 Dim N_byte As Byte                                         'количество байт в посылке
 Dim Beg_adr As Byte                                        'начальный адрес данных
 Dim Beg_adr_w As Byte                                      ' адрес данных  при записи
 Dim I As Byte                                              'счетчик циклов в for
 Dim Cnt_print As Byte
 Dim Error_mod As Integer                                   ' код ошибки
 Dim Frame_value As Byte                                    'значение паузы между фреймами загружаемое в счетчик

                            ' параметры для записи в энергонезависимую память
 Dim W_to_device As Byte                                    'признак записи в устройство
 Dim Modbus_slave As Eram Byte                              'адрес устройства в сети Modbus
 Dim Frame_value_dev As Eram Byte                           'значение паузы между фреймами
 Dim Ust1_up As Eram Integer                                'уставка1 верхняя
 Dim Ust1_dwn As Eram Integer                               'уставка1 нижняя

 Dim Md_t_start As Bit
 Config Timer0 = Timer , Prescale = 256                     'организация задержки отключения разрешения передачи, при передаче на порт 485             '4000000 0,065536 сек (15,25878906 в 1 секунду)          8000000  0,032768 30,51757813
 On Timer0 Modbus_timers

 ' **************** выходы*************
 'Config Portc.0 = Output
 Config Portc.5 = Output

   'Test_light Alias Portc.0
   Enable_tx Alias Portc.5                                  'разрешение на передачу по 485
' ****************      0


 Declare Sub Send_to_master                                 'подпрограмма передачи ответа мастеру
 Declare Sub Error_modbus                                   'подпрограмма формирования ошибки модбас

 ' Config Portc = Output                                     'настроим порт с как выходы
  Modc = 0                                                  'инициализация
  W_to_device = 0
  Error_mod = 0
  Cnt_print = 0
  Frame_value = Frame_value_dev

  If Frame_value = 255 Then Frame_value = 253

                 'ВАЖНО! - После Перопрошивки Значение Modbus_slave = 255 !!!!!!!
  Tmp_byte = Modbus_slave                                   ' нельзя писать ерам байт в инт. можно через промежуточную переменную
  Table_data(11) = Tmp_byte                                 ' адрес 4010 - номер устройства в сети модбас (читать писать)
  Table_data(12) = Ust1_up                                  ' адрес 4011 - уставка верх  (читать писать)
  Table_data(13) = Ust1_dwn                                 ' адрес 4012 - уставка низ (читать писать)
  Table_data(16) = Frame_value                              ' адрес 4015 - значение TIMER0 загружаемое при старте таймера TIMER0 (читать)



 On Urxc Urxc_isr                                           'прерывание по приему UART
 Enable Urxc
 On Utxc Utxc_isr                                           'прерывание по передаче UART

 Enable Timer0
 Enable Interrupts

 For I = 0 To 9                                             'заполняем для примера
    Tmp_byte = I + 1
    Table_data(tmp_byte) = I
 Next

  Do                                                        'начало основного цикла
                                'Важно!!! не использовать wait !!!

 If Md_t_start = 1 Then                                     '  если время между принятыми байтами больше 3.5 символа, в буфере принят фрейм

      Md_t_start = 0                                        ' обнуляем все признаки
      Error_mod = 0                                         ' обнуляем ошибку и начинаем разбирать принятый фрейм из буфера.

    If Mbuf(1) = Modbus_slave Or Mbuf(1) = 0 Then           'первый байт это адрес устройства

      Tmp_byte = Modc - 1                                   ' вычисляем адреса для расчета CRC
      Tmp_byte2 = Modc                                      ' вычисляем адреса для расчета CRC
      Modw = Makeint(mbuf(tmp_byte) , Mbuf(tmp_byte2))      ' считываем из принятого фрейма  CRC
      Tmp_byte = Modc - 2                                   ' вычисляем адреса для расчета CRC
      Tmp = Crcmb(mbuf(1) , Tmp_byte)                       ' вычисляем  CRC из фрейма принятых данных

      If Modw = Tmp Then                                    ' сравниваем расчитанный CRC и принятый CRC
                                                  'справедливо для функций 3,4 и 5,6.Если будут другие функции кроме 3,4 или 5,6 то  добавить сравнение с функциями
       Beg_adr = Makeint(mbuf(4) , Mbuf(3))
       Incr Beg_adr                                         'адрес региста чтения  (увеличиваем на 1 так как индекс массива начинается от 1, а адресация идет с 0 - 4000 адрес)


                                                             'второй байт это номер функции
        Select Case Mbuf(2)
                Case 3:                                     'функция 3- чтение регистров
                 N_word = Makeint(mbuf(6) , Mbuf(5))        'количество слов чтения
                 If N_word > 27 Then                        'я ограничил количество 27 словами
                    N_word = 1                              ' формируем ошибку если в запросе на чтение больше 27 слов
                    Error_mod = 2                           'если превышение размера буфера то формируем ошибку 2 - неправильный адрес
                 End If
                 N_byte = N_word + N_word                   'количество слов переводим в кол. байт
                 Mbuf(3) = N_byte                           'кол считываемых байт byte count wieviele Bytes sollen gesendet werden
                 Tmp_byte = 4                               'начинаем считать с 4-го байта(1-ый байт данных)

                  '************************ здесь был косяк For I = Beg_adr To N_word
                  Tmp_byte2 = Beg_adr + N_word              'формируем индекс количества слов с учетом смещения от начального адресаа
                 For I = Beg_adr To Tmp_byte2               'цикл записи в буфер обмена запрашиваемого количества слов
                     Tmp_byte_modbus = High(table_data(i))  'разбираем по байтам на старший байт
                     Mbuf(tmp_byte) = Tmp_byte_modbus       ' запись в буфер обмена  с разбивкой на байты (таблица данных)
                     Incr Tmp_byte                          '
                     Tmp_byte_modbus = Low(table_data(i))   'разбираем по байтам на младший байт
                     Mbuf(tmp_byte) = Tmp_byte_modbus       'запись в буфер обмена  с разбивкой на байты (таблица данных)
                     Incr Tmp_byte                          '
                 Next I

              N_byte = N_byte + 3                           'номер последнего байта передаваемых в посылке слов с данными (таблица данных) 3-количество байт перед данными (номер устройства, функция, количество передаваемых слов )
              Modw = Crcmb(mbuf(1) , N_byte)                ' create checksum
              Incr N_byte                                   'номер предпоследнего байта во всей посылке   ()  (CRC LOW)
              Mbuf(n_byte) = Low(modw)                      'Checksumme LOWer Byte
              Incr N_byte                                   'номер последнего байта  во всей посылке (CRC High)
              Mbuf(n_byte) = High(modw)                     'Checksumme HIGHer Byte

                Case 6:                                     'функция 6- запись одного регистра
                      Table_data(beg_adr) = Makeint(mbuf(6) , Mbuf(5))       'записываем полученное значение
                      W_to_device = 1                       'формируем признак записи в устройство
                      Beg_adr_w = Beg_adr                   'номер слова для записи в память
                      N_byte = 8                            'длина посылки для функции 6 всегда =8 байт

               Case Else:
                      Error_mod = 1                         'неподдерживаемая функция

        End Select


           If Error_mod > 0 Then
              Call Error_modbus                             'код ошибки неправильный функциональный код
           End If

           Call Send_to_master                              'ответ мастеру

        Else                                                'если неправильная контрольная сумма
                Error_mod = 3                               'код ошибки Checksumme
                Call Error_modbus
                Call Send_to_master                         'ответ мастеру
      End If
    End If

  Modc = 0
  End If



      If W_to_device = 1 Then                               'при наличии признака записи в устройство (уставки, настройки, выходыи т.д.)
         Select Case Beg_adr_w                              'при записи (функция 6) Beg_adr = индексу в массиве  Table_data

            Case 1 :                                        'Portc = Low(table_data(beg_adr))       'запись в выходной порт  состояния 0 регистра

            Case 11 :                                       ' адрес 4010 - номер устройства в сети модбас (читать писать)
                       Modbus_slave = Table_data(beg_adr_w) 'запись в энергонезависимую память
            Case 12 :                                       ' адрес 4011 - уставка верх  (читать писать)
                       Ust1_up = Table_data(beg_adr_w)      'запись в энергонезависимую память
            Case 13 :                                       ' адрес 4012 - уставка низ (читать писать)
                       Ust1_dwn = Table_data(beg_adr_w)     'запись в энергонезависимую память

            Case 14:                                        ' Frame_value=делитель -(время в мс / заданное значение времени прерывания за один такт)    256-(время в мс/0.0032)
                       Tmp = Table_data(beg_adr_w) * 100
                       Tmp = Tmp \ 32
                                    Table_data(15) = Tmp
                                    Frame_value = 256 - Tmp
                                    Table_data(16) = Frame_value       'от 1 до 82мсек

                       Frame_value = Frame_value_dev

         End Select
         W_to_device = 0
      End If

 Loop

  Urxc_isr:                                                 '  прерывание по приему данных
   sbis usr,7                                               ' Wait for character
   rjmp urxc_isr                                            ' wait until we can read the byte
  Modt = Udr                                                ' get the byte
  Load Timer0 Frame_value                                   'устанавливаем значение таймера тишины между фреймами
  Start Timer0                                              'стартуем таймер фрейма
  Incr Modc                                                 'увеличиваем счетчик принятого байта
  Mbuf(modc) = Modt                                         ' пишем в буфер значение принятого байта

 Return

 Utxc_isr:
                                                    'Подпрограмма передачи данных
 If Cnt_print = 1 Then                                      ' если последний байт передан
   Enable_tx = 0                                            ' разрешаем прием (запрещаем передачу )
   Cnt_print = 0                                            ' обнуляем признак последнего байта передачи
   Disable Utxc                                             ' запреаем прерывание.
  End If

 Return


 Sub Send_to_master
    Enable Utxc                                             'разрешаем прерывание по
    If Enable_tx = 0 Then
     Enable_tx = 1
     For I = 1 To N_byte                                    'ответ мастеру.  цикл для передачи буфера обмена с заданным кол. байт c заданного адреса
     Print Chr(mbuf(i));                                    'отправка буфера обмена в Нех
     Next
     Cnt_print = 1
   End If
 End Sub
 Sub Error_modbus                                           'функция формирования пакета исключительного ответа мастеру по ошибке.
      Mbuf(2).7 = 1                                         ' 1дрес,2функц.код с 1(единицей),3код ошибки,4,5CRC всего 5 байт
      Mbuf(3) = Error_mod                                   'код ошибки (1- неправильный фунциональный код(неподдерживаемая функция); 2- неправильный адрес; 3- неправильные данные (CRC). )
      Modw = Crcmb(mbuf(1) , 3)                             ' create checksum
      Mbuf(4) = Low(modw)                                   'Checksumme LOWer Byte
      Mbuf(5) = High(modw)                                  'Checksumme HIGHer Byte
      N_byte = 5

 End Sub

 Modbus_timers:                                             'прерывание по таймеру. В нем организовано два счетчика. По одному счетчику обработка пакета принятых сообщений модбас, по другому задержка на отключение передатчика TX в 485.

   Stop Timer0                                              'останавливаем прерывание по таймеру тишины между фреймами
   Md_t_start = 1                                           'выставляем признак того, что в буфере принят фрейм

 Return

Отредактировано Hex (2013-11-15 22:07:29)

0

3

Интересненько ))) А что городил ?? ))

0

4

Городил нагреватель с двумя датчиками температуры 1820.

0

5

Это я увидел по программе, модбас зачем ? )

0

6

Подправил свою версию с учётом новых знаний.
Модбас это универсальность. Теперь могу подключатся зерез OPC сервер и настраивать/контролировать свой нагреватель.

0

7

ПО для работы по протоколу modbus на vb6 (и пр. языках) можно собрать на основе компонента: MBAXP Modbus RTU/ASCII ActiveX Control. Вылеченную версию ocx можно взять тут (версия 1.4.9). В дистрибутиве к компоненту содержатся примеры проектов для разных сред. При установке компонент копируется в system32 и регистрируется в системе.

Отредактировано uni (2014-06-04 21:54:54)

+1

8

uni написал(а):

ПО для работы по протоколу modbus на vb6 (и пр. языках) можно собрать на основе компонента: MBAXP Modbus RTU/ASCII ActiveX Control. Вылеченную версию ocx можно взять тут (версия 1.4.9). В дистрибутиве к компоненту содержатся примеры проектов для разных сред. При установке компонент копируется в system32 и регистрируется в системе.

Отредактировано uni (Сегодня 20:54:54)


Вот спасибо тебе, человечище !!

0

9

Skull написал(а):

Once someone asked (and I, too).
Here the main Fct MODBAS interrupt. Customer.
accidentally hit parsing drives backup, thought gone forever)
Author Mladen Bruck, with my changes.
Client work, a couple of years plowing in industrial equipment, without glitches.

Edited Skull (2013-09-27 22:30:58)


hi Skull
i used this code but i couldn't connect to my device ,actually there isn't no response from micro
my device request this for reading holding register 9
01 03 00 09 00 01 54 08
but no response
could u help me how can i solve that?
thx

0