STM32 CAN协议讲解以及代码

这篇具有很好参考价值的文章主要介绍了STM32 CAN协议讲解以及代码。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

STM32 CAN


前言

前面学习了CAN的一些理论知识,他在我们的STM32里面是怎么用的呢
前面讲了一些can的知识,在STM32里是什么样的呢

一、CAN外设

1.主控制寄存器CAN_MCR

DBF调试冻结:处于程序调试模式才使用。可以设置CAN处于工作模式还是禁止收发状态,禁止收发时仍可以访问接受FIFO中的数据。
TTCM时间触发模式:设置CAN的时间触发通信模式。在此模式下,CAN使用它内部定时器产生时间戳,并把它保存在CAN_RDTxR,CAN_TDTxR寄存器中。可以利用它实现标准分时同步通信功能。
ABOM自动离线管理:当节点检测到他发送错误或者接受错误超过一定值时,会自动离线管理。离线状态下,不能接收或者发送。
AWUM自动唤醒:在使用软件进入睡眠后,如果使用自动唤醒,在检测到总线活动时,会自动唤醒。
NART自动重传:当报文发送失败会自动重传直到成功为止。
RFLM锁定模式:锁定接收FIFO。锁定之后,当接收FIFO溢出时,会丢弃下一个接收的报文。若不锁定,则会覆盖掉之前的报文。
TXFP报文发送优先级的判定方法:当邮箱中有多个报文需要发送时,控制它是根据报文的ID优先级还是报文存进邮箱的顺序来发送。

2.位时序寄存器CAN_BTR

SILM:为0,正常模式;为1,静默模式
LBKM:为1,允许回环模式;为0,禁止回环模式
CAN有四种工作模式。由位时序寄存器的SILM和LBKM组合控制。
stm32 can发送函数,stm32,嵌入式硬件,单片机
• 正常模式
正常模式下就是一个正常的 CAN 节点,可以向总线发送数据和接收数据。
• 静默模式
静默模式下,它自己的输出端的逻辑 0 数据会直接传输到它自己的输入端,逻辑 1 可以被发送到总线,所以它不能向总线发送显性位 (逻辑 0),只能发送隐性位 (逻辑 1)。输入端可以从总线接收内容。由于它只可发送的隐性位不会强制影响总线的状态,所以把它称为静默模式。这种模式一般用于监测,它可以用于分析总线上的流量,但又不会因为发送显性位而影响总线。
• 回环模式
回环模式下,它自己的输出端的所有内容都直接传输到自己的输入端,输出端的内容同时也会被传输到总线上,即也可使用总线监测它的发送内容。输入端只接收自己发送端的内容,不接收来自总线上的内容。使用回环模式可以进行自检。
• 回环静默模式
回环静默模式是以上两种模式的结合,自己的输出端的所有内容都直接传输到自己的输入端,并且不会向总线发送显性位影响总线,不能通过总线监测它的发送内容。输入端只接收自己发送端的内容,不接收来自总线上的内容。这种方式可以在“热自检”时使用,即自我检查的时候,不会干扰总线。

在STM32中的位时序:
SYNC_SEG,BS1,BS2三段,采样点位于BS1和BS2交界处。SYNC_SEG的固定长度是1Tq.BS1和BS2的长度SJW可以在位时序寄存器中配置。
波特率:
STM32的CAN1和CAN2挂载在APB1上。APB1总线的最大频率是36MHz。在使用CAN2时,必须打开CAN1的时钟。

波特率设置
stm32 can发送函数,stm32,嵌入式硬件,单片机
举两个例子
500bps

CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack);//CAN,波特率500Kbps    

这个是怎么计算的呢,根据前面提到4分频 4/36M *(1+8+9)=500Kbps
那么1M应该怎么配置呢

CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_5tq,CAN_BS1_3tq,4,CAN_Mode_LoopBack);//CAN 1Mbps

4/36*(1+5+3)=1M

3.CAN的发送邮箱

CAN外设有三个发送邮箱,即最多可以缓存3个待发送报文。 每个发送邮箱中包含有四个寄存器。

标识符寄存器CAN_TIxR(存储待发送报文的ID,扩展ID,IDE位及RTR位)
数据长度控制寄存器CAN_TDTxR(存储待发送报文的DLC段)
低位数据寄存器CAN_TDLxR(存储数据段的低四个字节内容)
高位数据寄存器CAN_TDHxR(存储高四字节的内容)
发送邮箱的工作过程:当需要发送报文时,把报文分解成各个段存储到不同的寄存器中,并对标识符寄存器的发送请求位置1,即可把数据发送出去。

