modbus protokol yardım

Başlatan EMKE, 06 Ekim 2015, 13:49:24

EMKE

Arkadaşlar modbus protokolü hakkında özellikle crc hesaplama kısmında öğrenmek istediklerim var internntten çok araştırdım ama bazı bilgileri kafamda oturtamadım bu konularda uygulama yapmış arkadaşlar bilgi verirlerse sevinirim, öğrenmek istediklerim crc hesaplamayı nasıl yapıyoruz neye göre yapıyoruz bunları anlatabilcek arkadaşlar varsa memnun olurum .

magic_gun

#1

CRC16:
V1 = 0
V2 = 0
V3 = 0
CRC_16 = 65535
For V1 = 0 To SR_BYTE_CNT - 3
V3 = CRC_16
CRC_16.Byte0 = V3.Byte0 ^ SR_STR[V1]
For V2 = 0 To 7
If CRC_16.0 = 1 Then
CRC_16 = CRC_16 >> 1
CRC_16 = CRC_16 ^ 40961
Else
CRC_16 = CRC_16 >> 1
End If
Next V2
Next V1
Return


bu arada :
http://web.eecs.umich.edu/~modbus/documents/PI_MBUS_300.pdf
hayal etemeden basaramazsınız
u cnt achieve w/out dreamin

Bahri Bilir

#2
Modbus ile 2 pic arası basit bir led kontrol kod örneği paylaşabilir misiniz?

Usart üzerinden 2 pic arası seri iletişimde bir sıkıntım yok.Ama CRC çevirip gönderme ve okurken crcden yine konu veriye çevirme kısmının mantığı hakkında hiçbir fikrim yok.Zaten bu kısım haricinde USARTtanda bir farkı yok sanırım.
"Hedeflerin bittiği tek yer, YENİ hedeflerin başlangıcıdır"

EMKE

Evet bende crc kısmının mantığını tam anlamıyla bilmiyorum eğer bu işi yapan bilen bir arkadaşımız  mantığını  anlatabilirse çok iyi olur .

Elzemefe

#4
Ekte deltanın verdiği örnekler aslında  mantık hepsinde  hemen  hemen aynı crc  toplamın komplementi alınmasıyla  oluşuyor
plc de  ama PIC  olarak nasıl işlenecek bilmiyorum

Bu  linktede bi tan örnek var

http://www.modbus.pl/node/18

magic_gun


umarım işinizi görür :)




Xtal = 20

ADCON1 = 7
Declare Adin_Res 10       
Declare Adin_Tad FRC     
Declare Adin_Stime 50     
Declare Hserial_RCSTA = %10010000 
Declare Hserial_TXSTA = %00100000       
Declare Hserial_Baud = 38400       
Declare Hserial_Clear = On         
Symbol RS485AKT = PORTB.1
'standart variable
Dim RCV_BYTE As Byte
Dim SR_BYTE_CNT As Byte
Dim SEND_BYTE_CNT As Word
Dim START_ADRESS As Word
Dim ZAMAN As Byte
Dim AI_ZAMAN As Byte
Dim SR_STR[110] As Byte
Dim IQ_TABLE[100] As Byte
Dim V1 As Byte
Dim V2 As Byte
Dim V3 As Word
Dim CRC_16 As Word
'Demo variable
Dim sayac As Byte
Dim sayac2 As Byte
Clear
'INTERRUPT
INTCON = %11100000
T0CON = %11000001       
PIE1.5 = 1
DelayMS 1000         
On Interrupt GoTo INT_LOOP
Enable
Low RS485AKT
IQ_TABLE[1] = ERead 0   'Modul adress
;********************** START ***********************************
start:
Inc sayac
If sayac = 0 Then Inc sayac2
IQ_TABLE[5] = sayac2
If sayac2.1 = 1 Then Inc IQ_TABLE[5]
If sayac2.2 = 1 Then Inc IQ_TABLE[7]

If PIE1.4 = 0 And PIE1.5 = 0  And ZAMAN > 5 Then  Low RS485AKT : ZAMAN = 0 : PIE1.5 = 1
GoTo start
;-------------------------------------------------------------------
;*********************** INTERRUPT *********************************
INT_LOOP: Disable
'RECEIVE BUFFER'DA BILGI VARSA ALMA ISLEMLERI
If PIE1.5 = 1 Then
    If PIR1.5 = 1 Then
        If ZAMAN > 4 Then SR_BYTE_CNT = 0
        ZAMAN = 0
        HSerIn [RCV_BYTE]
        SR_STR[SR_BYTE_CNT] = RCV_BYTE
        SR_BYTE_CNT = SR_BYTE_CNT + 1
        GoTo CIKIS
    EndIf       
