STM32 CAN 通信(一)

STM32 CAN 通信(一)

STM32 CAN 配置

STM32 CAN 控制器需要配置的参数比较多,本文根据 SAE J1939 协议数据单元 对 STM32 CAN 进行配置。

CAN 的 GPIO 配置

/**********************************************************************************
 * 函数名:CAN_GPIO_Config
 * 描述  :CAN 的 GPIO 配置,PA11 上拉输入,PA12 推挽输出
 * 输入  :无
 * 输出  :无
 * 返回  :无
 * 调用  :内部调用
 * 说明  :
**********************************************************************************/
static void CAN_GPIO_Config(void)
{
	GPIO_InitTypeDef	GPIO_InitStructure;
	//外设时钟设置 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
	//RX	PA11
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;			 
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	//TX	PA12
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;			 
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}

CAN 的 NVIC 配置

/**********************************************************************************
 * 函数名:CAN_NVIC_Config
 * 描述  :CAN 的 NVIC 配置
 * 输入  :无
 * 输出  :无
 * 返回  :无
 * 调用  :内部调用
 * 说明  :CAN 的中断由发送中断接收FIFO中断和错误中断构成。
						1、发送中断由三个发送邮箱任意一个为空构成。
						2、接收中断分为 FIFO0 和 FIFO1 的中断,接收 FIFO 收到新的报文
						或报文溢出触发。
**********************************************************************************/
static void CAN_NVIC_Config(void)
{
	NVIC_InitTypeDef	NVIC_InitStructure;

	NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;		//抢占优先级2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;				//响应优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;					//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);
	
	CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);		//使能 CAN 接收中断
}

CAN 的 Mode 配置

/**********************************************************************************
 * 函数名:CAN_Mode_Config
 * 描述  :CAN 的 Mode 配置
 * 输入  :无
 * 输出  :无
 * 返回  :无
 * 调用  :内部调用
 * 说明  :bxCAN有3个主要的工作模式:初始化、正常和睡眠模式。
**********************************************************************************/
static void CAN_Mode_Config(void)
{
	CAN_InitTypeDef	CAN_InitStructure;

	CAN_DeInit(CAN1);
	CAN_StructInit(&CAN_InitStructure);
 
	CAN_InitStructure.CAN_TTCM = DISABLE; 			//关闭时间触发通信模式使能
	CAN_InitStructure.CAN_ABOM = ENABLE; 			//自动离线管理
	CAN_InitStructure.CAN_AWUM = ENABLE; 			//自动唤醒模式
	CAN_InitStructure.CAN_NART = DISABLE; 			//禁止报文自动重传 DISABLE = 自动重传
	CAN_InitStructure.CAN_RFLM = DISABLE; 			//接收 FIFO 锁定模式 DISABLE = 溢出时新报文会覆盖原有报文
	CAN_InitStructure.CAN_TXFP = DISABLE; 			//发送 FIFO 优先级 DISABLE = 优先级取决于报文标识符
	CAN_InitStructure.CAN_Mode = CAN_Mode_Normal; 	//正常工作模式
	CAN_InitStructure.CAN_SJW = CAN_SJW_2tq;		//重新同步跳跃宽度为2个时间单位
	CAN_InitStructure.CAN_BS1 = CAN_BS1_6tq; 		//时间段1 占用6个时间单元
	CAN_InitStructure.CAN_BS2 = CAN_BS2_3tq; 		//时间段2 占用3个时间单元
	CAN_InitStructure.CAN_Prescaler = 30; 			//波特率分频器 定义了时间单元的长度 36/(1+6+3)/30 = 0.12Mbps
	CAN_Init(CAN1,&CAN_InitStructure);
}

CAN波特率配置
波特率 = APB1Clock/(1+CAN_BS1+CAN_BS2)/CAN_Prescaler

(PS:CAN_SJW 表示重新同步跳跃宽度,不参与波特率的计算,其值可以编程为1到4个时间单元,表示该总线对波特率范围的容差度。公式中1表示同步段固定为一个单位时间。)

尽可能地把采样点设置为 CAN 组织 CiA 推荐的值:

CiA波特率
75%>800K
80%>500K
87.5%<=500K

CAN 波特率与传输距离
标准波特率可以参考如下对应关系:

速率(Kbps)1000500250125100502010
距离(m)40130270530620130033006700

其它波特率也可以使shu用该公式:50/波特率(KBbps)10000.8 = 距离(m)

CAN 的 Filter 配置

