一、CAN初始化流程
①接收发送引脚初始化;
②接收和发送邮箱设置;
③邮箱使能;
④波特率配置;
⑤接收掩码设置;
⑥中断配置。
二、几个重要的知识点
①影子寄存器
因为ECanbRegs是不可以单独对位操作,所以需要设置先将其指向影子寄存器,设置影子寄存器的值,然后再把影子寄存器的值指向ECanbRegs,我们可以看到初始化中都是这样的套路;
②CANMD、CANME、CANMC、CANGIM
好几个类似的结构体成员,简直了是不是。。。他们分别是用来设置邮箱接收(1为RX)、使能邮箱(1为使能)、波特率配置、中断配置相关的;
③中断设置
CANA和CANB的中断初始化是不同的,并且每一路CAN都有2路中断线,如果配置错了,就进不了中断。
从上面手册可知,如果你自己的板子电路只使用了CANB,那接受中断就只能使用TNT9.7(中断线0)、或者INT9.8(中断线1),配置为别的都会是错误的。
④发送设置
修改ID前要先禁止邮箱才能往寄存器里面写值,所以假如未禁止邮箱或者寄存器操作错误(我误把ECanbShadow.CANME.bit.ME16 = 0;写成ECanbRegs.CANME.bit.ME16 = 0;结果死活改不了ID),那就肯定达不到效果。
⑤接收设置
要想接收任意ID,只需要设置LAM和AME两个寄存器即可,ECanaMboxes.MBOX0.MSGID.bit.AME = 1;(启用筛选器,如果不启用就默认只能接收自己设置的ID)ECanaLAMRegs.LAM0.all = 0xFFFFFFFF;(接收任意ID)
注意,调试CAN中断接收时,每次烧录后最好把单片机重启,可能筛选ID寄存器未清空,那么即便设置对,也不能接收任意ID,我就遇到了,真坑!
好啦,上面的就是我调试过程中遇到的问题啦,完整代码见下方,有问题评论区讨论吧~
/*
* can.c
*
* Created on: 2023年12月12日
* Author: Cyber.
*/
#include "can.h"
interrupt void ISRECanbRx(void)
{
PieCtrlRegs.PIEACK.bit.ACK9 = 1;
Uint16 group;
Uint32 high; //用于存储接收邮箱的内容
Uint32 low; //用于存储接收邮箱的内容
Uint32 id;
volatile struct MBOX* Mailbox;
group = (ECanbRegs.CANGIF0.all)&0x3F; //判断是哪个接收邮箱触发的中断
Mailbox = &ECanbMboxes.MBOX0 + group; //取触发中断邮箱的地址
if(Mailbox->MSGID.bit.IDE == 1) { //IDE =1 收到的消息有扩展标识位
id =Mailbox->MSGID.all&0x1FFFFFFF;
} else{
id = Mailbox->MSGID.bit.STDMSGID;
}
switch(group) //我这里是把0-5号邮箱配置成了接收邮箱,所以下面case的取值是0-5
{
case 0:
LED1_TOGGLE;
low = Mailbox->MDL.all; //低32位
high = Mailbox->MDH.all; //高32位
break;
}
ECanbRegs.CANRMP.all = 0x0000003F; //清除GIF0.GMIF位,即中断标志位
}
void ECAN_Init(void)
{
struct ECAN_REGS ECanbShadow;
//配置引脚
InitECanbGpio();
//配置引脚用于CAN
EALLOW;
ECanbShadow.CANTIOC.all = ECanbRegs.CANTIOC.all;
ECanbShadow.CANTIOC.bit.TXFUNC = 1;
ECanbRegs.CANTIOC.all = ECanbShadow.CANTIOC.all;
ECanbShadow.CANRIOC.all = ECanbRegs.CANRIOC.all;
ECanbShadow.CANRIOC.bit.RXFUNC = 1;
ECanbRegs.CANRIOC.all = ECanbShadow.CANRIOC.all;
EDIS;
EALLOW;
ECanbShadow.CANMC.all = ECanbRegs.CANMC.all;
ECanbShadow.CANMC.bit.STM = 0; //退出测试模式
ECanbShadow.CANMC.bit.SCB = 1; // eCAN mode (reqd to access 32 mailboxes)
ECanbRegs.CANMC.all = ECanbShadow.CANMC.all;
EDIS;
//设置邮箱是接收还是发送
ECanbRegs.CANME.all = 0;//先禁用所有邮箱,后面会打开指定使用的邮箱
EALLOW;
ECanbShadow.CANMD.all = ECanbRegs.CANMD.all;
ECanbShadow.CANMD.bit.MD0 = 1; //Rx
ECanbShadow.CANMD.bit.MD16 = 0; //Tx
ECanbRegs.CANMD.all = ECanbShadow.CANMD.all;
//设置邮箱使能和禁用
ECanbShadow.CANME.all = ECanbRegs.CANME.all;
ECanbShadow.CANME.bit.ME0 = 1;
ECanbShadow.CANME.bit.ME16 = 1;
ECanbRegs.CANME.all = ECanbShadow.CANME.all;
EDIS;
//波特率设置
EALLOW;
ECanbShadow.CANMC.all = ECanbRegs.CANMC.all;
ECanbShadow.CANMC.bit.CCR = 1;
ECanbRegs.CANMC.all = ECanbShadow.CANMC.all;
EDIS;
do
{
ECanbShadow.CANES.all = ECanbRegs.CANES.all;
}while(ECanbShadow.CANES.bit.CCE != 1 );
EALLOW;
ECanbShadow.CANBTC.all = ECanbRegs.CANBTC.all;
ECanbShadow.CANBTC.bit.BRPREG = 9;
ECanbShadow.CANBTC.bit.TSEG2REG = 2 ;
ECanbShadow.CANBTC.bit.TSEG1REG = 10;
ECanbShadow.CANBTC.bit.SAM = 1;
ECanbRegs.CANBTC.all = ECanbShadow.CANBTC.all;
ECanbShadow.CANMC.all = ECanbRegs.CANMC.all;
ECanbShadow.CANMC.bit.CCR = 0;
ECanbRegs.CANMC.all = ECanbShadow.CANMC.all;
EDIS;
do
{
ECanbShadow.CANES.all = ECanbRegs.CANES.all;
} while(ECanbShadow.CANES.bit.CCE != 0 );
ECanbRegs.CANTA.all = 0xFFFFFFFF; //清除所有TA位
//这里是设置接收任意ID的功能
ECanbLAMRegs.LAM0.all=0xffffffff;//邮箱15的局部验收屏蔽寄存器置位可接收任何id的报文(全局验收屏蔽寄存器用于scc模式)
ECanbMboxes.MBOX0.MSGID.all=0x40000000; //AME位为1使能验收屏蔽位
//中断设置
EALLOW;
ECanbRegs.CANGIM.all = 0;
ECanbRegs.CANMIM.all = 0x003F; //使能上面的接收邮箱(0-5号邮箱)中断
ECanbRegs.CANMIL.all = 0;
ECanbShadow.CANGIM.all = ECanbRegs.CANGIM.all;
ECanbShadow.CANGIM.bit.I0EN = 1; //选择中断线0
ECanbRegs.CANGIM.all = ECanbShadow.CANGIM.all;
PieCtrlRegs.PIECTRL.bit.ENPIE=1;
PieCtrlRegs.PIEIER9.bit.INTx7=1; //9.7
PieVectTable.ECAN0INTB = &ISRECanbRx;
IER|=M_INT9;
EINT;
EDIS;
}
//注意邮箱编号需要根据实际修改
//CANB 发送函数 Can_Id为CAN_ID, length为CAN数据长度(单位是字节), Data_L为低四位字节,Data_H为高四位字节
void CanBSend(Uint32 Can_Id, char length, Uint32 Data_L, Uint32 Data_H)
{
struct ECAN_REGS ECanbShadow;
//修改ID前要禁止邮箱才能往寄存器里面写值
ECanbShadow.CANME.all = ECanbRegs.CANME.all;
ECanbShadow.CANME.bit.ME16 = 0;
ECanbRegs.CANME.all = ECanbShadow.CANME.all;
/* Write to the MSGID field */
ECanbMboxes.MBOX16.MSGID.all = Can_Id; // stand Identifier
//使能邮箱
ECanbShadow.CANME.all = ECanbRegs.CANME.all;
ECanbShadow.CANME.bit.ME16 = 1;
ECanbRegs.CANME.all = ECanbShadow.CANME.all;
/* Write to DLC field in Master Control reg */
ECanbMboxes.MBOX16.MSGCTRL.bit.DLC = length; //8;
/* Write to the mailbox RAM field */
ECanbMboxes.MBOX16.MDL.all =Data_L; //低位4字节
ECanbMboxes.MBOX16.MDH.all =Data_H ; //高位4字节
//struct ECAN_REGS ECanbShadow;
ECanbShadow.CANTRS.all = 0;
ECanbShadow.CANTRS.bit.TRS16 = 1; // Set TRS for mailbox under test
ECanbRegs.CANTRS.all = ECanbShadow.CANTRS.all;
do
{
ECanbShadow.CANTA.all = ECanbRegs.CANTA.all;
}while(ECanbShadow.CANTA.bit.TA16 == 0 ); // Wait for TA5 bit to be set..
ECanbShadow.CANTA.all = 0;
ECanbShadow.CANTA.bit.TA16 = 1; // Clear TA5
ECanbRegs.CANTA.all = ECanbShadow.CANTA.all;
}