EndIf
'OUTPUT BUFFER'DA BILGI YOKSA YENİSİNİ GÖNDERME ISLEMLERI
If PIE1.4 = 1 Then
    If PIR1.4 = 1 Then
        ZAMAN = 0
        If SR_BYTE_CNT > SEND_BYTE_CNT - 1  Then
             PIE1.4 = 0 :  SR_BYTE_CNT = 0 : GoTo CIKIS
        EndIf
        HSerOut [SR_STR[SR_BYTE_CNT]]
        SR_BYTE_CNT = SR_BYTE_CNT + 1
        GoTo CIKIS
    EndIf
EndIf
If INTCON.2 = 1 Then
    INTCON.2 = 0
    Inc ZAMAN
    Inc AI_ZAMAN
    If ZAMAN > 6 Then
        ZAMAN = 0
        GoSub MODBUS
    EndIf
EndIf
CIKIS:
Resume
Enable
;
;******************* MODBUS SORGU ÇÖZME İŞLEMLERİ ******************
MODBUS:
If PIE1.5 = 0 Then Return
If SR_BYTE_CNT < 8 Then Return
PIE1.5 = 0  'RCV İNTERRUPT KAPATILIYOR
'ALINAN BİLGİLER TAMAMLANDI KONTROL EDİLİYOR       
If SR_STR[0] = IQ_TABLE[1] Then  'ADRES KONTROL EDİLİYOR
    GoSub CRC16 'CRC16 HESAPLA
    If CRC_16.Byte0 = SR_STR[SR_BYTE_CNT-2] Then     
        If CRC_16.Byte1 = SR_STR[SR_BYTE_CNT-1] Then
            High RS485AKT   
            START_ADRESS = ((SR_STR[2]*256) + SR_STR[3]) * 2
            'BİLGİLER OKUNMAK İSTENDİ
            If SR_STR[1] = 3 Or SR_STR[1] = 4 Then                     
                SEND_BYTE_CNT = (((SR_STR[4]*256) + SR_STR[5])* 2) + 5
                'İSTENİLEN ADRES SINIR DIŞINDA
                If START_ADRESS  + SEND_BYTE_CNT - 5 > 102 Then GoTo REG_ADR
                'GÖNDERİLEN STRİNG OLUŞTURMA
                SR_STR[2] = SEND_BYTE_CNT - 5
                For V1 = START_ADRESS To START_ADRESS + SEND_BYTE_CNT
                    SR_STR[V1-START_ADRESS + 3] = IQ_TABLE[V1]                   
                Next
                GoSub SEND_CRC16
                Return
            EndIf
            'TEK VARİABLE DEĞİŞTİRİLDİ
            If SR_STR[1] = 6 Then
                'İSTENİLEN ADRES SINIR DIŞINDA
                If START_ADRESS > 100 Then GoTo REG_ADR
                'LİMİT KONTROL   
                If START_ADRESS < 21 Then
                    If (SR_STR[4]*256) + SR_STR[5] > 1023 Then GoTo LIMIT_OUT
                EndIf                 
                If START_ADRESS > 20 Then
                    If START_ADRESS < 35 Then
                        If (SR_STR[4]*256) + SR_STR[5] = 0 Then GoTo LIMIT_OUT
                        If (SR_STR[4]*256) + SR_STR[5] > 255 Then GoTo LIMIT_OUT
                    EndIf
                EndIf                                                                                         
                IQ_TABLE[START_ADRESS] = SR_STR[4]
                IQ_TABLE[START_ADRESS + 1] = SR_STR[5]
                GoSub KAYIT
                'GÖNDERİLEN STRİNG OLUŞTURMA
                SEND_BYTE_CNT = 8
                GoSub SEND_CRC16
                Return
            EndIf           
            'ÇOKLU VARİABLE DEĞİŞTİRİLDİ
            If SR_STR[1] = 16 Then   
                SEND_BYTE_CNT = SR_STR[6] + 5  'GONDERİLEN DATA BYTE SAYISI
                'İSTENİLEN ADRES SINIR DIŞINDA
                If START_ADRESS  + SEND_BYTE_CNT - 5 > 102 Then GoTo REG_ADR
                'STRİNG BOYU HATALI
                If SEND_BYTE_CNT + 4 <> SR_BYTE_CNT Then GoTo REG_ADR                 
                For V1 = START_ADRESS To START_ADRESS + SEND_BYTE_CNT - 6                   
                    'LİMİT KONTROL   
                    If V1.0 = 0 Then 'SADECE FİRST BYTE'DA ÇALIŞMASI İÇİN
                        V3 = SR_STR[V1 - START_ADRESS + 7] * 256  'YAZILMAK İSTENEN DEĞER
                        V3 = V3 + SR_STR[V1 - START_ADRESS + 8]   'TESPİT EDİLİYOR
                        If START_ADRESS < 21 Then
                            If V3 > 1023 Then GoTo LIMIT_OUT
                        EndIf
                        If V1 > 20 Then
                            If V1 < 35 Then
                                If V3 = 0 Then GoTo LIMIT_OUT
                                If V3 > 255 Then GoTo LIMIT_OUT
                            EndIf
                        EndIf                                                                                                                             
                    EndIf                                                                                                                               
                    IQ_TABLE[V1] = SR_STR[V1 - START_ADRESS + 7]
                Next
                GoSub KAYIT
                'GÖNDERİLEN STRİNG OLUŞTURMA
                SEND_BYTE_CNT = 8                               
                GoSub SEND_CRC16
                Return
            EndIf                                                     
            'GEÇERSİZ FONKSİYON KODU
            SEND_BYTE_CNT = 5
            SR_STR[2] = 1
            GoSub SEND_CRC16
            Return
        EndIf   
    EndIf
