天天看点

STM32F4的CAN通信讲解

#include "CAN.h"
#define CAN_Tx_Port  GPIOH
#define CAN_Tx_Pin    GPIO_Pin_13
#define CAN_Rx_Port  GPIOI
#define CAN_Rx_Pin    GPIO_Pin_9
CanTxMsg CAN_Tx_Msg;
CanRxMsg CAN_Rx_Msg;
u8 msg_box;
u8 std;
/*
CAN 总线GPIO配置

*/
void CAN_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_init;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH|RCC_AHB1Periph_GPIOI,ENABLE);
	GPIO_PinAFConfig(CAN_Tx_Port,GPIO_PinSource13,GPIO_AF_CAN1);
	GPIO_PinAFConfig(CAN_Rx_Port,GPIO_PinSource9,GPIO_AF_CAN1);
	GPIO_init.GPIO_Mode = GPIO_Mode_AF;
	GPIO_init.GPIO_OType  = GPIO_OType_PP;
	GPIO_init.GPIO_PuPd  = GPIO_PuPd_UP;
	GPIO_init.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_init.GPIO_Pin = CAN_Tx_Pin;
	GPIO_Init(CAN_Tx_Port,&GPIO_init);
	GPIO_init.GPIO_Pin = CAN_Rx_Pin;
	GPIO_Init(CAN_Rx_Port,&GPIO_init);

}
void CAN_Config(void)
{
	CAN_InitTypeDef CAN_init;
	CAN_FilterInitTypeDef CAN_Filter_init;
	CAN_DeInit(CAN1);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
	//工作模式的设置
	CAN_init.CAN_Mode  = CAN_Mode_Normal;
       //工作模式的配置:可配置为正常模式,静默模式,回环模式,静默回环模式;
	//发送FIFO使能
	CAN_init.CAN_TXFP  = DISABLE;
	//自动重发功能使能
	CAN_init.CAN_NART = DISABLE;//不使能
	//FIFO锁定功能
	/*
		FIFO锁定功能主要用于管理接收邮箱
		如果不使能FIFO锁定功能,当FIFO使能时,则在FIFO邮箱已满之后,后续的信息将会覆盖最后接收的信息
		如果使能FIFO锁定功能,则在FIFO邮箱已满之后,将丢弃最新的消息,保留最原始的三则消息
	*/
	CAN_init.CAN_RFLM = DISABLE;
	//总线自动恢复功能
	/*
		当 TEC 大于 255 时,达到总线关闭状态,该状态由 CAN_ESR 寄存器的 BOFF 位指示。在总线关闭状态下, bxCAN 不能再发送和接收消息。
        bxCAN 可以自动或者应软件请求而从总线关闭状态中恢复(恢复错误主动状态),具体取决于 CAN_MCR 寄存器的 ABOM 位。但在两种情况下, bxCAN 都必须至少等待 CAN 标准中指定的恢复序列完成(在 CANRX 上监测到 128 次 11 个连续隐性位)。
		如果 ABOM 位置 1, bxCAN 将在进入总线关闭状态后自动启动恢复序列。
		如果 ABOM 位清零,则软件必须请求 bxCAN 先进入再退出初始化模式,从而启动恢复序列。
		注意: 在初始化模式下, bxCAN 不会监视 CANRX 信号,因此无法完成恢复序列。 要进行恢复,bxCAN 必须处于正常模式。
	*/
	CAN_init.CAN_ABOM  = DISABLE;
	//---------------
	CAN_init.CAN_AWUM = DISABLE;
	CAN_init.CAN_TTCM = DISABLE;
	//--------------------------
	//关于CAN总线比特率计算
	/*
		NominalBitTime = 1*Tq +tBS1 +  tBS2
		tBS1 = tq x (TS1[3:0] + 1);
		tBS2 = tq x (TS2[2:0] + 1),
		Tq = (BRP[9:0] + 1) x TPCLK;
		TPCLK = APB 时钟的时间周期;
		BRP[9:0], TS1[3:0] 和 TS2[2:0] 在 CAN_BTR 寄存器中定义;
	//-------------------------------------------------------------
			CAN 波特率 = RCC_APB1Periph_CAN1 / Prescaler / (SJW + BS1 + BS2);
		
		SJW = synchronisation_jump_width 
		BS = bit_segment
		本例中,设置CAN波特率为500Kbps		
		CAN 波特率 = 420000000 / 2 / (1 + 12 + 8) / = 1 MBps	
	*/
	CAN_init.CAN_BS1 = CAN_BS1_12tq;
	CAN_init.CAN_BS2 = CAN_BS2_8tq;
	CAN_init.CAN_SJW = CAN_SJW_1tq;
	CAN_init.CAN_Prescaler = 4;
	CAN_Init(CAN1,&CAN_init);
	//------------------------------------
	CAN_Filter_init.CAN_FilterActivation = ENABLE;//过滤器使能
//选择使用哪个FIFO,可为CAN_FilterFIFO0,CAN_FilterFIFO1;
	CAN_Filter_init.CAN_FilterFIFOAssignment = CAN_FilterFIFO0;
          
	CAN_Filter_init.CAN_FilterMode = CAN_FilterMode_IdMask;//掩码模式,此处可配置为掩码模式和列表模式
	CAN_Filter_init.CAN_FilterScale = CAN_FilterScale_16bit;//
	CAN_Filter_init.CAN_FilterNumber = 0;
	CAN_Filter_init.CAN_FilterIdHigh = 0x0000;
	CAN_Filter_init.CAN_FilterMaskIdHigh = 0x0000;
	CAN_Filter_init.CAN_FilterIdLow = 0x0000;
	CAN_Filter_init.CAN_FilterMaskIdLow = 0x0000;
	CAN_FilterInit(&CAN_Filter_init);
}
void CAN_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_init;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	NVIC_init.NVIC_IRQChannel = CAN1_RX0_IRQn;
	NVIC_init.NVIC_IRQChannelCmd  =ENABLE;
	NVIC_init.NVIC_IRQChannelPreemptionPriority  =0x00;
	NVIC_init.NVIC_IRQChannelSubPriority = 0x00;
	NVIC_Init(&NVIC_init);
	CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
}
u8 CAN_send_massage(u8 *data,u8 leng,u32 massage_id)
{
	
	u8 tx_cnt;
	u32 tx_time_out_cnt = 0;
	/*
		当数据帧的ID大于0x7FF时就认为是拓展帧,否则都为标准帧
	*/
	if(massage_id > 0x7FF)
	{
			CAN_Tx_Msg.IDE = CAN_ID_EXT  ;//发送帧的类型:CAN_Id_Standard   标准帧; CAN_Id_Extended  拓展帧
	}
	else
	{
			CAN_Tx_Msg.IDE = CAN_ID_STD  ;//发送帧的类型:CAN_Id_Standard   标准帧; CAN_Id_Extended  拓展帧
	}
	CAN_Tx_Msg.DLC = leng;//发送数据长度
	
	CAN_Tx_Msg.RTR = CAN_RTR_DATA;//发送帧的类型:CAN_RTR_DATA  发送数据帧;CAN_RTR_REMOTE 远程帧,远程帧中没有数据;
	CAN_Tx_Msg.StdId = massage_id;//标准帧的ID,11位
	CAN_Tx_Msg.ExtId = massage_id;//拓展帧的ID,29位
	for(tx_cnt = 0;tx_cnt < leng;tx_cnt++)
	{
		CAN_Tx_Msg.Data[tx_cnt] = data[tx_cnt];
	}
	do
	{
		tx_time_out_cnt++;
		msg_box = CAN_Transmit(CAN1,&CAN_Tx_Msg);
	}
	while(((CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP0) !=RESET) || \
              (CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP1) !=RESET) || \
              (CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP2) !=RESET))&&(tx_time_out_cnt < 10000));
	

	tx_time_out_cnt++;
	if(tx_time_out_cnt > 10000)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}
