CAN通信程序代码阅读总结

文章目录

    • 1. eCAN模块GPIO初始化
    • 2. 初始化eCanb模块:InitEcanb
    • 3. 主程序
    • 4. 中断服务子程序


1. eCAN模块GPIO初始化

void InitECanbGpio(void)
{
 EALLOW;//配置GPIO引脚工作在eCAN功能
   GpioCtrlRegs.GPAPUD.bit.GPIO16 = 1;   // Disable pull-up for GPIO16 (CANTXB)
   GpioCtrlRegs.GPAPUD.bit.GPIO17 = 0;   // Enable pull-up for GPIO17 (CANRXB)
   GpioCtrlRegs.GPAQSEL2.bit.GPIO17 = 3; // Asynch qual for GPIO17 (CANRXB)
   GpioCtrlRegs.GPAMUX2.bit.GPIO16 = 2;  // Configure GPIO16 for CANTXB operation
   GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 2;  // Configure GPIO17 for CANRXB operation
  EDIS;
}

    使用到的寄存器如下所示:
CAN通信程序代码阅读总结_第1张图片
    上拉输入的好处是减小了电流,输入的电平不会上下浮动而导致输入信号不稳定,在没有信号输入的情况下可以稳定在高电平。
CAN通信程序代码阅读总结_第2张图片
CAN通信程序代码阅读总结_第3张图片
总结:

  1. 使能接收引脚上拉,禁用发送引脚上拉;
  2. 设置接收引脚为异步模式;
  3. 设置GPIO引脚为CAN接收、输出引脚。

2. 初始化eCanb模块:InitEcanb

	EALLOW;       //配置eCAN的RX和TX分别为eCAN的接收和发送引脚
    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;

    涉及的寄存器如下:
CAN通信程序代码阅读总结_第4张图片
CAN通信程序代码阅读总结_第5张图片

EALLOW;
    ECanbShadow.CANMC.all = ECanbRegs.CANMC.all;
    ECanbShadow.CANMC.bit.STM = 0;//非自测模式
    ECanbShadow.CANMC.bit.SCB = 1;//eCAN模式
    ECanbRegs.CANMC.all = ECanbShadow.CANMC.all;
    EDIS;

CAN通信程序代码阅读总结_第6张图片
CAN通信程序代码阅读总结_第7张图片

//初始化所有主设备控制区域为0,MCF所有的位都初始化为0 
    ECanbMboxes.MBOX0.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX1.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX2.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX3.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX4.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX5.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX6.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX7.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX8.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX9.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX10.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX11.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX12.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX13.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX14.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX15.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX16.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX17.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX18.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX19.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX20.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX21.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX22.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX23.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX24.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX25.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX26.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX27.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX28.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX29.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX30.MSGCTRL.all = 0x00000000;
    ECanbMboxes.MBOX31.MSGCTRL.all = 0x00000000;

    接下来进行的是相关寄存器的置位工作,包括邮箱发送和接收相关、中断标志位置位,并请求对SCC模式下的CANBTC寄存器进行设置。

EALLOW;
    ECanbShadow.CANTA.all = ECanbRegs.CANTA.all;
    ECanbShadow.CANTA.all = 0xFFFFFFFF;
    ECanbRegs.CANTA.all = ECanbShadow.CANTA.all;

    ECanbShadow.CANRMP.all = ECanbRegs.CANRMP.all;
    ECanbShadow.CANRMP.all = 0xFFFFFFFF;
    ECanbRegs.CANRMP.all = ECanbShadow.CANRMP.all;


//添加

    ECanbShadow.CANGIF0.all = ECanbRegs.CANGIF0.all;
    ECanbShadow.CANGIF0.all = 0xFFFFFFFF;
    ECanbRegs.CANGIF0.all = ECanbShadow.CANGIF0.all;

//添加
    ECanbShadow.CANGIF1.all = ECanbRegs.CANGIF1.all;
    ECanbShadow.CANGIF1.all = 0xFFFFFFFF;
    ECanbRegs.CANGIF1.all = ECanbShadow.CANGIF1.all;


/* Configure bit timing parameters for eCANB*/

    ECanbShadow.CANMC.all = ECanbRegs.CANMC.all;
    ECanbShadow.CANMC.bit.CCR = 1 ;            // Set CCR = 1
    ECanbRegs.CANMC.all = ECanbShadow.CANMC.all;   

    CANME寄存器的CCE为被置位后,可以进行波特率的设置了。

