CAN Bus Flexcan_T4 help needed to decode data frames

Dsolberg8132

Active member
My CAN Bus interface from my Teensy 4.1 to a Huawei R4850g2 is receiving and filtering the data frames that I want from frame ID 0x108040FE. The following are two of the data frames:
Received on CAN3: ID=0x1081407F Data=1 75 0 0 0 0 C7 AE
75 in field 2 identifies this as output voltage, C7 AE is the hex value for the output voltage which is measured at 49.95V
Received on CAN3: ID=0x1081407F Data=1 81 0 0 0 0 0 0
81 in field 2 identifies this a output current, whis is zero as there was no load on the power supply.

There are 12 different data frames but I am mainly interested in getting a float value for voltage and current. This will be displayed on a Nextion display and send over a serial interface to a Visual Basic desktop application.

I have done a lot of serial communication and string manipulation but I am a novice when it comes to getting data out from a CAN bus frame. Can anyone help me with this?

Don K9AQ
 
@Dsolberg8132 (Don K9AQ): I don't know if it will help you directly, but take a look at <this> post, specifically the can_sniff_RX_isotp() function for ideas on how to access the data bytes in an extended frame. That particular sketch was developed to allow me to monitor the OBDII port on my Honda Civic, but the mechanics of receiving and parsing a CAN message should be very similar to what's needed for your power supply interface.

Hope that helps . . .

Mark J Culross
KD5RXT
 
My CAN Bus interface from my Teensy 4.1 to a Huawei R4850g2 is receiving and filtering the data frames that I want from frame ID 0x108040FE. The following are two of the data frames:
Received on CAN3: ID=0x1081407F Data=1 75 0 0 0 0 C7 AE
75 in field 2 identifies this as output voltage, C7 AE is the hex value for the output voltage which is measured at 49.95V
Received on CAN3: ID=0x1081407F Data=1 81 0 0 0 0 0 0
81 in field 2 identifies this a output current, whis is zero as there was no load on the power supply.

There are 12 different data frames but I am mainly interested in getting a float value for voltage and current. This will be displayed on a Nextion display and send over a serial interface to a Visual Basic desktop application.

I have done a lot of serial communication and string manipulation but I am a novice when it comes to getting data out from a CAN bus frame. Can anyone help me with this?

Don K9AQ
So, lets say your received frame is in a variable called frame.

Code:
    float voltage, current;
    switch (frame.buf[1])
   {
   case 0x75:
      voltage = (frame.buf[6] * 256 + frame[7]) / 1000.0f;
      break;
   case 0x81:
         current = (frame.buf[6] * 256 + frame[7]) / 1000.f;
         break;
   }

That is, if you accept that C7 AE really decodes to 51.11V, not 49.95. And, I'm totally guessing on the scale for current. But, the above gives you a general idea of how you'd do it. The values are encoded in two bytes so you have to recombine the two bytes like I did above. I'm assuming big endian format (most significant byte first) just because 0xC7AE = 51118 which divided by 1000 would then give you 51.11V
 
Collin,

I added the switch case statements using the received frame variable of msg. I get the following compile error "Compilation error: no match for 'operator[]' (operand types are 'CAN_message_t' and 'int')"

I am sure that I am missing something really simple and need another pair of eyes to look at.

This is my sketch:

Code:
/* This function will be used to test receiving and decoding data frames from a Huawei R485062 recifier module(50V power supply)
The Huawei has a CAN bus interface that can be used to monitor many of the power supply's parameters and to set default and on/line voltage output and current
limits.  I am only interested in being able to change the output voltage to obtain the highest efficiency in my amplifier when running at reduced
power.  I have the default (off-line) voltage set to 50V.  I will have transmit functions to lower the voltage to 41.5, which is the lowest it can be set.
  To obtain these values, you have to send a request data frame
which is 0x108040FE. For testing purposes I am using a USB CAN Bus analyer to send this data frame to the power supply,
The power supply responds with a 0x1081407F data frame with the parameters.
This function will be included in my amplifier controller sketch, which uses a PCB from S21RC
These are the values that are in the 0x1081407F data frame (1)

#define R48xx_DATA_INPUT_POWER    0x70
#define R48xx_DATA_INPUT_FREQ   0x71
#define R48xx_DATA_INPUT_CURRENT  0x72
#define R48xx_DATA_OUTPUT_POWER   0x73
#define R48xx_DATA_EFFICIENCY   0x74
#define R48xx_DATA_OUTPUT_VOLTAGE 0x75
#define R48xx_DATA_OUTPUT_CURRENT_MAX 0x76
#define R48xx_DATA_INPUT_VOLTAGE  0x78
#define R48xx_DATA_OUTPUT_TEMPERATURE 0x7F
#define R48xx_DATA_INPUT_TEMPERATURE  0x80
#define R48xx_DATA_OUTPUT_CURRENT 0x81
#define R48xx_DATA_OUTPUT_CURRENT1  0x82

At this time only interested in getting the output voltage and current.
*/
#include <FlexCAN_T4.h>
FlexCAN_T4<CAN3, RX_SIZE_256, TX_SIZE_16> myCan;  //The PCB that I am using has the CAN xcvr connected to CAN3 pins

