CAN通信

CAN(Controller Area Network)

ISO国际标准化 串行通讯协议
现在是欧洲汽车网络标准协议
可靠性高 广泛应用于 汽车电子 工业自动化 船舶 医疗设备 工业设备等

CAN协议标准

ISO11898标准

针对通信速率为125Kbps~1Mbps 的高速通信标准

ISO11519-2标准

针对通信速率为125Kbps以下的低速通信标准

CAN协议特点

多主控制

总线空闲 所有单元可发送消息
两个及以上单元同时发送 根据标识符(ID) 决定优先级
对个各ID的每个位进行仲裁比较 仲裁获胜的单元可继续发送消息 仲裁失利的单元立刻停止发送 进行接收工作

系统柔软性

总线上添加单元时 已连接的其他单元的软硬件和应用层不需要做改变

速度快 距离远

最高1Mbps(距离<40M) 最远10KM(速率<5Kbps)

错误检测 错误通知 错误恢复

单元可以检测错误
检测到错误的单元会通知其他所有的单元 正在发送消息的单元一旦检测到错误 会强制结束当前的发送
强制结束发送的单元会不断反复地重新发送此消息直到发送成功为止

故障封闭功能

暂时的数据错误:外部噪声等
持续的数据错误:单元内部故障、驱动器故障、断线等
CAN可以判断错误的类型
当总线上发生持续数据错误时 可将引起此故障的单元从总线上隔离出去

连接节点多

CAN总线可同时连接多个单元的总线
可连接的单元总数理论上没有限制
实际上受到总线时间延迟及电气负载的限制
降低通信速度 可连接的单元数增加
提高通信速度 可连接的单元数减少

综上 CAN特别适合工业过程监控设备的互连

CAN物理层特征

在这里插入图片描述
CAN控制器根据CAN_L和CAN_H上的电位差来判断总线电平
总线电平分为显形电平 和 隐形电平
二者必居其一
发送方通过使总线电平发生变化 将消息发送给接收方
显形/隐形 : 0/1
显性电平:CAN_H和CAN_L之差为2V左右
隐性电平:CAN_H和CAN_L之差为0V
显形电平有优先权 只要有一个单元输出显性电平 总线即为显性电平
只有所有单元输出隐性电平 总线才为隐性电平
在CAN总线的起止端都有一个120Ω的终端电阻 来做阻抗匹配 以减少回波反射

帧种类

数据帧

用于发送单元向接收单元传送数据的帧

遥控帧

用于接收单元向具有相同ID的发送单元请求数据

错误帧

用于当检测出错误时向其它单元通知错误

过载帧

用于接收单元通知其尚未做好接收准备

间隔帧

用于将数据帧及遥控帧与前面的帧分离开来

其中数据帧和遥控帧有标准格式和扩展格式两种格式
标准格式有11个位的标识符(ID)
扩展格式有29个位的ID

数据帧介绍

在这里插入图片描述
D:显性电平 R:隐性电平

帧起始:表示数据帧开始的段
仲裁段:表示该帧优先级
在这里插入图片描述
*** 基本ID 禁止高7位都为隐性 即不能:ID=1111111XXXX

控制段:表示数据的字节数及保留位的段
在这里插入图片描述
r0 r1:保留位 发送必须为显 接收可以是隐性
IDE=0/1 标准标识符/扩展标识符

数据段:数据的内容 一帧可发送0~8个字节的数据
从MSB 开始输出

CRC段:检查帧的传输错误的段
由15个位的CRC顺序和1个位的CRC界定符组成
在这里插入图片描述

ACK段:表示确认正常接收的段
在这里插入图片描述
正常消息是指:不含填充错误、格式错误、CRC错误的消息

帧结束:表示数据帧结束的段
7个位的隐性位组成

总线仲裁

在这里插入图片描述
一、总线空闲时 最先发送的单元获得发送优先权 一旦发送 其他单元无法抢占
二、若有多个单元同时发送 连续输出显性电平多的单元具有较高优先级

位时序-- 设置波特率