do 
    {ECanbShadow.CANES.all=ECanbRegs.CANES.all;}
    while(ECanbShadow.CANES.bit.CCE != 1 ) ;    // Wait for CCE bit to be set..


    ECanbShadow.CANBTC.all = ECanbRegs.CANBTC.all;  //添加
    ECanbShadow.CANBTC.all = 0;
    ECanbShadow.CANBTC.bit.BRPREG = 9;
    /*  TQ=1/(SYSCLKOUT/4)×(BRPREG+1) */
    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 ;            // Set CCR = 0
    ECanbRegs.CANMC.all = ECanbShadow.CANMC.all;


    do
    {
      ECanbShadow.CANES.all = ECanbRegs.CANES.all;
    } while(ECanbShadow.CANES.bit.CCE != 0 );       // Wait for CCE bit to be  cleared..

    对邮箱的相应配置进行设置。

ECanbRegs.CANME.all = 0;//屏蔽所有邮箱,在写MSGID之前必须要做

	EDIS;
	ECanbMboxes.MBOX0.MSGID.bit.IDE = 0;//标准帧格式
	...
	ECanbMboxes.MBOX31.MSGID.bit.IDE = 0;

	ECanbMboxes.MBOX0.MSGCTRL.bit.DLC = 8;//数据长度8个字节
	...
	ECanbMboxes.MBOX31.MSGCTRL.bit.DLC = 8;//数据长度8个字节

	ECanbMboxes.MBOX0.MSGCTRL.bit.TPL = 0;//设置优先级
	...
	ECanbMboxes.MBOX31.MSGCTRL.bit.TPL = 31;//设置优先级

	ECanbMboxes.MBOX0.MSGCTRL.bit.RTR = 0;//没有远程帧请求
	...
	ECanbMboxes.MBOX31.MSGCTRL.bit.RTR = 0;//没有远程帧请求

	EALLOW;
	EALLOW;
	ECanbRegs.CANMIM.all = 0xFFFFFFFE;
	//邮箱中断将产生在ECAN0INT
	ECanbRegs.CANMIL.all = 0;
	ECanbRegs.CANGIF0.all = 0xFFFFFFFF;
	ECanbRegs.CANGIF1.all = 0xFFFFFFFF;
	//ECAN0INT中断请求线被使能
	ECanbRegs.CANGIM.bit.I0EN = 1;

    EDIS;

总结:

  1. 配置接收和发送引脚;
  2. 配置eCAN模块在eCAN模式;
  3. 邮箱控制寄存器全部置位,邮箱接收和发送相关标志位置位,请求设置波特率等数据;
  4. 设置波特率等数据;
  5. 对邮箱进行配置,如格式、数据长度、优先级等;
  6. 设置eCAN模块的中断。

3. 主程序

    先要对中断向量进行配置,这里要查看中断向量表,查看ECAN0INTB中断是在哪一条中断线上,又是这条中断线上的第几个中断向量。

EALLOW;
	PieVectTable.TINT0 = &ISRTimer0;//计时器中断向量
	PieVectTable.ECAN0INTB = &ISRCanb;//eCAN模块中断向量
	EDIS;

	PieCtrlRegs.PIECTRL.bit.ENPIE = 1;//所有向量取自PIE向量表
	PieCtrlRegs.PIEIER1.bit.INTx5 = 1;//XINT2
	PieCtrlRegs.PIEIER1.bit.INTx7 = 1;//TINT0
	PieCtrlRegs.PIEIER9.bit.INTx7 = 1;//ECAN0INTB

	IER |= M_INT9;//中断9使能
	IER |= M_INT1;//中断1使能
	IER |= M_INT14;//中断14使能

	EINT;//使能全局中断
	ERTM;//使能实时中断

    接下来要设置接收邮箱和发送邮箱。

    MSGb_Init(0,0,0x0601);		//cana mail 0 send  电机1
	MSGb_Init(1,1,0x0581);		//cana mail 1 resive

	MSGb_Init(2,0,0x0602);		//cana mail 2 send  电机2
	MSGb_Init(3,1,0x0582);		//cana mail 3 resive  电机2

	MSGb_Init(4,0,0x0080);      //cana mail 4 send  发送同步帧

	MSGb_Init(5,0,0x0203);		//cana mail 5 send  发送数字量邮箱
	MSGb_Init(6,0,0x0303);		//cana mail 6 send  发送模拟量邮箱

	MSGb_Init(7,0,0x0403);		//cana mail 7 send  发送模拟量邮箱

	MSGb_Init(8,1,0x0183);      //cana mail 8 resive
	MSGb_Init(9,1,0x0283);		//cana mail 9 resive
	MSGb_Init(10,1,0x0383);		//cana mail 10 resive
	MSGb_Init(11,1,0x0483);		//cana mail 11 resive

	MSGb_Init(12,0,0x0000);     //启动所有节点
	MSGb_Init(13,0,0x0603);     //配置周期发送

    我们需要看一下MSGb_Init函数是怎么配置邮箱的。

