【STM32】 CAN通讯

CAN通讯初始化与各个基本函数:

CAN中断初始化:

void NVIC_Configuration(void)                              // 配置DMA的中断优先级
{  
	NVIC_InitTypeDef NVIC_InitStructure; 	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);        // 1 bit 用来设置抢占优先级,3 bits用来设置响应优先级。 
	NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;   // CAN 中断优先级   
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;    // 抢占优先级最高
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;           // 该抢占优先级下响应优先级最高
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    
	NVIC_Init(&NVIC_InitStructure); 
}

配置通信端口与CAN基本寄存器配置(CAN_TX PA12     CAN_RX_PA11) :

/*—————————————————————————————————- 
1.配置通信端口与CAN基本寄存器配置(CAN_TX PA12 (71pin) CAN_RX_PA11(70pin)) 
返回值:初始化状态 
参数列表: 
tsjw:重新同步跳跃时间单元.范围:1~3; 
tbs2:时间段2的时间单元.范围:1~8; 
tbs1:时间段1的时间单元.范围:1~16; 
brp :波特率分频器.范围:1~1024;(实际要加1,也就是1~1024) tq=(brp)*tpclk1 
注意以上参数任何一个都不能设为0,否则会乱. 
波特率=Fpclk1/((tbs1+tbs2+1)*brp); 
Fpclk1的时钟在初始化的时候设置为36M,如果设置CAN_init(1,4,7,6); 		//该工程中,采用外部时钟8M,即波特率为125k		//★★★使用USB-CAN时,若发送数据无用,可改为115200等附近波特率试试!!!
则波特率为:36M/((4+7+1)*6)= 0.5M(500K) 
返回值:0,初始化OK;
*/
unsigned char CAN_init(unsigned char tsjw,unsigned char tbs2,unsigned char tbs1,unsigned short brp)
{
		unsigned short i=0;
		if(tsjw==0||tbs2==0||tbs1==0||brp==0)
				return 1;
		--tsjw; //减一之后再设置
		--tbs2;
		--tbs1;
		--brp;
		//------------端口配置  
		RCC->APB2ENR |= (1<<2);    //使能PORTA时钟   
		GPIOA->CRH &= 0XFFF00FFF;  //清0 PA11 PA12端口寄存器状态
		GPIOA->CRH |= 0X000B8000;  //配置端口CAN_TX PA12(71pin)复用推挽输出 CAN_RX_PA11(70pin)上拉输入     
		GPIOA->ODR |= (3<<11);     //初始化端口高电平
		//------------寄存器配置                 
		RCC->APB1ENR |= (1<<25);  //使能CAN时钟 CAN使用的是APB1的时钟(max:36M)
		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);         //报文不锁定,新的覆盖旧的
		CAN1->MCR |= (0<<2);         //优先级由报文标识符决定
		CAN1->BTR = 0x00000000;      //清0设置.
		CAN1->BTR |= (0<<30);        //模式设置 0,普通模式;1,回环模式;
		CAN1->BTR |= (tsjw<<24);     //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位
		CAN1->BTR |= (tbs2<<20);     //Tbs2=tbs2+1个时间单位
		CAN1->BTR |= (tbs1<<16);     //Tbs1=tbs1+1个时间单位
		CAN1->BTR |= (brp<<0);      //分频系数(Fdiv)为brp+1
												//波特率:Fpclk1/((Tbs1+Tbs2+1)*Fdiv)
		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); //过滤器0不激活
		CAN1->FS1R |= (1<<0);   //过滤器位宽为32位.
		CAN1->FM1R |= (0<<0);   //过滤器0工作在标识符屏蔽位模式
		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);    //过滤器组进入正常模式
		//使用中断接收
		CAN1->IER |= (1<<1);    //FIFO0消息挂号中断允许.        
//		MY_NVIC_Init(1,1,USB_LP_CAN1_RX0_IRQn,1);  //中断组设置
		return 0; //初始化成功
}

CAN过滤器初始化以及过滤器设置:

