DBC文件是一种集成了CAN和CANFD报文格式帧的数据库,和整车厂合作开发项目时,必定会接触到DBC文件,解析DBC文件是考验一个汽车诊断工程师的终极水平题目!!!!!!
手头上刚好有和宝马公司合住的一个项目,宝马释放了一个DBC文件,本期就来用RA8D1进行DBC解析,破解整车厂通信奥秘!
板子连接,如下图所示

这里我是用了Vector公司的CANoe工具,通过连接到RA8D1开发板上的CANFD接口,只需要连接CAN_H和CAN_L就可以通信了。
1。打开RA Smart 配置软件进行CANFD配置
时钟配置如下

2。配置CANFD时钟

选择40MHZ
3。配置CANFD模块

这里有两路CANFD,只需要选择其一即可
4。以CANFD1为列子





至此配置完毕
生成代码,打开KEIL工程
5。按照如下代码封装号CANFD1接口
#ifndef __BSP_CANFD_1_H
#define __BSP_CANFD_1_H
#include "hal_data.h"
#include "stdio.h"
// CANFD1模块的调试信息输出控制
#define CANFD1_DEBUG 1
#if (1 == CANFD1_DEBUG)
#define CANFD1_MSG_PRINTF(format, ...) printf("[CANFD1 Operation] "format"\r\n", ##VA_ARGS)
#else
#define CANFD1_MSG_PRINTF(format, ...)
#endif
#define WAIT_TIME (0xFFFF)
void CANFD1_Init(void);
void CAN1_Operation(void);
void CANFD1_Operation(void);
void CANFD_SendMessage(uint32_t U32_transmitCANid, uint8_t *U8_dataarr, uint8_t U8_DLC);
void CAN_SendMessage(uint32_t U32_transmitCANid, uint8_t *U8_dataarr, uint8_t U8_DLC);
#endif
#include "bsp_canfd1.h"
/* CAN 初始化函数 */
void CANFD1_Init(void)
{
fsp_err_t err = R_CANFD_Open(&g_canfd1_ctrl, &g_canfd1_cfg);
assert(FSP_SUCCESS == err);
}
/* CANFD Channel 1 Acceptance Filter List (AFL) rule array /
const canfd_afl_entry_t p_canfd1_afl[CANFD_CFG_AFL_CH1_RULE_NUM] =
{
{
.id =
{
/ 指定要接受的ID、ID类型和帧类型。 */
.id = 0xfff,
.frame_type = CAN_FRAME_TYPE_DATA,
.id_mode = CAN_ID_MODE_STANDARD
},
.destination =
{
.minimum_dlc = CANFD_MINIMUM_DLC_0,
.rx_buffer = CANFD_RX_MB_0,
.fifo_select_flags = CANFD_RX_FIFO_0
}
},
};
/* CAN 帧 */
can_frame_t canfd1_tx_frame; //CAN transmit frame
can_frame_t canfd1_rx_frame;
/* 保存帧接收状态信息 */
can_info_t canfd1_rx_info;
/* 要在回调函数中设置的标志 */
volatile bool canfd1_tx_complete_flag = false;
volatile bool canfd1_rx_complete_flag = false;
volatile bool canfd1_err_status_flag = false;
volatile canfd_error_t canfd1_err_status = (canfd_error_t) 0;
static uint32_t CANFD_LengthToDLC(uint8_t length);
/* CANFD1 中断回调函数 */
void canfd1_callback(can_callback_args_t * p_args)
{
switch (p_args->event)
{
case CAN_EVENT_RX_COMPLETE: //接收完成中断
{
canfd1_rx_complete_flag = true; //canfd1接收到数据
memcpy(&canfd1_rx_frame, &(p_args->frame), sizeof(can_frame_t));
break;
}
case CAN_EVENT_TX_COMPLETE:
{
canfd1_tx_complete_flag = true;
break;
}
case CAN_EVENT_ERR_WARNING:
case CAN_EVENT_ERR_PASSIVE:
case CAN_EVENT_ERR_BUS_OFF:
case CAN_EVENT_BUS_RECOVERY:
case CAN_EVENT_MAILBOX_MESSAGE_LOST:
case CAN_EVENT_ERR_BUS_LOCK:
case CAN_EVENT_ERR_CHANNEL:
case CAN_EVENT_TX_ABORTED:
case CAN_EVENT_ERR_GLOBAL:
case CAN_EVENT_TX_FIFO_EMPTY:
{
canfd1_err_status_flag = true;
canfd1_err_status = (canfd_error_t) p_args->error;
break;
}
default:
{
break;
}
}
}
static uint32_t CANFD_LengthToDLC(uint8_t length)
{
uint32_t dlc_result;
if (length <= 8)
{
dlc_result = ((uint32_t)length);
}
else if (length <= 12)
{
dlc_result = CANFD_MINIMUM_DLC_12;
}
else if (length <= 16)
{
dlc_result = CANFD_MINIMUM_DLC_16;
}
else if (length <= 20)
{
dlc_result = CANFD_MINIMUM_DLC_20;
}
else if (length <= 24)
{
dlc_result = CANFD_MINIMUM_DLC_24;
}
else if (length <= 32)
{
dlc_result = CANFD_MINIMUM_DLC_32;
}
else if (length <= 48)
{
dlc_result = CANFD_MINIMUM_DLC_48;
}
else
{
dlc_result = CANFD_MINIMUM_DLC_64;
}
return dlc_result;
}
/* Transmit a CAN message. */
void CAN_SendMessage(uint32_t U32_transmitCANid, uint8_t *U8_dataarr, uint8_t U8_DLC)
{
fsp_err_t err = FSP_SUCCESS;
uint32_t time_out = WAIT_TIME;
canfd1_tx_frame.id = U32_transmitCANid;
canfd1_tx_frame.id_mode = CAN_ID_MODE_STANDARD;
canfd1_tx_frame.type = CAN_FRAME_TYPE_DATA;
canfd1_tx_frame.data_length_code = U8_DLC;
canfd1_tx_frame.options = 0;
memcpy(canfd1_tx_frame.data, U8_dataarr, canfd1_tx_frame.data_length_code);
CANFD1_MSG_PRINTF("CANID: 0x%x 传输CAN数据",canfd1_tx_frame.id);
err = g_canfd_on_canfd.write(&g_canfd1_ctrl, CAN_MAILBOX_NUMBER_0, &canfd1_tx_frame);
assert(FSP_SUCCESS == err);
}
/* Transmit a CANFD message. */
void CANFD_SendMessage(uint32_t U32_transmitCANid, uint8_t *U8_dataarr, uint8_t U8_DLC)
{
fsp_err_t err = FSP_SUCCESS;
uint32_t time_out = WAIT_TIME;
canfd1_tx_frame.id = U32_transmitCANid;
canfd1_tx_frame.id_mode = CAN_ID_MODE_STANDARD;
canfd1_tx_frame.type = CAN_FRAME_TYPE_DATA;
canfd1_tx_frame.data_length_code = 64;
canfd1_tx_frame.options = CANFD_FRAME_OPTION_FD | CANFD_FRAME_OPTION_BRS;
for( uint16_t j = 0; j < canfd1_tx_frame.data_length_code; j++)
{
canfd1_tx_frame.data[j] = (uint8_t) U8_dataarr[j];
}
err = R_CANFD_Write(&g_canfd1_ctrl, CAN_MAILBOX_NUMBER_0, &canfd1_tx_frame);
assert(FSP_SUCCESS == err)
}
6。解析DBC文件
首先让大家见识下DBC到底长啥样
用软件打开