4.CAN的接收FIFO

CAN外设有2个接收FIFO,每个FIFO中有3个邮箱,即最多可以缓存6个接收报文。当接收到报文时,FIFO报文计数器会自增,当报文被读取之后,计数器会自减。和发送邮箱类似,FIFO有四个寄存器。
标识符寄存器CAN_RIxR(存储接收报文的ID,扩展ID,IDE位及RTR位)
数据长度控制寄存器CAN_RDTxR(存储接收报文的DLC段)
低位数据寄存器CAN_RDLxR(存储数据段的低四个字节内容)
高位数据寄存器CAN_RDHxR(存储高四字节的内容)

5.验收筛选器

STM32F103的CAN外设有14个筛选器组,每组有两个寄存器。CAN1和CAN2共用筛选器。筛选器的作用下,节点只接受需要的报文到自己的FIFO中。筛选器可以调整筛选ID的长度和过滤模式

(1)根据筛选ID长度分类:

32位:STDID[10:0],EXTID[17:0],IDE,RTR
16位:STDID[10:0],EXTID[17:15],IDE,RTR
(2)根据过滤方式分为:

标识符列表模式:要求报文与列表中的ID的每一个标识符相同才接收。
掩码模式:只要报文ID中规定的某些位相同,就会被接收。
筛选尺度寄存器CAN_FS1R的FSCx位可以设置工作在32位还是16位;筛选模式寄存器CAN_FM1R的FBMx位可以设置工作在标识符列表模式还是掩码模式。每组筛选器有2个32位寄存器,分别为CAN_FxR1,CAN_FxR2,用来存储要筛选的ID或者掩码。
stm32 can发送函数,stm32,嵌入式硬件,单片机

二、代码配置

1.初始化

备注比正点的例程或者野火的都要详细

/**
* @brief CAN 初始化
* @param tsjw : 重新同步跳跃时间单元.范围: 1~3;
* @param tbs2 : 时间段 2 的时间单元.范围: 1~8;
* @param tbs1 : 时间段 1 的时间单元.范围: 1~16;
* @param brp : 波特率分频器.范围: 1~1024;
* @note 以上 4 个参数, 在函数内部会减 1, 所以, 任何一个参数都不能等于 0
* CAN 挂在 APB1 上面, 其输入时钟频率为 Fpclk1 = PCLK1 = 36Mhz
* tq = brp * tpclk1;
* 波特率 = Fpclk1 / ((tbs1 + tbs2 + 1) * brp);
* 我们设置 can_init(1, 8, 9, 4, 1), 则 CAN 波特率为:
* 36M / ((8 + 9 + 1) * 4) = 500Kbps
* @param mode : CAN_MODE_NORMAL, 普通模式;
 CAN_MODE_LOOPBACK,回环模式;
* @retval 0, 初始化成功; 其他, 初始化失败;
* */
u8 CAN_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 CAN_RX0_INT_ENABLE 
   	NVIC_InitTypeDef  NVIC_InitStructure;
#endif

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PORTA时钟	                   											 

  	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟	

    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);		//初始化IO
   
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化IO
	  
 	//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;//模式设置: mode:0,普通模式;1,回环模式; //
  	//设置波特率
  	CAN_InitStructure.CAN_SJW=tsjw;	//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位  CAN_SJW_1tq	 CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tq
  	CAN_InitStructure.CAN_BS1=tbs1; //Tbs1=tbs1+1个时间单位CAN_BS1_1tq ~CAN_BS1_16tq
  	CAN_InitStructure.CAN_BS2=tbs2;//Tbs2=tbs2+1个时间单位CAN_BS2_1tq ~	CAN_BS2_8tq
  	CAN_InitStructure.CAN_Prescaler=brp;  //分频系数
  	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表示匹配的数据帧将进入FIFO0缓冲区。
 	  CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0

  	CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
#if CAN_RX0_INT_ENABLE
	
	  CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许.		    
  
  	NVIC_InitStructure.NVIC_IRQChannel = USB_LP_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;
}   

CAN_FilterMode_IdMask宏指定过滤模式为标识符/掩码模式。在这种模式下,过滤器将使用标识符和掩码来匹配数据帧。标识符是数据帧的标识符,而掩码用于指定哪些位需要匹配。如果标识符和掩码的匹配条件满足,数据帧就会被允许通过过滤器。

CAN_FilterMode_IdList宏指定过滤模式为标识符列表模式。在这种模式下,过滤器将使用一个预定义的标识符列表来匹配数据帧。如果数据帧的标识符与列表中的任何一个匹配,数据帧就会被允许通过过滤器。

