Vai al contenuto
PLC Forum


Modbus Master pic


wer180m

Messaggi consigliati

Salve a tutti, è da un pò che studio i pic, ma non da abbastanza per fare questo che sto cercando di fare senza chiedere alcune cose:

L'obiettivo sarebbe costruire una periferica con interfaccia rs485 che legga dei registri da una slave e in base a questi, mandi i comandi all'altra slave.

Vi chiedevo se esiste un simulatore via pc in modo da vedere se la periferica manda correttamente o riceve correttamente i comandi, purtroppo dispongo solo di prese usb, esiste un modo per farlo? il programmatore è un pckit2 ho letto che è un debugger, ha qualche funzione di questo tipo?

il circuito sarà un pic16f628 con le usart collegate al max485, ma...per precisione logicamente metto un quarzo, ma che quarzo usare? da 4 o da 20?

come linguaggio uso il mikroc

PS: complimenti è un bellissimo forum questo!

Massimo

Modificato: da wer180m
Link al commento
Condividi su altri siti


aggiungo altre informazioni:

il dispositivo è un TISYSTEM della Bticino, e in particolare il M7TIC/CM che legge valori di corrente e tensioni, io devo leggere questi registri:

Indirizzo _____________Dimensione____________Descrizione____________Unità di misura____________Funzione

1000h_________________Long____________________tensione nella fase 1 ®______mV_________________________03h

1002h_________________Long____________________tensione nella fase 2 (S)_____mV_________________________03h

1004h_________________Long____________________tensione nella fase 3 (T)_____mV_________________________03h

1026h_________________Word____________________frequenza trifase__________1/10Hz______________________03h

e se questi non vanno bene, devo mandare il comando all'altro slave che è il M7TIC/IO sempre bticino

PS: oltre al 16f628, ho questi altri pic se sono più indicati non saprei:

PIC16f874A

PIC16F877A

PIC16F873A

PIC12F675

e aggiungo che la periferica è ad uso amatoriale quindi la vorrei ridurre al minimo, basta che funzioni

Modificato: da wer180m
Link al commento
Condividi su altri siti

Se intendi un programma che simula il master ce ne sono di freeware, come questo:

_http://www.modbus.pl/Modbus_Tester.html

E' solo per modo binario, altrimenti ce ne sono anche altri commerciali o no.

Dove?

Se e' sul PC non e' un problema, esistono degli adattatori USB->RS232 fanno egregiamente il loro lavoro e non costano neanche tanto (10/12 Euro).

Per testare delle apparecchiature e alcuni software ho realizzato solo "slave", ma non dovrebbe essere difficile convertire il software in "master": invece di fornire degli indici dovra' leggerli.

Rispetto a quanto chiedi pero' ho seguito altre strade e tutto dipende da quante elaborazioni davono essere fatte dopo aver letto/fornito gli indici.

In particolare:

- Non ho usato l' uart interno ma due pin qualsiasi del micro.

- Come core puo' andare bene qualsiasi PIC. Il primo che ho realizzato era con il 16F84, poi sono passato al 16F876 perche' mi servivano gli ADC.

- Le routine modbus richiedono un bel po' di memoria programma.

Ad esempio la versione con il PIC16F84 usato come slave per 3 indici a 2 byte ciascuno si prendeva circa 550 words di flash.

C'e' da dire che per produrre alcuni indici ho usato dei pin come "finto ADC" per leggere un potenziometro con il trucchetto della carica/scarica condensatore e questo procedura si porta via molta istruzioni.

- Quasi tutte le versioni usano un quarzo da 4MHz, tranne una con un 8MHz perche' non avevo piu' quarzi del primo tipo.

- Tutto il programma e' scritto in basic (picbasic) e quindi dovrai convertirlo perche' di C conosco poco niente.

E' probabile pero' che il compilatore per quest' ultimo tipo di linguaggio ti crei un codice piu' snello.

- Il protocollo implementato e' molto spartano e non e' possibile leggere dallo slave piu' indici contemporaneamente con una sola richiesta.

In pratica la risposta e' sempre di 8 byte, tranne il caso in qui il micro non riconosca la richiesta e allora risponde con 5byte simulando una "Illegal request" (funzione aumentata di 128).

Per darti un' idea della complessita' dello slave ho recuperatoquesto schema che avevo fatto a suo tempo:

user posted image

Non ho trovato il codice relativo, forse e' in qualche backup.

Come codice abbastanza commentato ho trovato questo per un PIC16F876, usa 3 indici per le funzioni "03" o "04", di cui uno fa capo al convertitore mentre le altre 2 forniscono solo dei valori fissi.

Tengo precisare che deriva da parti di codice lette anni fa in un forum estero (mi pare francese), soprattutto la parte per il calcolo del CRC.

'-----------------------------------

' Protocollo modbus per PIC16F876A