void CAN1_RX0_IRQHandler(void)
{
	if(CAN_GetITStatus(CAN1,CAN_IT_FMP0) == SET)
	{
		CAN_Receive(CAN1,CAN_FIFO0,&CAN_Rx_Msg);
		CAN_send_massage(&CAN_Rx_Msg.Data[0],CAN_Rx_Msg.DLC,CAN_Rx_Msg.ExtId);
	//	CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);
	}
}
           

以上是关于CAN的基本配置,主要是波特率相关配置

2016年7月17日

今天在对STM32F4的CAN总线进行学习,更加深刻的理解了SMT32的CAN总线模块功能。具体描述如下所示:

主要是关于CAN总线滤波器的设置的问题,STM32的CAN总线接收滤波器可以设置为掩码模式和标识符列表模式,两种模式都容易理解,关键是在参数设置时需要注意,在实验过程中采用的16位标识符列表模式那么一个滤波器可以设置4个标识符,27个滤波器就可以设置27*4=108个标识符,足够今后的应用;

STM32F4的CAN通信讲解

注意上图所对应的标识符和参数设置的问题,

假如我现在只需要接收ID为0x0321的标准数据帧,那么对应上图参数设置就应该为

CAN_Filter_init.CAN_FilterIdHigh      = 0x321<<5;为何要将数据右移5位??

