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