各种总线协议汇总(四)- CAN

四、CAN(Controller Area Network)

文章目录

      • 四、CAN(Controller Area Network)
        • (一)、CAN总线帧种类
          • 1、数据帧
          • 2、摇控帧
          • 3、错误帧
          • 4、过载帧
          • 5、帧间隔
        • (二)、CAN波特率计算
        • (三)、CAN电平类型
        • (五)、CAN总线设置程序

(一)、CAN总线帧种类

CAN协议是通过以下5种类型的帧进行的: 数据帧 、摇控帧 、错误帧 、过载帧 、帧间隔

1、数据帧

数据帧一般由7个段构成,即:
(1) 帧起始。表示数据帧开始的段。
(2) 仲裁段。表示该帧优先级的段。
(3) 控制段。表示数据的字节数及保留位的段。
(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。
(5) CRC段。检查帧的传输错误的段。
(6) ACK段。表示确认正常接收的段。
(7) 帧结束。表示数据帧结束的段。
各种总线协议汇总(四)- CAN_第1张图片

2、摇控帧

摇控帧只发ID不发数据,将ID发给另一台设备,请求返回数据。
各种总线协议汇总(四)- CAN_第2张图片

3、错误帧

CAN网络具有严格的错误诊断功能,该功能已固化在硅片之中,一旦错误被检测,正在传送的数据帧将会立即停止而待总线空闲时再次重发直至发送成功,该过程并不需要CPU的干涉除非错误累计该发送器退隐(Bus Off)。
各种总线协议汇总(四)- CAN_第3张图片

4、过载帧

过载帧是接收节点向总线上其它节点报告自身接收能力达到极限的帧。

各种总线协议汇总(四)- CAN_第4张图片

5、帧间隔

帧间隔是用来隔离数据帧(或者遥控帧)的,也就是说,数据帧(或者遥控帧)通过插入帧间隔可以将本帧与先行帧(数据帧、遥控帧、错误帧、过载帧)分隔开来。

各种总线协议汇总(四)- CAN_第5张图片

各种总线协议汇总(四)- CAN_第6张图片

(二)、CAN波特率计算

CAN通信波特率计算公式:
Baudrate = FPCLK / [ (tBS1+tBS2+t) * BRP]
tSJW:重新同步时间跳跃信号 range from 1~3
tBS1:时间段1的时间单元 range from 1~16
tBS2:时间段2的时间单元 range from 1~8
BRP:波特率分频器

Fpclk1/((tsjw+tbs1+tbs2) * brp)
各种总线协议汇总(四)- CAN_第7张图片

当然很多设备的波特率都是固定的,比如以下这些设备:
汽油车:500K,250K,125K,100K
柴油车:250K
伺服电机控制器:250K,125K
EPEC控制器:250K
消防主机通信:5K,10K,13.3K

(三)、CAN电平类型

CAN_H CAN_L 电位差 电平
2.5V 2.5V 0V 隐性电平
3.5V 1.5V 2V 显性电平

隐性电平->逻辑‘1’     显性电平->逻辑‘0’
显性电平能覆盖阴性电平(驱动能力差异导致)
各种总线协议汇总(四)- CAN_第8张图片

(五)、CAN总线设置程序

下面列出CAN(从)机相关代码:
(主机和从机CAN的配置是差不多的,只不过发送接受的数据不同而导致之后的操作不同)

#include "bsp_can_master.h"
/*
 * CAN 差分信号的表示
 * 1:隐性电平 H2.5v - L2.5v = 0v
 * 0:显性电平 H3.5v - L1.5v = 2v
 */
//主从机CAN设置都一样,只不过发送接收有些许差异
typedef unsigned char u8;
//接收数据缓冲区
u8 RXBUF[5];
u8 RX_FLAG = 0;

CanTxMsg TXMessage;			//发送数据缓冲区
CanRxMsg RXMessage;			//接收数据缓冲区

void CAN_Master_GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;												//配置CAN对应引脚
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);	//使能GPIO和复用IO时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);				//使能CAN1时钟
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;      //RX  PB8
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;     //上拉输入(浮空输入或带上拉输入)
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;			
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;      //RX  PB9
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //推挽输出	(推挽复用输出)
	GPIO_Init(GPIOB, &GPIO_InitStructure);	
}

void CAN_Master_NVIC_Configuration(void)
{	
	NVIC_InitTypeDef NVIC_InitStructure;												
    //配置CAN相关的嵌套向量中断控制器
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);	       //中断优先级1
	NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;	//CAN1 RX0 中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	//抢占优先为0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;      //子优先级为0
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

/*
CAN 的中断由发送中断、接收 FIFO 中断和错误中断构成
发送中断由三个发送邮箱任意一个为空的事件构成。
接收 FIFO 中断分为 FIFO0 和 FIFO1 的中断,接收 FIFO 收到新的报文或报文溢出的事件可以引起中断。
*/