解释如下所述:在上面的截图中可以看出这16位数据中不仅仅包括数据ID还有远程帧和数据帧选择位(RTR)及其

标准帧和扩展帧选择位(IDE),今天 今天白天的测试一直不通过问题就在这儿,当时仅仅将该设置参数理解为数据ID的,导致一直无法成功。

 最后的测试程序如下所示:(程序是16位列表模式)

#include "CAN.h"
#define CAN_Tx_Port  GPIOH
#define CAN_Tx_Pin    GPIO_Pin_13
#define CAN_Rx_Port  GPIOI
#define CAN_Rx_Pin    GPIO_Pin_9
CanTxMsg CAN_Tx_Msg;
CanRxMsg CAN_Rx_Msg;
u8 msg_box;
u8 std;
void CAN_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_init;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH|RCC_AHB1Periph_GPIOI,ENABLE);
	GPIO_PinAFConfig(CAN_Tx_Port,GPIO_PinSource13,GPIO_AF_CAN1);
	GPIO_PinAFConfig(CAN_Rx_Port,GPIO_PinSource9,GPIO_AF_CAN1);
	GPIO_init.GPIO_Mode = GPIO_Mode_AF;
	GPIO_init.GPIO_OType  = GPIO_OType_PP;
	GPIO_init.GPIO_PuPd  = GPIO_PuPd_UP;
	GPIO_init.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_init.GPIO_Pin = CAN_Tx_Pin;
	GPIO_Init(CAN_Tx_Port,&GPIO_init);
	GPIO_init.GPIO_Pin = CAN_Rx_Pin;
	GPIO_Init(CAN_Rx_Port,&GPIO_init);

}
void CAN_Config(void)
{
	CAN_InitTypeDef CAN_init;
	CAN_FilterInitTypeDef CAN_Filter_init;
	CAN_DeInit(CAN1);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
	//工作模式的设置
	CAN_init.CAN_Mode  = CAN_Mode_Normal;//工作模式的配置:可配置为正常模式,静默模式,回环模式,静默回环模式;
	//发送FIFO使能
	CAN_init.CAN_TXFP  = DISABLE;
	//自动重发功能使能
	CAN_init.CAN_NART = DISABLE;//不使能
	//FIFO锁定功能
	/*
		FIFO锁定功能主要用于管理接收邮箱
		如果不使能FIFO锁定功能,当FIFO使能时,则在FIFO邮箱已满之后,后续的信息将会覆盖最后接收的信息
		如果使能FIFO锁定功能,则在FIFO邮箱已满之后,将丢弃最新的消息,保留最原始的三则消息
	*/
	CAN_init.CAN_RFLM = DISABLE;
	//总线自动恢复功能
	/*
		当 TEC 大于 255 时,达到总线关闭状态,该状态由 CAN_ESR 寄存器的 BOFF 位指示。在总线关闭状态下, bxCAN 不能再发送和接收消息。
        bxCAN 可以自动或者应软件请求而从总线关闭状态中恢复(恢复错误主动状态),具体取决于 CAN_MCR 寄存器的 ABOM 位。但在两种情况下, bxCAN 都必须至少等待 CAN 标准中指定的恢复序列完成(在 CANRX 上监测到 128 次 11 个连续隐性位)。
		如果 ABOM 位置 1, bxCAN 将在进入总线关闭状态后自动启动恢复序列。
		如果 ABOM 位清零,则软件必须请求 bxCAN 先进入再退出初始化模式,从而启动恢复序列。
		注意: 在初始化模式下, bxCAN 不会监视 CANRX 信号,因此无法完成恢复序列。 要进行恢复,bxCAN 必须处于正常模式。
	*/
	CAN_init.CAN_ABOM  = DISABLE;
	//---------------
	CAN_init.CAN_AWUM = DISABLE;
	CAN_init.CAN_TTCM = DISABLE;
	//--------------------------
	//关于CAN总线比特率计算
	/*
		NominalBitTime = 1*Tq +tBS1 +  tBS2
		tBS1 = tq x (TS1[3:0] + 1);
		tBS2 = tq x (TS2[2:0] + 1),
		Tq = (BRP[9:0] + 1) x TPCLK;
		TPCLK = APB 时钟的时间周期;
		BRP[9:0], TS1[3:0] 和 TS2[2:0] 在 CAN_BTR 寄存器中定义;
	//-------------------------------------------------------------
			CAN 波特率 = RCC_APB1Periph_CAN1 / Prescaler / (SJW + BS1 + BS2);
		
		SJW = synchronisation_jump_width 
		BS = bit_segment
		本例中,设置CAN波特率为500Kbps		
		CAN 波特率 = 420000000 / 4/ (1 + 12 + 8) / = 500kBps	
	*/
	CAN_init.CAN_BS1 = CAN_BS1_12tq;
	CAN_init.CAN_BS2 = CAN_BS2_8tq;
	CAN_init.CAN_SJW = CAN_SJW_1tq;
	CAN_init.CAN_Prescaler = 4;
	CAN_Init(CAN1,&CAN_init);
	//------------------------------------
	CAN_Filter_init.CAN_FilterActivation = ENABLE;//过滤器使能
	CAN_Filter_init.CAN_FilterFIFOAssignment = CAN_FilterFIFO0;//选择使用哪个FIFO,可为CAN_FilterFIFO0,CAN_FilterFIFO1;
	CAN_Filter_init.CAN_FilterMode = CAN_FilterMode_IdList;//标识符列表模式
	CAN_Filter_init.CAN_FilterScale = CAN_FilterScale_16bit;//
	CAN_Filter_init.CAN_FilterNumber = 0;
        /*
            以下配置CAN总线可以接收数据帧,标准帧同时帧ID仅仅是0x321,0x322,0x7AE及其0x000才能接收。

*/
	CAN_Filter_init.CAN_FilterIdHigh      = 0x321<<5;
	CAN_Filter_init.CAN_FilterIdLow       = 0x0000;
	CAN_Filter_init.CAN_FilterMaskIdHigh  = 0x0322<<5;
	CAN_Filter_init.CAN_FilterMaskIdLow   = 0x07AE<<5;
	CAN_FilterInit(&CAN_Filter_init);
}
void CAN_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_init;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	NVIC_init.NVIC_IRQChannel = CAN1_RX0_IRQn;
	NVIC_init.NVIC_IRQChannelCmd  =ENABLE;
	NVIC_init.NVIC_IRQChannelPreemptionPriority  =0x00;
	NVIC_init.NVIC_IRQChannelSubPriority = 0x00;
	NVIC_Init(&NVIC_init);
	CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
}
u8 CAN_send_massage(u8 *data,u8 leng,u32 massage_id)
{
	
	u8 tx_cnt;
	u32 tx_time_out_cnt = 0;
	/*
		当数据帧的ID大于0x7FF时就认为是拓展帧,否则都为标准帧
	*/
	if(massage_id > 0x7FF)
	{
			CAN_Tx_Msg.IDE = CAN_ID_EXT  ;//发送帧的类型:CAN_Id_Standard   标准帧; CAN_Id_Extended  拓展帧
	}
	else
	{
			CAN_Tx_Msg.IDE = CAN_ID_STD  ;//发送帧的类型:CAN_Id_Standard   标准帧; CAN_Id_Extended  拓展帧
	}
	CAN_Tx_Msg.DLC = leng;//发送数据长度
	
	CAN_Tx_Msg.RTR = CAN_RTR_DATA;//发送帧的类型:CAN_RTR_DATA  发送数据帧;CAN_RTR_REMOTE 远程帧,远程帧中没有数据;
	CAN_Tx_Msg.StdId = massage_id;//标准帧的ID,11位
	CAN_Tx_Msg.ExtId = massage_id;//拓展帧的ID,29位
	for(tx_cnt = 0;tx_cnt < leng;tx_cnt++)
	{
		CAN_Tx_Msg.Data[tx_cnt] = data[tx_cnt];
	}
	do
	{
		tx_time_out_cnt++;
		msg_box = CAN_Transmit(CAN1,&CAN_Tx_Msg);
	}
	while(((CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP0) !=RESET) || \
              (CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP1) !=RESET) || \
              (CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP2) !=RESET))&&(tx_time_out_cnt < 10000));
	

	tx_time_out_cnt++;
	if(tx_time_out_cnt > 10000)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}