EndIf   
SR_BYTE_CNT = 0
Return 
'REGISTIR ADRES SINIR DIŞI
REG_ADR:
SEND_BYTE_CNT = 5
SR_STR[2] = 2
GoSub SEND_CRC16
Return
'LİMİT SINIR DIŞI
LIMIT_OUT:
SEND_BYTE_CNT = 5
SR_STR[2] = 3
GoSub SEND_CRC16
Return   
;
;************************** GÖNDERİLEN CRC-HESAPLATMA ****************
SEND_CRC16:
SR_BYTE_CNT = SEND_BYTE_CNT
GoSub CRC16
SR_STR[SEND_BYTE_CNT - 2] = CRC_16.Byte0
SR_STR[SEND_BYTE_CNT - 1] = CRC_16.Byte1
SR_BYTE_CNT = 0
PIE1.4 = 1 
Return
;
;**************************  CRC-16 hesap *************************
CRC16:
V1 = 0
V2 = 0
V3 = 0
CRC_16 = 65535
For V1 = 0 To SR_BYTE_CNT - 3
    V3 = CRC_16
    CRC_16.Byte0 = V3.Byte0 ^ SR_STR[V1]   
    For V2 = 0 To 7
        If CRC_16.0 = 1 Then
            CRC_16 = CRC_16 >> 1           
            CRC_16 = CRC_16 ^ 40961
        Else
            CRC_16 = CRC_16 >> 1
        End If
    Next V2
Next V1
Return
;

KAYIT:
If IQ_TABLE[1] <> ERead 0 Then EWrite 0,[IQ_TABLE[1]]
Return




hayal etemeden basaramazsınız
u cnt achieve w/out dreamin

Elzemefe

magic_gun hocam
süper bir algoritma  görüyorum ama  o kadar karışık ki ..  yada bana karışık geliyor
hmı panel ile okunan 2 adet adc bilgisini panelde göstermek için bir  örnek yapalım
bende panel var delta  devreyi ben  kurarım burayada  örnek  olur pıc  yazılımınıda
siz yazarım derseniz. Ben varım

efor

gun han bey :D merhaba,

'LİMİT KONTROL   
                    If V1.0 = 0 Then 'SADECE FİRST BYTE'DA ÇALIŞMASI İÇİN
                        V3 = SR_STR[V1 - START_ADRESS + 7] * 256  'YAZILMAK İSTENEN DEĞER
                        V3 = V3 + SR_STR[V1 - START_ADRESS + 8]   'TESPİT EDİLİYOR
                        If START_ADRESS < 21 Then
                            If V3 > 1023 Then GoTo LIMIT_OUT
                        EndIf
                        If V1 > 20 Then
                            If V1 < 35 Then
                                If V3 = 0 Then GoTo LIMIT_OUT
                                If V3 > 255 Then GoTo LIMIT_OUT
                            EndIf
                        EndIf                                                                                                                             
                    EndIf               

kodu derlerken şu kısımda hata alıyorum;

                        V3 = SR_STR[V1 - START_ADRESS + 7] * 256  'YAZILMAK İSTENEN DEĞER
                        V3 = V3 + SR_STR[V1 - START_ADRESS + 8]   'TESPİT EDİLİYOR


bunun yerine ;
                        dım str1 as byte
                        dım str2 as byte

                        str1=V1 - START_ADRESS + 7
                        str2=V1 - START_ADRESS + 8

                        V3 = SR_STR[str1] * 256  'YAZILMAK İSTENEN DEĞER
                        V3 = V3 + SR_STR[str2]   'TESPİT EDİLİYOR


şeklinde düzeltsek aynı işlem olurmu ?


birde bu kod için isiste şema kurdum fakat çalıştırmadım. isis simulasyonu kurabilirmsiniz?


emrah...


magic_gun


aldığın hata zannedersem kulladigin compilerden kaynaklı


ky=V1 - START_ADRESS + 7
V3 = SR_STR[ky] * 256
V3 = V3 + SR_STR[V1 - START_ADRESS + 8]




tabiki olur :)

tahmin ediyorumki elinde plc var direk canlı canlı dene :)

hayal etemeden basaramazsınız
u cnt achieve w/out dreamin

gogoce

Merhaba . Konuyu hortlatıyorum ama bu crc olayını çözebildiniz mi?
benzer projem var
Ne ukalayı affederim nede yapılan haksızlığı ...
Ya sus adam sansınlar , yada adam gibi kouş ilham alsınlar

Powered by EzPortal