关于单片机 CAN通讯的学习

CAN

bxCAN 简介
基本扩展 CAN 外设又称 bxCAN,可与 CAN 网络进行交互。该外设支持 2.0A 和 B 版本的
CAN 协议,旨在以最少的 CPU 负载高效管理大量的传入消息,并可按需要的优先级实现消
息发送。
在攸关安全性的应用中,CAN 控制器提供所有必要的硬件功能来支持 CAN 时间触发通信
方案。
24.2 bxCAN 主要特性
● 支持 2.0 A 及 2.0 B Active 版本 CAN 协议
● 比特率高达 1 Mb/s
● 支持时间触发通信方案
发送
● 三个发送邮箱
● 可配置的发送优先级
● SOF 发送时间戳
接收
● 两个具有三级深度的接收 FIFO
● 可调整的筛选器组:
— CAN1 和 CAN2 之间共享 28 个筛选器组
● 标识符列表功能
● 可配置的 FIFO 上溢
● SOF 接收时间戳
时间触发通信方案
● 禁止自动重发送模式
● 16 位自由运行定时器
● 在最后两个数据字节发送时间戳
管理
● 可屏蔽中断
● 在唯一地址空间通过软件实现高效的邮箱映射
双 CAN
● CAN1:主 bxCAN,用于管理 bxCAN 与 512 字节 SRAM 存储器之间的通信。
● CAN2:从 bxCAN,无法直接访问 SRAM 存储器。
● 两个 bxCAN 单元共享 512 字节 SRAM 存储器
在这里插入图片描述在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
keil 5 中can.c代码

#include "can.h"
#include "led.h"
#include "delay.h"
#include "usart.h"

//CAN初始化¯
//tsjw:重新同步跳跃时间单元,范围:1~3;
//tbs2:时间段2的时间单元1~8;
//tbs1:时间段1的时间单元1~16
//brp 波特率分频器1~1024;
// tq=(brp*tpclkl
//注意以上参数都不能设为0,会乱
//波特率=Fpclk1/((tbs1+tbs2+1)*brp);
//mode:0,普通模式;1,回环模式;
//Fpclkl的时钟初始化的时候设置为45M,如果设置CAB1_Mode--Init(1,5,9,6,1);
//波特率为45M/((5+9+1)*6)=500Kbps
//返回值:0,初始化ok;
// 其他,初始化失败;
//u8 CAN1_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
u8 CAN1_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)//初始化
{
  u16 i=0;
	if(tsjw==0||tbs2==0||brp==0)return 1;
	tsjw-=1;
	tbs2-=1;
  	tbs1-=1;
	brp-=1;
	
	RCC->AHB1ENR|=1<<0; 	//使能PORTA时钟
	GPIO_Set(GPIOA,PIN11|PIN12,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_50M,GPIO_PUPD_PU);//PA11,PA12,复用上拉输出
 	GPIO_AF_Set(GPIOA,11,9);//PA11,AF9
	GPIO_AF_Set(GPIOA,12,9);//PA12,AF9 	      
 
	RCC->APB1ENR|=1<<25;//使能CAN1时钟
	CAN1->MCR=0x0000;//退出睡眠模式(同时设置所有位为0)
	CAN1->MCR|=1<<0;//CAN进入初始化
	while((CAN1->MSR&1<<0)==0)
	{
	  i++;
		if(i>100)return 2;//初始化失败
	}
	CAN1->MCR|=0<<7;           //禁止时间触发通信模式
	CAN1->MCR|=0<<6;           //自动的总线关闭管理
	CAN1->MCR|=0<<5;           //在软件通过将 CAN_MCR 寄存器的 SLEEP 位清零发出请求后,退出睡眠模式。
	CAN1->MCR|=1<<4;        	 //无论发送结果如何(成功、错误或仲裁丢失),消息均只发送一次
	CAN1->MCR|=0<<3;           //接收 FIFO 上溢后不锁定。接收 FIFO 装满后,下一条传入消息将覆盖前一条消息。
	CAN1->MCR|=0<<2;		       //优先级由消息标识符确定
	CAN1->BTR=0x0000000000;    //清除原来的设置
	CAN1->BTR=mode<<30;
	CAN1->BTR=tsjw<<24; 	//重新同步跳跃宽度(tsjw)为tsjw+1个时间单位
	CAN1->BTR|=tbs2<<20; 	//tbs1=tbs2+1
	CAN1->BTR|=tbs1<<16;	//Tbs1=tbs1+1
	CAN1->BTR|=brp<<0;  	//预分频系数brp+1
	
		CAN1->MCR&=~(1<<0);		//请求CAN退出初始化模式
	while((CAN1->MSR&1<<0)==1)
	{
		i++;
		if(i>0XFFF0)return 3;//退出初始化失败
	}
	//过滤器初始化
	CAN1->FMR|1<<0;        //筛选器初始化
	CAN1->FA1R&=~(1<<0);   //筛选器分配到 FIFO 0
	CAN1->FS1R|=1<<0; 		//单 32 位尺度配置
	CAN1->FM1R|=0<<0;		//筛选器存储区 x 的两个 32 位寄存器处于标识符屏蔽模式
	CAN1->FFA1R|=0<<0;		//¹ýÂËÆ÷0¹ØÁªµ½FIFO0
	CAN1->sFilterRegister[0].FR1=0X00000000;//32λID
	CAN1->sFilterRegister[0].FR2=0X00000000;//32λMASK
	CAN1->FA1R|=1<<0;     //¼¤»î¹ýÂËÆ÷0
	CAN1->FMR&=0<<0;		//¹ýÂËÆ÷×é½øÈëÕý³£Ä£Ê½
	
#if CAN1_RXO_INT_ENABLE     //ʹÄÜÖжϽÓÊÕ
	CAN1->IER|=1<<1;          //FIFO0ÏûÏ¢¹ÒºÅÖжÏÔÊÐí
	MY_NVIC_Init(1,0,CAN1_RX0_IRQn,2);//×é2
#endif
	return 0;
}   
  //id:±ê×¼ID(11λ)/À©Õ¹ID(11λ+18λ)	    
	//ide:0,±ê×¼Ö¡;1,À©Õ¹Ö¡
	//rtr:0,Êý¾ÝÖ¡;1,Ô¶³ÌÖ¡
	//len:Òª·¢Ë͵ÄÊý¾Ý³¤¶È(¹Ì¶¨Îª8¸ö×Ö½Ú,ÔÚʱ¼ä´¥·¢Ä£Ê½ÏÂ,ÓÐЧÊý¾ÝΪ6¸ö×Ö½Ú)
	//*dat:Êý¾ÝÖ¸Õë.
	//·µ»ØÖµ:0~3,ÓÊÏä±àºÅ.0XFF,ÎÞÓÐЧÓÊÏä.
