fultek_salih
Fultek Temsilcisi
- Katılım
- 2 Nis 2008
- Mesajlar
- 315
- Puanları
- 6
- Yaş
- 53
Umarım işinize yarar. Bu code ile hatasız ve son derece hızlı haberleşme sağlayabilirsiniz. Modbus software ürünlerimizle yaptığımız testlerde pic 20 mhz’de saniyede 30 bilgi hatasız olarak alınabiliyor. Programınızı start bloğuna yazın. Bu code 50 registers (100 byt)’lık bir data alanındaki tüm verileri okuyup yazmanız için geliştirildi.Pic 18f452’nin seri portunu kullanarak RS232 ve RS485 olarak çalışabilir.
device 18f452
XTAL = 20
DEFINE LOADER_USED 1
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 TIME 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 'STATION 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 TIME > 5 THEN LOW RS485AKT : TIME = 0 : PIE1.5 = 1
GOTO START
;-------------------------------------------------------------------
;*********************** INTERRUPT *********************************
INT_LOOP: disable
'IF RECEIVE BUFFER NOT EMPTY
if PIE1.5 = 1 then
if PIR1.5 = 1 then
IF TIME > 4 THEN SR_BYTE_CNT = 0
TIME = 0
hserin [RCV_BYTE]
SR_STR[SR_BYTE_CNT] = RCV_BYTE
SR_BYTE_CNT = SR_BYTE_CNT + 1
GOTO CIKIS
endif
endif
'IF OUTPUT BUFFER EMPTY SEND NEXT
if PIE1.4 = 1 then
if PIR1.4 = 1 then
TIME = 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 TIME
if TIME > 6 then
TIME = 0
gosub modbus
ENDIF
endif
CIKIS:
RESUME
ENABLE
;
;******************* MODBUS QUERY ANALYSIS ******************
MODBUS:
IF PIE1.5 = 0 THEN return
IF SR_BYTE_CNT < 8 THEN return
PIE1.5 = 0 'RCV INTERRUPT CLOSE
'RECEIVE COMPLETE
IF SR_STR[0] = IQ_TABLE[1] THEN 'ADRESS CHECK
GOSUB CRC16 'CRC16 CALCULATE
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
'FUNCTION CODE 3-4
IF SR_STR[1] = 3 or SR_STR[1] = 4 THEN
SEND_BYTE_CNT = (((SR_STR[4]*256) + SR_STR[5])* 2) + 5
'REQUEST ADRESS REGISTERS ADRESS CHECK
if START_ADRESS + SEND_BYTE_CNT - 5 > 102 then GOTO REG_ADR
'SEND STRING BUILDING
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
'FUNCTION CODE 6 SINGLE VARIABLE
IF SR_STR[1] = 6 THEN
'REQUEST ADRESS REGISTERS ADRESS CHECK
if START_ADRESS > 100 then GOTO REG_ADR
'VALUE LIMIT CHECK
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
'SEND STRING BUILDING
SEND_BYTE_CNT = 8
GOSUB SEND_CRC16
RETURN
ENDIF
'FUNCTION CODE 16
IF SR_STR[1] = 16 THEN
SEND_BYTE_CNT = SR_STR[6] + 5 'SEND DATA BYTE COUNT
'REQUEST ADRESS REGISTERS ADRESS CHECK
if START_ADRESS + SEND_BYTE_CNT - 5 > 102 then GOTO REG_ADR
'RECEIVE STRING LENGTH CHECK
IF SEND_BYTE_CNT + 4 <> SR_BYTE_CNT then GOTO REG_ADR
FOR V1 = START_ADRESS TO START_ADRESS + SEND_BYTE_CNT - 6
'VALUE LIMIT CHECK
IF V1.0 = 0 THEN 'LIMIT CHECK ONLY FIRST BYTE RUNING
V3 = SR_STR[V1 - START_ADRESS + 7] * 256
V3 = V3 + SR_STR[V1 - START_ADRESS + 8] 'VALUE
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
'SEND STRING BUILDING
SEND_BYTE_CNT = 8
GOSUB SEND_CRC16
RETURN
ENDIF
'INVALID FUNCTION CODE
SEND_BYTE_CNT = 5
SR_STR[2] = 1
GOSUB SEND_CRC16
RETURN
ENDIF
ENDIF
ENDIF
SR_BYTE_CNT = 0
RETURN
'REGISTIRS ADRESS OUT OFF LIMIT
REG_ADR:
SEND_BYTE_CNT = 5
SR_STR[2] = 2
GOSUB SEND_CRC16
return
'VALUE OUT OFF LIMIT
LIMIT_OUT:
SEND_BYTE_CNT = 5
SR_STR[2] = 3
GOSUB SEND_CRC16
RETURN
;
;************************** SEND QUERY BUILDING ****************
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 'SEND INTERRUPT CLOSE
RETURN
;
;************************** CALCULATE CRC-16 *************************
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
;
;************************* VARIABLE SAVE ***************
KAYIT:
IF IQ_TABLE[1] <> EREAD 0 THEN EWrite 0,[IQ_TABLE[1]]
return
;
;################################################################
device 18f452
XTAL = 20
DEFINE LOADER_USED 1
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 TIME 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 'STATION 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 TIME > 5 THEN LOW RS485AKT : TIME = 0 : PIE1.5 = 1
GOTO START
;-------------------------------------------------------------------
;*********************** INTERRUPT *********************************
INT_LOOP: disable
'IF RECEIVE BUFFER NOT EMPTY
if PIE1.5 = 1 then
if PIR1.5 = 1 then
IF TIME > 4 THEN SR_BYTE_CNT = 0
TIME = 0
hserin [RCV_BYTE]
SR_STR[SR_BYTE_CNT] = RCV_BYTE
SR_BYTE_CNT = SR_BYTE_CNT + 1
GOTO CIKIS
endif
endif
'IF OUTPUT BUFFER EMPTY SEND NEXT
if PIE1.4 = 1 then
if PIR1.4 = 1 then
TIME = 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 TIME
if TIME > 6 then
TIME = 0
gosub modbus
ENDIF
endif
CIKIS:
RESUME
ENABLE
;
;******************* MODBUS QUERY ANALYSIS ******************
MODBUS:
IF PIE1.5 = 0 THEN return
IF SR_BYTE_CNT < 8 THEN return
PIE1.5 = 0 'RCV INTERRUPT CLOSE
'RECEIVE COMPLETE
IF SR_STR[0] = IQ_TABLE[1] THEN 'ADRESS CHECK
GOSUB CRC16 'CRC16 CALCULATE
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
'FUNCTION CODE 3-4
IF SR_STR[1] = 3 or SR_STR[1] = 4 THEN
SEND_BYTE_CNT = (((SR_STR[4]*256) + SR_STR[5])* 2) + 5
'REQUEST ADRESS REGISTERS ADRESS CHECK
if START_ADRESS + SEND_BYTE_CNT - 5 > 102 then GOTO REG_ADR
'SEND STRING BUILDING
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
'FUNCTION CODE 6 SINGLE VARIABLE
IF SR_STR[1] = 6 THEN
'REQUEST ADRESS REGISTERS ADRESS CHECK
if START_ADRESS > 100 then GOTO REG_ADR
'VALUE LIMIT CHECK
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
'SEND STRING BUILDING
SEND_BYTE_CNT = 8
GOSUB SEND_CRC16
RETURN
ENDIF
'FUNCTION CODE 16
IF SR_STR[1] = 16 THEN
SEND_BYTE_CNT = SR_STR[6] + 5 'SEND DATA BYTE COUNT
'REQUEST ADRESS REGISTERS ADRESS CHECK
if START_ADRESS + SEND_BYTE_CNT - 5 > 102 then GOTO REG_ADR
'RECEIVE STRING LENGTH CHECK
IF SEND_BYTE_CNT + 4 <> SR_BYTE_CNT then GOTO REG_ADR
FOR V1 = START_ADRESS TO START_ADRESS + SEND_BYTE_CNT - 6
'VALUE LIMIT CHECK
IF V1.0 = 0 THEN 'LIMIT CHECK ONLY FIRST BYTE RUNING
V3 = SR_STR[V1 - START_ADRESS + 7] * 256
V3 = V3 + SR_STR[V1 - START_ADRESS + 8] 'VALUE
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
'SEND STRING BUILDING
SEND_BYTE_CNT = 8
GOSUB SEND_CRC16
RETURN
ENDIF
'INVALID FUNCTION CODE
SEND_BYTE_CNT = 5
SR_STR[2] = 1
GOSUB SEND_CRC16
RETURN
ENDIF
ENDIF
ENDIF
SR_BYTE_CNT = 0
RETURN
'REGISTIRS ADRESS OUT OFF LIMIT
REG_ADR:
SEND_BYTE_CNT = 5
SR_STR[2] = 2
GOSUB SEND_CRC16
return
'VALUE OUT OFF LIMIT
LIMIT_OUT:
SEND_BYTE_CNT = 5
SR_STR[2] = 3
GOSUB SEND_CRC16
RETURN
;
;************************** SEND QUERY BUILDING ****************
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 'SEND INTERRUPT CLOSE
RETURN
;
;************************** CALCULATE CRC-16 *************************
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
;
;************************* VARIABLE SAVE ***************
KAYIT:
IF IQ_TABLE[1] <> EREAD 0 THEN EWrite 0,[IQ_TABLE[1]]
return
;
;################################################################