您的位置 首页 解答

STM32 CAN通讯 滤波器装备总结

首先声明stm32手册写的太蛋疼,让我看了好长时间没看懂,后来根据实践再回头看了,才看懂一些,在这里还要感激网友发表的博客,下面内容为…

首要声明stm32手册写的太蛋疼,让我看了好长时刻没看懂,后来依据实践再回头看了,才看懂一些,在这里还要感谢网友宣布的博客,下面内容为转载:

一、在STM32互联型产品中,CAN1和CAN2共享28个过滤器组,其它STM32F103xx系列产品中有14个过滤器组,用以对接纳到的帧进行过滤。

每组过滤器包含了2个可装备的32位寄存器:CAN_FxR0和CAN_FxR1。这些过滤器相当于关卡,每逢收到一条报文时,CAN要先将收到的报文从这些过滤器上”过”一下,能经过的报文是有用报文,收进相相关FIFO(FIFO1或FIFO2),不能经过的是无效报文(不是发给”我”的报文),直接丢掉。

(规范CAN的标志长度是11位。扩展格局CAN的标志长度是29。CAN2.0A协议规矩CAN控制器有必要有一个11位的标识符。CAN2.0B协议中规矩CAN控制器的标明符长度可所以11位或29位。STM32一同支撑CAN2.0A/CAN2.0B协议。)

每组过滤器组有两种作业方式:标识符列表方式和标识符屏蔽位方式。

标识符屏蔽位方式:可过滤出一组标识符。此刻,这样CAN_FxR0中保存的便是标识符匹配值,CAN_FxR1中保存的是屏蔽码,即CAN_FxR1中假设某一位为1,则CAN_FxR0中相应的位有必要与收到的帧的标志符中的相应位契合才干经过过滤器;CAN_FxR1中为0的位表明CAN_FxR0中的相应位可不必与收到的帧进行匹配。

标识符列表方式:可过滤出一个标识。此刻CAN_FxR0和CAN_FxR1中的都是要匹配的标识符,收到的帧的标识符有必要与其间的一个契合才干经过过滤。

留意:CAN_FilterIdHigh是指高16位CAN_FilterIdLow是低16位应该将需求得到的帧的和过滤器的设置值左对齐起。

一切的过滤器是并联的,即一个报文只需经过了一个过滤器,便是算是有用的。

按作业方式和宽度,一个过滤器组能够变成以下几中方式之一:
(1)1个32位的屏蔽位方式的过滤器。
(2)2个32位的列表方式的过滤器。
(3)2个16位的屏蔽位方式的过滤器。
(4)4个16位的列表方式的过滤器。

每组过滤器组有两个32位的寄存器用于存储过滤用的”规范值”,别离是FxR1,FxR2。
在32位的屏蔽位方式下:
有1个过滤器。
FxR2用于指定需求关怀哪些位,FxR1用于指定这些位的规范值。
在32位的列表方式下:
有两个过滤器。
FxR1指定过滤器0的规范值FxR2指定过滤器1的规范值。

收到报文的标识符只需跟FxR1与FxR1其间的一个完全相一同,才算经过。
在16位的屏蔽位方式下:
有2个过滤器。
FxR1装备过滤器0,其间,[31-16]位指定要关怀的位,[15-0]位指定这些位的规范值。
FxR2装备过滤器1,其间,[31-16]位指定要关怀的位,[15-0]位指定这些位的规范值。
在16位的列表方式下:
有4个过滤器。
FxR1的[15-0]位装备过滤器0,FxR1的[31-16]位装备过滤器1。
FxR2的[15-0]位装备过滤器2,FxR2的[31-16]位装备过滤器3。

STM32的CAN有两个FIFO,别离是FIFO0和FIFO1。为了便于区别,下面FIFO0写作FIFO_0,FIFO1写作FIFO_1。
每组过滤器组有必要相关且只能相关一个FIFO。复位默许都相关到FIFO_0。
所谓“相关”是指假设收到的报文从某个过滤器经过了,那么该报文会被存到该过滤器相连的FIFO。
从另一方面来说,每个FIFO都相关了一串的过滤器组,两个FIFO刚好瓜分了一切的过滤器组。

