使用DSP28346与上位机进行CAN通信

tech2022-09-12  95

1.准备: DSP28346板子(DSP28335很相似,基本一样)、USB-CAN分析仪(只要能USB转CAN就可以,电子发烧友淘宝店有那种六合一的就可以,9.9包邮好像)、杜邦线; 2.搭建: 用杜邦线按下图所示连接USB-CAN和DSP28346板子,通过USB线连接PC和USB-CAN分析仪; 需要注意的是:USB-CAN需要与DSP板的数字地GND共地,直接短接即可]

3.代码实现 思路:1)配置GPIO、2)初始化eCAN模块,选择相应的模式,配置波特率、3)邮箱配置:我是用eCANb,邮箱15接收任何id的报文,邮箱16发送任何id的报文、4)写发送、接收函数

// TI File $Revision: /main/6 $ // Checkin $Date: August 19, 2008 14:09:24 $ //########################################################################### // // FILE: DSP2834x_ECan.c // // TITLE: DSP2834x Enhanced CAN Initialization & Support Functions. // //########################################################################### // $TI Release: 2834x Header Files V1.12 $ // $Release Date: March 2011 $ //########################################################################### #include "DSP2834x_Device.h" // DSP28 Headerfile Include File #include "DSP2834x_Examples.h" // DSP28 Examples Include File #include "DSP28x_Project.h" struct ECAN_REGS ECanaShadow; struct ECAN_REGS ECanbShadow; Uint32 ecan_data_h;//获取接收报文的数据,用于CANOpen解析 Uint32 ecan_data_l; //步骤一:ECana和ECanb模块的GPIO初始化设置 //******************************************************** //函数名称:InitECanbGpio() //函数功能:初始化ECanb模块的GPIO引脚,要根据硬件来设置 //******************************************************** void InitECanbGpio(void) { EALLOW; // GpioCtrlRegs.GPAPUD.bit.GPIO8 = 1; // Disable pull-up for GPIO8 (CANTXB) // GpioCtrlRegs.GPAPUD.bit.GPIO12 = 1; // Disable pull-up for GPIO12 (CANTXB) // GpioCtrlRegs.GPAPUD.bit.GPIO16 = 1; // Disable pull-up for GPIO16 (CANTXB) GpioCtrlRegs.GPAPUD.bit.GPIO20 = 1; // Disable pull-up for GPIO20 (CANTXB) // GpioCtrlRegs.GPAPUD.bit.GPIO10 = 0; // Enable pull-up for GPIO10 (CANRXB) // GpioCtrlRegs.GPAPUD.bit.GPIO13 = 0; // Enable pull-up for GPIO13 (CANRXB) // GpioCtrlRegs.GPAPUD.bit.GPIO17 = 0; // Enable pull-up for GPIO17 (CANRXB) GpioCtrlRegs.GPAPUD.bit.GPIO21 = 0; // Enable pull-up for GPIO21 (CANRXB) /* Set qualification for selected CAN pins to asynch only */ // Inputs are synchronized to SYSCLKOUT by default. // This will select asynch (no qualification) for the selected pins. // Comment out other unwanted lines. // GpioCtrlRegs.GPAQSEL1.bit.GPIO10 = 3; // Asynch qual for GPIO10 (CANRXB) // GpioCtrlRegs.GPAQSEL1.bit.GPIO13 = 3; // Asynch qual for GPIO13 (CANRXB) // GpioCtrlRegs.GPAQSEL2.bit.GPIO17 = 3; // Asynch qual for GPIO17 (CANRXB) GpioCtrlRegs.GPAQSEL2.bit.GPIO21 = 3; // Asynch qual for GPIO21 (CANRXB) /* Configure eCAN-B pins using GPIO regs*/ // This specifies which of the possible GPIO pins will be eCAN functional pins. // GpioCtrlRegs.GPAMUX1.bit.GPIO8 = 2; // Configure GPIO8 for CANTXB operation // GpioCtrlRegs.GPAMUX1.bit.GPIO12 = 2; // Configure GPIO12 for CANTXB operation // GpioCtrlRegs.GPAMUX2.bit.GPIO16 = 2; // Configure GPIO16 for CANTXB operation GpioCtrlRegs.GPAMUX2.bit.GPIO20 = 3; // Configure GPIO20 for CANTXB operation // GpioCtrlRegs.GPAMUX1.bit.GPIO10 = 2; // Configure GPIO10 for CANRXB operation // GpioCtrlRegs.GPAMUX1.bit.GPIO13 = 2; // Configure GPIO13 for CANRXB operation // GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 2; // Configure GPIO17 for CANRXB operation GpioCtrlRegs.GPAMUX2.bit.GPIO21 = 3; // Configure GPIO21 for CANRXB operation EDIS; } //步骤二:初始化eCANb模块 //*********************************************** //函数名称:InitECANb //函数功能:初始化ECanb模块:波特率 //注意事项:ECanb模块初始化并没有配置邮箱方向和MSGID //Author:Liuxiang 20191008 //*********************************************** void InitECANb() { struct ECAN_REGS ECanbShadow; EALLOW; //CANTX和CANRX引脚设定 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; ECanbShadow.CANMC.all = ECanbRegs.CANMC.all; ECanbShadow.CANMC.bit.SCB = 1; //选择为eCAN模式 ECanbRegs.CANMC.all = ECanbShadow.CANMC.all; //初始化消息控制寄存器 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; ECanbMboxes.MBOX15.MDH.all = 0x00000000; ECanbMboxes.MBOX15.MDL.all = 0x00000000; ECanbMboxes.MBOX16.MDH.all = 0x00000000; ECanbMboxes.MBOX16.MDL.all = 0x00000000; //清零消息确认寄存器、接收寄存器、中断0、中断1 ECanbRegs.CANTA.all = 0xFFFFFFFF; /* Clear all TAn bits */ ECanbRegs.CANRMP.all = 0xFFFFFFFF; /* Clear all RMPn bits */ ECanbRegs.CANGIF0.all = 0xFFFFFFFF; /* Clear all interrupt flag bits */ ECanbRegs.CANGIF1.all = 0xFFFFFFFF; //配置eCANb的波特率,500kbps=(SYSCLKOUT/2)/(BRP*位时间) //DSP28346的SYSCLKOUT为300MHz, DSP28335为150MHz, 此代码使用300MHz,BRP=BRPREG+1; //位时间 = (TSEG1REG + TSEG2REG)+3 //500kbps = (300000000 / 2) / ((9+1)*(10+2+3)) = ECanbShadow.CANMC.all = ECanbRegs.CANMC.all; ECanbShadow.CANMC.bit.CCR = 1 ; // Set CCR = 1 ECanbRegs.CANMC.all = ECanbShadow.CANMC.all; ECanbShadow.CANES.all = ECanbRegs.CANES.all; do { ECanbShadow.CANES.all = ECanbRegs.CANES.all; } while(ECanbShadow.CANES.bit.CCE != 1 ); // Wait for CCE bit to be cleared.. ECanbShadow.CANBTC.all = 0; 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 ; // Set CCR = 0 ECanbRegs.CANMC.all = ECanbShadow.CANMC.all; ECanbShadow.CANES.all = ECanbRegs.CANES.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; // Required before writing the MSGIDs EDIS; } //步骤三:配置ECana和ECanb模块的邮箱配置 //************************************************** //函数名称:InitECanbConfig //函数功能:配置ECana邮箱,邮箱方向配置、邮箱ID、接收中断配置等, // 使用邮箱15接收任何id的报文,使用邮箱16发送任何id的报文 //Author:Liuxiang 20191016 //************************************************** void InitECanbConfig(void) { struct ECAN_REGS ECanbShadow; InitECANb(); ECanbShadow.CANMD.all = ECanbRegs.CANMD.all; ECanbShadow.CANMD.all = 0x0000FFFF; //0~15接收 16~31发送 ECanbRegs.CANMD.all = ECanbShadow.CANMD.all; // 接收中断配置(0-15号邮箱) EALLOW; ECanbShadow.CANMIM.all = ECanbRegs.CANMIM.all; ECanbShadow.CANMIM.all = 0x0000FFFF;//使能中断邮箱0~15的中断; ECanbRegs.CANMIM.all = ECanbShadow.CANMIM.all; ECanbShadow.CANMIL.all = ECanbRegs.CANMIL.all; ECanbShadow.CANMIL.all = 0x0000FFFF;//将中断0~15连接至中断1; ECanbRegs.CANMIL.all = ECanbShadow.CANMIL.all; ECanbShadow.CANGIM.all = ECanbRegs.CANGIM.all; //ECanbShadow.CANGIM.all= 0x01;//中断0启用 ECanbShadow.CANGIM.all= 0x02;//中断1启用 ECanbRegs.CANGIM.all = ECanbShadow.CANGIM.all; EDIS; //配置15号邮箱可接收任何ID的报文, ECanbLAMRegs.LAM15.all=0xffffffff;//邮箱15的局部验收屏蔽寄存器置位可接收任何id的报文(全局验收屏蔽寄存器用于scc模式) ECanbMboxes.MBOX15.MSGID.all=0x40000000; //AME位为1使能验收屏蔽位 ECanbShadow.CANME.all = ECanbRegs.CANME.all; ECanbShadow.CANME.all = 0xffff;//使能0-15号接收邮箱, ECanbRegs.CANME.all = ECanbShadow.CANME.all; } //**********发送报文***************************************** //*********************************************** //函数名称:ECanbSend //函数功能:邮箱16发送函数,可以发送任何标准帧ID的报文 //输入参数:帧id、数据长度、数据 //Author:Liuxiang 20191016 //*********************************************** void ECanbSend(Uint16 CanId,Uint16 dlc,Uint32 data_l,Uint32 data_h) { struct ECAN_REGS ECanbShadow; //修改ID前要禁止邮箱才能往寄存器里面写值 ECanbShadow.CANME.all = ECanbRegs.CANME.all; ECanbShadow.CANME.all = 0; ECanbRegs.CANME.all = ECanbShadow.CANME.all; //输入要发送的报文id、数据、数据长度、是否是远程帧 ECanbMboxes.MBOX16.MSGID.all = ((CanId|0x10000000)<<18); // stand Identifier ECanbMboxes.MBOX16.MSGCTRL.bit.DLC=dlc; //消息控制R(是否是远程帧、数据长度) ECanbMboxes.MBOX16.MDH.all=data_h; ECanbMboxes.MBOX16.MDL.all=data_l; ECanbShadow.CANME.all=ECanbRegs.CANME.all; ECanbShadow.CANME.all=0xffffffff;//使能邮箱16 ECanbRegs.CANME.all=ECanbShadow.CANME.all; ECanbShadow.CANTRS.all=ECanbRegs.CANTRS.all; ECanbShadow.CANTRS.all = 0;//首先清零消息发送请求寄存器 ECanbShadow.CANTRS.bit.TRS16=1;//邮箱0请求发送 ECanbRegs.CANTRS.all=ECanbShadow.CANTRS.all; /* //方法一:等待邮箱发送并清除发送确认位,以保证下一帧报文可以正常发送 do { ECanbShadow.CANTA.all = ECanbRegs.CANTA.all; } while(ECanbShadow.CANTA.bit.TA16 == 0 ); // Wait for TA16 bit to be set.. ECanbShadow.CANTA.all = 0; ECanbShadow.CANTA.bit.TA16 = 1; // Clear TA16 ECanbRegs.CANTA.all = ECanbShadow.CANTA.all;*/ //方法二 while(ECanbRegs.CANTA.bit.TA16 != 1){} //等待邮箱0发送确认标志被置位 ECanbShadow.CANTA.all=ECanbRegs.CANTA.all; ECanbShadow.CANTA.bit.TA16=1; //写1清除,为同一个邮箱下一个传输,发送确认必须被清除 ECanbRegs.CANTA.all=ECanbShadow.CANTA.all; } //*********接收报文***************************************** //******************************************************** //函数名称:ECana_rx_isr() //函数功能:通过CANa0接收中断从CAN总线上接收相应的报文 //******************************************************** interrupt void ECana_rx_isr(void) { Uint16 idx = 0; Uint16 id,len; Uint32 dl,dh; Uint32 base = 0x01; volatile struct MBOX *mbox; ECanaShadow.CANRMP.all = ECanaRegs.CANRMP.all;//接收消息等待R for(idx=0;idx<16;idx++) { if(ECanaShadow.CANRMP.all&(base<<idx)) {//读取该位是知道当前哪一个邮箱收到数据 mbox = &ECanaMboxes.MBOX0 + idx; if(mbox->MSGID.bit.IDE == 1) { //IDE =1 收到的消息有扩展标识位 id =mbox->MSGID.all&0x1FFFFFFF; } else{ id = mbox->MSGID.bit.STDMSGID; } len = mbox->MSGCTRL.bit.DLC; dl = mbox->MDL.all; //ecan_data_l = dl; dh = mbox->MDH.all; //ecan_data_h = dh; //canReceive(id,len,dh, dl); }else if(ECanaShadow.CANRMP.all==0) break; } ECanaRegs.CANRMP.all = ECanaShadow.CANRMP.all; PieCtrlRegs.PIEACK.bit.ACK9 = 1; } //******************************************************** //函数名称:ECanb_rx_isr() //函数功能:通过CANb0接收中断从CAN总线上接收相应的报文 //Author:Suzhou //******************************************************** interrupt void ECanb_RX_Isr(void) { struct ECAN_REGS ECanbShadow; Uint16 id,len;//报文id,报文的数据长度 Uint32 dl,dh;//数据低位、高位 PieCtrlRegs.PIEACK.all = PIEACK_GROUP9; dl = ECanbMboxes.MBOX15.MDL.all; dh = ECanbMboxes.MBOX15.MDH.all; id = ECanbMboxes.MBOX15.MSGID.bit.STDMSGID; //只能识别标准帧的id ECanbShadow.CANGIF1.all = ECanbRegs.CANGIF1.all; ECanbShadow.CANGIF1.bit.GMIF1 = 1; //清除中断标志位 ECanbRegs.CANGIF1.all = ECanbShadow.CANGIF1.all; ECanbRegs.CANRMP.all = 0XFFFF; //清中断接收标志 } //=========================================================================== // End of file. //=========================================================================== main函数 #include "DSP28x_Project.h"//*我的这个头文件包含了很多头文件,大家自己copy的时候要确保自己的头文件正确,否则会出错* #include "stdio.h" //20190926解决了同一邮箱连续发送的问题(发送成功后先等待,再写1清除发送确认位,波特率500kbps) //20191008解决了不同邮箱连续发送的问题(位与&运算,在每次消息发送成功后对应邮箱的传输确认寄存器TAn写1清除) //20191009解决了CAN中断接收的问题(寄存器配置AAM=0、AME=1、接收中断配置、清零接收消息等待寄存器、使能接收邮箱) //20191016解决了邮箱16连续发送任何标准帧id报文的问题 //20191016解决了邮箱15接收任何标准帧id报文的问题 //20191021可实现电机控制子函数(发控制字后加延时、未计算传动比) void main() { //step1:系统初始化 InitSysCtrl(); //step2:初始化外设引脚 InitECanbGpio(); //清除所有中断,初始化PIE向量表 DINT; InitPieCtrl(); IER = 0x0000; IFR = 0x0000; InitPieVectTable(); //step3:初始化外设模块 InitECanbConfig(); //step4:指定中断服务函数地址 EALLOW; PieVectTable.ECAN1INTB = &ECanb_RX_Isr; EDIS; IER |= M_INT9; //canb EnableInterrupts();//使能总中断 PieCtrlRegs.PIEIER9.bit.INTx8 = 1; //ecanb rx EINT; // Enable Global interrupt INTM ERTM; // Enable Global realtime interrupt DBGM ECanbMboxes.MBOX15.MDH.all=0x00000000; ECanbMboxes.MBOX15.MDL.all=0x00000000; //发送一帧报文 ECanbSend(0x601,8,0x2f606000,0x01000000);//写入位置模式 }

在上位机中可以检测到DSP发送的CAN报文,包括id、数据长度、数据;

4.上位机发送ban报文给DSP 使用上位机发送一帧报文,id:602 数据:2B406000000000 上位机发送该帧报文后,在CCS>debug串口的寄存器观察窗口中可以看到DSP的邮箱15已经成功接收到该报文。 至此,验证了该程序可发送、接收CAN报文。希望对大家有所帮助。

备注:dsp28346ECAN模块实验的工程代码放在某度网盘里了,大家可以点击链接直接下载,在CCS添加工程使用,如有问题请在下方评论,作者会尽量第一时间回复。 某度网盘链接:链接:https://pan.baidu.com/s/13Ncky-Tnl8gqbAwJhEnOuQ 提取码:chgu

最新回复(0)