STM32F40x CAN控制器

一、CAN控制器简介

STM32自带了基本扩展CAN外设,又称bxCAN,bxCAN的特点如下:

  • 支持CAN协议2.0A和2.0B主动模式

  • 波特率最高达1Mbps

  • 支持时间触发通信

  • 具有3个发送邮箱

  • 具有3级深度的2个接收FIFO

  • 可变的筛选器组(也称过滤器组,最多28个)
    CAN总线模式:
    1、工作模式

  • 初始化模式(INRQ=1、SLEEP=0)

  • 正常模式(INRQ=0、SLEEP=0)

  • 睡眠模式(SLEEP=1)

2、测试模式

  • 静默模式(LBKM=0、SILM=1)

  • 环回模式(LBKM=1、SILM=0)

  • 环回静默模式(LBKM=1、SILM=1)

3、调试模式
CAN控制器框图:STM32F40x CAN控制器_第1张图片
**CAN发送流程:**程序选择1个空置的邮箱(TME=1)-> 设置标识符(ID),数据长度和发送数据 -> 设置CAN_TIxR的TXRQ位为1,请求发送 -> 邮箱挂号(等待成为最高优先级)-> 预定发送(等待总线空闲)-> 发送 ->邮箱空置。
STM32F40x CAN控制器_第2张图片
CAN接收流程:FIFO空 -> 收到有效报文 -> 挂号_1(存入FIFO的一个邮箱,这个由硬件控制,我们不需要理会)-> 收到有效报文 -> 挂号_2 -> 收到有效报文 -> 挂号_3-> 收到有效报文 -> 溢出。
STM32F40x CAN控制器_第3张图片
**注意:**报文FIFO具有锁定功能(由CAN_MCR,RFLM位控制),锁定后,新数据将丢弃,不锁定则新数据将替代老数据
STM32的CAN位时序:STM32F40x CAN控制器_第4张图片

STM32F103,设TS1=8、TS2=7、BRP=3,波特率=36000/[(9+8+1)*4]=500Kbps。
STM32F407,设TS1=6、TS2=5、BRP=5,波特率=42000/[(7+6+1)*6]=500Kbps。

二、STM32的CAN寄存器

1、CAN主控制寄存器(CAN_MCR)
STM32F40x CAN控制器_第5张图片
设置INRQ=0,可使CAN从初始化模式进入正常工作模式。
设置INRQ=1,可使CAN从正常工作模式进入初始化模式 。
注意:CAN初始化时,先设置INRQ=1 ,进入初始化模式,进行初始化(尤其是CAN_BTR的设置,该寄存器,必须在CAN正常工作之前设置),之后再设置INRQ=0,进入正常工作模式。
2、CAN位时序寄存器(CAN_BTR)STM32F40x CAN控制器_第6张图片
3、CAN接收FIFO寄存器(CAN_RF0R\CAN_RF1R)
STM32F40x CAN控制器_第7张图片
4、CAN发送邮箱标识符寄存器(CAN_TIxR,其中x=0~2)
STM32F40x CAN控制器_第8张图片
5、CAN发送邮箱数据长度和时间戳寄存器 (CAN_TDTxR 其中x=0~2)
STM32F40x CAN控制器_第9张图片
6、CAN发送邮箱数据寄存器(CAN_TDLxR/CAN_TDHxR 其中x=0~2)
STM32F40x CAN控制器_第10张图片
7、CAN接收FIFO邮箱标识符寄存器(CAN_RIxR 其中x=0/1)
STM32F40x CAN控制器_第11张图片
8、CAN接收FIFO邮箱数据长度和时间戳寄存器(CAN_RDTxR 其中x=0/1)
STM32F40x CAN控制器_第12张图片
9、CAN接收FIFO邮箱邮箱数据寄存器(CAN_RDLxR/CAN_RDHxR 其中x=0/1)
STM32F40x CAN控制器_第13张图片
10、CAN筛选器模式寄存器(CAN_FM1R)STM32F40x CAN控制器_第14张图片
注意:该寄存器设置筛选器的工作模式,必须在CAN_FMR寄存器FINIT=1时配置,对于STM32F103ZET6,只有[13:0]位有效,对于互联性STM32F1或者STM32F407,则全部有效。
11、CAN筛选器尺度寄存器(CAN_FS1R)
STM32F40x CAN控制器_第15张图片
注意:该寄存器用于设置筛选器的位宽,必须在CAN_FMR寄存器FINIT=1时配置,对于STM32F103ZET6,只有[13:0]位有效,对于互联性STM32F1或者STM32F407,则全部有效。
12、CAN筛选器FIFO关联寄存器(CAN_FFA1R)
STM32F40x CAN控制器_第16张图片
注意:该寄存器设置报文通过筛选器组之后,被存入的FIFO,如果对应位为0,则存放到FIFO0;如果为1,则存放到FIFO1。该寄存器也只能在过滤器处于初始化模式( CAN_FMR 寄存器的FINIT=1 )下配置。
13、CAN筛选器激活寄存器(CAN_FA1R)
STM32F40x CAN控制器_第17张图片
注意:该寄存器用于设置筛选器组的开启和关闭。对对应位置1,即开启对应的筛选器组;置0则关闭该筛选器组。
14、CAN筛选器组i寄存器x(CAN_FiRx 其中i=0~27,x=1/2)
STM32F40x CAN控制器_第18张图片