void CAN1_RX0_IRQHandler(void)
{
	if(CAN_GetITStatus(CAN1,CAN_IT_FMP0) == SET)
	{
		CAN_Receive(CAN1,CAN_FIFO0,&CAN_Rx_Msg);
		CAN_send_massage(&CAN_Rx_Msg.Data[0],CAN_Rx_Msg.DLC,CAN_Rx_Msg.StdId);
	//	CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);
	}
}
           

这几天一直困惑在32位标识符列表模式的配置,昨天晚上通过寻找相关例程问题解决详细讲程序说明:

STM32F4的CAN通信讲解
#include "CAN.h"
#define CAN_Tx_Port  GPIOH
#define CAN_Tx_Pin    GPIO_Pin_13
#define CAN_Rx_Port  GPIOI
#define CAN_Rx_Pin    GPIO_Pin_9
CanTxMsg CAN_Tx_Msg;
CanRxMsg CAN_Rx_Msg;
u8 msg_box;
u8 std;
void CAN_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_init;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH|RCC_AHB1Periph_GPIOI,ENABLE);
	GPIO_PinAFConfig(CAN_Tx_Port,GPIO_PinSource13,GPIO_AF_CAN1);
	GPIO_PinAFConfig(CAN_Rx_Port,GPIO_PinSource9,GPIO_AF_CAN1);
	GPIO_init.GPIO_Mode = GPIO_Mode_AF;
	GPIO_init.GPIO_OType  = GPIO_OType_PP;
	GPIO_init.GPIO_PuPd  = GPIO_PuPd_UP;
	GPIO_init.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_init.GPIO_Pin = CAN_Tx_Pin;
	GPIO_Init(CAN_Tx_Port,&GPIO_init);
	GPIO_init.GPIO_Pin = CAN_Rx_Pin;
	GPIO_Init(CAN_Rx_Port,&GPIO_init);

}
void CAN_Config(void)
{
	CAN_InitTypeDef CAN_init;
	u32 temp;
	CAN_FilterInitTypeDef CAN_Filter_init;
	CAN_DeInit(CAN1);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
	//工作模式的设置
	CAN_init.CAN_Mode  = CAN_Mode_Normal;//工作模式的配置:可配置为正常模式,静默模式,回环模式,静默回环模式;
	//发送FIFO使能
	CAN_init.CAN_TXFP  = DISABLE;
	//自动重发功能使能
	CAN_init.CAN_NART = DISABLE;//不使能
	//FIFO锁定功能
	/*
		FIFO锁定功能主要用于管理接收邮箱
		如果不使能FIFO锁定功能,当FIFO使能时,则在FIFO邮箱已满之后,后续的信息将会覆盖最后接收的信息
		如果使能FIFO锁定功能,则在FIFO邮箱已满之后,将丢弃最新的消息,保留最原始的三则消息
	*/
	CAN_init.CAN_RFLM = DISABLE;
	//总线自动恢复功能
	/*
		当 TEC 大于 255 时,达到总线关闭状态,该状态由 CAN_ESR 寄存器的 BOFF 位指示。在总线关闭状态下, bxCAN 不能再发送和接收消息。
        bxCAN 可以自动或者应软件请求而从总线关闭状态中恢复(恢复错误主动状态),具体取决于 CAN_MCR 寄存器的 ABOM 位。但在两种情况下, bxCAN 都必须至少等待 CAN 标准中指定的恢复序列完成(在 CANRX 上监测到 128 次 11 个连续隐性位)。
		如果 ABOM 位置 1, bxCAN 将在进入总线关闭状态后自动启动恢复序列。
		如果 ABOM 位清零,则软件必须请求 bxCAN 先进入再退出初始化模式,从而启动恢复序列。
		注意: 在初始化模式下, bxCAN 不会监视 CANRX 信号,因此无法完成恢复序列。 要进行恢复,bxCAN 必须处于正常模式。
	*/
	CAN_init.CAN_ABOM  = DISABLE;
	//---------------
	CAN_init.CAN_AWUM = DISABLE;
	CAN_init.CAN_TTCM = DISABLE;
	//--------------------------
	//关于CAN总线比特率计算
	/*
		NominalBitTime = 1*Tq +tBS1 +  tBS2
		tBS1 = tq x (TS1[3:0] + 1);
		tBS2 = tq x (TS2[2:0] + 1),
		Tq = (BRP[9:0] + 1) x TPCLK;
		TPCLK = APB 时钟的时间周期;
		BRP[9:0], TS1[3:0] 和 TS2[2:0] 在 CAN_BTR 寄存器中定义;
	//-------------------------------------------------------------
			CAN 波特率 = RCC_APB1Periph_CAN1 / Prescaler / (SJW + BS1 + BS2);
		
		SJW = synchronisation_jump_width 
		BS = bit_segment
		本例中,设置CAN波特率为500Kbps		
		CAN 波特率 = 420000000 / 2 / (1 + 12 + 8) / = 1 MBps	
	*/
	CAN_init.CAN_BS1 = CAN_BS1_12tq;
	CAN_init.CAN_BS2 = CAN_BS2_8tq;
	CAN_init.CAN_SJW = CAN_SJW_1tq;
	CAN_init.CAN_Prescaler = 4;
	CAN_Init(CAN1,&CAN_init);
	//------------------------------------
	CAN_Filter_init.CAN_FilterActivation = ENABLE;//过滤器使能
	CAN_Filter_init.CAN_FilterFIFOAssignment = CAN_FilterFIFO0; 
    //选择使用哪个FIFO,可为CAN_FilterFIFO0,CAN_FilterFIFO1;
	CAN_Filter_init.CAN_FilterNumber = 2;
	CAN_Filter_init.CAN_FilterMode = CAN_FilterMode_IdList;//标识符列表模式
	CAN_Filter_init.CAN_FilterScale = CAN_FilterScale_32bit;//
/*
以下是关于标识符列表模式的配置,需要将扩展帧的标识符的高16位赋值给
CAN_Filter_init.CAN_FilterIdHigh;
低13位赋值给CAN_Filter_init.CAN_FilterMaskIdLow;具体的程序如下所示
*/
	CAN_Filter_init.CAN_FilterIdHigh      = 0x07909ADC>>13;
	CAN_Filter_init.CAN_FilterIdLow       = ((0x07909ADC<<3)&0xFFFF)|0x04;
		CAN_Filter_init.CAN_FilterMaskIdHigh  = (0x07909AD0>>13)&0xFFFF;
	CAN_Filter_init.CAN_FilterMaskIdLow   = ((0x07909AD0<<3)&0xFFFF)|0x4;
	
	CAN_FilterInit(&CAN_Filter_init);
}
void CAN_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_init;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	NVIC_init.NVIC_IRQChannel = CAN1_RX0_IRQn;
	NVIC_init.NVIC_IRQChannelCmd  =ENABLE;
	NVIC_init.NVIC_IRQChannelPreemptionPriority  =0x00;
	NVIC_init.NVIC_IRQChannelSubPriority = 0x00;
	NVIC_Init(&NVIC_init);
	CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
}
u8 CAN_send_massage(u8 *data,u8 leng,u32 massage_id)
{
	
	u8 tx_cnt;
	u32 tx_time_out_cnt = 0;
	/*
		当数据帧的ID大于0x7FF时就认为是拓展帧,否则都为标准帧
	*/
	if(massage_id > 0x7FF)
	{
			CAN_Tx_Msg.IDE = CAN_ID_EXT  ;//发送帧的类型:CAN_Id_Standard   标准帧; CAN_Id_Extended  拓展帧
	}
	else
	{
			CAN_Tx_Msg.IDE = CAN_ID_STD  ;//发送帧的类型:CAN_Id_Standard   标准帧; CAN_Id_Extended  拓展帧
	}
	CAN_Tx_Msg.DLC = leng;//发送数据长度
	
	CAN_Tx_Msg.RTR = CAN_RTR_DATA;//发送帧的类型:CAN_RTR_DATA  发送数据帧;CAN_RTR_REMOTE 远程帧,远程帧中没有数据;
	CAN_Tx_Msg.StdId = massage_id;//标准帧的ID,11位
	CAN_Tx_Msg.ExtId = massage_id;//拓展帧的ID,29位
	for(tx_cnt = 0;tx_cnt < leng;tx_cnt++)
	{
		CAN_Tx_Msg.Data[tx_cnt] = data[tx_cnt];
	}
	do
	{
		tx_time_out_cnt++;
		msg_box = CAN_Transmit(CAN1,&CAN_Tx_Msg);
	}
	while(((CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP0) !=RESET) || \
              (CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP1) !=RESET) || \
              (CAN_GetFlagStatus(CAN1, CAN_FLAG_RQCP2) !=RESET))&&(tx_time_out_cnt < 10000));
	tx_time_out_cnt++;
	if(tx_time_out_cnt > 10000)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}