'-----------------------------------

'

'Indirizzi EEPROM interna:

'00= Indirizzo del dispositivo $01-$FF (1-255)

'01= BaudRate:

'19200 = 32 = $20

'9600 = 84 = $54

'4800 =188 = $BC

'

'Gli altri valori per la comunicazione seriale sono fissi:

'Parita' = nessuna

'Dati= 8 bit

'Stop = 1 bit

'----------------------------

DEFINE OSC 4 ' clock a 4MHz

'Variabili per parte seriale e ModBus

CRC_Ok VAR BIT ' controllo del CRC : 0=OK, 1=ERRATO

BRx_Ok VAR BIT ' controllo del buffer RX

i VAR BYTE ' generica

j VAR BYTE ' generica

Indirizzo VAR BYTE 'Address del dispositivo

BR VAR BYTE ' BaudRate della comunicazione

Nbr VAR BYTE ' Numero di byte da ricevere/trasmettere

CRCL VAR BYTE ' Byte Low CRC

CRCH VAR BYTE ' Byte High CRC

CRC16 VAR WORD ' Valore CRC

BufRx VAR BYTE[8] 'Buffer RX

BufTx VAR BYTE[8] 'Buffer TX

RS485 VAR PORTB.0 ' Commutazione transciever RS485 0=RX 1=TX

InOut VAR PORTB.1 ' Pin RX/TX su RS485

Val_AD VAR BYTE 'Valore convertitore AD

led VAR PORTB.7 'Led sur PORTB.7

'resist var PORTB.6

INCLUDE "modedefs.bas"

EEPROM 0,[1,84] ' Imposta i valori di default in EEPROM

' Address=1 e BaudRate=9600

' Per altri valori cambiarli nell'editor del programma

' utilizzato per caricare il micro (campo EEPROM) prima della

' scrittura.

' Inizializzazione al avvio (power on, reset)

' ----- Inizio -----

Inizio:

Low RS485 ' Porta RS485 in ricezione

For i=0 to 7 'Inizializza i buffer RX e TX (tutti i byte=0)

BufRx=0

BufTx=0

Next i

Read 1,Indirizzo 'Legge da eeprom interna l' indirizzo dispositivo

Read 2,BR 'Legge da eeprom interna la velocita' di comunicazione

GoTo Principale

'----- Programma principale -----

Principale:

Nbr=8 ' imposta il numero di byte

SerIn2 InOut,BR,5,Principale,[sTR BufRx\Nbr] 'legge 8 byte -> buffer RX

' il timeout e' di 5 msec, se non riceve niente entro questo tempo torna alla

' label "Principale".

IF (BufRx[0]=Indirizzo) Then ' Verifica se l' indirizzo richiesto = dispositivo

' se il dispositivo e' questo

For i=0 to 7

BufTx=BufRx 'copia nel buffer TX i byte del buffer RX

Next i

BRx_Ok=1

GoSub Calcolo_CRC16 ' passa alla calcolo del CRC16-modbus

'Verifica se il CRC calcolato corrisponde

IF (CRC16.LowByte<>BufRx[6]) OR (CRC16.HighByte<>BufRx[7]) Then

CRC_Ok=1 ' CRC = ERRATO!!!

Else

CRC_Ok=0 'CRC = CORRETTO

'high led

EndIF

'Verifica se c'e' una richiesta di lettura (3 o 4)

IF (BufRx[1]=3)OR (BufRx[1]=4) Then

'Err pas traité (BufRx[2]<>0) AND (BufRx[4]<>0)

' high led

'-------------------------

'Valori di risposta (Dati)

'-------------------------

if bufrx[3]=1 then 'indice 40002

pot PORTB.6,50,VAl_AD

nbr=7

BufTx[2]= 2

BufTx[3]= VAl_AD

BufTx[4]= 0

goto invia

endif

if bufrx[3]=3 then 'indice 40004

nbr=7

BufTx[2]= 2

BufTx[3]= $22

BufTx[4]= $44

goto invia

endif

if bufrx[3]=5 then 'indice 40006

nbr=7

BufTx[2]= 2

BufTx[3]= $33

BufTx[4]= $55

goto invia

endif

'.....Inserire qui eventuali altri indici.....

' 40008

' 40010

' ...

EndIF

'----- Risposta di ERRORE -----

'Viene fornita la risposta che il master interpreta come "ILLEGAL REQUEST"

'Formata da 5 byte totali:ADD,FNC,NBYTE,CRCL,CRCH

'La Function in richiesta viene trasmessa aumentata di 128

IF (BRx_Ok=1) Then 'Toute autre valeur de

'BufRx[1] #3,4,6

Nbr=5 '

BufTx[1]=BufRx[1]+128

BufTx[2]=1

EndIF

'invia:

IF (CRC_OK=0) Then 'Risposta CRC=OK

