Il protocollo implementato utilizza una comunicazione standard ASCII. Ciò rende il sistema compatibile con qualsiasi programma (Python, LabVIEW, MATLAB etc), semplice da adattare al proprio progetto.
Il primo passo da fare è installare la libreria MCP_CAN (se non l’avete già installata), nell’editor Arduino. Qui trovate il link della libreria:
Create un progetto con il codice esempio qui riportato o in alternativa scaricate il progetto allegato e scompattatelo nella vostra cartella di lavoro.
//revisione 2 del 30/03/2018, con Arduino 1.8.5
/*
CAN BUS + ARDUINO --> CANINO interface :)
USB <--> CAN BUS interface
Author: Luigi Rubino
Adesso accetta 3 byte di indirizzo
STRING EXAMPLE:
@00A0102030405060708\n
*/
#include "mcp_can.h"
#include <SPI.h>
#define CAN0_INT 2 // Set INT to pin 2
MCP_CAN CAN0(10); // Set CS to pin 10
// the cs pin of the version after v1.1 is default to D9
// v0.9b and v1.0 is default D10
// Can_Bus_shield-ISO-v1 is default D10
//const int SPI_CS_PIN = 10;
//MCP_CAN CAN(SPI_CS_PIN); // Set CS pin
unsigned char buf[8];
unsigned char canId;
long unsigned int rxId;
#define LEN_STRING 10
unsigned char ReceivedString[LEN_STRING]; //stringa ricezione carattere da USB
int inByte = 0; // incoming serial byte
//global var
int digValue, sign=1;
char rxpos, rxpos2; //per il parser seriale
int address; //comando da eseguire
int DT;
void setup() {
// start serial port at 115200 bps:
Serial.begin(115200); //provare velocità 115200
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
if(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) == CAN_OK)
Serial.println("MCP2515 Initialized Successfully!");
else
Serial.println("Error Initializing MCP2515...");
CAN0.setMode(MCP_NORMAL); // Set operation mode to normal so the MCP2515 sends acks to received data.
pinMode(CAN0_INT, INPUT); // Configuring pin for /INT input
Serial.println("CANINO READY...");
}
void loop() {
unsigned char len = 0;
// if we get a valid byte, read analog ins:
if (Serial.available() > 0) {
// get incoming byte:
inByte = Serial.read();
//Serial.write(inByte);
// delay 10ms to let the ADC recover:
//delay(10);
/* Get the character received from the USART */
if (inByte=='@')
{
rxpos = 1;
digValue = 0;
}
else
{
// Serial.print("-->");
// Serial.print((int) rxpos);
// Serial.println();
switch(rxpos)
{
case 1:
address = hex2int(inByte);
rxpos += 1;
break;
case 2:
address <<=4;
address += hex2int(inByte);
rxpos += 1;
break;
case 3:
address <<=4;
address += hex2int(inByte);
rxpos += 1;
rxpos2 = 0;
break;
case 4: //byte 1
DT = hex2int(inByte);
rxpos += 1;
break;
case 5:
DT <<=4;
DT += hex2int(inByte);
ReceivedString[rxpos2] = DT;
rxpos += 1;
rxpos2 += 1;
break;
case 6: //byte 2
DT = hex2int(inByte);
rxpos += 1;
break;
case 7:
DT <<=4;
DT += hex2int(inByte);
ReceivedString[rxpos2] = DT;
rxpos += 1;
rxpos2 += 1;
break;
case 8: //byte 3
DT = hex2int(inByte);
rxpos += 1;
break;
case 9:
DT <<=4;
DT += hex2int(inByte);
ReceivedString[rxpos2] = DT;
rxpos += 1;
rxpos2 += 1;
break;
case 10: //byte 4
DT = hex2int(inByte);
rxpos += 1;
break;
case 11:
DT <<=4;
DT += hex2int(inByte);
ReceivedString[rxpos2] = DT;
rxpos += 1;
rxpos2 += 1;
break;
case 12: //byte 5
DT = hex2int(inByte);
rxpos += 1;
break;
case 13:
DT <<=4;
DT += hex2int(inByte);
ReceivedString[rxpos2] = DT;
rxpos += 1;
rxpos2 += 1;
break;
case 14: //byte 6
DT = hex2int(inByte);
rxpos += 1;
break;
case 15:
DT <<=4;
DT += hex2int(inByte);
ReceivedString[rxpos2] = DT;
rxpos += 1;
rxpos2 += 1;
break;
case 16: //byte 7
DT = hex2int(inByte);
rxpos += 1;
break;
case 17:
DT <<=4;
DT += hex2int(inByte);
ReceivedString[rxpos2] = DT;
rxpos += 1;
rxpos2 += 1;
break;
case 18: //byte 8
DT = hex2int(inByte);
rxpos += 1;
break;
case 19:
DT <<=4;
DT += hex2int(inByte);
ReceivedString[rxpos2] = DT;
rxpos += 1;
rxpos2 += 1;
break;
case 20: //eseguo il comando
CAN0.sendMsgBuf(address, 0, 8, ReceivedString);
//byte sndStat = CAN0.sendMsgBuf(0x100, 0, 8, data);
//delay(100); // send data per 100ms
rxpos = 0;
//da rinuovere
// Serial.print(address, HEX);
// for (int kk=0;kk<=7; kk++)
// {
// Serial.print(" ");
// Serial.print(ReceivedString[kk], HEX);
//
// }
// Serial.println();
break;
default:
rxpos = 0;
break;
}
} //fine gestione acquisizione
} //fine gestione seriale
// --------------------------------------------------
//gestione CAN BUS
if(!digitalRead(CAN0_INT)) // If CAN0_INT pin is low, read receive buffer
{
CAN0.readMsgBuf(&rxId, &len, buf); // Read data: len = data length, buf = data byte(s)
canId = (unsigned char) rxId;
// canId = CAN0.getCanId(); // indirizzo risposta
// Serial.println("-----------------------------");
// Serial.print("Get data from ID: ");
Serial.print("@");
Serial.print(canId, HEX);
for(int i = 0; i<len; i++) // print the data
{
if (buf[i]<=15) { Serial.print('0');}
Serial.print(buf[i], HEX);
}
Serial.println();
}
}
void establishContact() {
while (Serial.available() <= 0) {
Serial.print('A'); // send a capital A
delay(300);
}
}
int hex2int (char c)
{
if (c >= '0' && c <= '9')
{
return (int) (c-'0');
}
else
{
return (int) ((c - 'A')+10);
}
}
CANINO library
Adesso siamo pronti per iniziare!
Test del codice (Trasmissione)
Una tipica connessione CAN-Bus nel campo dell’automazione industriale è quella mostrata in figura, dove c’è un master e vari multi slave. Nel master/slave ogni dispositivo o processo (chiamato master) controlla uno o più dispositivi o processi (chiamati slaves). Una volta che la connessione master/slave si è stabilita, la direzione del controllo è sempre dal master allo slave(s).
Per il test del codice è necessario creare una micro-rete CAN-BUS, ad esempio utilizzando due interfacce CAN-BUS Arduino. Per l’esempio qui riportato abbiamo utilizzato una interfacca CAN-BUS Arduino connessa a una interfaccia commerciale.
NB. L’interfaccia è configurata per una velocità di comunicazione CAN di 500kbps. Cambiate questo valore nel codice per una velocità diversa. Gli indirizzi sono configurati ad 11bit.
Aprite il terminale seriale dall’editor Arduino e configuratela per una velocità di 115200 baud, nessun controllo di flusso.
Digitate la seguente stringa: @00A0102030405060708 e premete invio.
La stringa è composta di tre parti:
@ (Attention) avverte l’interfaccia che una nuova stringa sta arrivando e che deve riallinearsi per un nuovo invio
00A indirizzo di destinazione
01 02 03 04 05 06 07 08 sono gli 8 byte da inviare in formato esadecimale. Ricordiamo che un byte esadecimale è compreso tra 00 e FF.
Se tutte le operazioni sono state effettuate correttamente, l’altra interfaccia riceverà all’indirizzo 0A i byte come nella sequenza mostrata.
Test del codice (Ricezione)
Per il test del codice in ricezione, si effettua l’operazione inversa.
In ricezione avremo una stringa ASCII formattata in modo analogo alla trasmissione, come di seguito riportato:
Esempio (Canino+LabView)
Un video YouTube dove CAN-ISO dialoga con una centralina industriale con CAN BUS, utilizzando il codice “CANINO” e interfaccia grafica “LabView”:
Conclusioni
Adesso che il codice è testato e siamo in grado di trasmettere/ricevere un pacchetto generico, opportunamente formattato, il prossimo step è utilizzare l’interfaccia con un programma. Nei prossimi tutorial vedremo come utilizzare l’interfaccia con Python, LabVIEW, MATLAB, bash shell ed altri.
Contattateci per farci conoscere le vostre opinioni, o proporci una vostra idea/progetto. Per scriverci: info(at)rubinolab dot com
We use cookies to ensure that we give you the best experience on our website. If you continue to use this site we will assume that you are happy with it.Ok