Grunderna:
Vi kan börja med grunderna. J1939-21 är alltså ett CAN-bus protokoll för att skicka data fram och tillbaka. J1939-21 formar alltså meddelanden. Det är ingen mjukvara med andra ord, utan snarare regler på hur saker och ting ska se ut.
I J1939-21 så finns det något som heter ACU och ECU. ACU är alltså t.ex. motorer, givare osv. ECU är alltså din dator som är uppkopplad på CAN-bus-nätverket. ECU:n sätter du till en valfri adress igenom att bara säga att du har en adress. Jag väljer att min ECU adress ska vara 0x22. ACU har för nuvarande 0x8D som källadress. ACU har också en destinationsadress, som jag inte vet direkt vad den är. Men i denna frågeställning så fyller den ingen funktion.
Skicka 8 byte data:
Att skicka data med J1939-21 kan enkelt göras igenom att sätta sitt ID och data. ID består utav operation, destination och vart det skickas från någonstans. Datat är alltså det du vill skicka. Max 8 bit.
Notera att J1939-21 använder utökad IT-typ.
Kod: Markera allt
static void write_j1939_message(uint32_t ID, uint8_t data[]) {
txMessage.frame.idType = dEXTENDED_CAN_MSG_ID_2_0B;
txMessage.frame.id = ID;
txMessage.frame.dlc = 8;
txMessage.frame.data0 = data[0];
txMessage.frame.data1 = data[1];
txMessage.frame.data2 = data[2];
txMessage.frame.data3 = data[3];
txMessage.frame.data4 = data[4];
txMessage.frame.data5 = data[5];
txMessage.frame.data6 = data[6];
txMessage.frame.data7 = data[7];
CANSPI_Transmit(&txMessage);
}
För att skicka data som är längre än 8 så börjar man anropa något som heter Transport Protocol. Connexion Management Broadcast Announce Message, även kalalt TP BAM.
Där efter så skickar man sin data i antal korrekt mängder som kallas för Transport Protocol.Data Transfer, men även kallat TP DT
Procedur TP BAM:
Först så skapar man sitt ID för TP BAM. ID skall vara 0x1CEC"DA""SA", där DA är din destination t.ex. ACU adressen och SA är din källa t.ex. ECU adressen.
Där efter fyller du in din data byte1...byte8. Denna TP BAM är viktig för att meddela mottagaren att hur mycket data som kommer skickas och hur många omgångar det kommer skickas.
Procedur TP DT:
Efter man har skickat sitt TP BAM till mottagaren så är det bara att skicka sin data vid TP DT.
Här skall ID vara 0x1CEB"DA""SA". Alltså det skiljer sig lite från TP BAM. Där efter fyller man i data som beskriver vilken omgång det är och vad det är för data.
Tid mellan meddelanden:
För varje meddelande man skickar så måste man vänta 50 till 100 ms.
Praktiken:
Nu tänker jag skicka data. Det jag tänker göra är att ändra ACU:ns källadress till 0x83. Men det fungerar inte för mig.
Kod: Markera allt
/* Skicka TP BAM */
uint32_t ID_BAM = 0x1CECFF22; // TP BAM ID där 0xFF är destinationen(Broadcast with DA = 255) och 0x22(källan där vi skickar ifrån) är min ACU adress. Jag har själv valt att kalla den för 0x22. Jag kan lika gärna kalla den för 0x8D.
uint8_t data_BAM[8];
data_BAM[0] = 0x20; // Kontroll byte - Denna indikerar att vi ska skicka BAM meddelande.
data_BAM[1] = 0x9; // Vi ska skicka totalt bytes!
data_BAM[2] = 0; // Antalet bytes. data_BAM[1] är alltså LSB och data_BAM[2] är MSB.
data_BAM[3] = 0x2; // Hur många omgångar ska vi skicka. I detta fall två omgångar.
data_BAM[4] = 0x0; // Används inte
data_BAM[5] = 0xD8;
data_BAM[6] = 0xFE;
data_BAM[7] = 0x0; // data[5] till data[7] är allså PGN nummret. PGN nummret betyder vilken operation vi skall utföra, i detta fall byta källadress på ACU:n. data_BAM[5] är LSB och data_BAM[7] är MSB.
write_j1939_message(ID_BAM, data_BAM);
HAL_Delay(100);
/* Skicka omgång 1 */
uint32_t ID_TP = 0x1CEBFF22; // TP DT ID som skiljer sig inte mycket från TP BAM ID
uint8_t data1[8] = {0x1, 0x0, 0x0, 0xE0, 0x28, 0x0, 0x81, 0x2}; // Första elementet är alltså omgång 1
write_j1939_message(ID_TP, data1);
HAL_Delay(100);
/* Skicka omgång 2 */
uint8_t data2[8] = {0x2, 0x20, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // Första elementet är omgång 2 där element nummer 3 är 0x80 = Nya källadressen för ACU(nuvarande
write_j1939_message(ID_TP, data2);
HAL_Delay(200);
Om ni undrar vad övriga data betyder på omgångarna så är det dessa typer av data. CA Name är alltså identiteten på ACU:n. Här kan vi bestämma vad ACU:n skall heta och vad den ska ha i för uppgift.
Byta adress på ACU:
För att byta adress på ACU:n så måste vi alltså skicka 9 bytes. Där dom första 8 bytes är identiteten och uppgifterna på ACU:n.
9:e byte är alltså nya källadressen på ACU:n.
Som du ser här så använder vi PGN = 0xD8 0xFE 0x00 när vi skickar TP BAM för det betyder just Commanded address. Notera att PGN är LSB, inte MSB.
Frågeställning:
Trots att jag skickar datat ovan så ändras inte min källadress på ACU:n. Varför inte då? Har jag missat något?
Jag har bifogat protokollet.
För det första så KAN jag skriva till den. Jag kan styra min ACU igenom detta. Detta betyder att min ACU fungerar. Men jag kan ändå inte sätta källadressen på den.
Kod: Markera allt
// Write flow between -250 and 250
void write_sonceboz_valve_command(uint8_t DA, uint8_t SA, float flow){
uint8_t state;
if (flow > 0) {
state = 0x1; // Extend
} else if (flow < 0) {
state = 0x2; // Retract
} else {
state = 0x0; // Neutral
}
uint32_t ID = (0x0CFE << 16) | (DA << 8) | SA;
uint8_t data[8] = {fabsf(flow), 0xFF, state, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
write_j1939_message(ID, data);
}