float output_voltage;
float output_current;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  myCan.begin();
  myCan.setBaudRate(125000);
}
void loop() {
  digitalToggle(LED_BUILTIN);  // Toggle LED to show activity
  CAN_message_t msg;
  msg.flags.extended = 1;  //sets extended frames

  // Check for received messages on CAN3 filter out unsolicited frames
  if (myCan.read(msg) && msg.id == 0x1081407F) {

    Serial.print("Received on CAN3: ID=0x");
    Serial.print(msg.id);
    Serial.print(" Data=");
    for (int i = 0; i < msg.len; i++) {
      Serial.print(msg.buf[i]);
      Serial.print(" ");
      Serial.println("");

      switch (msg.buf[1]) {
        case 0x75:
          output_voltage = (msg.buf[6] * 256 + msg[7]) / 1000.0f;
          break;
        case 0x81:
          output_current = (msg.buf[6] * 256 + msg[7]) / 1000.0f;
          break;
      }
      Serial.print("voltage =");
      Serial.println()(output_voltage);
      Serial.print("current =");
      Serial.println(output_current);
      Serial.println("");

      delay(1000);  // Delay before sending the next message
    }
 
@Dsolberg8132:

The following should work better (note changes in BOLD - sorry for the lack of formatting . . . can't do color/bold inside of CODE tags !!):

switch (msg.buf[1]) {
case 0x75:
output_voltage = (msg.buf[6] * 256 + msg.buf[7]) / 1000.0f;
break;
case 0x81:
output_current = (msg.buf[6] * 256 + msg.buf[7]) / 1000.0f;
break;
}

Good luck & have fun !!

Mark J Culross
KD5RXT
 
Yeah, sorry, that was a typo on my part. I was typing in the code directly to the forum here without having ever tested it. So, I just forgot the .buf on the second byte of each line.
 
Aside from the above, I believe you have a bit of a logic bug in your posted code
Code:
    for (int i = 0; i < msg.len; i++) {
      Serial.print(msg.buf[i]);
      Serial.print(" ");
      Serial.println("");

      switch (msg.buf[1]) {
        case 0x75:
          output_voltage = (msg.buf[6] * 256 + msg.buf[7]) / 1000.0f;
          break;
        case 0x81:
          output_current = (msg.buf[6] * 256 + msg.buf[7]) / 1000.0f;
          break;
      }
You should remove the switch from the loop so that it is only executed once per message. Something like this
Code:
    for (int i = 0; i < msg.len; i++) {
      Serial.print(msg.buf[i]);
      Serial.print(" ");
    }
    Serial.println("");
    switch (msg.buf[1]) {
        case 0x75:
          output_voltage = (msg.buf[6] * 256 + msg.buf[7]) / 1000.0f;
          break;
        case 0x81:
          output_current = (msg.buf[6] * 256 + msg.buf[7]) / 1000.0f;
          break;
      }
 
I found on the Internet that the scaling factor for all of the data frames, except one, is 1024. My voltage with that scaling factor is almost exact. The maximum current has a scaling factor of 30. I have not tested this yet. My plan is to put my LDMOS amp back on the air this week and then I can start monitoring current and max current. I added case statements for all of the data frames but I don't plan on using most of them.

I have one last question. In some sketches I have seen this statement myCan.events(); What is the purpose for that and were in the sketch should it be added?

Thanks again,

Don K9AQ
 
Back
Top