Jump to content

How to handle hexadecimal in RPM canBUS stream?


magguza

Recommended Posts

I managed to get an Arduino reading a canBUS stream for RPM but I'm not sure where to go from here as I'm unfamiliar with CAN. Here's a video of the values being read within the serial monitor on the Arduino. I've played the video in slow motion and the RPM values seem to be correct for the most part to whatever is displayed in PCLink. However there are some cases where I don't know how to convert hexadecimal over for use in my own program. For example these lines:

Timestamp                                ID (1000 here)    RPM

16:29:27.344 -> 0280.701 RX: [000003E8](00) 0F F8
16:29:27.391 -> 0280.722 RX: [000003E8](00) 0F F4
16:29:27.391 -> 0280.741 RX: [000003E8](00) 0F F0
16:29:27.391 -> 0280.762 RX: [000003E8](00) 0F E4
16:29:27.436 -> 0280.782 RX: [000003E8](00) 0F DC
16:29:27.436 -> 0280.802 RX: [000003E8](00) 10 0C
16:29:27.484 -> 0280.822 RX: [000003E8](00) 10 44
16:29:27.484 -> 0280.842 RX: [000003E8](00) 10 54
16:29:27.530 -> 0280.862 RX: [000003E8](00) 10 3C
16:29:27.530 -> 0280.882 RX: [000003E8](00) 10 4C
16:29:27.530 -> 0280.902 RX: [000003E8](00) 10 44
16:29:27.576 -> 0280.922 RX: [000003E8](00) 10 00

 

In the cases where "A-F" isn't present like "10 44", I assumed the RPM was just 1044. But for cases where the RPM was in the 900's, the value was "0F##". With a straight conversion to decimal, a value like 0FDC is 4060 which clearly isn't correct. Are there any solutions within CAN setup to avoid this? Or any documentation of conversion I can program around? When hexadecimal is present in the second half I'm not sure how to handle it as well.

cansetup1.PNG

cansetup2.PNG

Link to comment
Share on other sites

two things here, you have a multi of 4 (typically this would be 1) so if the engine speed was 1000rpm the CAN Bus value would be 4000 or 0x0FA0.

Secondly 10 44 isn't 1044 it is 0x10 0x44 (i.e. is hexidecimal values) and as the Byte order is set to MS First the first byte (0x10) is the bigger half of the 16bit number and the 2nd byte (0x44) is the smaller half of the 16bit value. The total value is 0x1044 which is 4164, divide this by 4 (because of your multi value) and you get 1041rpm.

to display the values in a usable form convert both bytes to Decimal (base 10) which would be 16 (0x10) and 68 (0x44) and then multiply the MS Byte by 256 (0xFF) which would give 4096 (0x1000) and then add the least significant byte value to it - 4096 + 68 = 4164 (0x1044). Alternatively instead of multiplying you can cast to a uint16_t and then bitshift by 8 (value << 8) and then add the 2nd byte.

Link to comment
Share on other sites

I had just copied over the settings for RPM from the help section without fully understanding it, but I think I understand where I went wrong after your explanation. I had multiplied the value by 4 using the multiplier and created an extra step by needing to divide by 4 later? For optimization and the fastest runtime possible I should just revert the multiplier to 1, right? The MSB first and multiplying the first byte by 256 I understand and luckily I didn't mess with it. I'll look into uint16_t and bitshifting, admittedly I've never heard of these two things in my life.

cansetuphelp.PNG

Link to comment
Share on other sites

14 minutes ago, magguza said:

I had multiplied the value by 4 using the multiplier and created an extra step by needing to divide by 4 later?

yes

14 minutes ago, magguza said:

For optimization and the fastest runtime possible I should just revert the multiplier to 1, right?

yes

14 minutes ago, magguza said:

The MSB first and multiplying the first byte by 256 I understand and luckily I didn't mess with it. I'll look into uint16_t and bitshifting, admittedly I've never heard of these two things in my life.

All of your values as being displayed as a pair of hexidecimal bytes (each 8 bits long) so you need to pick a way to combine them into a single value.

0x10 is equivalent to 16 which is equivalent to 0001 000, casting to a uint16_t would give you 0000 0000 0001 0000 and then bit shifting by 8 would give you 0001 0000 0000 0000 which is equivalent to 0x1000 or 4096. Multiplying by 256 is the same as bit shifting by 8 (16*256 = 4096).

using the windows calculator in programmer mode is quite useful for converting between hexidecimal, decimal and binary.

Capture2.PNG

Capture.PNG

Link to comment
Share on other sites

Im no coder, but I thought I would give a quick example. 

Usually in arduino you wouldnt even need to do any conversion - just declare your incoming bytes as "unsigned char" and your RPM variable type as "int" at the beginning of the sketch.   I have attached an example from a device I made to send data into my dyno controller via bluetooth or wired serial, it might give you some ideas.  This sketch reads 2 CAN messages on ID 1200 & 1300 then "prints" them to serial in a format my dyno controller could interpret (so be aware not all of these variables will be scaled with the correct resolution in this example as some of it is done later at the dyno end).   There are probably far more efficient ways of doing this so dont take this as a good example or the way it must be done, my coding method is trial & error, then google it when it doesnt work...  This did however do the job correctly from memory.  

 

Simple 2 ID CAN message read.txt

Link to comment
Share on other sites

  • 2 weeks later...

After both of your suggestions I was able to get the values reading on the Arduino the very next day. It took a while but I was also able to get it displaying live in my personal program's GUI as well. There was one question I had with values that cross into decimal territory. For stuff like lambda it didn't display decimal precision using the MSB and unsigned format for the other values above, is there any setting I should be using for values with decimals?

Link to comment
Share on other sites

Confused has it right.  Note you can use the "test calculator" tab of the CAN set up screen to see how the multi/div/offsets work. 

Also, slightly related - for some stuff where you want to send a small negative value but large positive value (for example ECT you might want to measure down to -20 but up to +230) it is nicer to use an offset rather than changing to signed which gives you half the resolution in each direction.  

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...