mcp2515, convert hex string to decimal/int

I am trying to pull my car’s engine rpm, speed, throttle position from the can bus. I am new to advanced stiff like this. I have gotten as far as being able to print them out on screen but I need them stored in a variable, converted to an integer from hex, so that I may use that info in other ways. Anyways, I am using the can bus library from sparkfun and I’m using a modified can read demo.

The problem I have is it prints out undefined boxes instead of head, but I believe it’s because I am trying to store a byte in a char variable. With that said how can I store a hex string (0x00-0xFF) in a variable and then convert it to an integer?

Here is the code, when it’s just printed using

  Serial.print(message.data[i],HEX);

It comes out perfectly fine in hex

Here is the entire sketch as it is now

/****************************************************************************
CAN Read Demo for the SparkFun CAN Bus Shield. 
Written by Stephen McCoy. 
Original tutorial available here: http://www.instructables.com/id/CAN-Bus-Sniffing-and-Broadcasting-with-Arduino
Used with permission 2016. License CC By SA. 
Distributed as-is; no warranty is given.
*************************************************************************/
#include <stdlib.h>
#include <Canbus.h>
#include <defaults.h>
#include <global.h>
#include <mcp2515.h>
#include <mcp2515_defs.h>
char rpm[2];
int newrpm;
//********************************Setup Loop*********************************//

void setup() {
  Serial.begin(9600); // For debug use
  Serial.println("CAN Read - Testing receival of CAN Bus message");  
  delay(1000);
  
  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;
if (mcp2515_check_message()) 
 {
    if (mcp2515_get_message(&message)) 
 {
        if(message.id == 0x201)  //uncomment when you want to filter
               {
               
               //Serial.print("ID: ");
               //Serial.print(message.id,HEX);
               //Serial.print(", ");
               // Serial.print("Data: ");
               //Serial.print(message.header.length,DEC);
               for(int i=0;i<message.header.length;i++) 
                { 
                  if (i<2)                 // only process first two bytes
                  {
                  rpm[i] = message.data[i];  //Store each byte
                //   Serial.print(message.data[i],HEX);
                //  Serial.print(" ");
                  }
                 
                }
                Serial.println(rpm);
                 long int newrpm = strtol(rpm, NULL, 16); //convert hex string to decimal
               // newrpm = (newrpm+1)/4;                //divide by 4 to get rpm
               //    Serial.println(newrpm);
             }
           }}
}
                Serial.println(rpm);

rpm is NOT a string. Do not pass it to functions that expect strings.

Having printed a variable in HEX format does NOT mean that the variable contains a value in HEX format.

long int newrpm = strtol(rpm, NULL, 16); //convert hex string to decimal

I think I mentioned that rpm is NOT a string. Do not pass it to functions that expect strings.

It is pointless to ask questions about code that contains Serial.print() statements, even stupid anonymous print statements, without showing the serial output.

Well, it was raining at the time and I have to pull the output while connected to my car. The only thing it prints (if not attempting to manipulate it into a strong) is a hex value (00-FF). Here is the full output from the original code I boiled down

message ID: 620
data: 8 10 80 FF FF 80 20 00 80

I only need the first 2 bytes of data (in this case 10 80 as 8 is the message length) and I need to keep them in a 2 byte arrangement to keep their meaning (0x1080) and convert it to decimal. The only reason I was treating it as a string was because I was reading that a lot of these shield return this data as a string. If it's not a string, I have no idea how to pull this off.

If it's not a string, I have no idea how to pull this off.

A string is a NULL terminated array of chars. You have an array of chars, but no NULL terminator.

NULL terminate the array to make it a string. Of course, your array is too small to include the NULL...

I’m at work right now so I don’t have the liberty to post output. I should really start saving it when I test. Anyways, if it is not a string, how can I join the two bytes and maintain their correct values? I tried changing rpm and newrpm into unsigned integers and used this code new rpm = (rpm[1] << 8) + rpm[2];
but it gave me numbers all over the place. Not sure what I am doing wrong or how to go about this. :confused:

When I get home I will get the current code and output as well as the results of some bug tracking code (lots of serial printing) to see where the breakdown is occurring.

Alright, so with this code

/****************************************************************************
CAN Read Demo for the SparkFun CAN Bus Shield. 

Written by Stephen McCoy. 
Original tutorial available here: http://www.instructables.com/id/CAN-Bus-Sniffing-and-Broadcasting-with-Arduino
Used with permission 2016. License CC By SA. 

Distributed as-is; no warranty is given.
*************************************************************************/
#include <stdlib.h>
#include <Canbus.h>
#include <defaults.h>
#include <global.h>
#include <mcp2515.h>
#include <mcp2515_defs.h>
unsigned int rpm[2];
unsigned int newrpm;
//********************************Setup Loop*********************************//

void setup() {
  Serial.begin(9600); // For debug use
  Serial.println("CAN Read - Testing receival of CAN Bus message");  
  delay(1000);
  
  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;
if (mcp2515_check_message()) 
	{
    if (mcp2515_get_message(&message)) 
	{
        if(message.id == 0x201)  //uncomment when you want to filter
               {
               
               //Serial.print("ID: ");
               //Serial.print(message.id,HEX);
               //Serial.print(", ");
                Serial.println("Data: ");
               //Serial.print(message.header.length,DEC);
               for(int i=0;i<message.header.length;i++) 
                {	
                  if (i<2)                 // only process first two bytes
                  {
                  rpm[i] = message.data[i];  //Store each byte
                   Serial.print("  Raw:  ");
                   Serial.print(message.data[i],HEX);
                   Serial.print("   Variable:  ");
                   Serial.print(rpm[i]);
                  }
                 
                }
                //Serial.println(rpm);
                //newrpm = (rpm[1] << 8) + rpm[2];
                //newrpm = (newrpm+1)/4;                //divide by 4 to get rpm
               //Serial.println(newrpm);
             }
           }}

}