每逢收到一个报文,CAN就将这个报文先与FIFO_0相关的过滤器比较,假设被匹配,就将此报文放入FIFO_0中。
假设不匹配,再将报文与FIFO_1相关的过滤器比较,假设被匹配,该报文就放入FIFO_1中。
假设仍是不匹配,此报文就被丢掉。

每个FIFO的一切过滤器都是并联的,只需经过了其间任何一个过滤器,该报文就有用。
假设一个报文既契合FIFO_0的规矩,又契合FIFO_1的规矩,明显,依据操作次序,它只会放到FIFO_0中。

每个FIFO中只需激活了的过滤器才起作用,换句话说,假设一个FIFO有20个过滤器,可是只激话了5个,那么比较报文时,只拿这5个过滤器作比较。
一般要用到某个过滤器时,在初始化阶段就直接将它激活。
需求留意的是,每个FIFO有必要至少激活一个过滤器,它才有或许收到报文。假设一个过滤器都没有激活,那么是一切报文都作废的。
一般的,假设不想用杂乱的过滤功用,FIFO能够只激活一组过滤器组,且将它设置成32位的屏蔽位方式,两个规范值寄存器(FxR1,FxR2)都设置成0。这样一切报文均能经过。(STM32供给的例程里便是这么做的!)

STM32CAN中,另一个较难了解的便是过滤器编号。
过滤器编号用于加快CPU对收到报文的处理。
收到一个有用报文时,CAN会将收到的报文以及它所经过的过滤器编号,一同存入接纳邮箱中。CPU在处理时,能够依据过滤器编号,快速的知道该报文的用处,然后作出相应处理。
不必过滤器编号其实也是能够的,这时分CPU就要剖析所收报文的标识符,然后知道报文的用处。
因为标识符所含的信息较多,处理起来就慢一点了。

STM32运用以下规矩对过滤器编号:
(1)FIFO_0和FIFO_1的过滤器别离独立编号,均从0开端按次序编号。
(2)一切相关同一个FIFO的过滤器,不论有没有被激活,均一致进行编号。
(3)编号从0开端,按过滤器组的编号从小到大,按次序排列。
(4)在同一过滤器组内,按寄存器从小到大编号。FxR1装备的过滤器编号小,FxR2装备的过滤器编号大。
(5)同一个寄存器内,按位序从小到大编号。[15-0]位装备的过滤器编号小,[31-16]位装备的过滤器编号大。
(6)过滤器编号是弹性的。当更改了设置时,每个过滤器的编号都会改动。
可是在设置不变的情况下,各个过滤器的编号是相对安稳的。

这样,每个过滤器在自己在FIFO中都有编号。
在FIFO_0中,编号从0–(M-1),其间M为它的过滤器总数。
在FIFO_1中,编号从0–(N-1),,其间N为它的过滤器总数。

一个FIFO假设有许多的过滤器,,或许会有一条报文,在几个过滤器上均能经过,这时分,,这条报文算是从哪儿过来的呢?
STM32在运用过滤器时,按以下次序进行过滤:
(1)位宽为32位的过滤器,优先级高于位宽为16位的过滤器。
(2)关于位宽相同的过滤器,标识符列表方式的优先级高于屏蔽位方式。
(3)位宽和方式都相同的过滤器,优先级由过滤器号决议,过滤器号小的优先级高。

按这样的次序,报文能经过的第一个过滤器,便是该报文的过滤器编号,被存入接纳邮箱中。

二、下面是我的代码:


/*时钟初始化*/

