V tomto díle seriálu o CAN bus skriptech v programu PP2CAN si ukážeme jak simulovat data z joysticku s CAN sběrnicí, který používá protokol SAE J1939. Zároveň si ukážeme funkce pro snadné nastavení dat do CAN zprávy, pokud data nejsou zarovnána na jednotlivé bajty a jejich délka není násobkem 8 bitů.
Aby byl tento příklad funkční, je třeba použít překladač CAN bus skriptů verze 1.90. Tato verze překladače je součástí programu PP2CAN verze 3.041. Novinkou je v ní kromě podpory funkcí pro snadné dekódování dat z CAN zprávy i opačná funkce snadného vkládání dat do CAN zprávy a také obsahuje počáteční podporu formátu dat unsigned64 a int64. Poslední verzi software najdete ke stažení vždy zde.
Pokud si chcete skript otestovat, ale nemáte po ruce joystick, je možné použít softwarový emulátor - virtuální joystick. Jeden takový který bez problému se skriptem funguje najdete zde.
Norma SAE J1939 popisuje zprávu kterou použijeme takto:
PGN 64982 Basic Joystick Message 1
Parameter Group Number: 64982 (0x00FDD6)
- Start Position / Length / Parameter Name SPN
- 1.1 - 2 bits Joystick 1 X-Axis Neutral Position Status 2675
- 1.3 - 2 bits Joystick 1 X-Axis Lever Left Negative Position Status 2670
- 1.5 - 2 bits Joystick 1 X-Axis Lever Right Positive Position Status 2665
- 1.7 - 2 10 bits Joystick 1 X-Axis Position 2660
- 3.1 - 2 bits Joystick 1 Y-Axis Neutral Position Status 2676
- 3.3 - 2 bits Joystick 1 Y-Axis Lever Back Negative Position Status 2671
- 3.5 - 2 bits Joystick 1 Y-Axis Lever Forward Positive Position Status 2666
- 3.7 - 4 10 bits Joystick 1 Y-Axis Position 2661
- 5.5 - 2 bits Joystick 1 Y-Axis Detent Position Status 2681
- 5.7 - 2 bits Joystick 1 X-Axis Detent Position Status 2680
- 6.1 - 2 bits Joystick 1 Button 4 Pressed Status 2688
- 6.3 - 2 bits Joystick 1 Button 3 Pressed Status 2687
- 6.5 - 2 bits Joystick 1 Button 2 Pressed Status 2686
- 6.7 - 2 bits Joystick 1 Button 1 Pressed Status 2685
- 7.1 - 2 bits Joystick 1 Button 8 Pressed Status 2692
- 7.3 - 2 bits Joystick 1 Button 7 Pressed Status 2691
- 7.5 - 2 bits Joystick 1 Button 6 Pressed Status 2690
- 7.7 - 2 bits Joystick 1 Button 5 Pressed Status 2689
- 8.1 - 2 bits Joystick 1 Button 12 Pressed Status 2696
- 8.3 - 2 bits Joystick 1 Button 11 Pressed Status 2695
- 8.5 - 2 bits Joystick 1 Button 10 Pressed Status 2694
- 8.7 - 2 bits Joystick 1 Button 9 Pressed Status 2693
Naším skriptem si budeme simulovat zvýrazněné položky. Celý skript je ke stažení v archivu zip zde. Archiv obsahuje i soubor EYE, který můžeme použít pro zobrazení dat generovaných skriptem na CAN (nebo simulovaných přes virtuální CAN - V2CAN) v nástroji Signal receiver nebo Data view. Při použití nástroje Signál receiver je dle potřeby nutno upravit položku TX - směr dat. Pokud odesíláme data na skutečný CAN, je třeba dekódovat pro zobrazení hodnot směr TX. V režimu V2CAN pak směr RX - data čteme v režimu V2CAN zpět. Nástroj Data view zobrazuje oba směry.
Skript je uveden níže a obsahuje komentáře, které podrobně vysvětlují jeho funkci. Pokud se Vám výpis skriptu nezobrazuje, najeďte na jeho pole myší.
script:
//Typ skriptu
//Chci data generovat periodicky - tedy periodicky typ skriptu.
type = TIMER_SCRIPT;
end
// Definice promenych
variables:
unsigned x_neutral;
unsigned x_left;
unsigned x_right;
unsigned y_neutral;
unsigned y_back;
unsigned y_forward;
unsigned64 value;
double x;
double y;
bool button_1;
bool button_2;
end
// Definice objektu
// Je definovan jeden objekt a to objekt CAN zpravy.
objects:
obj_can_msg can_msg;
end
// Init sekce - tato sekce je volana jednou po spusteni skriptu.
// Sekce se pouziva na inicializaci dat.
init:
logs("Simulace joysticku dle SAE J1939");
log_endl();
//Nastavuji datove bajty na FF, tedy nevyuzite polozky budou signalizovat neznama data.
can_msg.set_all(0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF);
//Rozsireny - 29 bitovy identifikator.
can_msg.stext=true;
//Nejedna se o RTR, ale o datovou zpravu.
can_msg.rtr=false;
//8 datovych bajtu
can_msg.size = 8;
//29 bitove ID: 0xCFDD6FE=217962238 ,PGN:FDD6
can_msg.set_ID29(217962238);
//Skript bude spousten kazdych 100ms a se stejnou periodou se budou generovat data.
//Casovani lze ovládat sliderem v okne skriptu, nicmene timto si prednastavim pozadovanou hodnotu.
ui_set_timer_script_period (100);
end
body:
//------------------------------------------------------
x_neutral = 0;
x_left = 0;
x_right = 0;
//Ctu hodnotu X pripojeneho joysticku (X-leva/prava).
//Ctena hodnota je v rozsahu 0-65535, stred odpovida 32767.
//Data dle SAE J1939 maji rozsah 0-1000. Smer neni rozlisovan a udava se
//pomoci Left/Right Positive Position Status.
x = ui_joy_x(0);
//Leva strana
if(x>32767)
{
x_left = 1;
x_right = 0;
x = x-32767;
x = (x/32767.0) * 1000.0;
}
//Neutral
else if(x==32767)
{
x_left = 0;
x_right = 0;
x = x-32767;
x = 0;
}
//Prava strana
else
{
x_left = 0;
x_right = 1;
x = 32768-x;
x = (x/32768.0) * 1000.0;
}
//Okno skriptu obsahuje univerzalni ovladaci a zobrazovaci prvky.
//Do prvniho okna pro zobrazeni ciselne hodnoty vypisu vypoctenou hodnotu.
ui_set_d0(x);
//Osetreni aby maximalni hodnota byla 1000 a bylo ji vzdy dosazeno.
//Diky nepresnostem nemusi vypocet zmeny rozsahu koncit presne na hodnote 1000.
if(x>999)
{
x=1000;
}
//Dle normy by snimani neutralni hodnoty melo byt zajisteno jinym mechanismem
//nez je mereni polohy (bezpecnost).
//Neutralni polohu budeme signalizovat v rozsahu -10 az 10 od stredu.
if(x<10)
{
x_neutral=1;
}
//Jelikoz se jedna o konverzi z double na unsigned, nefunguje automaticke pretypovani timto smerem,
//provedeme tak nejprve urceni cele casti a prevod do signed a pak konverzi na unsigned.
//Konverze unsigned na unsigned64 je automaticka.
value = i2u(truncd(x));
//Nastavujeme hodnotu x_neutral jako polozku Neutral Position Status do CAN zpravy.
//Metoda set_value objektu CAN zpravy ma parametry:
// - index prvniho bitu (0), CAN zprava ma 8 datovych bajtu, tedy 64 bitu, index 0 az 63
// - bitova delka (2 bity)
// - data se nastavuji ve formatu little endian (false)
// - data nejsou signed (false)
//Status je dle SAE J1939 dvoubitovy. My signalizujeme 0/1, stavy neznama data zde neuvazujeme,
//jsou vzdy znama, nicmene u dalsich nevyuzitych polozek jsou bity nastaveny na 1 - neznama data.
can_msg.set_value(x_neutral,0,2,false,false);
//Nastaveni statusu Lever Left Negative Position Status.
can_msg.set_value(x_left,2,2,false,false);
//Nastaveni statusu Lever Right Positive Position Status.
can_msg.set_value(x_right,4,2,false,false);
//Nastaveni X-Axis Position.
can_msg.set_value(value,6,10,false,false);
//------------------------------------------------------
//Identicky kod avsak tentokrat pro osu Y.
y_neutral = 0;
y_back = 0;
y_forward = 0;
y = ui_joy_y(0);
if(y>32767)
{
y_back = 1;
y_forward = 0;
y = y-32767;
y = (y/32767.0) * 1000.0;
}
else if(y==32767)
{
y_back = 0;
y_forward = 0;
y = y-32767;
y = 0;
}
else
{
y_back = 0;
y_forward = 1;
y = 32768-y;
y = (y/32768.0) * 1000.0;
}
ui_set_d1(y);
if(y>1000)
{
y=1000;
}
if(y<10)
{
y_neutral=1;
}
value = i2u(truncd(y));
can_msg.set_value(y_neutral,16,2,false,false);
can_msg.set_value(y_back,18,2,false,false);
can_msg.set_value(y_forward,20,2,false,false);
can_msg.set_value(value,22,10,false,false);
//------------------------------------------------------
//Zobrazeni hodnoty tlacitek joysticku ve tretim a ctvrtem okne pro zobrazeni ciselne hodnoty
//v okne skriptu.
ui_set_b0(ui_joy_b(0,0));
ui_set_b1(ui_joy_b(0,1));
//Ulozeni hodnoty tlacitek joysticku.
button_1 = ui_joy_b(0,0);
button_2 = ui_joy_b(0,1);
//Vlozeni hodnot tlacitek do CAN zpravy.
can_msg.set_value(button_1,46,2,false,false);
can_msg.set_value(button_2,44,2,false,false);
//------------------------------------------------------
//Odeslani zpravy na CAN sbernici.
can_msg.send();
end

Další díly seriálu:
- Díl 1: Periodické generování dat na CAN sběrnici.
- Díl 2: Uživatelské prvky pro řízení skriptu
- Díl 3: Simulace joysticku dle SAE J1939
- Díl 4: Monitorování a zápis událostí do souboru CSV
- Díl 5: Měření periody a zápis do CSV pomocí přiřazení objektu
- Díl 6: Komunikace pomocí TCP
- Díl 7: Komunikace pomocí sériové linky
- Díl 8: PID regulátor
- Díl 9: Výpočet CRC a objekt obj_dataset
- Díl 10: Volání funkce z externí DLL