u8 CAN1_Tx_Msg(u32 id,u8 ide,u8 rtr,u8 len,u8 *dat)
{
	u8 mbox;
	if(CAN1->TSR&(1<<26))      mbox=0;          //ÓÊÏä0Ϊ¿Õ
	else if(CAN1->TSR&(1<<27)) mbox=1;		    	//ÓÊÏä1Ϊ¿Õ
	else if(CAN1->TSR&(1<<28)) mbox=2;					//ÓÊÏä2Ϊ¿Õ
	else return 0XFF;														//ÎÞ¿ÕÓÊÏä,ÎÞ·¨·¢ËÍ 
	CAN1->sTxMailBox[mbox].TIR=0;								//Çå³ý֮ǰµÄÉèÖÃ
	if(ide==0)  //±ê×¼Ö¡
	{
		id&=0x7ff;//È¡µÍ11λstdid
	  id<<=21;	
	}
	else		//À©Õ¹Ö¡
	{
		id&=0X1FFFFFFF;//È¡µÍ32λextid
		id<<=3;									   
	}
	CAN1->sTxMailBox[mbox].TIR|=id;		          //¸øCAN·¢ËÍÓÊÏä±êʶ·û¼Ä´æÆ÷ID
	CAN1->sTxMailBox[mbox].TIR|=ide<<2;	  			//Ñ¡Ôñ±êʶ·ûÊDZê×¼0 »¹ÊÇÀ©Õ¹1
	CAN1->sTxMailBox[mbox].TIR|=rtr<<1;         //Ñ¡ÔñÔ¶³Ì·¢ËÍÊÇÊý¾ÝÖ¡0 »¹ÊÇÒ£¿ØÖ¡1
	len&=0X0F;//µÃµ½µÍËÄλ
		CAN1->sTxMailBox[mbox].TDTR&=~(0X0000000F);
	CAN1->sTxMailBox[mbox].TDTR|=len;		   //ÉèÖÃDLC.Êý¾Ý³¤¶È
  	//´ý·¢ËÍÊý¾Ý´æÈëÓÊÏä.
	CAN1->sTxMailBox[mbox].TDHR=(((u32)dat[7]<<24)|       //CANÓÊÏä¸ßλÊý¾Ý¼Ä´æÆ÷
								((u32)dat[6]<<16)|
 								((u32)dat[5]<<8)|
								((u32)dat[4]));
	CAN1->sTxMailBox[mbox].TDLR=(((u32)dat[3]<<24)|				//CANÓÊÏäµÍλÊý¾Ý¼Ä´æÆ÷
								((u32)dat[2]<<16)|
 								((u32)dat[1]<<8)|
								((u32)dat[0]));
	CAN1->sTxMailBox[mbox].TIR|=1<<0; //ÇëÇó·¢ËÍÓÊÏäÊý¾Ý
	return mbox;
}
//»ñµÃ·¢ËÍ״̬.
//mbox:ÓÊÏä±àºÅ;
//·µ»ØÖµ:·¢ËÍ״̬. 0,¹ÒÆð;0X05,·¢ËÍʧ°Ü;0X07,·¢Ëͳɹ¦.
u8 CAN1_Tx_Staus(u8 mbox)
{	
	u8 sta=0;					    
	switch (mbox)                           //ÓÃstaÅжÏÓÊÏä״̬
	{
		case 0: 
			sta |= CAN1->TSR&(1<<0);			//RQCP0
			sta |= CAN1->TSR&(1<<1);			//TXOK0
			sta |=((CAN1->TSR&(1<<26))>>24);	//TME0
			break;
		case 1: 
			sta |= CAN1->TSR&(1<<8)>>8;		//RQCP1
			sta |= CAN1->TSR&(1<<9)>>8;		//TXOK1
			sta |=((CAN1->TSR&(1<<27))>>25);	//TME1	   
			break;
		case 2: 
			sta |= CAN1->TSR&(1<<16)>>16;	  //RQCP2
			sta |= CAN1->TSR&(1<<17)>>16;  	//TXOK2
			sta |=((CAN1->TSR&(1<<28))>>26);	//TME2
			break;
		default:
			sta=0X05;//ÓÊÏäºÅ²»¶Ô,¿Ï¶¨Ê§°Ü.
		break;
	}
		return sta;
} 
//µÃµ½ÔÚFIFO0/FIFO1ÖнÓÊÕµ½µÄ±¨ÎĸöÊý.
//fifox:0/1.FIFO񅧏;
//·µ»ØÖµ:FIFO0/FIFO1Öеı¨ÎĸöÊý.
u8 CAN1_Msg_Pend(u8 fifox)
{
	if(fifox==0)
		return CAN1->RF0R&0x03;       // Ëã¹ÒÆðµÄÏûÏ¢Êý£¬ 3¸öÓÊÏä¹ÒÆðÁ˼¸¸ö
	else if(fifox==1)
		return CAN1->RF1R&0X03;
	else 
		 return 0;
}
//½ÓÊÕÊý¾Ý
//fifox:ÓÊÏäºÅ
//id:±ê×¼ID(11λ)/À©Õ¹ID(11λ+18λ)	    
//ide:0,±ê×¼Ö¡;1,À©Õ¹Ö¡
//rtr:0,Êý¾ÝÖ¡;1,Ô¶³ÌÖ¡
//len:½ÓÊÕµ½µÄÊý¾Ý³¤¶È(¹Ì¶¨Îª8¸ö×Ö½Ú,ÔÚʱ¼ä´¥·¢Ä£Ê½ÏÂ,ÓÐЧÊý¾ÝΪ6¸ö×Ö½Ú)
//dat:Êý¾Ý»º´æÇø

