Buonasera, appena iscritto, quindi spreco due righe per descriverMi.
anni da poco compiuti, passione elettronica da sempre, tecnico manutenzione sistemi di sicurezza ed ora al momento mi arrangio...
Mi sono avvicinato al sistema Arduino non da molto, ho realizzato alcune cosette, che funzionano alla grande ora volevo cimentarmi con la realizzazione di un coso che cosa le cose.
Possiedo:
Arduino nano
MCP 2515
Display lcd 44780 4X20 car.
Una Nissan Micra, benzina ed un Mercedes Classe A diesel.
Ho messo insieme i componenti ed ora leggo i dati scorrere, dati nudi e crudi.
Ho girato il web abbastanza da capire che chi ha realizzato questo che sto provando a fare, o lo mette su youtube, senza uno straccio di codice o lo Vende.
Io vorrei realizzare un display per la vettura, allegando codice e procedure per adattarlo alle varie vetture.
Renderlo pubblico e GRATIS.
Ma non so come filtrare e utilizzare le sole tringhe PID che mi interessano.
Potete darmi una man?
Grazie infinite, anche per il tempo dedicato a leggermi.
Buonasera e benvenuto,
essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con molta attenzione tutto il su citato REGOLAMENTO ... Grazie.
Guglielmo
P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposito thread, nessuno ti potrà rispondere, quindi ti consiglio di farla al più presto.
Aggiornamento, ovvio mi sono presentato lo stesso giorno, ma immagino che non lo abbiate visto-
Comunque ho messo insieme qualcosa.
Il problema che ho, è che il pin INT che dovrebbe variare a seconda se è in TX o RX resta sempre alto.
Quindi non ricevo.
Ho provato a mettere un altro pin e lasciarlo fluttuante e il programma trasmette e riceve, ovvio non riceve dati sensati causa mancanza di sync.
Ma a voi è capitato qualcosa di simile.
Con due MCP mi accade.
Grazie
ciszko:
Aggiornamento, ovvio mi sono presentato lo stesso giorno, ma immagino che non lo abbiate visto ...
... tranquillo, visto è stato visto ... se non hai ricevuto risposte è perché probabilmente non è capitato sul tuo thread qualcuno che potesse darti indicazioni ... :
Guglielmo
RIeccomi, intanto ho risolto con il problema ricezione, probabilmente alcune librerie son diverse da altre, a parità di nome
Ora ricevo i dati, ma ancora non so esattamente come estrarre il dato che mi interessa, adattarlo al valore con le apposite formule, memorizzarlo e visualizzarlo a display.
Ora sono al lavoro e su questo PC non ho il codice, lo allego con i risultati della ricezione.
Intanto Grazie
ciszko:
Ora ricevo i dati, ma ancora non so esattamente come estrarre il dato che mi interessa, adattarlo al valore con le apposite formule, memorizzarlo e visualizzarlo a display.
Il primo è quello più "complesso" perché ogni produttore può usare sue codifiche per imessaggi OBD2, quindi sapere "quale" dato leggere o lo trovi in qualche documentazione tecnica per quella vettura specifica, oppure cercare di "dedurlo" studiandoti i messaggi che ricevi (ad esempio i giri del motore: se mentre registri tutti i dati dal minimo porti il motore a 4000 giri, dovresti trovare un valore che si incrementa).
Ma se hai un OBD2 bluetooth, hai provato a vedere con una delle tante app per Android (cerca "OBD2" nel Play Store, troverai ad esempio Car Scanner) che analizzano i dati da un OBD2 e te li mostrano sul display?
Una volta identificato, fai un programmino che riconosce ed intercetta solo quel parametro, e lo mostri sulla seriale. Quando questo funziona, tutto il resto verrà da sé (e dipende strettamente da quale parametro stai ricevendo, quale l'unità di misura, cosa vuoi farci, eccetera...).
Siccome la cosa mi interessa
Se posti un esempio di cosa ottieni possiamo provarci..
Grazie per le risposte, come dicevo, stasera posto il codice e i risultati.
Ho usato anche Torque sul telefono, che mi da informazioni, diciamo plausibili.
Mi interessava il carico del motore e la temperatura liquido.
Ho un Mercedes Classe A diesel e una Nissan Micra 1.2 B. Che nessuna delle due ha il termometro.
Ad esempio il consumo istantaneo sul Mercedes non va mai sotto i 10 Km/l mentre so che ne fa almeno 17 18 .
A stasera.
ciszko:
Ho usato anche Torque sul telefono, che mi da informazioni, diciamo plausibili.
Mi interessava il carico del motore e la temperatura liquido.
Ho un Mercedes Classe A diesel e una Nissan Micra 1.2 B. Che nessuna delle due ha il termometro.
Ma sei sicuro che quei parametri ci siano? Se non hanno il termometro è pure possibile che non sia tra i parametri che manda via OBD2.
Ad esempio il consumo istantaneo sul Mercedes non va mai sotto i 10 Km/l mentre so che ne fa almeno 17 18 .
Il consumo istantaneo è un valore che non serve a molto, va comunque fatta una media (mobile) su un certo numero di letture. Secondo me ti conviene cercare in rete se ci sono documentazioni tecniche (dei "service manual") con la descrizione dei parametri inviati su OBD2 per avere la certezza. Per il resto cercare di fare "reverse engineering" sui dati grezzi potrebbe essere complicato.
PS: comunque quelli sono parametri che sulla mia Renault Zoe non ho perché non ha carburante... A parte questo, la Zoe ZE50 come la mia ha un protocollo su OBD2 modificato rispetto alle serie precedenti, e (pare) anche in qualche modo "non in chiaro", tanto che app come CanZE (che è dedicata proprio alle Zoe) ed i vari OBD funzionano con le altre ma non ancora con le nuove ZE50 (tranne una sola app, Power Cruise Control).
Dunque, il parametro temperatura motore c'è in entrambi i mezzi, anzi c'è in tutte le vetture, che abbiano o meno l'indicatore.
Il Mercedes gestisce la temperatura del motore per inserire ad esempio la ventola radiatore che è controllata via PWM poichè varia continuamente la velocità se serve.Oltre che avviamento a freddo ecc ecc..
La Nissan ha la spia motore freddo, che si disinserisce superati i 40°, quindi anche qui la temperature è letta.
Ed ovvio a freddo parte leggermente accelerata e poi cala di giri.
Il parametro temperatura liquido è uno dei parametri necessari anche alla carburazione, ritengo sia imprescindibile.
Per i veicoli elettrici 100% non so, so che ZOE e Leaf alla fine sono gli stessi veicoli.
Ma che il protocollo EOBD2 contiene già i PID relativi alle info dei veicoli ibridi ed elettrici.
AL momento ho la Nissan ferma a casa, abito in campagna e posso fare più o meno tutto, sto leggendo i dati da quella.
Non so se uso i comandi giusti, allego pochi secondi di lettura, da vettura chiusa, primo rigo che da lo start al tutto, immediatamente avviamento, sgasata e spento.
19:25:35.866 -> ⸮Entering Configuration Mode Successful!
19:25:35.866 -> Setting Baudrate Successful!
19:25:35.866 -> MCP2515 Init Okay!!
19:25:35.866 -> Starting to Set Mask!
19:25:35.866 -> Setting Mask Successful!
19:25:35.935 -> Starting to Set Mask!
19:25:35.935 -> Setting Mask Successful!
19:25:35.935 -> Starting to Set Filter!
19:25:35.935 -> Setting Filter Successfull!
19:25:35.935 -> Starting to Set Filter!
19:25:35.935 -> Setting Filter Successfull!
19:25:35.935 -> Starting to Set Filter!
19:25:35.935 -> Setting Filter Successfull!
19:25:35.935 -> Starting to Set Filter!
19:25:35.935 -> Setting Filter Successfull!
19:25:35.935 -> Starting to Set Filter!
19:25:35.935 -> Setting Filter Successfull!
19:25:35.935 -> Starting to Set Filter!
19:25:35.935 -> Setting Filter Successfull!
19:25:35.935 -> MCP2515 Library Mask & Filter Example...
19:29:17.483 -> ID: 682 Data: 00
19:29:22.000 -> ID: 2DE Data: 00 08 00 FF FF FF 01 9F
19:29:22.000 -> ID: 2DE Data: 00 08 00 FF FF FF 01 9F
19:29:22.048 -> ID: 2DE Data: 00 08 00 FF FF FF 01 9F
19:29:22.048 -> ID: 2DE Data: 00 08 00 FF FF FF 01 9F
19:29:22.048 -> ID: 351 Data: 1C 08 1A D0 00 05 00 00
19:29:22.048 -> ID: 2DE Data: 00 08 00 FF FF FF 01 9F
19:29:22.048 -> ID: 2DE Data: 00 08 00 FF FF FF 01 9F
19:29:22.048 -> ID: 2DE Data: 00 08 00 FF FF FF 01 9F
19:29:22.096 -> ID: 2DE Data: 00 08 00 FF FF FF 01 9F
19:29:22.096 -> ID: 2DE Data: 00 08 00 FF FF FF 01 9F
19:29:22.096 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.096 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.096 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.143 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.143 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.143 -> ID: 351 Data: 1C 08 1F 60 00 05 00 00
19:29:22.143 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.143 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.143 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.190 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.190 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.190 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.190 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.237 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.237 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.237 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.237 -> ID: 351 Data: 1C 08 27 60 00 05 00 00
19:29:22.237 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.237 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.285 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.285 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.285 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.285 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.285 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.332 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.332 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.332 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.332 -> ID: 351 Data: 1C 08 2F 60 00 05 00 00
19:29:22.332 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.332 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.378 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.378 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.378 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.378 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.425 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.425 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.425 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.425 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:22.425 -> ID: 351 Data: 1C 08 37 60 00 05 00 00
19:29:22.425 -> ID: 2DE Data: 00 08 00 FF FF FF FF FF
19:29:30.847 -> ID: 300 Data: 00
19:29:30.847 -> ID: 300 Data: 00
19:29:30.847 -> ID: 300 Data: 00
19:29:30.894 -> ID: 300 Data: 00
19:29:30.894 -> ID: 300 Data: 00
19:29:30.894 -> ID: 351 Data: 1C 08 37 60 00 00 00 00
19:29:30.941 -> ID: 300 Data: 00
19:29:30.941 -> ID: 300 Data: 00
19:29:30.941 -> ID: 300 Data: 00
19:29:30.987 -> ID: 300 Data: 00
19:29:30.987 -> ID: 300 Data: 00
Il codice che sto usando..
// MCP2515 Mask and Filter example for standard CAN message frames.
// Written by Cory J. Fowler (20140717)
/***********************************************************************************
If you send the following standard IDs below to an Arduino loaded with this sketch
you will find that 0x102 and 0x105 will not get in.
ID in Hex - Two Data Bytes! - Filter/Mask in HEX
0x100 + 0000 0000 0000 0000 = 0x01000000
0x101 + 0000 0000 0000 0000 = 0x01010000
0x102 + 0000 0000 0000 0000 = 0x01020000 This example will NOT be receiving this ID
0x103 + 0000 0000 0000 0000 = 0x01030000
0x104 + 0000 0000 0000 0000 = 0x01040000
0x105 + 0000 0000 0000 0000 = 0x01050000 This example will NOT be receiving this ID
0x106 + 0000 0000 0000 0000 = 0x01060000
0x107 + 0000 0000 0000 0000 = 0x01070000
This mask will check the filters against ID bit 8 and ID bits 3-0.
MASK + 0000 0000 0000 0000 = 0x010F0000
If there is an explicit filter match to those bits, the message will be passed to the
receive buffer and the interrupt pin will be set.
This example will NOT be exclusive to ONLY the above frame IDs, for that a mask such
as the below would be used:
MASK + 0000 0000 0000 0000 = 0x07FF0000
This mask will check the filters against all ID bits and the first data byte:
MASK + 1111 1111 0000 0000 = 0x07FFFF00
If you use this mask and do not touch the filters below, you will find that your first
data byte must be 0x00 for the message to enter the receive buffer.
At the moment, to disable a filter or mask, copy the value of a used filter or mask.
Data bytes are ONLY checked when the MCP2515 is in 'MCP_STDEXT' mode via the begin
function, otherwise ('MCP_STD') only the ID is checked.
***********************************************************************************/
#include <mcp_can.h>
#include <SPI.h>
long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
MCP_CAN CAN0(10); // Set CS to pin 10
void setup()
{
Serial.begin(115200);
if(CAN0.begin(MCP_STDEXT, CAN_500KBPS, MCP_16MHZ) == CAN_OK) Serial.print("MCP2515 Init Okay!!\r\n");
else Serial.print("MCP2515 Init Failed!!\r\n");
pinMode(2, INPUT); // Setting pin 2 for /INT input
CAN0.init_Mask(0,0,0x010F0000); // Init first mask...
CAN0.init_Filt(0,0,0x01000000); // Init first filter...
CAN0.init_Filt(1,0,0x01010000); // Init second filter...
CAN0.init_Mask(1,0,0x010F0000); // Init second mask...
CAN0.init_Filt(2,0,0x01030000); // Init third filter...
CAN0.init_Filt(3,0,0x01040000); // Init fouth filter...
CAN0.init_Filt(4,0,0x01060000); // Init fifth filter...
CAN0.init_Filt(5,0,0x01070000); // Init sixth filter...
Serial.println("MCP2515 Library Mask & Filter Example...");
CAN0.setMode(MCP_NORMAL); // Change to normal mode to allow messages to be transmitted
}
void loop()
{
if(!digitalRead(2)) // If pin 2 is low, read receive buffer
{
CAN0.readMsgBuf(&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)
Serial.print("ID: ");
Serial.print(rxId, HEX);
Serial.print(" Data: ");
for(int i = 0; i<len; i++) // Print each byte of the data
{
if(rxBuf[i] < 0x10) // If data byte is less than 0x10, add a leading zero
{
Serial.print("0");
}
Serial.print(rxBuf[i], HEX);
Serial.print(" ");
}
Serial.println();
}
}
/*********************************************************************************************************
END FILE
*********************************************************************************************************/
Spero venga leggibile.
Ho tagliato un pò i report poichè superavo i 9k caratteri
Ancora una domanda:
Ho visto alcuni codici che utilizzano ELM327, che il buon Cory J. Fowler non lo ritiene un gran modulo a causa di problemi...
Le librerie di questi ELM però contengono comendi diretti per la ricerca di stringhe, mi spiego meglio, se devo leggere i giri motore richiedo un RPM ecc ecc... cosa che non trovo in MCP2515.
Sono io che non so cercare? Probabile... ma se esiste un qualcosa potreste indicarmelo?
Ancora una domanda sui PID letti.
Ad esempio a porta aperta e vettura ferma leggo
ID: 280ID: Data: 00 00 32 80 00 00 00 01
ID: 280ID: Data: 00 00 38 60 00 00 00 01
ID: 280ID: Data: 00 00 24 50 00 00 00 01
ID: 280ID: Data: 00 00 31 00 00 00 00 01
Ma PID indicato.. 280 lo dovrei cercare cosi' come lo leggo per trovare l'appartenenza o va trasformato in qualcos'altro? Poichè non trovo corrispondenze.
Grazie
una lettura seria di questo può aiutare OBD-II PIDs - Wikipedia
Ho letto anche quello, ma non trovo corrispondenza.
Tuttavia in questo sito ho trovato questo codice, che ha però incluso una libreria "pids.h" che ritengo sia una libreria fatta ad hoc dallo stesso autore.
Che non trovo da nessuna parte.
#include <Canbus.h> // don't forget to include these
#include <defaults.h>
#include <global.h>
#include <mcp2515.h>
#include <mcp2515_defs.h>
#include <pids.h>
#include <stdio.h>
char buffer[456];
char data_buffer[456];
//unsigned char pid=0x0C; //test per verificare 0x0C
int CAN_data=0;
int data[255];
/* data[255] è un array di parametri
* 0x0C = 12 data[12] = RPM
* 0x0D = 13 data[13] = SPEED
* 0x0E = 14 data[14] = TIMING ADVANCE
* 0x10 = 16 data[16] = MAF
* 0x11 = 17 data[17] = THROTTLE POSITION
* 0x45 = 69 data[69] = RELATIVE THROTTLE POSITION
* 0x04 = 4 data[4] = ENGINE LOAD
* 0x5C = 92 data[92] = OIL TEMPERATURE
*/
unsigned char pid[7] ={4, 12, 13, 14, 16, 17, 92}; //pid presenti sulla mia auto
int i=0;
void setup() {
Serial.begin(115200);
/* AVAILABLE OPTION FOR CAN SPEED ARE :
* CANSPEED_125 //CAN speed at 125Kbps
* CANSPEED_250 //CAN speed at 250Kbps
* CANSPEED_500 //CAN speed at 500Kbps
*/
if(Canbus.init(CANSPEED_500)) /* Initialise MCP2515 CAN controller at the specified speed */
{
Serial.println("CAN Init ok");
} else
{
Serial.println("Can't init CAN");
}
delay(1000);
}
//********************************Main Loop*********************************//
void loop()
{
tCAN message;
//char *buffer;
float engine_data;
int timeout = 0;
char message_ok = 0;
// Prepair message
message.id = PID_REQUEST;
message.header.rtr = 0;
message.header.length = 8;
message.data[0] = 0x02;
message.data[1] = 0x01;
message.data[2] = pid[i];
message.data[3] = 0x00;
message.data[4] = 0x00;
message.data[5] = 0x00;
message.data[6] = 0x00;
message.data[7] = 0x00;
mcp2515_bit_modify(CANCTRL, (1<<REQOP2)|(1<<REQOP1)|(1<<REQOP0), 0);
//Serial.print("PID : "); Serial.print(pid,HEX); Serial.print("\t");
if (mcp2515_send_message(&message)) {
}
while(timeout < 4000)
{
timeout++;
if (mcp2515_check_message())
{
if (mcp2515_get_message(&message))
{
if((message.id == PID_REPLY) && (message.data[2] == pid[i])) // Check message is the reply and its the right PID
{
//Serial.print ("PID: ");Serial.print(message.data[2],HEX);Serial.print("\t");
/* Serial.print(message.data[0],HEX);Serial.print("\t");
Serial.print(message.data[1],HEX);Serial.print("\t");
Serial.print(message.data[2],HEX);Serial.print("\t");
Serial.print(message.data[3],HEX);Serial.print("\t");
Serial.print(message.data[4],HEX);Serial.print("\t");
Serial.print(message.data[5],HEX);Serial.print("\t");
Serial.print(message.data[6],HEX);Serial.print("\t");
Serial.println(message.data[7],HEX);
*/
Conversione(pid[i], message.data[3],message.data[4],message.data[5],message.data[6]);
// Serial.println(((message.data[3]* 256) + message.data[4])/4);
//Serial.write(Conversione(pid,buffer));
}
}
}
}
i++;
if(i>5)
i=0;
//Serial.println();
//Print();
delay(50);
}
void Conversione (unsigned char pid, char A, char B, char C, char D)
{
switch(pid)
{
case ENGINE_RPM: // ((A*256)+B)/4 [RPM]
data[12] = ((A* 256) + B)/4;
//Serial.print(data[12]);Serial.print(" rpm");
break;
case VEHICLE_SPEED: // A [km]
data[13] = A;
//Serial.print(data[13]);Serial.println("km");
break;
case MAF_SENSOR: // ((256*A)+B) / 100 [g/s]
data[16] = ((A*256) + B)/100;
//Serial.print(data[16]);Serial.println(" g/s");
break;
case THROTTLE: // Throttle Position
data[17] = (A*100)/255;
//Serial.print(data[16]);Serial.println(" %");
break;
case ENGINE_LOAD: //Engine Load
data[4] = (A*100)/255;
//Serial.print(data[17]);Serial.println(" %");
break;
case ENGINE_COOLANT_TEMP: //A-40
data[5] = A-40;
//Serial.print(data[5]);Serial.println(" °C");
break;
case ENGINE_OIL_TEMP: // A - 40
data[92] = A-40;
//Serial.print(data[92]);Serial.println(" °C");
break;
case TIMING_ADVANCE: //(A-128)/2
data[14] = (A-128)/2;
//Serial.print(data[14]);Serial.println(" °");
break;
}
Print();
}
void Print()
{
/* data[255] è un array di parametri
* 0x0C = 12 data[12] = RPM
* 0x0D = 13 data[13] = SPEED
* 0x0E = 14 data[14] = TIMING ADVANCE
* 0x10 = 16 data[16] = MAF
* 0x11 = 17 data[17] = THROTTLE POSITION
* 0x04 = 4 data[4] = ENGINE LOAD
* 0x5C = 92 data[92] = OIL TEMPERATURE
*/
Serial.println("PARAMETRI VETTURA");
Serial.println("*************************************************");
Serial.print("CARICO MOTORE :"); Serial.print(data[4]);
Serial.print("\t");
Serial.print("POSIZIONE ACCELARATORE : ");Serial.println(data[17]);
Serial.print("GIRI MOTORE :"); Serial.print(data[12]);
Serial.print("\t");
Serial.print("VELOCITA' : ");Serial.println(data[13]);
Serial.print("ANTICIPO :"); Serial.print(data[14]);
Serial.print("\t");
Serial.print("MAF : ");Serial.println(data[16]);
}
In pratica usa una libreria dove ci sono i comandi già realizzati e/o filtrati.
Credo... ma posso dire vaccate.
Questa la discussione. Can Bus Shield [RISOLTO] - Software - Arduino Forum
Grazie
Io sto provando a replicarsi tuo lavoro
Ma che hardware usi?
Mi trovo un po' in impiccio con lo hardware
Grazie della risposta.
Il mio HW è composto da un Arduino NANO, display LCD 44780, e breakout MCP2515
8 MHz di clock.
Ho fatto altre prove con altri sketch, ed incontro un problema.
Tralasciando il filtraggio dei PID, quando uso uno sketch solo ricezione riesco a vedere il traffico dati senza problemi, se utilizzo uno sketch che interroga la ECU, inviando appunto una richiesta, il pin INT resta perennemente alto impedendo di fatto la ricezione. Quindi servirebbe un qualcosa che forzi in ricezione il sistema.
Poichè in trasmissione non penso che la scheda MCP abbia il buffer pieno.
Questo è quello che penso, da ignorante del campo.
Aggiornamento.
#include <LiquidCrystal.h>
#include <mcp_can.h>
#include <mcp_can_dfs.h>
#include <SPI.h>
// Service 01 PIDs (more detail: https://en.wikipedia.org/wiki/OBD-II_PIDs)
#define PID_ENGINE_LOAD 0x04
#define PID_COOLANT_TEMP 0x551
#define PID_SHORT_TERM_FUEL_TRIM_1 0x06
#define PID_LONG_TERM_FUEL_TRIM_1 0x07
#define PID_SHORT_TERM_FUEL_TRIM_2 0x08
#define PID_LONG_TERM_FUEL_TRIM_2 0x09
#define PID_FUEL_PRESSURE 0x0A
#define PID_INTAKE_MAP 0x0B
#define PID_ENGINE_RPM 0x180
#define PID_VEHICLE_SPEED 0x0D
#define PID_TIMING_ADVANCE 0x0E
#define PID_INTAKE_TEMP 0x0F
#define PID_MAF_FLOW 0x10
#define PID_THROTTLE 0x11
#define PID_AUX_INPUT 0x1E
#define PID_RUNTIME 0x1F
#define PID_DISTANCE_WITH_MIL 0x21
#define PID_COMMANDED_EGR 0x2C
#define PID_EGR_ERROR 0x2D
#define PID_COMMANDED_EVAPORATIVE_PURGE 0x2E
#define PID_FUEL_LEVEL 0x2F
#define PID_WARMS_UPS 0x30
#define PID_DISTANCE 0x31
#define PID_EVAP_SYS_VAPOR_PRESSURE 0x32
#define PID_BAROMETRIC 0x33
#define PID_CATALYST_TEMP_B1S1 0x3C
#define PID_CATALYST_TEMP_B2S1 0x3D
#define PID_CATALYST_TEMP_B1S2 0x3E
#define PID_CATALYST_TEMP_B2S2 0x3F
#define PID_CONTROL_MODULE_VOLTAGE 0x42
#define PID_ABSOLUTE_ENGINE_LOAD 0x43
#define PID_AIR_FUEL_EQUIV_RATIO 0x44
#define PID_RELATIVE_THROTTLE_POS 0x45
#define PID_AMBIENT_TEMP 0x46
#define PID_ABSOLUTE_THROTTLE_POS_B 0x47
#define PID_ABSOLUTE_THROTTLE_POS_C 0x48
#define PID_ACC_PEDAL_POS_D 0x49
#define PID_ACC_PEDAL_POS_E 0x4A
#define PID_ACC_PEDAL_POS_F 0x4B
#define PID_COMMANDED_THROTTLE_ACTUATOR 0x4C
#define PID_TIME_WITH_MIL 0x4D
#define PID_TIME_SINCE_CODES_CLEARED 0x4E
#define PID_ETHANOL_FUEL 0x52
#define PID_FUEL_RAIL_PRESSURE 0x59
#define PID_HYBRID_BATTERY_PERCENTAGE 0x5B
#define PID_ENGINE_OIL_TEMP 0x5C
#define PID_FUEL_INJECTION_TIMING 0x5D
#define PID_ENGINE_FUEL_RATE 0x5E
#define PID_ENGINE_TORQUE_DEMANDED 0x61
#define PID_ENGINE_TORQUE_PERCENTAGE 0x62
#define PID_ENGINE_REF_TORQUE 0x63
#define PID_FUEL_NISSAN 0x5D
#define PID_ENGINE_LOAD_NISSAN 0x5E
#define PID_ENGINE_RPM_NISSAN 0x180
#define PID_ENGINE_COOLANT_NISSAN 0x551
#define PID_MICRA_STATUS 0x63
//----------------------------------------------
//----------------------------------------------
#define CAN_ID_PID 0x7DF //OBD-II CAN frame ID
#define CAN0_INT 2 // Set INT to pin 2 <----verificre se INT è al pin
MCP_CAN CAN0(10); // Set CS to pin 10 <-----Verificare, secondo la versione può essere pin 9
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // Inizializzo LCD
long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
char msgString[128]; // Appoggio la stringa ricevuta
void setup()
{
lcd.begin(20,4);
Serial.begin(115200);
// Initializzo MCP2515 con velocità a 8MHz con baudrate of 500kb/s
if (CAN0.begin(MCP_STDEXT, CAN_500KBPS, MCP_8MHZ) == CAN_OK) { //< -------- mcp esteso, velocità e clock scheda
Serial.println("MCP2515 Init OK!");lcd.print("MCP2515 Init ok");
delay(2500); //Lascio un po la scritta
lcd.clear(); // Pulisco il display
}
else {
Serial.println("Errore inizializzazione MCP2515..."); // Se non comunico con la scheda
while (1);
}
//Setto le maschere per ricevere solo pacchetti con 0x7xx CAN IDs
CAN0.init_Mask(0, 0, 0x04000000); // Init first mask...
CAN0.init_Mask(1, 0, 0x00000000); // Init second mask...
for (uint8_t i = 0; i < 6; ++i) {
CAN0.init_Filt(i, 0, 0x70000000); //Inizializzo filtro
}
CAN0.setMode(MCP_NORMAL); // Set operation mode to normal so the MCP2515 sends acks to received data.
pinMode(CAN0_INT, INPUT); // Pin INT settato a ingresso /INT input
Serial.println("TX & RX OBD-II_PIDs debug...");
}
void loop()
{
lcd.noCursor();// ci provo ma non va
//Chiamo temperatura
sendPID(PID_COOLANT_TEMP);
delay(10); //Ritardo per risposta da ECU
receivePID(PID_COOLANT_TEMP);
//Chiamo levello carb
sendPID(PID_FUEL_LEVEL);
delay(10); //Ritardo per risposta da ECU
receivePID(PID_FUEL_LEVEL);
//Chiamo carico motore
sendPID(PID_ENGINE_LOAD);
delay(10); //Ritardo per risposta da ECU
receivePID(PID_ENGINE_LOAD);
//Chiamo numero giri
sendPID (PID_ENGINE_RPM);
delay(10); //Ritardo per risposta da ECU
receivePID(PID_ENGINE_RPM);
//ritardo 20 msec
delay(8);
}
void sendPID(unsigned char __pid)
{
unsigned char tmp[8] = {0x02, 0x01, __pid, 0, 0, 0, 0, 0};
byte sndStat = CAN0.sendMsgBuf(CAN_ID_PID, 0, 8, tmp);
if (sndStat == CAN_OK) {
// Serial.print("PID Inviato: 0x");
// Serial.println(__pid, HEX);
/* lcd.setCursor(17, 3); // top left
lcd.print("O");lcd.println("K"); */
}
else {
Serial.println("Errore Invio richiesta...");
/* lcd.setCursor(15, 3); // top left
lcd.print("Err");lcd.println("1");*/
}
}
void receivePID(unsigned char __pid)
{
if (!digitalRead(CAN0_INT)) { // Se CAN0_INT pin è basso, ricevo i dati
CAN0.readMsgBuf(&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)
sprintf(msgString, "Standard ID: 0x%.3lX, DLC: %1d, Data: ", rxId, len);
Serial.print(msgString);
for (byte i = 0; i < len; i++) {
sprintf(msgString, " 0x%.2X", rxBuf[i]);
Serial.print(msgString);
}
Serial.println("");
switch (__pid) {
case PID_COOLANT_TEMP:
if(rxBuf[3] == PID_COOLANT_TEMP){
uint8_t temp;
temp = rxBuf[3] - 40; //come da formula A-40
Serial.print("Temp. liquido raff (degC): ");
lcd.setCursor(0, 2); // top left
lcd.print("Temp. Motore : ");lcd.print(temp, DEC );
Serial.println(temp, DEC);
}
break;
case PID_ENGINE_RPM:
if(rxBuf[2] == PID_ENGINE_RPM){
uint16_t rpm;
rpm = (( rxBuf[3]) + rxBuf[4]) / 4; //come da formula 256 *A+B/4
Serial.print("Giri motore (rpm): ");
lcd.setCursor(0, 3); // top left
lcd.print("Giri. Mot : ");lcd.print(rpm, DEC );
Serial.println(rpm, DEC);
}
break;
case PID_ENGINE_LOAD:
if(rxBuf[2] == PID_ENGINE_LOAD){
uint16_t loa;
loa = ( rxBuf[4]) / 2.55; //come da formula A/255
Serial.print("Carico Motore (%): ");
lcd.setCursor(0, 0); // top left
lcd.print("Carico Mot (%) : ");lcd.print(loa,DEC) ;
Serial.println(loa, DEC);
}
break;
case PID_FUEL_LEVEL:
if(rxBuf[2] == PID_FUEL_LEVEL){
uint16_t lev;
lev = ((100 * rxBuf[1]) ) / 255; //come da formula 100*A/255
Serial.print("Benzina (%): ");
lcd.setCursor(0,1); // top left
lcd.print("Benzina (%) : ");lcd.print(lev,DEC) ;
Serial.println(lev, DEC);
}
break;
lcd.noCursor(); // ci provo ma non va
delay(160);
}
}
}
Sono arrivato ad usare questo codice che ho trovato il più versatile,
Ma mi sono riarenato con i filtri e le maschere.
In alcuni post ho letto che le maschere ed i filtri lavorano su due buffer, o che funzionano bene su PID estesi e meno bene su quelli standard.
Per il resto visualizzo a display i dati, ma non sempre in real time, suppongo per la notevole quantità di dati in arrivo poichè non filtrati correttamente. E la MCU non riesce a lavorare bene .
E non capisco il motivo di due maschere ed un filtro.
Se qualcuno sa dirmi il motivo.
Grazie
Sto impazzendo con il filtraggo.
Mi sapete spiegare questo esempio?
Inizialmente mi pareva di una chiarezza estrema.
Mask... se tutti i bit a 0 ignora,se 1 verifica la corrispondenza del Filter, se risultauguale manda a buffer se diverso lo ignora.
Ho provato vari set ma o passa un solo PID o non passa nulla o tutto.
Leggevo anche se funzionano solo i filtri e mask 1 per tutto il pacchetto, mentre la mask e filter 2 filtra solo i PID, a me starebbe bene, se riuscissi a far passare solo i PID che mi occorrono.
Idee? Consigli?
Grazie a tutti.
Grazie,ho trovato spiegazioni chiare facili da mettere in pratica.
Buona serata a tutti.