void CAN1_RX0_IRQHandler(void)
{
	if(CAN_GetITStatus(CAN1,CAN_IT_FMP0) == SET)
	{
		CAN_Receive(CAN1,CAN_FIFO0,&CAN_Rx_Msg);
		if(CAN_Rx_Msg.IDE == CAN_ID_STD)
		{
		CAN_send_massage(&CAN_Rx_Msg.Data[0],CAN_Rx_Msg.DLC,CAN_Rx_Msg.StdId);
		}
		else if(CAN_Rx_Msg.IDE == CAN_ID_EXT)
		{
			CAN_send_massage(&CAN_Rx_Msg.Data[0],CAN_Rx_Msg.DLC,CAN_Rx_Msg.ExtId);
			
		}
	//	CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);
	}
}
           

CAN_FilterInitStructure.CAN_FilterIdLow=(can_addr<<(CMD_WIDTH+3))|0x04; 

0x04是设置ID为扩展ID,3表示寄存器中的最低有3bit不是过滤器的ID,命令放在ID的低bit位,一共CMD_WIDTH个bit,所以这里一共要左移CMD_WIDTH+3个bit

注意,一个寄存器是16bit,CAN_FilterIdLow中有效地址位数为16-3-CMD_WIDTH,所以有了第一行的代码:

CAN_FilterInitStructure.CAN_FilterIdHigh=can_addr>>(16-CMD_WIDTH-3); 

因为can_addr的低16-3-CMD_WIDTH位已经放到CAN_FilterIdLow中,所以CAN_FilterIdHigh位就放can_addr>>(16-CMD_WIDTH-3)

0xF8FA7FFF

继续阅读