'----- Trsmissione della risposta -----

Invia:

High RS485 'transciever RS485 in trasmissione

GoSub Calcolo_CRC16 ' Calcola il CRC

CRCL=Nbr-2 'CRCL = penultimo byte

CRCH=Nbr-1 'CRCH = ultimo byte

BufTx[CRCL]=CRC16.LowByte 'Prepara il CRC nel buffer

BufTx[CRCH]=CRC16.HighByte

SerOut2 InOut,BR,[sTR BufTx\Nbr] 'Trasmissione risposta

'High led

'Inzializza il buffer RX (byte=0) per cancellare ev. vecchi valori

For i=0 to 7

BufRx=0

Next i

Low RS485 ' Riporta in ricezione RS485

EndIF

EndIF

GoTo Principale ' Ripete la routine "Principale"

'----- SubRoutine per il calcolo del CRC16 formato modbus -----

'nota: viene effettuato solo sui byte del buffer TX

Calcolo_CRC16:

CRC16=$FFFF 'inizializza registro

For i=0 to Nbr-3 'ciclo di controllo sui byte escluso CRC

CRC16=CRC16^BufTx ' xor

For j=1 to 8

IF CRC16.Bit0=1 Then

CRC16=$A001^(CRC16>>1) 'xor con $A001=polinomio dopo shift a dx di uno

Else

CRC16=CRC16>>1 'shift a dx di uno

EndIF

Next j

Next i

Return

End

Link al commento
Condividi su altri siti

Grazie mf2hd sei stato molto molto gentile! Mi studio bene il tuo circuito e il tuo software...

Ti volevo chiedere dato che hai già avuto esperienze, se il modo in cui vorrei muovermi col il software potrebbe andare bene dato che avevo iniziato ad abbozzarlo:

1. Da master inviare questo comando:

1h 03h 1000h 0003h CRC

1h___________indirizzo di M7TIC/CM (Slave)

03h__________comando di lettura

1000h________primo registro di lettura

0003h________lettura dei 3 registri contigui

CRC_________controllo errori

2. Attesa. se non mi arriva risposta risposta rimando il comando,

3. Altrimenti mi arriva la risposta in questo formato:

1h 03h 0Ah VR VS VT CRC

1h___________Indirizzo di M7TIC/CM (slave, mmi dice che è lui)

03h__________Operazione effettuata

0Ah__________numero di byte campo dati

VR VS VT_____Dati che abbiamo chiesto, ovvero tensioni delle linee (come specificato in post numero 2)

CRC__________controllo errori

4.Controllo il crc, se è tutto ok mi prendo le mie 3 variabili VR VS e VT e me le gestisco via software.

potrebbe andare?

ah...grazie ancora per avermi dedicato il tuo tempo mf2hd

Link al commento
Condividi su altri siti

Scusa se non ho risposto ma non ho avuto molto tempo per seguire il forum e tentare delle prove che volevo fare: un pic come master non l' ho mai usato.

La sequenza del programma "master" la vedrei piu' o meno cosi' :

- Preparazione della stringa di richiesta (address, funzione, indici, crc, ecc.).

Nel caso la richiesta sia sempre la stessa puoi prepararla "fissa" e corretta, saltando la parte di controllo su questa (crc).

- Interrogazione dello "slave", con un time out (es. 10msec)

- Se non riceve niente dopo un po' di tentativi (es. 5) con timeout, significa che c'e' qualcosa che non va = errore di comunicazione.

- C'e' risposta:

. Verifica se CRC=OK

. Verifica se la funzione e' la stessa di quella richiesta, se aumentata di 128d (80h)= richiesta illegale, ovvero stai tentando un' operazione di lettura che lo "slave" non conosce.

. Se le verifiche sono OK passa all' estrazione dei byte che ti interessano.

- Operazioni in base ai byte (misure) estratti : conversione, visualizza, comanda, ecc.

- Ripeti il ciclo.

Nota:

Studiati bene come vengono gestite le chiamate al dispostivo slave nella documentazione del costruttore:

La risposta potrebbe seguire anche altri formati, come ad esempio inserire, prima dei byte della misura, altri byte aggiuntivi per confermare che quella che segue e' valida.

Cosi' come l' inversione dei byte (H>L o L>H).

Da quello che ho capito le misure sono analogiche (tensioni?), se i byte forniti sono il valore in floating point e un po' complicato da fare con un PIC, almeno con quelli "piccoli".

Appena trovo il tempo faccio delle prove con un PIC e un regolatore che usa questo protocollo.

La cosa mi ha molto incuriosito, non mi servira' a niente... ma tanto per imparare qualcosa in piu'... smile.gif

Link al commento
Condividi su altri siti

Mitico mf2hd!