三、CNA总线初始化流程

  • ①配置相关引脚的复用功能,使能CAN时钟。
    要用CAN,先要使能CAN的时钟,CAN的时钟通过APB1ENR的第25位来设置。其次要设置CAN的相关引脚为复用输出,这里我们需要设置PA11为上拉输入(CAN_RX引脚)PA12为复用输出(CAN_TX引脚),并使能PA口的时钟
  • ②设置CAN工作模式及波特率等。
    通过先设置CAN_MCR寄存器的INRQ位,让CAN进入初始化模式,然后设置CAN_MCR的其他相关控制位。再通过CAN_BTR设置波特率和工作模式(正常模式/环回模式)等信息。
    最后设置INRQ为0,退出初始化模式。
  • ③设置滤波器。
    我们将使用筛选器组0,并工作在32位标识符屏蔽位模式下。先设置CAN_FMR的FINIT位,进入初始化模式,然后设置筛选器组0的工作模式以及标识符ID和屏蔽位。最后激活筛选器,并退出初始化模式。

四、代码展示

//CAN初始化
//tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1tq~ CAN_SJW_4tq
//tbs2:时间段2的时间单元.   范围:CAN_BS2_1tq~CAN_BS2_8tq;
//tbs1:时间段1的时间单元.   范围:CAN_BS1_1tq ~CAN_BS1_16tq
//brp :波特率分频器.范围:1~1024; tq=(brp)*tpclk1
//波特率=Fpclk1/((tbs1+1+tbs2+1+1)*brp);
//mode:CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回环模式;
//Fpclk1的时钟在初始化的时候设置为42M,如果设置CAN1_Mode_Init(CAN_SJW_1tq,CAN_BS2_6tq,CAN_BS1_7tq,6,CAN_Mode_LoopBack);
//则波特率为:42M/((6+7+1)*6)=500Kbps
//返回值:0,初始化OK;
//    其他,初始化失败; 


