STM32G431xxxx系列CAN通信实战教程(四)
一、Keil中的J-Link配置
J-Link的配置以及一些注意事项如图1-1所示:
图1-1 J-Link的配置
此外还可以用ST-Link(后面会讲到)和串口下载程序,串口下载在这里就不详细介绍了。
二、芯片资料和代码准备
PartA-STM32G431K8T6回环模式
(1)新建文件夹命名为“STM32G431CBT6_CAN_LoopBack”,然后再在STM32CubeMX里进行如上篇文章所配置的初始化,与上篇文章不同的是,这里需要设置内部回环模式,也需要对滤波器数量进行配置,注意画蓝框和画红线的部分,如图A-1所示:
图A-1 波特率和模式配置
(2)配置USART1并打开其中断,为以后串口输出数据做准备;
图A-2 串口设置为异步模式
图A-3 打开串口中断
(3)配置Keil;
①在fdcan. c里声明和定义以下结构体和变量:
/* USER CODE BEGIN 0 */
extern uint8_t TxData[8]; //声明发送数组存储发送数据
extern FDCAN_TxHeaderTypeDef FDCAN1_TxHeader; //声明发送头结构体
extern FDCAN_RxHeaderTypeDef FDCAN1_RxHeader; //声明接收头结构体
extern uint8_t TxState; //声明发送返回状态
extern uint8_t RxState; //声明接收返回状态
FDCAN_RxHeaderTypeDef FDCAN1_RxHeader; //定义接收头结构体
FDCAN_TxHeaderTypeDef FDCAN1_TxHeader; //定义发送头结构体
uint8_t RxData[8]; //定义接收数组存储接收数据
uint32_t RxID;
/* USER CODE END 0 */
②在fdcan.c里封装发送函数:
/* USER CODE BEGIN 1 */
uint8_t SendData(uint8_t *Tx_Data,uint8_t Len) //封装CAN发送函数
{
if(Len>8) //如果数据长度大于8字节
{
Len=8; //数据长度截断至8字节
}
FDCAN1_TxHeader.FDFormat=FDCAN_CLASSIC_CAN; //选择CAN模式为经典模式
FDCAN1_TxHeader.IdType=FDCAN_EXTENDED_ID; //配置ID类型为扩展型
FDCAN1_TxHeader.Identifier=0x02205050; //配置Identifier(标识符、ID)为...
FDCAN1_TxHeader.MessageMarker=0; //用FIFO0作为发送FIFO
FDCAN1_TxHeader.TxFrameType=FDCAN_DATA_FRAME; //选择帧类型为数据帧
FDCAN1_TxHeader.DataLength=Len; //配置数据长度
FDCAN1_TxHeader.BitRateSwitch=FDCAN_BRS_OFF; //波特率切换失能
FDCAN1_TxHeader.ErrorStateIndicator=FDCAN_ESI_ACTIVE;
FDCAN1_TxHeader.TxEventFifoControl=FDCAN_NO_TX_EVENTS;
if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1,&FDCAN1_TxHeader,Tx_Data)==HAL_OK)
{
HAL_Delay(1); //延迟1ms,防止发送邮箱被填满
return 1; //发送成功,返回1
}
else
{
return 0; //发送失败,返回0
} //将要发送的数据及其头通过此函数放入FIFO0中
}
③在fdcan.c里封装接收函数:
uint8_t ReceiveData(void) //封装接收函数
{
if(HAL_FDCAN_GetRxMessage(&hfdcan1,FDCAN_RX_FIFO0,&FDCAN1_RxHeader,RxData)==HAL_OK)
{
RxID=FDCAN1_RxHeader.Identifier;
return 1; //接收成功,返回1
}
else
{
return 0; //接收失败,返回0
} //将要接收的数据及其头通过此函数放入FIFO0中
}
④在fdcan.c里封装过滤器初始化函数:
void FDCAN1_Filter_Init(void) //封装过滤器初始化函数
{
FDCAN_FilterTypeDef Std_FilterConfig; //定义标准过滤器初始化结构体
Std_FilterConfig.IdType=FDCAN_STANDARD_ID; //选择标准形式的ID
Std_FilterConfig.FilterIndex=0; //选用1号过滤器
Std_FilterConfig.FilterType=FDCAN_FILTER_RANGE; //选择滤波器类型过滤模式
Std_FilterConfig.FilterConfig=FDCAN_FILTER_TO_RXFIFO0; //选择以FIFO0作为接收FIFO
Std_FilterConfig.FilterID1=0x000; //设置可通过的起始ID为0x000
Std_FilterConfig.FilterID2=0x7FF; //设置可通过的结束ID为0x7FF
if(HAL_FDCAN_ConfigFilter(&hfdcan1,&Std_FilterConfig)!=HAL_OK)
{
Error_Handler();
}
FDCAN_FilterTypeDef Ext_FilterConfig; //定义扩展过滤器初始化结构体
Ext_FilterConfig.IdType=FDCAN_EXTENDED_ID; //选择扩展形式的ID
Ext_FilterConfig.FilterIndex=1; //选用1号过滤器
Ext_FilterConfig.FilterType=FDCAN_FILTER_RANGE; //选择滤波器类型为过滤模式
Ext_FilterConfig.FilterConfig=FDCAN_FILTER_TO_RXFIFO0; //选择以FIFO0作为接收FIFO
Ext_FilterConfig.FilterID1=0x00000000; //设置可通过的起始ID为0x00000000
Ext_FilterConfig.FilterID2=0x1FFFFFFF; //设置可通过的结束ID为0x1FFFFFFF
if(HAL_FDCAN_ConfigFilter(&hfdcan1,&Ext_FilterConfig)!=HAL_OK)
{
Error_Handler();
}
if(HAL_FDCAN_ConfigGlobalFilter(&hfdcan1,FDCAN_REJECT,FDCAN_REJECT,FDCAN_FILTER_REMOTE,FDCAN_FILTER_REMOTE)!=HAL_OK)
{
Error_Handler();
}
⑤在fdcan.c里激活接收FIFO0的中断:
if(HAL_FDCAN_ActivateNotification(&hfdcan1,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0)!=HAL_OK)
{
Error_Handler();
} //激活FDCAN1的接收FIFO
⑥在fdcan.c里开启CAN通信:
HAL_FDCAN_Start(&hfdcan1); //调用CAN通信开始函数
}
/* USER CODE END 1 */
⑦在fdcan.h里声明自定义的函数:
/* USER CODE BEGIN Includes */
uint8_t SendData(uint8_t* Tx_Data, uint8_t Len);
uint8_t ReceiveData(void);
void FDCAN1_Filter_Init(void);
/* USER CODE END Includes */
⑧在main.c里定义以下变量:
/* USER CODE BEGIN PV */
uint8_t TxData[8]={0,1,2,3,4,5,6,7}; //定义发送数组存储接收数据
uint8_t TxState; //定义发送状态标志位
uint8_t RxState; //定义接收状态标志位
/* USER CODE END PV */
⑨在main.c里调用滤波器初始化函数:
/* USER CODE BEGIN 2 */
FDCAN1_Filter_Init(); //FDCAN1滤波器初始化
//HAL_TIM_Base_Start(&htim3); //以中断的形式开启TIM3的时基单元
/* USER CODE END 2 */
⑩在main.c的while(1)里调用收发函数:
/* USER CODE BEGIN WHILE */
while (1)
{
TxState=SendData(TxData,8);
// if(TxState == 0)
// {
// count++;
// }
// for(uint8_t j=0;j<4;j++)
// {
// RxID_Arr[j]=(RxID>>(8*(3-j)))&0xFF;
// }
//用循环将RxID的四个字节依次取出放到数组里
// HAL_UART_Transmit(&huart1,RxID_Arr,4,0x1000);
RxState=ReceiveData();
// for(uint8_t i=0;i<8;i++)
// {
// TxData[i]++;
// HAL_Delay(500);
// }
// HAL_UART_Transmit(&huart1,RxData,8,0x1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
⑪编译、下载之后进行步进调试:
点击d
进入步进调试模式,再点击左侧的望远镜
,在新窗口的Enter expression
中输入并观察TxData、RxData、TxState、RxState和RxID,运行之前先点击RST
将上述值进行复位(这里有个疑问,程序开始运行前好像已经进行了一次发送和接收了,虽然发送、接收标志都为1,但RxData里的元素全为0)。
猜想:保留了上次的状态!
图A-4-1 复位前的数据
图A-4-2 复位后的数据
未加自增和延时运行后的数据如下:
图A-4-3 运行后的数据
⑫将⑩中的代码更改至如下:
/* USER CODE BEGIN WHILE */
while (1)
{
TxState=SendData(TxData,8);
// if(TxState == 0)
// {
// count++;
// }
// for(uint8_t j=0;j<4;j++)
// {
// RxID_Arr[j]=(RxID>>(8*(3-j)))&0xFF;
// }
//用循环将RxID的四个字节依次取出放到数组里
// HAL_UART_Transmit(&huart1,RxID_Arr,4,0x1000);
RxState=ReceiveData();
for(uint8_t i=0;i<8;i++)
{
TxData[i]++;
HAL_Delay(500);
}
// HAL_UART_Transmit(&huart1,RxData,8,0x1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
可以看到RxData里的各字节每秒递增1:
图A-4-4 运行后的数据
调试过程中出现了一些问题,列举如下:
a.接收数组RxData里的元素全为零且不确定是接收还是发送方的问题。
——将发送和接收函数定义成可返回的类型,将返回状态读出,根据其值判断是哪方的错误。
b.发送、接收状态标志始终为0。
——这个问题目前还未得到根本解决,但猜测是因为while(1)循环进行的太快,导致每执行完一次,发送和接收状态标志就被置0,本例暂时通过在while(1)里添加TxData元素递增并且延迟1s来解决。
⑬为了进一步确认芯片是否真正接收到RxData,本例程选用两种验证方式,第一种是用ST-Link下载器替换J-Link下载器,再用ST-Link的上位机,读取RxData的地址0x20000010~0x20000017存储的数据;第二种方式是用UART将RxData直接读到串口助手里,下面进行两种方式的验证;
⑭用ST-Link上位机验证:
图A-5 ST-Link接线图
图A-6 ST-Link上位机显示
从图A-6中可以看到,0x20000010-0x20000017分别对应了RxData的8个字节,然后0x20000050-0x20000053这4个字节对应了ID号,从上述验证可知,此回环模式可以完成CAN的正常收发。
⑮用串口助手验证,需要进行以下代码改造:
/* USER CODE BEGIN PV */
extern uint8_t RxData[8]; //外部声明接收数组存储接收数据
uint8_t TxData[8]={0,1,2,3,4,5,6,7}; //定义发送数组存储接收数据
extern uint32_t RxID; //外部声明接收ID存储接收ID
uint8_t RxID_Arr[4]; //定义接收ID的数组,将ID以4字节的形式存储下来
uint8_t TxState; //定义发送状态标志位
uint8_t RxState; //定义接收状态标志位
/* USER CODE END PV */
/* USER CODE BEGIN WHILE */
while (1)
{
TxState=SendData(TxData,8);
// if(TxState == 0)
// {
// count++;
// }
for(uint8_t j=0;j<4;j++)
{
RxID_Arr[j]=(RxID>>(8*(3-j)))&0xFF;
}
//用循环将RxID的四个字节依次取出放到数组里
HAL_UART_Transmit(&huart1,RxID_Arr,4,0x1000);
RxState=ReceiveData();
for(uint8_t i=0;i<8;i++)
{
TxData[i]++;
HAL_Delay(500);
}
HAL_UART_Transmit(&huart1,RxData,8,0x1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
图A-7 ST-Link+串口接线图
图A-8 串口助手接收区图
从A-8中可以看到,串口助手每隔4s接受一次数据和ID,而且接收到的数据是递增的说明CAN回环模式收发正常。
PartB-STM32G431K8T6正常模式
正常模式的代码不根据上篇文章的配置,根据上述回环模式配置,并且不通过串口将ID号发出,而通过CAN将ID号发送给其上位机。
(1)将CubeMX里的CAN模式选择为“正常模式”,务必记住设置扩展/标准过滤器数量;
(2)Keil的发送配置如下所示;
①在fdcan.c里定义以下结构体:
/* USER CODE BEGIN 0 */
FDCAN_TxHeaderTypeDef FDCAN1_TxHeader; //定义发送头结构体
/* USER CODE END 0 */
②在fdcan.c里封装发送函数:
/* USER CODE BEGIN 1 */
uint8_t SendData(uint8_t *Tx_Data,uint8_t Len) //封装CAN发送函数
{
if(Len>8) //如果数据长度大于8字节
{
Len=8; //数据长度截断至8字节
}
FDCAN1_TxHeader.FDFormat=FDCAN_CLASSIC_CAN; //选择CAN模式为经典模式
FDCAN1_TxHeader.IdType=FDCAN_EXTENDED_ID; //配置ID类型为扩展型
// FDCAN1_TxHeader.IdType=FDCAN_STANDARD_ID; //配置ID类型为标准型
FDCAN1_TxHeader.Identifier=0x02205050; //配置扩展Identifier(标识符、ID)为...
// FDCAN1_TxHeader.Identifier=0x022; //配置标准Identifier(标识符、ID)为...
// FDCAN1_TxHeader.Identifier=Rx_ID; //配置Identifier(标识符、ID)为...
FDCAN1_TxHeader.MessageMarker=0; //用FIFO0作为发送FIFO
FDCAN1_TxHeader.TxFrameType=FDCAN_DATA_FRAME; //选择帧类型为数据帧
FDCAN1_TxHeader.DataLength=Len; //配置数据长度
FDCAN1_TxHeader.BitRateSwitch=FDCAN_BRS_OFF; //波特率切换失能
FDCAN1_TxHeader.ErrorStateIndicator=FDCAN_ESI_ACTIVE;
FDCAN1_TxHeader.TxEventFifoControl=FDCAN_NO_TX_EVENTS;
if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1,&FDCAN1_TxHeader,Tx_Data)==HAL_OK)
{
HAL_Delay(1); //延迟1ms,防止发送邮箱被填满
return 1; //发送成功,返回1
}
else
{
return 0; //发送失败,返回0
}
//将要发送的数据及其头通过此函数放入FIFO0中
}
③在main.c里声明/定义上述变量:
/* USER CODE BEGIN PV */
extern uint8_t TxData[8]; //声明发送数组存储发送数据
extern uint8_t TxState_Data; //声明数据发送返回状态
extern uint8_t TxState_ID; //声明报文ID发送返回状态
extern uint8_t RxData[8]; //声明接收数组存储接收数据
extern uint8_t RxID_Arr[4]; //声明接收报文ID的数组
extern uint32_t RxID; //声明变量存储接收报文ID
extern FDCAN_TxHeaderTypeDef FDCAN1_TxHeader; //声明发送头结构体
extern FDCAN_RxHeaderTypeDef FDCAN1_RxHeader; //声明接收头结构体
//uint8_t TxData[8]; //定义发送数组存储发送数据
uint8_t TxData[8]={0,1,2,3,4,5,6,7}; //定义发送数组存储发送数据
uint8_t TxState_Data;
uint8_t TxState_ID;
/* USER CODE END PV */
④在main.c里调用发送函数:
/* USER CODE BEGIN WHILE */
while (1)
{
// for(uint8_t n=0;n<sizeof(TxData);n++) //以循环的方式将接收数组赋值给发送数组
// {
// TxData[n]=RxData[n];
// }
TxState_Data=SendData(TxData,sizeof(TxData)); //用CAN将TxData里的数据发送出去
// TxState_ID=SendData(RxID_Arr,sizeof(RxID_Arr)); //用CAN将接收报文ID数组发送出去
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
发送的数据为0x01234567,扩展ID为0x02205050,标准ID为0x022,每隔1s将上述Data和ID发送至CAN上位机,结果如图B-1所示:
图B-1 上位机接收扩展ID报文图
测试标准ID的发送时,需要改一下②里的代码,测试结果如图B-2所示:
图B-2 上位机接收标准ID报文图
由上两图可得,上位机接收的扩展/标准帧的ID和Data与G431芯片发送的一致。
(3)Keil的接收配置如下所示;
⑤在fdcan.c里封装过滤器初始化函数:
void FDCAN1_Filter_Init(void) //封装过滤器初始化函数
{
FDCAN_FilterTypeDef Std_FilterConfig; //定义标准过滤器初始化结构体
Std_FilterConfig.IdType=FDCAN_STANDARD_ID; //选择标准形式的ID
Std_FilterConfig.FilterIndex=0; //选用1号过滤器
Std_FilterConfig.FilterType=FDCAN_FILTER_RANGE; //选择滤波器类型过滤模式
Std_FilterConfig.FilterConfig=FDCAN_FILTER_TO_RXFIFO0; //选择以FIFO0作为接收FIFO
Std_FilterConfig.FilterID1=0x000; //设置可通过的起始ID为0x000
Std_FilterConfig.FilterID2=0x7FF; //设置可通过的结束ID为0x7FF
if(HAL_FDCAN_ConfigFilter(&hfdcan1,&Std_FilterConfig)!=HAL_OK)
{
Error_Handler();
}
FDCAN_FilterTypeDef Ext_FilterConfig; //定义扩展过滤器初始化结构体
Ext_FilterConfig.IdType=FDCAN_EXTENDED_ID; //选择扩展形式的ID
Ext_FilterConfig.FilterIndex=1; //选用1号过滤器
Ext_FilterConfig.FilterType=FDCAN_FILTER_RANGE; //选择滤波器类型为过滤模式
Ext_FilterConfig.FilterConfig=FDCAN_FILTER_TO_RXFIFO0; //选择以FIFO0作为接收FIFO
Ext_FilterConfig.FilterID1=0x00000000; //设置可通过的起始ID为0x00000000
Ext_FilterConfig.FilterID2=0x1FFFFFFF; //设置可通过的结束ID为0x1FFFFFFF
if(HAL_FDCAN_ConfigFilter(&hfdcan1,&Ext_FilterConfig)!=HAL_OK)
{
Error_Handler();
}
if(HAL_FDCAN_ConfigGlobalFilter(&hfdcan1,FDCAN_REJECT,FDCAN_REJECT,FDCAN_FILTER_REMOTE,FDCAN_FILTER_REMOTE)!=HAL_OK)
{
Error_Handler();
}
if(HAL_FDCAN_ActivateNotification(&hfdcan1,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0)!=HAL_OK)
{
Error_Handler();
}
//激活FDCAN1的接收FIFO
HAL_FDCAN_Start(&hfdcan1); //调用CAN通信开始函数
}
/* USER CODE END 1 */
⑥在stm32g4xx_it.c里定义/声明以下结构体和变量:
/* USER CODE BEGIN PV */
uint8_t RxData[8]; //定义接收数组存储接收数据
FDCAN_RxHeaderTypeDef FDCAN1_RxHeader; //定义接收头结构体
/* USER CODE END PV */
⑦在stm32g4xx_it.c里调用fdcan.h函数:
/* USER CODE BEGIN Includes */
#include "fdcan.h"
/* USER CODE END Includes */
⑧在stm32g4xx_it.c的FDCAN1中断区里调用/封装接收函数:
/* USER CODE BEGIN FDCAN1_IT0_IRQn 1 */
HAL_FDCAN_GetRxMessage(&hfdcan1,FDCAN_RX_FIFO0,&FDCAN1_RxHeader,RxData);
/* USER CODE END FDCAN1_IT0_IRQn 1 */
⑨在main.c里更新定义的变量:
/* USER CODE BEGIN PV */
extern uint8_t TxData[8]; //声明发送数组存储发送数据
extern uint8_t TxState_Data; //声明数据发送返回状态
extern FDCAN_TxHeaderTypeDef FDCAN1_TxHeader; //声明发送头结构体
extern FDCAN_RxHeaderTypeDef FDCAN1_RxHeader; //声明接收头结构体
uint8_t TxData[8]; //定义发送数组存储发送数据
//uint8_t TxData[8]={0,1,2,3,4,5,6,7}; //定义发送数组存储接收数据
uint8_t TxState_Data;
/* USER CODE END PV */
⑩在main.c的while(1)里更新发送代码 :
/* USER CODE BEGIN WHILE */
while (1)
{
for(uint8_t n=0;n<sizeof(TxData);n++) //以循环的方式将接收数组赋值给发送数组
{
TxData[n]=RxData[n];
}
TxState_Data=SendData(TxData,sizeof(TxData)); //用CAN将TxData里的数据发送出去
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
⑪由测试上位机发送,G431芯片接收功能,结果由图B-3、图B-4所示:
图B-3 上位机发送扩展ID
图B-4 上位机发送标准ID
由上两图可知,上位机发送成功,并接收到自己发送的数据,说明G431芯片接收成功。
⑫接下来将上位机发送的标准、扩展ID也一并发出来,在main.c里进行如下代码更新:
/* USER CODE BEGIN PV */
extern uint8_t TxData[8]; //声明发送数组存储发送数据
extern uint8_t RxData[8]; //声明接收数组存储接收数据
extern uint8_t RxID_Arr[4]; //声明接收报文ID的数组
extern uint32_t RxID; //声明变量存储接收报文ID
extern uint8_t TxState_Data; //声明数据发送返回状态
extern uint8_t TxState_ID; //声明报文ID发送返回状态
extern FDCAN_TxHeaderTypeDef FDCAN1_TxHeader; //声明发送头结构体
extern FDCAN_RxHeaderTypeDef FDCAN1_RxHeader; //声明接收头结构体
uint8_t TxData[8]; //定义发送数组存储发送数据
//uint8_t TxData[8]={0,1,2,3,4,5,6,7}; //定义发送数组存储接收数据
uint8_t TxState_Data;
uint8_t TxState_ID;
/* USER CODE END PV */
⑬在while(1)里进行如下改造:
/* USER CODE BEGIN WHILE */
while (1)
{
for(uint8_t n=0;n<sizeof(TxData);n++) //以循环的方式将接收数组赋值给发送数组
{
TxData[n]=RxData[n];
}
TxState_Data=SendData(TxData,sizeof(TxData)); //用CAN将TxData里的数据发送出去
TxState_ID=SendData(RxID_Arr,sizeof(RxID_Arr)); //用CAN将接收报文ID数组发送出去
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
⑭在stm32g4xx_it.c里进行如下改造:
/* USER CODE BEGIN PV */
extern uint32_t Rx_ID; //声明接收ID将其传出去
uint8_t RxData[8]; //定义接收数组存储接收数据
uint32_t RxID; //定义变量接收报文ID
uint8_t RxID_Arr[4]; //定义接收报文ID的数组
FDCAN_RxHeaderTypeDef FDCAN1_RxHeader; //定义接收头结构体
/* USER CODE END PV */
⑮在stm32g4xx_it.c的FDCAN1中断区里进行如下改造:
/* USER CODE BEGIN FDCAN1_IT0_IRQn 1 */
HAL_FDCAN_GetRxMessage(&hfdcan1,FDCAN_RX_FIFO0,&FDCAN1_RxHeader,RxData);
RxID=FDCAN1_RxHeader.Identifier;
Rx_ID=RxID;
for(uint8_t j=0;j<sizeof(RxID_Arr);j++)
{
RxID_Arr[j]=(RxID>>(8*(3-j)))&0xFF;
}
//用循环将RxID的四个字节依次取出放到数组里
/* USER CODE END FDCAN1_IT0_IRQn 1 */
⑯在fdcan.c的过滤器里进行如下改造:
FDCAN1_TxHeader.FDFormat=FDCAN_CLASSIC_CAN; //选择CAN模式为经典模式
FDCAN1_TxHeader.IdType=FDCAN_EXTENDED_ID; //配置ID类型为扩展型
// FDCAN1_TxHeader.IdType=FDCAN_STANDARD_ID; //配置ID类型为标准型
// FDCAN1_TxHeader.Identifier=0x02205050; //配置扩展Identifier(标识符、ID)为...
// FDCAN1_TxHeader.Identifier=0x022; //配置标准Identifier(标识符、ID)为...
FDCAN1_TxHeader.Identifier=Rx_ID; //配置Identifier(标识符、ID)为...
⑰由测试上位机发送,G431芯片接收功能,上位机发送数据0x01234567,扩展ID为0x10102020,标准ID为0x101,结果如图B-5所示:
图B-5 标准、扩展完整通信
绿框和红框分别展示了标准ID报文和扩展ID报文的收与发。
三、Keil的Debug模式使用
表3-1 Keil的Debug模式使用
四、小结
本篇文章作为基于STM32G4xx系列芯片实现CAN物理层和数据链路层通信的最后一篇文章,本系列旨在引导读者配置G4系列的CAN底层通信代码以及进行了一些CAN知识点的介绍,如有不当,请各位读者指正。后续可能会更新CAN的应用层—-CANopen和J1939协议相关的知识点。
现在关注一波,以后的路还长着呢!
作者:Star Watcher