ti ho risposto anche nell'altra conversazione, ma se la cosa diventa pallosa per te dato che sto incasinando le cose, non vorrei affatto essere di disturbo, apprezzo molto l'aiuto che mi hai dato (e già a questo punto, direi che ti devo una birra wink.gif )

Ma adesso ho il dubbio: ma io li posso mandare in esadecimale i valori, oppure no per via dei bit di parità e di stop? (questa funzione la potrei prendere pure dalle librerie?)

esempio:

1h 03h 1000h 0003h CRC

bit___bit___word____word_____crc

01___03___10 00___00 03___bit bit

che con i tempi sarebbe (t1>3,5; t2<1,5):

t1 01 t2 03 t2 10 t2 00 t2 00 t2 03 t2 bit t2 bit t1

La cosa è molto incasinata...ah mf2hd anche io lo faccio per imparare, questa periferica serve ad un mio amico che ha comprato queste 2 apparecchiature e solo dopo ha scoperto che non se ne poteva fare niente senza il master...

Massimo

Modificato: da wer180m
Link al commento
Condividi su altri siti

Ho trovato questo codice su un sito per leggere da un registro:

Program modbus

include crc

Dim RESULT as byte

dim MACH96_TX_Buffer as byte[8]

dim MACH96_RX_Buffer as byte[9]

'==============================================================================

'REQUEST FROM MACH96

'==============================================================================

Sub procedure MACH96_Send

MACH96_TX_Buffer[0]=$21 'address

MACH96_TX_Buffer[1]=$03 'This function reads one or more memory adjacent locations,

MACH96_TX_Buffer[2]=$00 'data start register High

MACH96_TX_Buffer[3]=$69 'data start register Low

MACH96_TX_Buffer[4]=$00 'data of # High

MACH96_TX_Buffer[5]=$02 'data of # Low

'--------------------------------------------------------------------------------

CRC_TX(MACH96_TX_Buffer,MACH96_TX_Buffer[6], MACH96_TX_Buffer[7])

'--------------------------------------------------------------------------------

Setbit(Portc,2) 'RS485 CHIP TX MODE

Usart_write(MACH96_TX_Buffer[0])

Usart_write(MACH96_TX_Buffer[1])

Usart_write(MACH96_TX_Buffer[2])

Usart_write(MACH96_TX_Buffer[3])

Usart_write(MACH96_TX_Buffer[4])

Usart_write(MACH96_TX_Buffer[5])

Usart_write(MACH96_TX_Buffer[6])

Usart_write(MACH96_TX_Buffer[7])

Clearbit(Portc,2)

End Sub

main:

TRISC = %00111011

TRISD = %00000000

PORTD = 0

PortC.2 = 0

'==============================================================================

'USART INIT

'==============================================================================

USART_INIT(9600)

while true

result = RCREG ' read value off top of RX register stack

If Testbit(RCSTA, 1) = 1 Then ' if there was an overrun error on the stack

RCSTA.4 = 0 ' clear continuous receive

RCSTA.4 = 1 ' reset continuous receive

End If ' overrun error is now cleared

MACH96_Send

'========================================================================

'REPLY FROM MACH96

'========================================================================

i=0

while i < 10

If Usart_Data_Ready = 1 then

MACH96_RX_Buffer[i-1]=usart_read

Inc(i)

end if

wend

'=======================================================================

End.

e per il crc:

Module CRC

dim i,j as short

dim acc,tmp as word

Sub procedure CRC_TX(Dim byref data as byte[6],Dim BYREF C1 as byte, Dim BYREF C2 as byte)

acc=$FFFF

for i = 0 to 5

acc=acc Xor data

for j = 1 to 8

tmp = acc and $0001

acc = acc >> 1

if tmp = 1 then

acc = acc Xor $A001

end if

next j

next i

C1 = acc and $FF

C2 = word((acc and $FF00) >> 8 )

end sub

Sub procedure CRC_RX(Dim byref data as byte[7],Dim BYREF C1 as byte, Dim BYREF C2 as byte)

acc=$FFFF

for i = 0 to 6

acc=acc Xor data

for j = 1 to 8

tmp = acc and $0001

acc = acc >> 1

if tmp = 1 then

acc = acc Xor $A001

end if

next j

next i

C1 = acc and $FF

C2 = word((acc and $FF00) >> 8 )

end sub

end.

Ma io con il basic non ci vado molto daccordo e non riesco a capire la parte sulla risposta dallo slave wallbash.gif , più tardi studierò bene il codice, adesso per me è ora di andare a dormire...

Link al commento
Condividi su altri siti

Crea un account o accedi per commentare

Devi essere un utente per poter lasciare un commento

Crea un account

Registrati per un nuovo account nella nostra comunità. è facile!

Registra un nuovo account

Accedi

Hai già un account? Accedi qui.

Accedi ora
×
×
  • Crea nuovo/a...