u8 CAN1_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
{

  	GPIO_InitTypeDef GPIO_InitStructure; 
	  CAN_InitTypeDef        CAN_InitStructure;
  	CAN_FilterInitTypeDef  CAN_FilterInitStructure;
#if CAN1_RX0_INT_ENABLE 
   	NVIC_InitTypeDef  NVIC_InitStructure;
#endif
    //使能相关时钟
	  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能PORTA时钟	                   											 

  	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟	
	
    //初始化GPIO
	  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11| GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化PA11,PA12
	
	  //引脚复用映射配置
	  GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_CAN1); //GPIOA11复用为CAN1
	  GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_CAN1); //GPIOA12复用为CAN1
	  
  	//CAN单元设置
   	CAN_InitStructure.CAN_TTCM=DISABLE;	//非时间触发通信模式   
  	CAN_InitStructure.CAN_ABOM=DISABLE;	//软件自动离线管理	  
  	CAN_InitStructure.CAN_AWUM=DISABLE;//睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
  	CAN_InitStructure.CAN_NART=ENABLE;	//禁止报文自动传送 
  	CAN_InitStructure.CAN_RFLM=DISABLE;	//报文不锁定,新的覆盖旧的  
  	CAN_InitStructure.CAN_TXFP=DISABLE;	//优先级由报文标识符决定 
  	CAN_InitStructure.CAN_Mode= mode;	 //模式设置 
  	CAN_InitStructure.CAN_SJW=tsjw;	//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq
  	CAN_InitStructure.CAN_BS1=tbs1; //Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq
  	CAN_InitStructure.CAN_BS2=tbs2;//Tbs2范围CAN_BS2_1tq ~	CAN_BS2_8tq
  	CAN_InitStructure.CAN_Prescaler=brp;  //分频系数(Fdiv)为brp+1	
  	CAN_Init(CAN1, &CAN_InitStructure);   // 初始化CAN1 
    
		//配置过滤器
 	  CAN_FilterInitStructure.CAN_FilterNumber=0;	  //过滤器0
  	CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; 
  	CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位 
  	CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;32位ID
  	CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
  	CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASK
  	CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
   	CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
  	CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0
  	CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
		
#if CAN1_RX0_INT_ENABLE
	
	  CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许.		    
  
  	NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     // 主优先级为1
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            // 次优先级为0
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  	NVIC_Init(&NVIC_InitStructure);
#endif
	return 0;
}   
 
#if CAN1_RX0_INT_ENABLE	//使能RX0中断
//中断服务函数			    
void CAN1_RX0_IRQHandler(void)
{
  	CanRxMsg RxMessage;
	int i=0;
    CAN_Receive(CAN1, 0, &RxMessage);
	for(i=0;i<8;i++)
	printf("rxbuf[%d]:%d\r\n",i,RxMessage.Data[i]);
}
#endif

//can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)	
//len:数据长度(最大为8)				     
//msg:数据指针,最大为8个字节.
//返回值:0,成功;
//		 其他,失败;
u8 CAN1_Send_Msg(u8* msg,u8 len)
{	
  u8 mbox;
  u16 i=0;
  CanTxMsg TxMessage;
  TxMessage.StdId=0x12;	 // 标准标识符为0
  TxMessage.ExtId=0x12;	 // 设置扩展标示符(29位)
  TxMessage.IDE=0;		  // 使用扩展标识符
  TxMessage.RTR=0;		  // 消息类型为数据帧,一帧8位
  TxMessage.DLC=len;							 // 发送两帧信息
  for(i=0;i<len;i++)
  TxMessage.Data[i]=msg[i];				 // 第一帧信息          
  mbox= CAN_Transmit(CAN1, &TxMessage);   
  i=0;
  while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++;	//等待发送结束
  if(i>=0XFFF)return 1;
  return 0;		

}
//can口接收数据查询
//buf:数据缓存区;	 
//返回值:0,无数据被收到;
//		 其他,接收的数据长度;
u8 CAN1_Receive_Msg(u8 *buf)
{		   		   
 	u32 i;
	CanRxMsg RxMessage;
    if( CAN_MessagePending(CAN1,CAN_FIFO0)==0)return 0;		//没有接收到数据,直接退出 
    CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);//读取数据	
    for(i=0;i<RxMessage.DLC;i++)
    buf[i]=RxMessage.Data[i];  
	return RxMessage.DLC;	
}

你可能感兴趣的:(STM32F4,stm32,嵌入式,can)