位速率

发送单元在非同步的情况下发送的每秒钟的位数称为波特率 一个位一般可分为四段
同步段
传播时间段
相位缓冲段1
相位缓冲段2
段又由最小时间单位Tq(Time Quantum)构成
1位分为4个段 每个段又由若干个Tq 构成 称为位时序
通过设置位时序 实现单元采样
在这里插入图片描述
一个位:
在这里插入图片描述

STM32 CAN控制器 bxCAN

在这里插入图片描述

特点

波特率最高1Mbps
支持时间触发通信
具有3个发送邮箱
具有3级深度的2个接收FIFO
可变筛选器组(也称过滤器组 最多28个)

模式

工作模式
通过CAN_MCR 寄存器控制
①初始化模式(INRQ=1,SLEEP=0)
②正常模式(INRQ=0,SLEEP=0)
③睡眠模式(SLEEP=1)

测试模式
通过CAN_BTR寄存器控制
①静默模式(LBKM=0,SILM=1)
②环回模式((LBKM=1,SILM=0 )
③环回静默模式(LBKM=1, SILM=1)

调试模式

标识符筛选器

CAN标识符表示发送优先级
CAN控制器提供了28个可配置的筛选器组
每个筛选器组由2个32位寄存器组成

筛选器模式

屏蔽位模式
标识符列表模式
在这里插入图片描述
过滤一组标识符 – 屏蔽位模式
过滤一个标识符 – 标识符列表模式

发送流程

在这里插入图片描述

程序选择1个空置的邮箱(TME=1)→
设置标识符(ID)数据长度和发送数据→
设置CANTlxR的TXRQ位为1,请求发送→
邮箱挂号(等待成为最高优先级)→
预定发送(等待总线空闲)→
发送→
邮箱空置

接收流程

在这里插入图片描述
FIFO空→收到有效报文→挂号1(存入FIFO的一个邮箱,这个由硬件控制)>收到有效报文→挂号2>收到有效报文→挂号3→收到有效报文→溢出。

位时序

在这里插入图片描述
时间段1 包含 传播时间段和相位缓冲时间段1

主控制寄存器

在这里插入图片描述
INRQ位 控制初始化请求
0/1:初始化进入正常工作模式/正常工作模式进入初始化

位时序寄存器

在这里插入图片描述

FIFO寄存器

在这里插入图片描述

发送邮箱标识符寄存器

在这里插入图片描述

发送邮箱数据长度和时间戳寄存器

在这里插入图片描述

发送邮箱数据寄存器

在这里插入图片描述
要发送的数据就是存储在这两个存储器

接收FIFO邮箱标识符寄存器

在这里插入图片描述

接收FIFO邮箱数据长度和时间戳寄存器

在这里插入图片描述

接收FIFO邮箱数据寄存器

在这里插入图片描述
接收的数据便储存在这两个寄存器

筛选器模式寄存器

在这里插入图片描述

筛选器尺度寄存器

在这里插入图片描述
用于设置筛选器的宽度

筛选器FIFO关联寄存器

在这里插入图片描述
0/1:FIFO0/FIFO1

筛选器激活寄存器

在这里插入图片描述

筛选器组i寄存器x

在这里插入图片描述

初始化流程

配置引脚复用 使能CAN时钟
设置CAN工作模式 波特率 等
设置滤波器

源码

硬件连接

在这里插入图片描述

初始化函数

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_InitStructure.CAN_NART=ENABLE;	//禁止报文自动传送
  	CAN_InitStructure.CAN_RFLM=DISABLE;	//报文不锁定
  	CAN_InitStructure.CAN_TXFP=DISABLE;	//报文标识符决定优先级
  	CAN_InitStructure.CAN_Mode= mode;	 //模式设置
  	CAN_InitStructure.CAN_SJW=tsjw;	//同步跳跃
  	CAN_InitStructure.CAN_BS1=tbs1; //Tbs1范围
  	CAN_InitStructure.CAN_BS2=tbs2;//Tbs2范围CAN_BS2_1tq ~	CAN_BS2_8tq
  	CAN_InitStructure.CAN_Prescaler=brp;  //分频
  	CAN_Init(CAN1, &CAN_InitStructure);   // 初始化CAN1 
    
		//过滤器
 	  CAN_FilterInitStructure.CAN_FilterNumber=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 关联FIFO
  	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;
}