I get this output at idle at roughly 550-650 rpm:

  Raw:  9   Variable:  9  Raw:  6B   Variable:  107Data: 
  Raw:  9   Variable:  9  Raw:  63   Variable:  99Data: 
  Raw:  9   Variable:  9  Raw:  4B   Variable:  75Data: 
  Raw:  9   Variable:  9  Raw:  3B   Variable:  59Data: 
  Raw:  9   Variable:  9  Raw:  33   Variable:  51Data: 
  Raw:  9   Variable:  9  Raw:  33   Variable:  51Data: 
  Raw:  9   Variable:  9  Raw:  23   Variable:  35Data: 
  Raw:  9   Variable:  9  Raw:  43   Variable:  67Data: 
  Raw:  9   Variable:  9  Raw:  4B   Variable:  75Data: 
  Raw:  9   Variable:  9  Raw:  3B   Variable:  59Data: 
  Raw:  9   Variable:  9  Raw:  3B   Variable:  59Data: 
  Raw:  9   Variable:  9  Raw:  4B   Variable:  75Data: 
  Raw:  9   Variable:  9  Raw:  6B   Variable:  107Data: 
  Raw:  9   Variable:  9  Raw:  63   Variable:  99Data: 
  Raw:  9   Variable:  9  Raw:  7B   Variable:  123Data: 
  Raw:  9   Variable:  9  Raw:  8B   Variable:  139Data: 
  Raw:  9   Variable:  9  Raw:  7B   Variable:  123Data: 
  Raw:  9   Variable:  9  Raw:  8B   Variable:  139Data:

I find it too difficult
to read
your piss-poorly
// indented code
// full of commented
out
stuff that
you should
have deleted.

I do not understand why you think that the 2 bytes somehow give you rpm.

I do not understand why you can’t take a little effort to format what you print. I don’t understand printing "Data: ", which is supposed to start a new record is followed by a carriage return and line feed, while the last part of the record is not.

I do not understand printing “Raw:” when what you mean is “hex:”. I do not understand printing “Variable:” when what you mean is “dec:”.

Use Tools + Auto Format before you post code again, and delete code that doesn’t do what you want/expect.

I don’t understand the post title when you are no longer attempting to make a string (a NULL terminated array of chars).

PaulS:
I find it too difficult
to read
your piss-poorly
// indented code
// full of commented
out
stuff that
you should
have deleted.

No need to be a jerk, for your info I am planning on using most of that code that is commented out. Second, I am on a 7" tablet with an on screen keyboard with no tab, so I’m using spaces which gets awkward. If you don’t want to help, just don’t.

PaulS:
I do not understand why you think that the 2 bytes somehow give you rpm.

It is most definitely RPM. Stays nearly constant at idle and raises with rpm and I have verified it by holding rpm at 3k and doing the math on the values.

PaulS:
I do not understand why you can’t take a little effort to format what you print. I don’t understand printing "Data: ", which is supposed to start a new record is followed by a carriage return and line feed, while the last part of the record is not.

I’ll give you this one, it was an oversight and I felt the output was still readable so I did not redo it at the time.

PaulS:
I do not understand printing “Raw:” when what you mean is “hex:”. I do not understand printing “Variable:” when what you mean is “dec:”.

Sure

PaulS:
Use Tools + Auto Format before you post code again, and delete code that doesn’t do what you want/expect.

Didn’t know that existed, thanks!

PaulS:
I don’t understand the post title when you are no longer attempting to make a string (a NULL terminated array of chars).

Are you referring to the top of each post or the whole topic? If the whole topic, how can I change that? If you are indeed talking about each posting title, then you are just being petty and should try a different mattress because you are clearly waking up on the wrong side of the bed.

As I said, I am new to stuff like this and would appreciate not being belittled while trying to understand all of this.

Now that I understand that is not a string and is in fact an integer, I would like to understand how to shift the bits over and combine rpm[1] and rpm[2]. My understanding is that it is done like this:

newrpm = (rpm[1] << 8) + rpm[2];

But that seems to be where the values get mucked.

So to reiterate, I have 2 decimal values like 9 and 51, that I would like to combine bitwise to make 2,355. I understand at this point I could just multiply manually to get the same results, but now I would like to understand how to do this with shifting the bits. Also, keep in mind this decimal number can go up to 28,000 ( /4 is 7000 which is my redline). I don’t know if that matters.

Now that I understand that is not a string and is in fact an integer, I would like to understand how to shift the bits over and combine rpm[1] and rpm[2]

A two element array does not have a rpm[2] element.

It has a rpm[ 0 ] element and a rpm[ 1 ] element.

Perhaps that is the only real problem...

Yup, that is indeed my problem. Thank you :grinning:

laser411:
Yup, that is indeed my problem. Thank you :grinning:

Not sure how I missed that in your original code, but I'm glad you're working now.