2.发送数据

//can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)	
//len:数据长度(最大为8)				     
//msg:数据指针,最大为8个字节.
//返回值:0,成功;
//		 其他,失败;
u8 Can_Send_Msg(u8* msg,u8 len)
{	
  u8 mbox;
  u16 i=0;
  CanTxMsg TxMessage;
  TxMessage.StdId=0x12;					 // 标准标识符 
  TxMessage.ExtId=0x12;				   // 设置扩展标示符 
  TxMessage.IDE=CAN_Id_Standard; // 标准帧
  TxMessage.RTR=CAN_RTR_Data;		 // 数据帧
  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;		

}

首先定义了一个CanTxMsg类型的变量TxMessage,用于存储要发送的数据帧的相关信息,包括标识符、帧类型、数据长度和数据内容等。
然后根据输入参数msg和len,将要发送的数据存储到TxMessage.Data数组中。
调用CAN_Transmit函数发送数据帧,并返回发送邮箱(mbox)的编号。
等待发送结束,直到CAN_TransmitStatus返回CAN_TxStatus_Failed或者经过一定的时间限制,才退出等待循环。
如果发送成功,则返回0,否则返回1。
stm32 can发送函数,stm32,嵌入式硬件,单片机

3.接收数据

//can口接收数据查询
//buf:数据缓存区;	 
//返回值:0,无数据被收到;
//		 其他,接收的数据长度;
u8 Can_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<8;i++)
    buf[i]=RxMessage.Data[i];  
	return RxMessage.DLC;	
}

首先定义了一个CanRxMsg类型的变量RxMessage,用于存储接收到的数据帧的相关信息,包括标识符、帧类型、数据长度和数据内容等。
使用CAN_MessagePending函数检查CAN1的FIFO0中是否有待接收的数据帧。如果没有数据帧待接收,则直接退出函数并返回0。
调用CAN_Receive函数从CAN1的FIFO0中读取接收到的数据帧,并将其存储到RxMessage变量中。
将接收到的数据存储到输入参数buf指向的缓冲区中。
返回接收到的数据帧的数据长度RxMessage.DLC。
stm32 can发送函数,stm32,嵌入式硬件,单片机

4.main.c

  
	CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack);//CAN初始化环回模式,波特率500Kbps    

 	while(1)
	{
		key=KEY_Scan(0);
		if(key==KEY0_PRES)//KEY0按下,发送一次数据
		{
			for(i=0;i<8;i++)
			{
				canbuf[i]=i;//填充发送缓冲区
				printf("发送%d\r\n",canbuf[i]);
 			}
			res=Can_Send_Msg(canbuf,8);//发送8个字节 
			if(res)printf("发送失败\r\n");		//提示发送失败
			else printf("发送\r\n");		 		//提示发送成功								   
		}else if(key==WKUP_PRES)//WK_UP按下,改变CAN的工作模式
		{	   
			mode=!mode;
  			CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,mode);//CAN普通模式初始化, 波特率500Kbps 
			if(mode==0)//普通模式,需要2个开发板
			{
				printf("正常模式\r\n");
			}else //回环模式,一个开发板就可以测试了.
			{
 						printf("回环模式\r\n");
			}
 			
		}		 
		key=Can_Receive_Msg(canbuf);
		if(key)//接收到有数据
		{			
			
 			for(i=0;i<key;i++)
			{									    
				printf("接收到%d\r\n",canbuf[i]);
 			}
		}
		t++; 
		delay_ms(10);
		if(t==20)
		{
			LED0=!LED0;//提示系统正在运行	
			t=0;
		}		   
	}
}

初始化CAN模式为回环模式,波特率为500Kbps。
进入循环,不断检测按键状态。
如果KEY0按键按下,将canbuf数组填充为0-7的连续数值,并调用Can_Send_Msg函数发送8个字节的数据帧。如果发送失败,打印"发送失败";如果发送成功,打印"发送"。
如果WK_UP按键按下,切换CAN的工作模式。如果当前为普通模式,将其切换为回环模式,并打印"回环模式";如果当前为回环模式,将其切换为普通模式,并打印"正常模式"。
调用Can_Receive_Msg函数接收数据帧,并将接收到的数据打印出来。
按下KEY0之后
stm32 can发送函数,stm32,嵌入式硬件,单片机文章来源地址https://www.toymoban.com/news/detail-765789.html