void MSGb_Init(Uint16 msgnum,Uint16 dir,Uint32 id)
{
    struct ECAN_REGS ECanbShadow;
    switch (msgnum)
	{
	  case 0:
			    ECanbShadow.CANMD.all = ECanbRegs.CANMD.all;
				ECanbShadow.CANMD.bit.MD0 = dir;  //邮箱0设置为发送
				ECanbRegs.CANMD.all = ECanbShadow.CANMD.all;
				if(dir==1)
				{
					ECanbMboxes.MBOX0.MSGID.bit.AME=1;//接收屏蔽
			   	}
	  			ECanbMboxes.MBOX0.MSGID.all = (id << 18);
	        	ECanbShadow.CANME.all = ECanbRegs.CANME.all;
	        	ECanbShadow.CANME.bit.ME0 = 1;//使能
	        	ECanbRegs.CANME.all = ECanbShadow.CANME.all;
	            break;
	            ......

CAN通信程序代码阅读总结_第8张图片
    当我们定义的接收邮箱收到信息后,就会触发邮箱中断,转而去执行中断子程序,中断路线如下。
CAN通信程序代码阅读总结_第9张图片
    根据之前的初始化工作,我们知道当邮箱1或邮箱3收到信息后,就会将其RMP为置1,即触发中断邮箱接收中断,同时若CANMIM和CANMIL寄存器对应位都被使能,则会通过CANGIM寄存器将所有中断映射到ECAN0INT中断线上。

4. 中断服务子程序

interrupt void ISRCanb(void)
{
    switch(ECanbRegs.CANRMP.all)//如果收到消息,CANRMP将有位被置1
   	{
   		......
		case 0x00000002://1
		ECanbRegs.CANRMP.all=0xffffffff;//清除接收完成标志
		L[1] = ECanbMboxes.MBOX1.MDL.all;
		H[1] = ECanbMboxes.MBOX1.MDH.all;
		if(L[1] == 0x436C6000)
		{
			HisBuffer_v1[0] = 0x05;
			HisBuffer_v1[1] = 0x81;
			HisBuffer_v1[2] = (L[1] >> 24) & 0xff;
			HisBuffer_v1[3] = (L[1] >> 16) & 0xff;
			HisBuffer_v1[4] = (L[1] >> 8) & 0xff;
			HisBuffer_v1[5] = L[1] & 0xff;
			HisBuffer_v1[6] = H[1] & 0xff;
			HisBuffer_v1[7] = (H[1] >> 8) & 0xff;
			HisBuffer_v1[8] = (H[1] >> 16) & 0xff;
			HisBuffer_v1[9] = (H[1] >> 24) & 0xff;
			flag_send_v1 = 1;
		}
		break;

		case 0x00000004:    //2
		ECanbRegs.CANRMP.all=0xffffffff;
		L[2] = ECanbMboxes.MBOX2.MDL.all;
		H[2]= ECanbMboxes.MBOX2.MDH.all;
		break;

		case 0x00000008:   //3                     电机2
		ECanbRegs.CANRMP.all=0xffffffff;//清除接收完成标志
		L[3] = ECanbMboxes.MBOX3.MDL.all;
		H[3] = ECanbMboxes.MBOX3.MDH.all;
		if(L[3] == 0x436C6000)
		{
			HisBuffer_v2[0] = 0x05;
			HisBuffer_v2[1] = 0x82;
			HisBuffer_v2[2] = (L[3] >> 24) & 0xff;
			HisBuffer_v2[3] = (L[3] >> 16) & 0xff;
			HisBuffer_v2[4] = (L[3] >> 8) & 0xff;
			HisBuffer_v2[5] = L[3] & 0xff;
			HisBuffer_v2[6] = H[3] & 0xff;
			HisBuffer_v2[7] = (H[3] >> 8) & 0xff;
			HisBuffer_v2[8] = (H[3] >> 16) & 0xff;
			HisBuffer_v2[9] = (H[3] >> 24) & 0xff;
			flag_send_v2 = 1;
		}
		break;
		......

    由程序可以发现,当任意RMP位被置位后,就会进入中断,而我们使能的接收邮箱是邮箱1和邮箱3,那么其对应RMP位被置位,就会进入对应的程序段。我们所要做的是将接收到的数据重新进行处理,写入数组HisBuffer中,然后将以太网发送标志置1,再通过以太网发送出去。以太网通信是后续我们需要讨论的了。

你可能感兴趣的:(DSP学习,dsp开发,嵌入式,单片机,CAN,中断)