stm32之CAN配置流程

一.CAN初始化(以初始化CAN1为例)

(注:几个参数)
tsjw:重新同步跳跃单元
tbs2:时间段2的时间单元
tbs1:时间段1的时间单元
brp:波特率分频器
mode:模式


1.使能相应的PORT时钟
RCC->APB2ENR |= 1 << 2; //使能PORTA时钟

2.配置端口输出模式

GPIOA->CRH &= 0xfff00fff;
GPIOA->CRH |= 0x000B8000;	//PA11 RX, pA12 TX推挽输出
GPIOA->ODR |= 3 << 11;

3.使能CAN时钟
RCC->APB1ENR |= 1 << 25; //使能CAN时钟 CAN使用的是APB1的时钟max:36M

4.配置MCR寄存器

CAN1->MCR = 0x0000;//退出睡眠模式,同时设置所有位为0
CAN1->MCR |= 1 << 0;//请求CAn进入初始化模式
while((CAN1->MSR & 1 << 0) == 0)
{
	i++;
	if(i >> 0);
	//进入初始化模式失败,此时可以写成函数进行返回值的判别确认是否初始化成功
}
CAN1->MCR |= 0 << 7; //非时间触发通信模式
CAN1->MCR |= 0 << 6;//软件自动离线管理
CAN1->MCR |= 0 << 5;//睡眠模式通过软件唤醒
CAN1->MCR |= 1 << 4;//禁止报文自动传送
CAN1->MCR |= 0 << 3;//报文不锁定,新的覆盖旧的
CAN1->MCR |= 0 << 2;//优先级由报文标识符决定

5.配置BTR寄存器

CAN1->BTR = 0x00000000; //清除原来的设置
CAN1->BTR |= mode << 30;//模式设置
CAN1->BTR |= tsjw << 24;//重新同步跳跃宽度为tsjw+1个时间单位
CAN1->BTR |= tbs2 << 20;//tbs2=tbs2+1个时间单位
CAN1->BTR |= tbs1 << 16;//
CAN1->BTR |= brp << 0;//分频系数(Fdiv)为brp+1 波特率:Fpclk/((tbs1 + tbs2 + 1) * Fdiv)

6.退出初始化模式

CAN1->MCR &= ~(0x01 << 0);//请求CAN退出初始化模式
while((CAN1->MSR & 1 << 0) == 1)
{
	i++;
	if(i > 0xfff0)return 3;//退出初始化模式失败
}

7.过滤器初始化

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[1].FR2 = 0x00000000;//32位MASK
CAN1->FA1R |= 1 << 0;//激活过滤器0
CAN1->FMR &= 0 << 0;//过滤器组进入正常模式

8.中断设置

#if CAN_RX0_INT_ENABLE
//使用终端接收
CAN1->IER |= 1<< 1; // FIFO0信息挂号终端允许
MY_NVIC_Init(1,0,USB_LP_CAN1_RX0_IRQn,2);
#endif

二.发送数据

(注:参数列表:id:标准ID或扩展ID;ide:0标准帧、1扩展帧;rtr:0数据帧、1远程帧;len:要发送的数据长度(固定为8个字节,在时间触发模式下,有效数据为6个字节);*dat:数据指针)


1.判断3个发送邮箱是否为空(确定发送邮箱编号)

if(CAN1->TSR & (1 << 26)) mbox=0;//邮箱0为空
else if(CAN1->TSR & (1 << 27)) mbox=1;
else if(CAN1->TSR & (1 << 28)) mbox=2;
else return 0xFF;//无空邮箱,无法发送

2.设置发送邮箱帧格式

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;//得到低4位
CAN1->sTxMailBox[mbox].TDTR &= ~(0x0000000f);
CAN1->sTxMailBox[mbox].TDTR |= len;

3.待发送数据存入邮箱。

CAN1->sTxMailBox[mbox].TDHR = (((unsigned int)dat[7] << 24)|((unsigned int)dat[6] << 16)| ((unsigned int)dat[5] << 8) | ((unsigned int)dat[4]));
CAN1->sTxMailBox[mbox].TDLR = (((unsigned int)dat[3] << 24) | ((unsigned int)dat[2] << 16) | ((unsigned int)dat[1] << 8) | ((unsigned int)dat[0]));
CAN1->sTxMailBox[mbox].TIR |= 1 << 0;//请求发送邮箱数据
return mbox;//返回邮箱编号,便于下面的判断是否发送成功

三.获得邮箱发送状态

返回0表示挂起,0x05发送失败,0x07发送成功

switch(mmbox)
{
	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;

四.得到已接收到的报文个数

if(fifox == 0)return CAN1->RF0R & 0x03;
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:数据缓存区)
1.得到数据帧格式

*ide = CAN1->sFIFOMailBox[fifox].RIR & 0x40;//得到标识符选择位的值
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].RCTR & 0x0f;//得到DLC

2.得到具体数据

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;

3.释放邮箱

if(fifox == 0) CAN1->RF0R |= 0x20;	//释放FIFO0邮箱
else if(fifox == 1) CAN1->RF1R |= 0x20;//释放FIFO1邮箱


下面,请将上述的发送,接收,判断发送,计数接收报文部分想成四个函数
CAN_Tx_Msg(id,ide,rtr,len,msg);
CAN_Rx_Msg(fifox,&id,&ide,&len,buf);
CAN_Yx_Status(mbox);
CAN_Msg_Pend(fifox);
接下来使用这四个函数整合成两个发送数据与接收数据的完整函数
1.send data

unsigned char CAN_Send_MSg(unsigned char *msg, unsigned char len)
{
	unsigned char mbox;
	unsigned short i = 0;
	mbox = CAN_Tx_Msg(0x12,0,0,len,msg);//自定义固定的ID格式
	while((CAN_Tx_Status(mbox) != 0x07) && (i < 0xffff)) i++; //等待发送结束
	if(i >= 0xfff) return 1;	//发送失败
	return 0;					//发送成功
}

2.receive data

unsigned char CAN_Receive_Msg(unsigned char *buf)
{
	unsigned int id;
	unsigned char ide, rtr, len;
	if(CAN_Msg_Pend(fifox) == 0) return 0;//没有接收到数据,直接退出
	CAN_Rx_Msg(0,&id,&ide,&rtr,&len,buf);//读取数据
	if(id != 0x12 || ide != 0 || rtr != 0) len = 0;//接收错误,由于这些参数的值是自定义的,
	return len;
}

你可能感兴趣的:(stm32之CAN配置流程)