/**********************************************************************************
 * 函数名:CAN_Filter_Config
 * 描述  :CAN 的 Filter 配置
 * 输入  :无
 * 输出  :无
 * 返回  :无
 * 调用  :内部调用
 * 说明  :(过滤器)配置,id 中目标地址为本机地址,接收时标识符完全相同才保存数据
			1: 在各种过滤器模式下,CAN ID与寄存器相应位置一定要匹配;
			2:在屏蔽方式下,屏蔽码寄存器某位为1表示接收到的CAN ID对应的位必须对验
			证码寄存器对应的位相同。
**********************************************************************************/
static void CAN_Filter_Config(void)
{
	CAN_FilterInitTypeDef CAN_FilterInitStructure; 
	//过滤器组0,只接受广播信息(PF = 240 - 255)
	CAN_FilterInitStructure.CAN_FilterNumber = 0; 							
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; 		//工作在标识符屏蔽位模式
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; 		//过滤器位宽为单个32位
	CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)0xf000<<3)&0xffff0000)>>16;	//要过滤的ID高位
	CAN_FilterInitStructure.CAN_FilterIdLow = ((u32)0xf000<<3)&0xffff; 				//要过滤的ID低位
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0007; 				//过滤器高16位 (MaskId << 3) >>16  左移3位--寄存器低3位为 保留位、RTR、IDE
	CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x1f00; 				//过滤器低16位
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FilterFIFO0; //过滤器被关联到FIFO0
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; 				//使能过滤器
	CAN_FilterInit(&CAN_FilterInitStructure);
	//过滤器组1,只接受全局地址(CAN_GLOBAL_ADDRESS)
	CAN_FilterInitStructure.CAN_FilterNumber = 1; 							
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; 		//工作在标识符屏蔽位模式
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; 		//过滤器位宽为单个32位
	CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)CAN_Address<<11)&0xffff0000)>>16;	//要过滤的ID高位
	CAN_FilterInitStructure.CAN_FilterIdLow = ((u32)CAN_Address<<11)&0xffff; 	//要过滤的ID低位	CAN_Address
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0007; 					//过滤器高16位
	CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x1f00; 					//过滤器低16位
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FilterFIFO0; 	//过滤器被关联到FIFO0,即通过过滤器的消息存储到FIFO0
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; 					//使能过滤器
	CAN_FilterInit(&CAN_FilterInitStructure);
}
/**********************************************************************************
 * 函数名:Port_SetAddressFilter
 * 描述  :CAN 的 Filter 配置
 * 输入  :Address 要过滤的地址
 * 输出  :无
 * 返回  :无
 * 调用  :内部调用
 * 说明  :随着程序的运行,将改变滤波器2,来适应程序逻辑。
**********************************************************************************/
void Port_SetAddressFilter(u8 Address)
{
	CAN_FilterInitTypeDef CAN_FilterInitStructure;
		 
	//过滤器组2,只接受全局地址(CAN_GLOBAL_ADDRESS)
	CAN_FilterInitStructure.CAN_FilterNumber = 2; 							
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; 		//工作在标识符屏蔽位模式
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; 		//过滤器位宽为单个32位
	CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)Address<<11)&0xffff0000)>>16;		//要过滤的ID高位
	CAN_FilterInitStructure.CAN_FilterIdLow = ((u32)Address<<11)&0xffff;	//要过滤的ID低位
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0007; 					//过滤器高16位
	CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x1f00; 					//过滤器低16位
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FilterFIFO0; 	//过滤器被关联到FIFO0
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; 					//使能过滤器
	CAN_FilterInit(&CAN_FilterInitStructure);
}

SAE J1939 只用扩展帧格式全面定义了标准化通信。

SAE J1939 协议数据单元结构

PDU优先权保留位数据页PDU格式PDU特定域源地址数据域
PRDPPFPSSADATA
3118880-64

定义:P 是优先级,R 是保留位,DP 是数据页,PF 是 PDU 格式,PS 是特定 PDU,SA 是源地址
PS : 目标地址(即接收机地址)
SA : 源地址(即发送机地址)

STM32 CAN ID过滤器
根据 SAE J1939 协议数据单元结构采用位宽为32位的屏蔽模式
CAN_FilterIdHighCAN_FilterIdLow 为要过滤的 ID 高位与低位。
CAN_FilterMaskIdHighCAN_FilterMaskIdLow 为屏蔽位的高位与低位。

比如,我们要配置为只接收与本机源地址一致的数据
发送机 SA = 0x01
接收机 SA = 0x02
则接收机的过滤器配置如下:

PDU优先权保留位数据页PDU格式PDU特定域源地址数据域
FilterId00000000000000000001000000000DATA
MaskId000000000000011111111000000000- 64

FilterId = (0x02 << 8) << 3;
FilterMaskId = (0xff << 8) << 3;
左移3位寄存器低3位为:保留位、RTR、IDE

接收到的帧 ID 与 MaskId 中为1的位所对应的 FilterId 必须完全相同才将接收到的数据存入 FIFO 中。在这里即接收到的 ID 帧的PDU特定域必须为00000010,即接收机的源地址 0x02

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值