/****************************标准帧CAN过滤器初始化***********************************
* 函数名  : Filter_Init
* 描述    : 标准帧CAN过滤器初始化,只接收某一编号的标准帧
* 说明    : 
ID	    CAN_FxR1[31:24]		CAN_FxR1[23:16]	    CAN_FxR1[15:8]		CAN_FxR1[7:0]
屏蔽	CAN_FxR2[31:24]		CAN_FxR2[23:16]		CAN_FxR2[15:8]		CAN_FxR2[7:0]
映像	STID[10:3]	   STID[2:0] EXID[17:13]	EXID[12:5]	        EXID[4:0]   IDE	RTR	0
****************************************************************************/
void Filter_Init_Only(u8 number)	//编号值00~0F				0F为编号不成功	
{
		u32	net_num = 0;				//网络编号
		net_num	= number;
		CAN1->FMR |= (1<<0);    //过滤器组工作在初始化模式
		CAN1->FA1R &= ~(1<<0); 	//过滤器0不激活
		CAN1->FS1R |= (1<<0);   //过滤器位宽为32位.
		CAN1->FM1R |= (0<<0);   //过滤器0工作在标识符屏蔽位模式
		CAN1->FFA1R |= (0<<0);  //过滤器0关联到FIFO0
		CAN1->sFilterRegister[0].FR1=(0X00000000 | (net_num<<21)	);//32位ID//标识符
		CAN1->sFilterRegister[0].FR2=0X01E00000;//32位MASK//屏蔽位([24:21]即[ID3:ID0]为编号,用于网络节点标记)
		CAN1->FA1R |= (1<<0);   //激活过滤器0
		CAN1->FMR &= (0<<0);    //过滤器组进入正常模式

}

		//过滤器初始化
void Filter_Init(void)
{
		CAN1->FMR |= (1<<0);    //过滤器组工作在初始化模式
		CAN1->FA1R &= ~(1<<0); //过滤器0不激活
		CAN1->FS1R |= (1<<0);   //过滤器位宽为32位.
		CAN1->FM1R |= (0<<0);   //过滤器0工作在标识符屏蔽位模式
		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);    //过滤器组进入正常模式
}

 

CAN接收发送程序与中断函数:

//-------------------------------------------------------------------------
//接收数据
//fifox:邮箱号
//id:标准ID(11位)/扩展ID(11位+18位)        
//ide:0,标准帧;1,扩展帧
//rtr:0,数据帧;1,远程帧
//len:接收到的数据长度(固定为8个字节,在时间触发模式下,有效数据为6个字节)
//dat:数据缓存区
void Can_Rx_Msg(unsigned char fifox,unsigned long *id,unsigned char *ide,unsigned char *rtr,unsigned char *len,unsigned char *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=(CAN->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邮箱  
} 
 
 
 
 
 
 
//------------------------------------------------------------------------------------
 void can_tx_data_pack(void)  //can数据发送处理函数
{
    unsigned char buffer[10];
//    buffer[0]=can_id;
	buffer[0]=0x01;
	buffer[1]=0x02;
	buffer[2]=0x03;
	buffer[3]=0x04;
	buffer[4]=0x05;
	buffer[5]=0x06;
	buffer[6]=0x07;
	buffer[7]=0x08;
    //.....根据实际添加数据
//---------------------------------------------------------------------------------     
 Can_Send_Msg(buffer,8);//发送
}

//-------------------------------------------------------------------------
//can发送一组数据(固定格式:ID为can_tx_id,标准帧,数据帧)  
//len:数据长度(最大为8)                     
//msg:数据指针,最大为8个字节.
//返回值:0,成功;
//       其他,失败;
unsigned long can_tx_id = 0x00;
unsigned char Can_Send_Msg(unsigned char * msg,unsigned char len)
{   
    unsigned char mbox;
    unsigned short i=0;                                    
    mbox=Can_Tx_Msg(can_tx_id,0,0,len,msg);
    while((Can_Tx_Staus(mbox)!=0X07)&&(i<0XFFF))i++;//等待发送结束
    if(i>=0XFFF)return 1;               //发送失败
    return 0;                                       //发送成功
}   

//------------------------------------------------------------------------------------
//id:标准ID(11位)/扩展ID(11位+18位)        
//ide:0,标准帧;1,扩展帧
//rtr:0,数据帧;1,远程帧
//len:要发送的数据长度(固定为8个字节,在时间触发模式下,有效数据为6个字节)
//*dat:数据指针.
//返回值:0~3,邮箱编号.0XFF,无有效邮箱.
unsigned char Can_Tx_Msg(unsigned long id,unsigned char  ide,unsigned char rtr,unsigned char len,unsigned char *dat)
{      
    unsigned char 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;      
    CAN1->sTxMailBox[mbox].TIR|=ide<<2;   
    CAN1->sTxMailBox[mbox].TIR|=rtr<<1;
    len&=0X0F;//得到低四位
    CAN1->sTxMailBox[mbox].TDTR&=~(0X0000000F);
    CAN1->sTxMailBox[mbox].TDTR|=len;          //设置DLC.
    //待发送数据存入邮箱.
    CAN1->sTxMailBox[mbox].TDHR=(((unsigned long)dat[7]<<24)|
                                ((unsigned long)dat[6]<<16)|
                                ((unsigned long)dat[5]<<8)|
                                ((unsigned long)dat[4]));
    CAN1->sTxMailBox[mbox].TDLR=(((unsigned long)dat[3]<<24)|
                                ((unsigned long)dat[2]<<16)|
                                ((unsigned long)dat[1]<<8)|
                                ((unsigned long)dat[0]));
    CAN1->sTxMailBox[mbox].TIR|=1<<0; //请求发送邮箱数据
    return mbox;
}   
//------------------------------------------------------------------------- 
//获得发送状态.
//mbox:邮箱编号;
//返回值:发送状态. 0,挂起;0X05,发送失败;0X07,发送成功.
unsigned char Can_Tx_Staus(unsigned char mbox)
{   
    unsigned char sta=0;                        
    switch (mbox)
    {
        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中的报文个数.
unsigned char Can_Msg_Pend(unsigned char fifox)
{
    if(fifox==0)return CAN1->RF0R&0x03; 
    else if(fifox==1)return CAN1->RF1R&0x03; 
    else return 0;
}   
  

//-------------------------------------------------------------------------
//can口接收数据查询
//buf:数据缓存区;     
//返回值:0,无数据被收到;
//其他,接收的数据长度;
unsigned char Can_Receive_Msg(unsigned char *buf)
{                  
    unsigned long id;
    unsigned char ide,rtr,len; 
    if(Can_Msg_Pend(0)==0)return 0;         //没有接收到数据,直接退出   
    Can_Rx_Msg(0,&id,&ide,&rtr,&len,buf);   //读取数据
    if(id!=0x12||ide!=0||rtr!=0)len=0;      //接收错误     
    return len; 
}   
//-------------------------------------------------------------------------

//—-CAN接收中断服务函数 ———————————————————————
void USB_LP_CAN1_RX0_IRQHandler(void)
{
    unsigned char rxbuf[8];
    unsigned long id = 0;
    unsigned char ide,rtr,len;    
		u8 command = 0;
		u8 i;	
    Can_Rx_Msg(0,&id,&ide,&rtr,&len,rxbuf); //接收数据
		//fifox:邮箱号
		//id:标准ID(11位)/扩展ID(11位+18位)        
		//ide:0,标准帧;1,扩展帧
		//rtr:0,数据帧;1,远程帧
		//len:接收到的数据长度(固定为8个字节,在时间触发模式下,有效数据为6个字节)
		//dat:数据缓存区
}


//-------------------------------------------------------------------------
//can从机发送注册数据(固定格式:标准帧,数据帧)  
//len:数据长度(最大为8)                     
//msg:数据指针,最大为8个字节.
//can_slave_id:包含注册命令和编号
//返回值:0,成功;
//       其他,失败;
unsigned char Can_Send_Standard_data_frame(unsigned char * msg,unsigned char len,unsigned long can_slave_id)
{   
    unsigned char mbox;
    unsigned short i=0;                                    
    mbox=Can_Tx_Msg(can_slave_id,0,0,len,msg);			//(ID,标准帧,数据帧,长度,内容)
    while((Can_Tx_Staus(mbox)!=0X07)&&(i<0XFFF))i++;//等待发送结束
    if(i>=0XFFF)return 1;               //发送失败
    return 0;                                       //发送成功
}  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yiquhui666

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

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

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

打赏作者

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

抵扣说明:

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

余额充值