到了这里,关于STM32 CAN协议讲解以及代码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32基于CAN总线协议控制步进电机

    如上图所示,实现了以下功能: 1.两块stm32单片机通过CAN控制器与收发器进行半双工通信; 2.stm32主机通过检测按键,切换不同的模式,将不同模式的case值发送给stm32从机; 3.stm32从机根据收到的case值,控制步进电机进行不同的运动操作; 4.OLED用于显示收发内容与按键状态等

    2024年01月19日
    浏览(34)
  • 【通讯协议备忘录】stm32的CAN外设

    CAN的报文结构: 静默模式: 环回模式: 环回静默模式: 选好对应GPIO即可,APB1 36 Mhz, 500kbps: 不配置过滤器亦可使用 根据不同位长模式,每个过滤器组,32位模式可以配置一个屏蔽掩码或两个白名单列表,16位模式翻倍 标准帧和扩展帧的ID长度分别为11比特和29比特,通过移位

    2024年02月16日
    浏览(31)
  • STM32进阶学习(6)-通信协议之CAN详解

    CAN通信的背景可以追溯到上世纪80年代初,当时汽车制造商面临着一个共同的挑战: 如何有效地传输和共享大量的传感器数据和控制信息 。 传统的电缆布线方式非常复杂且容易出错,而且无法满足日益增长的数据传输需求。 为了解决这个问题,德国的汽车制造商奔驰(Mer

    2024年02月03日
    浏览(26)
  • STM32单片机CAN通讯连续发送多包数据,发生丢包现象

    使用例程连续发送两三包数据时没有问题,发送多包数据时,发现丢包现象; 例程代码如下: CAN_TxStatus_Failed :状态标志位,不足以判断发送完成,当发送多个数据包时,就会产生问题,修改代码如下: 改成 CAN_TxStatus_Ok 发送成功标志位后,可以连续发送多包数据

    2024年02月16日
    浏览(29)
  • STM32F4 CAN驱动配置,以及SEG1,SEG2的最佳配置

    平台:MDK5 单片机型号:STM32F407VG HAL库版本:V1.8.1 该程序在APB1时钟为42M速率的情况下,将CAN配置为500KBps. 通过SystemClock_Config函数,将主频配置为168M(最大),APB1为42M(最大)。CAN的波特率=42M/(1 + TimeSeg1 + TimeSeg2) = 42M/(1+12+8)=500Kbps。 先附上参考链接 https://blog.csdn.net/qfmzhu/article/det

    2024年02月09日
    浏览(29)
  • STM32 cubemx CAN STM32 CAN初始化详解

    接收用到的结构体如下: CAN概念:         全称Controller Area Network,是一种半双工,异步通讯。 物理层:         闭环:允许总线最长40m,最高速1Mbps,规定总线两端各有一个120Ω电阻,闭环        开环:最大传输距离1Km,最高速125Kbps,规定每根线串联一个2.2kΩ的电阻,

    2024年02月13日
    浏览(42)
  • STM32——CAN通讯

    can通讯传输的是一种 差分信号 ,关于具体的硬件电路略。 1、发送流程 前置工作:如 时钟的开启、引脚的配置; CAN邮箱和模式等配置 参考下面或HAL库选择 选择一个 空置 的邮箱(判断空置:CAN_TSR的TMEx位); 在这个空置邮箱中按数据帧格式设置ID、数据长度以及要发送的数

    2024年03月09日
    浏览(43)
  • STM32——CAN通信

    STM32F103有两个CAN,都分别有自己的发送接收邮箱。 发送邮箱共有3个来发送报文,发送调度器根据优先级决定哪个邮箱的报文先被发送。 共有2个接收FIFO,每个FIFO都可以存放3个完整的报文。它们完全由硬件来管理。 CAN通信通过CAN_H、CAN_L两根线实现通信,电平特性分为显性电

    2024年02月08日
    浏览(36)
  • STM32—CAN通信

    🎀 文章作者:二土电子 🌸 关注文末公众号获取其他资料和工程文件! 🐸 期待大家一起学习交流! CAN全称是Controller Area Network,控制器局域网络,是ISO国际标准化的串行通信协议。CAN是国际上应用最广泛的现场总线之一。CAN通信只有两根信号线,分别是CAN_H和CAN_L,CAN 控制

    2024年02月16日
    浏览(31)
  • STM32——CAN

    1、两个 CAN 与 2.0A 和 B (主动)规范兼容,比特率最高达 1 Mbit/s。 2、它们可接收和发送包含11 位标识符的标准帧和包含 29 位标识符的扩展帧。 3、每个 CAN 有三个发送邮箱,发送报文的优先级可以使用软件控制,还可以记录发送的时间; 4、具有两个3级深度的接收FIFO,28 个

    2024年02月15日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包