void RCC_Configuration(void)
{
ErrorStatus HSEStartUpStatus;
// RCC system reset(for debug purpose)
RCC_DeInit();

// Enable HSE
RCC_HSEConfig(RCC_HSE_ON);

//Enable HSI for Flash Operation
RCC_HSICmd(ENABLE);

// Wait till HSE is ready
HSEStartUpStatus = RCC_WaitForHSEStartUp();

if(HSEStartUpStatus == SUCCESS)
{
// HCLK = SYSCLK AHB时钟为体系时钟 72MHz
RCC_HCLKConfig(RCC_SYSCLK_Div1);

// PCLK2 = HCLK APB2时钟为体系时钟 72MHz
RCC_PCLK2Config(RCC_HCLK_Div1);

// PCLK1 = HCLK/2 APB1时钟为体系时钟 72MHz/2=36MHz
RCC_PCLK1Config(RCC_HCLK_Div2);

// Flash 2 wait state
FLASH_SetLatency(FLASH_Latency_2);
// Enable Prefetch Buffer
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

// PLLCLK = 8MHz * 9 = 72 MHz
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

// Enable PLL
RCC_PLLCmd(ENABLE);

// Wait till PLL is ready
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}

// Select PLL as system clock source
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

// Wait till PLL is used as system clock source
while(RCC_GetSYSCLKSource() != 0x08)
{
}
}

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO |
RCC_APB2Periph_GPIOA |
RCC_APB2Periph_GPIOB |
RCC_APB2Periph_GPIOC |
RCC_APB2Periph_USART1 |
RCC_APB2Periph_SPI1
, ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG |
RCC_APB1Periph_USART2 |
RCC_APB1Periph_USART3 |
RCC_APB1Periph_TIM3 |
RCC_APB1Periph_TIM4 |
RCC_APB1Periph_CAN1
// RCC_APB1Periph_CAN2
, ENABLE);
}

/*NVIC装备*/

void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;

#ifdef VECT_TAB_RAM
// Set the Vector Table base location at 0x20000000
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else /* VECT_TAB_FLASH */
// Set the Vector Table base location at 0x08000000
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif

// Configure one bit for preemption priority
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NV%&&&&&%_InitStructure);

}

/*管脚初始化*/

void CAN_PinInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

/* Configure CAN pin: RX */
GPIO_InitStructure.GPIO_Pin = PIN_CAN_RX;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIO_CAN, &GPIO_InitStructure);

/* Configure CAN pin: TX */
GPIO_InitStructure.GPIO_Pin = PIN_CAN_TX;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//GPIO_Mode_Out_PP;
GPIO_Init(GPIO_CAN, &GPIO_InitStructure);
}

/*CAN1装备函数*/

void CAN_Configuration(void)
{
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;

// CAN register init
CAN_DeInit(CAN1);
CAN_StructInit(&CAN_InitStructure);

// CAN cell init
CAN_InitStructure.CAN_TTCM=DISABLE;//制止时刻触发通讯方式
CAN_InitStructure.CAN_ABOM=DISABLE;
CAN_InitStructure.CAN_AWUM=DISABLE;//睡觉方式经过铲除sleep位来唤醒
CAN_InitStructure.CAN_NART=ENABLE;//ENABLE;报文主动重传
CAN_InitStructure.CAN_RFLM=DISABLE;//接纳溢出时,FIFO未确定
CAN_InitStructure.CAN_TXFP=DISABLE;//发送的优先级由标明符的巨细决议
CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;//正常方式下
//设置can通讯波特率为50Kbps
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1=CAN_BS1_8tq;
CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;
CAN_InitStructure.CAN_Prescaler=45;
CAN_Init(CAN1,&CAN_InitStructure);

// CAN filter init
CAN_FilterInitStructure.CAN_FilterNumber=0;
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;//CAN_FilterScale_16bit; //32bit

CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<21)&0xffff0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<21)|CAN_ID_STD|CAN_RTR_DATA)&0xffff;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFF;

CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //时能过滤器
CAN_FilterInit(&CAN_FilterInitStructure);

CAN_ITConfig(CAN1,CAN_IT_FMP0|CAN_IT_EPV, ENABLE);
}

/*CAN 发送函数*/

