STM32F40x CAN控制器

news/2024/11/25 0:52:19/

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

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

三、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时钟	//初始化GPIOGPIO_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;//100MHzGPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化PA11,PA12//引脚复用映射配置GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_CAN1); //GPIOA11复用为CAN1GPIO_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_4tqCAN_InitStructure.CAN_BS1=tbs1; //Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tqCAN_InitStructure.CAN_BS2=tbs2;//Tbs2范围CAN_BS2_1tq ~	CAN_BS2_8tqCAN_InitStructure.CAN_Prescaler=brp;  //分频系数(Fdiv)为brp+1	CAN_Init(CAN1, &CAN_InitStructure);   // 初始化CAN1 //配置过滤器CAN_FilterInitStructure.CAN_FilterNumber=0;	  //过滤器0CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位 CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;32位IDCAN_FilterInitStructure.CAN_FilterIdLow=0x0000;CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASKCAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化#if CAN1_RX0_INT_ENABLECAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许.		    NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     // 主优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            // 次优先级为0NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
#endifreturn 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;	 // 标准标识符为0TxMessage.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;	
}

http://www.ppmy.cn/news/515332.html

相关文章

【stm32f407】CAN总线

一&#xff0e;CAN简介 CAN是ControllerArea Network的缩写&#xff08;以下称为CAN&#xff09;&#xff0c;是ISO国际标准化的串行通信协议。在当前的汽车产业中&#xff0c;出于对安全性、舒适性、方便性、低公害、低成本的要求&#xff0c;各种各样的电子控制系统被开发了…

AC78013CAN模块测试(二)CAN错误寄存器

上一节我们发现无论CANH、CANL接地或者断开&#xff0c;调用函数CAN_TransmitMessage(CAN_Type *CANx, const CAN_MsgInfoType *info, CAN_TransmitBufferType type)发送的数据返回值永远是0&#xff0c;查看原函数发现这里只管数据能正常丢入缓冲区。对于发送错误并没有相关判…

S32K1XX系列单片机 ——MCAL 的CAN模块配置

本文整理一下用EB配置S32K144单片机的CAN MCAL的时候遇到的问题及解决方案。 1. Can Counter ref Can Counter ref是定义CAN模块引用OS的哪个counter&#xff0c;当工程中没有OS的时候&#xff0c;可以置为空&#xff0c;并勾选&#xff1a; Can define loop as cycle 即可…

28004x芯片的CAN通讯配置

1、区别 2807x、28004x芯片的CAN通讯模块与28335、28067芯片模块配置有很大区别&#xff0c; 28004x 官方例程只有库函数&#xff0c; 没有直接配置寄存器写法 2806x 例程有直接操作寄存器 2、28004x的CAN配置步骤 需参考 C2000Ware_DigitalPower_SDK_3_02_00_00\c20…

MPC5744P-CAN模块

1、CAN模块结构 5744CAN模块主要由CHI&#xff08;Control Host Interface&#xff09;、PE&#xff08;Protocol Engine&#xff09;和MBs三个部分组成&#xff0c;其中CHI负责发送仲裁和接收匹配&#xff0c;PE负责时钟等的配置&#xff0c;MBs进行消息的存储。结构如下图所…

国产CAN芯片SIT1043应用

1 CAN 收发器概述 CAN 是一个双线差分通信接口&#xff0c;其物理层根据 ISO11898-2 标准定义。该物理层包含 CAN 收 发器和双绞线&#xff0c;后者将所有的 CAN 节点连接在一起。连接 CAN 收发器和电缆的两条线路被称 为 CANH 和 CANL。另外&#xff0c;还建议用一个分裂终…

HC32L130国产超低功耗华大MCU芯片介绍

华大HC32L130 系列32 位 ARM Cortex-M0 微控制器 HC32L130 系列是一款旨在延长便携式测量系统的电池使用寿命的超低功耗、宽电压工作范围的 MCU。集成 12 位 1M sps 高精度 SARADC&#xff0c;以及集成了比较器、运放、内置高性能 PWM 定时器、LCD 显示、多路 UART、SPI、I2C …

CH340芯片选型

CH340是一个USB总线的转接芯片&#xff0c;其中转串口的应用场合居多&#xff0c;且市场占有率很高。CH340芯片根据不同的功能可以实现为USB转串口、打印口和IrDA红外接口&#xff0c;因此选型的时候就首先需要根据功能加以区分了。如下表所示&#xff1a;&#xff08;以下数据…