/
void CAN1_Rx_Msg(u8 fifox,u32 *id,u8 *ide,u8 *rtr,u8 *len,u8 *dat)
{	   
	*ide=CAN1->sFIFOMailBox[fifox].RIR&0x04;//µÃµ½±êʶ·ûÑ¡ÔñλµÄÖµ  
 	if(*ide==0)//±ê×¼±êʶ·û
	{
		*id=CAN1->sFIFOMailBox[fifox].RIR>>21;
	}else	   //À©Õ¹±êʶ·û
	{
		*id=CAN1->sFIFOMailBox[fifox].RIR>>3;
	}
	*rtr=CAN1->sFIFOMailBox[fifox].RIR&0x02;	//µÃµ½Ô¶³Ì·¢ËÍÇëÇóÖµ.
	*len=CAN1->sFIFOMailBox[fifox].RDTR&0x0F; //µÃµ½DLC
 	//*fmi=(CAN1->sFIFOMailBox[FIFONumber].RDTR>>8)&0xFF;//µÃµ½FMI
	//½ÓÊÕÊý¾Ý
	dat[0]=CAN1->sFIFOMailBox[fifox].RDLR&0XFF;
	dat[1]=(CAN1->sFIFOMailBox[fifox].RDLR>>8)&0XFF;
	dat[2]=(CAN1->sFIFOMailBox[fifox].RDLR>>16)&0XFF;
	dat[3]=(CAN1->sFIFOMailBox[fifox].RDLR>>24)&0XFF;    
	dat[4]=CAN1->sFIFOMailBox[fifox].RDHR&0XFF;
	dat[5]=(CAN1->sFIFOMailBox[fifox].RDHR>>8)&0XFF;
	dat[6]=(CAN1->sFIFOMailBox[fifox].RDHR>>16)&0XFF;
	dat[7]=(CAN1->sFIFOMailBox[fifox].RDHR>>24)&0XFF;    
  	if(fifox==0)CAN1->RF0R|=0X20;//ÊÍ·ÅFIFO0ÓÊÏä
	else if(fifox==1)CAN1->RF1R|=0X20;//ÊÍ·ÅFIFO1ÓÊÏä	 
}