unsigned char CAN1_SendData(void)
{
uint16 i;
CanTxMsg TxMessage;
unsigned char TransmitMailbox;

TxMessage.StdId=0x11; //规范标识符
TxMessage.RTR=CAN_RTR_DATA;//数据帧
TxMessage.IDE=CAN_ID_STD;//规范帧
TxMessage.DLC=2; //数据长度 2
TxMessage.Data[0]=0xCA; //发送的数据
TxMessage.Data[1]=0xFE;
TransmitMailbox=CAN_Transmit(CAN1,&TxMessage); //发送数据
i = 0xFFF;
do
{
_NOP_(5);
}
while((CAN_TransmitStatus(CAN1,TransmitMailbox) != CANTXOK) && (–i));

if(i <= 0x01)
return 0;
else
return 1;
}

/*中止服务函数*/

void USB_LP_CAN1_RX0_IRQHandler(void)
{
CanRxMsg RxMessage;
CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
}

三、滤波器装备具体如下:1、对扩展数据帧进行过滤:(只接纳扩展数据帧) CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<3)&0xFFFF0000)>>16; CAN_FilterInitStructure.CAN_FilterIdLo=(((u32)slave_id<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF; CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFF;(注:规范帧数据帧、规范长途帧和扩展长途帧均被过滤)2、对扩展长途帧过滤:(只接纳扩展长途帧) CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<3)&0xFFFF0000)>>16; CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<3)|CAN_ID_EXT|CAN_RTR_REMOTE)&0xFFFF; CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF; CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFF;
3、对规范长途帧过滤:(只接纳规范长途帧) CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<21)&0xffff0000)>>16; CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<21)|CAN_ID_STD|CAN_RTR_REMOTE)&0xffff; CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF; CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFF;4、对规范数据帧过滤:(只接纳规范数据帧) CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<21)&0xffff0000)>>16; CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<21)|CAN_ID_STD|CAN_RTR_DATA)&0xffff; CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF; CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFF;
5、对扩展帧进行过滤:(扩展帧不会被过滤掉) CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<3)&0xFFFF0000)>>16; CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<3)|CAN_ID_EXT)&0xFFFF; CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF; CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFC;6、对规范帧进行过滤:(规范帧不会被过滤掉) CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<21)&0xffff0000)>>16; CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<21)|CAN_ID_STD)&0xffff; CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF; CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFC;注:slave_id为要过滤的id号。

其间咱们能够敞开can过错中止,设置呼应的标志位,在大循环里边不断的检测是否过错,一旦过错就重新装备can,这样有用地确保了CAN的正常通讯。具体操作代码如下:


/*CAN过错中止服务函数*/、

void CAN1_SCE_IRQHandler(void)
{
CANWorkFlag &= ~CAN_RESET_COMPLETE;
}

/*CAN过错处理函数*/

/************************************************************************
*函数称号: CanErrorProcess
*功用: CAN毛病,过错处理
*参数阐明: 无
************************************************************************/
void CanErrorProcess(void)
{
if ((CANWorkFlag & CAN_RESET_COMPLETE) == 0)
{
CAN1_Configuration();
//CAN2_Configuration();
CANWorkFlag |= CAN_RESET_COMPLETE;
}

//if((CANWorkFlag & CAN2_RESET_COMPLETE) == 0)
//{
//CAN1_Configuration();
//CAN2_Configuration();
//CANWorkFlag |= CAN2_RESET_COMPLETE;
//}
}

/*过错标志的界说*/

extern uint8 CANWorkFlag;
/************************************************************************
* CANWorkFlag 标志位掩码界说
************************************************************************/
#define CAN_INIT_COMPLETE 0x80 //CAN初始化完结标志
//#define CAN_BUS_ERROR 0x40 //CAN总线过错标志
#define CAN_RESET_COMPLETE 0x40 //CAN控制器复位完结标志

#define CAN2_INIT_COMPLETE 0x20 //CAN2初始化完结标志
//#define CAN_BUS_ERROR 0x40 //CAN总线过错标志
#define CAN2_RESET_COMPLETE 0x10 //CAN2控制器复位完结标志


以上是我再调试时分增加的,挺有用的;

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/changshang/jieda/268198.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部