发送函数

u8 CAN1_Send_Msg(u8* msg,u8 len)
{	
  u8 mbox;
  u16 i=0;
  CanTxMsg TxMessage;
  TxMessage.StdId=0x12;	 // 标准标识符0
  TxMessage.ExtId=0x12;	 //设置扩展标识符
  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;		

}

接收函数

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;	
}

main函数

{ 
	u8 key;
	u8 i=0,t=0;
	u8 cnt=0;
	u8 canbuf[8];
	u8 res;
	u8 mode=1;//CAN工作模式  1 环回模式
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	delay_init(168);    //初始化延时
	uart_init(115200);	//初始化串口波特率115200
	LED_Init();					//初始化LED 
 	LCD_Init();					//LCD初始化
	KEY_Init(); 				  
	CAN1_Mode_Init(CAN_SJW_1tq,CAN_BS2_6tq,CAN_BS1_7tq,6,CAN_Mode_LoopBack);//CAN初始化环回模式 波特率500Kbps    
 	POINT_COLOR=RED;
	LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");	
	LCD_ShowString(30,70,200,16,16,"CAN TEST");	
	LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
	LCD_ShowString(30,110,200,16,16,"2021/9/26");
	LCD_ShowString(30,130,200,16,16,"LoopBack Mode");	 
	LCD_ShowString(30,150,200,16,16,"KEY0:Send WK_UP:Mode");//显示提示	
  POINT_COLOR=BLUE;  
	LCD_ShowString(30,170,200,16,16,"Count:");		  	//当前计数值
	LCD_ShowString(30,190,200,16,16,"Send Data:");		//提示发送
	LCD_ShowString(30,250,200,16,16,"Receive Data:");	//提示接收	
 									  
while(1)
	{
		key=KEY_Scan(0);
		if(key==KEY0_PRES)//KEY0按下 发送一次
		{
			for(i=0;i<8;i++)
			{
				canbuf[i]=cnt+i;//填充发送缓冲区
				if(i<4)LCD_ShowxNum(30+i*32,210,canbuf[i],3,16,0X80);	  
				else LCD_ShowxNum(30+(i-4)*32,230,canbuf[i],3,16,0X80);	
 			}
			res=CAN1_Send_Msg(canbuf,8);
			if(res)LCD_ShowString(30+80,190,200,16,16,"Failed");		
			else LCD_ShowString(30+80,190,200,16,16,"OK    ");	 									   
		}else if(key==WKUP_PRES)
		{	   
			mode=!mode;
			CAN1_Mode_Init(CAN_SJW_1tq,CAN_BS2_6tq,CAN_BS1_7tq,6,mode);	
  			POINT_COLOR=RED;
			if(mode==0)
			{
				LCD_ShowString(30,130,200,16,16,"Nnormal Mode ");	    
			}else 
			{
 				LCD_ShowString(30,130,200,16,16,"LoopBack Mode");
			}
 			POINT_COLOR=BLUE;
		}		 
		key=CAN1_Receive_Msg(canbuf);
		if(key)
		{			
			LCD_Fill(30,270,160,310,WHITE);
 			for(i=0;i<key;i++)
			{									    
				if(i<4)LCD_ShowxNum(30+i*32,270,canbuf[i],3,16,0X80);	
				else LCD_ShowxNum(30+(i-4)*32,290,canbuf[i],3,16,0X80);	
 			}
		}
		t++; 
		delay_ms(10);
		if(t==20)
		{
			LED0=!LED0;
			t=0;
			cnt++;
			LCD_ShowxNum(30+48,170,cnt,3,16,0X80);	
		}		   
	} 
	
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

。✧* ꧁流痕꧂✧*。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值