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协议相关的知识点。
现在关注一波,以后的路还长着呢!

  • 34
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32G431是一款32位ARM Cortex-M4微控制器,拥有高性能和丰富的外设。 在STM32G431中,CANFD是指支持CAN Flexible Data Rate(灵活数据率)的CAN控制器。CANFD相较于传统的CAN控制器,可以提供更高的数据传输速率和更大的数据负载容量。 STM32G431的CANFD控制器与传统的CAN控制器相比,有以下特点: 1. 数据传输速率更高:传统的CAN控制器通常支持最高1Mbps的数据传输速率,而CANFD控制器可以支持最高8Mbps的数据传输速率,使数据的传输更加快速高效。 2. 更大的数据负载容量:传统的CAN控制器的数据帧长度限制为8字节,而CANFD控制器可以支持长度为64字节的数据帧,使得更多的数据可以在一帧内传输,提高了总线的效率。 3. 兼容性良好:CANFD控制器与传统的CAN控制器兼容,可以支持标准CAN和CANFD协议的同时工作,使得升级过程更加方便。 4. 灵活的数据速率:CANFD控制器可以根据需要调整数据传输速率,可以根据不同的应用需求选择合适的速率,增加了系统的灵活性。 总之,STM32G431的CANFD功能提供了更高的数据传输速率和更大的数据负载容量,使得物联网、工业自动化以及汽车电子等领域的应用能够更好地满足高速数据传输和大容量数据处理的需求。 ### 回答2: STM32G431系列是意法半导体公司推出的一款高性能嵌入式微控制器产品系列,它集成了CAN-FD(Flexible Data Rate)的功能。 CAN-FD是一种扩展的控制器局域网络通信协议,允许更高的数据传输速率和更大的数据负载。相比传统的CAN协议,CAN-FD支持更高的比特率,从而提供了更快的数据传输速率,同时还支持更大的数据负载,能够传输更多的数据。这使得STM32G431在应用场景中能够处理更多的数据,并提供更高的通信效率。 STM32G431 in terms of the CAN-FD功能是指该系列的微控制器具备了CAN-FD的相关硬件和软件特性,可以直接支持CAN-FD的通信。这意味着开发人员可以通过STM32G431来构建支持CAN-FD的系统,从而实现高速、大容量的数据通信。 总结来说,通过将CAN-FD集成到STM32G431系列中,意法半导体提供了一种高性能的解决方案,用于构建支持更快速、更大容量的数据传输的嵌入式系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值