static void CAN_Master_Mode_Configuration(void)
{
	CAN_InitTypeDef CAN_InitStructure;						//配置CAN1
	
	CAN_DeInit(CAN1);															//使CAN1配置为缺省值
	CAN_StructInit(&CAN_InitStructure);						//CAN1寄存器初始化
	
	CAN_InitStructure.CAN_TTCM = DISABLE;					//关闭时间触发通信模式使能(Time Triggered Communication Mode)
	CAN_InitStructure.CAN_ABOM = ENABLE;					//启动自动离线管理(Automatic Bus-Off Management)
	CAN_InitStructure.CAN_AWUM = ENABLE;					//使用自动唤醒模式(Automatic Wake-Up Mode)
	CAN_InitStructure.CAN_NART = DISABLE;					//禁止报文自动重传(No-Automatic Retransmission mode)
	CAN_InitStructure.CAN_RFLM = DISABLE;					//接收FIFO锁定模式 (Receive FIFO Locked Mode)溢出时新报文会覆盖原有报文
	CAN_InitStructure.CAN_TXFP = DISABLE;					  //发送 FIFO 优先级(Transmit FIFO Priority)优先级取决于报文标示符
	CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;	        //正常工作模式
	CAN_InitStructure.CAN_SJW = CAN_SJW_2tq;			    //重新同步跳跃宽度为2个时间单位(CAN_Synchronisation_Jump_width )
	CAN_InitStructure.CAN_BS1 = CAN_BS1_6tq;			    //时间段1占用6个时间单元
	CAN_InitStructure.CAN_BS2 = CAN_BS2_3tq;			    //时间段2占用3个时间单元
	CAN_InitStructure.CAN_Prescaler = 4;					  //波特率分频器
	/*
	BaudRate = Fpclk1/((tsjw+tbs1+tbs2) * brp)
	36000Kbps/(1+6+3)/4 = 900Kbps = 0.9Mbps
	*/
	CAN_Init(CAN1, &CAN_InitStructure);
	
}

/*我们还要对 CAN 的过滤器进行配置,使接收 FIFO 只接收特定的报文。
所谓的过滤就是 CAN 接口根据收到报文的 ID,选择是否把该报文保存到接收 FIFO 中。*/

/*STM32 的 ID 过滤方式有两种。一种为标识符列表模式,它把要接收报文的 ID 列成一
个表,要求报文 ID 与列表中的某一个标识符完全相同才可以接收,可以理解为白名单管
理。另一种称为标识符屏蔽模式,它把可接收报文 ID 的某几位作为列表,这几位被称为
屏蔽位,可以把它理解成关键字搜索,只要屏蔽位(关键字)相同就符合要求。*/

static void CAN_Master_Filter_Configuration(void){
	CAN_FilterInitTypeDef CAN_FilterInitStructure;				//配置CAN过滤器
	
	CAN_FilterInitStructure.CAN_FilterNumber = 0;			//过滤器组 0  It ranges from 0 to 13. 
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;			//工作在标识符屏蔽位模式
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;										//过滤器位宽为32位。
	CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)0x00001314<<3)&0xFFFF0000)>>16;		//要过滤的ID的高16位
	CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)0x00001314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;//要过滤的ID的低16位
	/*#define CAN_Id_Extended             ((uint32_t)0x00000004)  Extended Id 		IDE位为隐性位,且报文为数据帧
	#define CAN_RTR_Data                ((uint32_t)0x00000000)  Data frame 			RTR位为显性位				*/
//	赋值时标识符 0x0000 1314 左移三位是因为寄存器的低三位意义为保留位、RTR 位和 IDE 位
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;							//Specifies the filter mask number or identification number
	CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFF;								//值为 1 的寄存器位就是屏蔽位,值为0 的寄存器位不参与比较。
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FilterFIFO0;	//Specifies the FIFO (0 or 1) which will be assigned to the filter
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;							//使能过滤器 Enable or disable the filter.
    CAN_FilterInit(&CAN_FilterInitStructure);														//初始化过滤器
	CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);														//CAN 通信中断使能
//	FIFO0 消息挂号中断使能(CAN_IT_FMP0)在 CAN 接口的 FIFO0 收到报文时,我们在中断服务函数中从 FIFO0 读数据到内存。
}

void CAN_Master_Configuration(void)
{
	CAN_Master_GPIO_Configuration();
	CAN_Master_NVIC_Configuration();
	CAN_Master_Mode_Configuration();
	CAN_Master_Filter_Configuration();
}

//打包并发送报文  如果要触发中断的话	data[]里数据要是0xABCD
void CAN_Master_SetMsg(uint8_t data[])
{	
//	TXMessage.StdId = 0x00;				//由于我们使用拓展ID,所以不需要对他赋值
	TXMessage.ExtId = 0x1314;			//使用拓展的ID
	TXMessage.IDE = CAN_ID_EXT;			//拓展模式
	TXMessage.RTR = CAN_RTR_DATA;		//发送的是数据 Specifies the type of frame for the received message.
	TXMessage.DLC = 2;					//数据长度为2字节
	TXMessage.Data[0] = data[0];		// Contains the data to be received. It ranges from 0 to 0xFF. 
	TXMessage.Data[1] = data[1];	

}

void CAN_Master_SendMsg(void)
{
	CAN_Transmit(CAN1, &TXMessage);	//发送报文
}
	
void USB_LP_CAN1_RX0_IRQHandler(void)					//中断函数名在startup_stm32f10x_xx.s里可看到
{
	CAN_Receive(CAN1, CAN_FIFO0, &RXMessage);		
	if((RXMessage.ExtId == 0x1314) && 					// 比较是否是发送的数据和 ID 
		(RXMessage.IDE == CAN_ID_EXT) && 
		(RXMessage.DLC == 2) && 
		(RXMessage.Data[1] | RXMessage.Data[0]<<8)==0xDCBA)		//判断接受的数据是否为0XDCBA
	{
		RX_FLAG = 0;			//接收成功
	}
	else
		RX_FLAG = 0xff;		   //接收失败	
}

参考资料:
使用STM32F103做CAN的收发通信
STM32固件库

你可能感兴趣的:(总线协议,CAN)