#if CAN1_RX0_INT_ENABLE	//ʹÄÜRX0ÖжÏ
//ÖжϷþÎñº¯Êý	
void CAN1_RX0_IRQHandler(void)
{
	u8 rxbuf[8];
	u32 id;
	u8 ide,rtr,len;     
 	CAN1_Rx_Msg(0,&id,&ide,&rtr,&len,rxbuf);
    printf("id:%b\r\n",id);
    printf("ide:%b\r\n",ide);
    printf("rtr:%b\r\n",rtr);
    printf("len:%b\r\n",len);
    printf("rxbuf[0]:%b\r\n",rxbuf[0]);
    printf("rxbuf[1]:%b\r\n",rxbuf[1]);
    printf("rxbuf[2]:%d\r\n",rxbuf[2]);
    printf("rxbuf[3]:%d\r\n",rxbuf[3]);
    printf("rxbuf[4]:%d\r\n",rxbuf[4]);
    printf("rxbuf[5]:%d\r\n",rxbuf[5]);
    printf("rxbuf[6]:%d\r\n",rxbuf[6]);
    printf("rxbuf[7]:%d\r\n",rxbuf[7]);
}
#endif


//can·¢ËÍÒ»×éÊý¾Ý(¹Ì¶¨¸ñʽ:IDΪ0X12,±ê×¼Ö¡,Êý¾ÝÖ¡)	
//len:Êý¾Ý³¤¶È(×î´óΪ8)				     
//msg:Êý¾ÝÖ¸Õë,×î´óΪ8¸ö×Ö½Ú.
//·µ»ØÖµ:0,³É¹¦;
//		 ÆäËû,ʧ°Ü;
u8 CAN1_Send_Msg(u8* msg,u8 len)
{
	u8 mbox;
	u16 i=0;
	 mbox=CAN1_Tx_Msg(0x12,0,0,len,msg);
	while((CAN1_Tx_Staus(mbox)!=0X07)&&(i<0xFFFF))i++;    //µÈ´ý·¢ËͽáÊø
	if(i>=0xFFFF) return 1;               //·¢ËÍʧ°Ü           
	return 0;                             //·¢Ëͳɹ¦
  
}
//can¿Ú½ÓÊÕÊý¾Ý²éѯ
//buf:Êý¾Ý»º´æÇø;	 
//·µ»ØÖµ:0,ÎÞÊý¾Ý±»ÊÕµ½;
//		 ÆäËû,½ÓÊÕµÄÊý¾Ý³¤¶È;
u8 CAN1_Receive_Msg(u8 *buf)
{		   		   
	u32 id;
	u8 ide,rtr,len; 
	if(CAN1_Msg_Pend(0)==0)return 0;		//ûÓнÓÊÕµ½Êý¾Ý,Ö±½ÓÍ˳ö 	 
  	CAN1_Rx_Msg(0,&id,&ide,&rtr,&len,buf); 	//¶ÁÈ¡Êý¾Ý
    if(id!=0x12||ide!=0||rtr!=0)len=0;		//½ÓÊÕ´íÎó	   
	return len;	
}

keil 5中can.h代码

#ifndef __CAN_H
#define __CAN_H	 
#include "sys.h"	    
//CAN接收RXO中断使能
#define CAN1_RX0_INT_ENABLE			0		
//1使能,0不使能 																							    										 							 				    
u8 CAN1_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode);	            //CAN初始化				
u8 CAN1_Tx_Msg(u32 id,u8 ide,u8 rtr,u8 len,u8 *dat);					//发送数据
u8 CAN1_Msg_Pend(u8 fifox);												//查询邮箱报文
void CAN1_Rx_Msg(u8 fifox,u32 *id,u8 *ide,u8 *rtr,u8 *len,u8 *dat);		//接收数据
u8 CAN1_Tx_Staus(u8 mbox);  											//返回发送状态
u8 CAN1_Send_Msg(u8* msg,u8 len);										//发送数据
u8 CAN1_Receive_Msg(u8 *buf);											//接收数据
#endif
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值