上面就是DBC文件了
这些就是它包含的CAN报文

7。在主函数中解析DBC文件
#include "hal_data.h"
#include "bsp_debug_uart.h"
#include "bsp_canfd1.h"
#include "CANFD_A2B.h"
extern volatile bool uart_send_complete_flag;
//CAN
extern volatile bool canfd1_rx_complete_flag;
extern can_frame_t canfd1_rx_frame;
extern can_frame_t canfd1_tx_frame;
FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER
static const uint8_t txData[10] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x70, 0x80,0xff,0xaa};
/*******************************************************************************************************************//**
-
main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used. This function
-
is called by main() when no RTOS is used.
*********************************************************************************************************************/
void hal_entry(void)
{
/ TODO: add your own code here */
Debug_UART9_Init();
CANFD1_Init();
printf("RA8D1 CANFD解析DBC文件报文信息\r\n");
while(1)
{
//R_BSP_SoftwareDelay(100, BSP_DELAY_UNITS_MILLISECONDS);
//CAN_SendMessage(0x112, txData, 2);
//CANFD_SendMessage(0x223, txData,10);
if (true == canfd1_rx_complete_flag)
{
canfd1_rx_complete_flag = false;
#if 0
printf("Canfd6 Last Receive Pdu: \r\n");
printf("ID: 0x%08x \r\n", canfd1_rx_frame.id);
printf("DataLength: %d \r\n", canfd1_rx_frame.data_length_code);
printf("Data: \r\n");
for (uint32_t i = 1; i <= canfd1_rx_frame.data_length_code; i++)
{
printf("%d ", canfd1_rx_frame.data[i - 1]);
if (i % 8 == 0)
{
printf("\r\n");
}
else
{
}
}
printf("\r\n");
#endif
if (canfd1_rx_frame.id == CANFD_A2_B_EAMP_1_FRAME_ID)
{
canfd_a2_b_eamp_1_unpack(&EAMP_1,canfd1_rx_frame.data, canfd1_rx_frame.data_length_code);
printf("STAT_AMPNaviVolume: 0x%x \r\n",EAMP_1.stat_amp_navi_volume);
printf("STAT_AMPVRVolume: 0x%x \r\n",EAMP_1.stat_ampvr_volume);
printf("STAT_AMPKeyTone: 0x%x \r\n",EAMP_1.stat_amp_key_tone);
printf("STAT_AMPMediaVolume: 0x%x \r\n",EAMP_1.stat_amp_media_volume);
printf("STAT_AMPPhoneVolume: 0x%x \r\n",EAMP_1.stat_amp_phone_volume);
printf("STAT_AMPSoundFocus: 0x%x \r\n",EAMP_1.stat_amp_sound_focus);
printf("STAT_AMPSoundEffect: 0x%x \r\n",EAMP_1.stat_amp_sound_effect);
printf("STAT_AMPSoundEffectBass: 0x%x \r\n",EAMP_1.stat_amp_sound_effect_bass);
printf("STAT_AMPSoundEffectMidrange: 0x%x \r\n",EAMP_1.stat_amp_sound_effect_midrange);
printf("STAT_AMPSoundEffectTreble: 0x%x \r\n",EAMP_1.stat_amp_sound_effect_treble);
printf("STAT_AMPSoundFieldBalance: 0x%x \r\n",EAMP_1.stat_amp_sound_field_balance);
printf("STAT_AMPSoundFieldFader: 0x%x \r\n",EAMP_1.stat_amp_sound_field_fader);
printf("STAT_REQ_AMPA2BMediaSound: 0x%x \r\n",EAMP_1.stat_req_ampa2_b_media_sound);
printf("STAT_REQ_AMPA2BNaviSound: 0x%x \r\n",EAMP_1.stat_req_ampa2_b_navi_sound);
printf("STAT_REQ_AMPA2BVRSound: 0x%x \r\n",EAMP_1.stat_req_ampa2_bvr_sound);
printf("STAT_REQ_AMPA2BTTSSound: 0x%x \r\n",EAMP_1.stat_req_ampa2_btts_sound);
printf("STAT_REQ_AMPA2BPhoneSound: 0x%x \r\n",EAMP_1.stat_req_ampa2_b_phone_sound);
printf("STAT_REQ_AMPAlarm: 0x%x \r\n",EAMP_1.stat_req_amp_alarm);
}
else if (canfd1_rx_frame.id == CANFD_A2_B_EAMP_2_FRAME_ID)
{
canfd_a2_b_eamp_2_unpack(&EAMP_2,canfd1_rx_frame.data, canfd1_rx_frame.data_length_code);
printf("STAT_AMPMediaDuck: 0x%x \r\n",EAMP_2.stat_amp_media_duck);
printf("STAT_AMPSpeedVolume: 0x%x \r\n",EAMP_2.stat_amp_speed_volume);
printf("STAT_AMPMute: 0x%x \r\n",EAMP_2.stat_amp_mute);
printf("STAT_AMPRestoreDefaults: 0x%x \r\n",EAMP_2.stat_amp_restore_defaults);
printf("STAT_AMPAlarmVolume: 0x%x \r\n",EAMP_2.stat_amp_alarm_volume);
printf("STAT_Headrest_Mode: 0x%x \r\n",EAMP_2.stat_headrest_mode);
printf("STAT_AMPSoundEffectMegaBass: 0x%x \r\n",EAMP_2.stat_amp_sound_effect_mega_bass);
printf("STAT_AMPSoundEffectMidBass: 0x%x \r\n",EAMP_2.stat_amp_sound_effect_mid_bass);
printf("STAT_AMPSoundEffectMidTreble:0x%x \r\n",EAMP_2.stat_amp_sound_effect_mid_treble);
printf("STAT_VirtualSbwfrOnOff: 0x%x \r\n",EAMP_2.stat_virtual_sbwfr_on_off);
printf("STAT_SurndFnOnOff: 0x%x \r\n",EAMP_2.stat_surnd_fn_on_off);
printf("STAT_AMPBackgroundVolume: 0x%x \r\n",EAMP_2.stat_amp_background_volume);
printf("STAT_AMPSoundBypass: 0x%x \r\n",EAMP_2.stat_amp_sound_bypass);
printf("STAT_AMPPwrRdySts: 0x%x \r\n",EAMP_2.stat_amp_pwr_rdy_sts);
printf("STAT_AMPVersion: 0x%x \r\n",EAMP_2.stat_amp_version);
}
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
/*******************************************************************************************************************//**
-
This function is called at various points during the startup process. This implementation uses the event that is
-
called right before main() to set up the pins.
-
@param[in] event Where at in the start up process the code is currently at
**********************************************************************************************************************/
void R_BSP_WarmStart (bsp_warm_start_event_t event)
{
if (BSP_WARM_START_RESET == event)
{
#if BSP_FEATURE_FLASH_LP_VERSION != 0
R_FACI_LP->DFLCTL = 1U;
#endif
}
if (BSP_WARM_START_POST_C == event)
{
R_IOPORT_Open(&g_ioport_ctrl, &IOPORT_CFG_NAME);
}
}
#if BSP_TZ_SECURE_BUILD
FSP_CPP_HEADER
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ();
/* Trustzone Secure Projects require at least one nonsecure callable function in order to build (Remove this if it is not required to build). */
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ()
{
}
FSP_CPP_FOOTER
#endif
8。打开Vector的CANoe软件上位机
加载DBC文件进行发送

这里,我们发送报文0X461

每间隔500ms周期发送一次

打开串口助手

我们可以修改其中的


把它改为1

至此,DBC解析正确完成!!!!!!
破解了整车厂的奥秘——————