平衡車后續調試需要監控角度、加速度、速度等波形;思考了許久,之前學習Can驅動的時候自己寫了一個畫波形的上位機,這時候剛好能派得上場;軟件安裝和界面操作如下圖,先安裝軟件,在桌面上打開CanScope監控軟件,界面上運行模式選擇正常模式,點擊連接(連接失敗會提示),然后點擊啟動CAN,即可接收波形;操作界面上面還有發送CAN數據的界面,需要發數據給下位機可以通過該界面操作。
CAN用的是下面這個型號,上位機是基于該型號提供的驅動文件開發的,其他型號的CAN可能會連接不上;
F28035的CAN驅動程序是之前做項目一直沿用下來的,稍微修改了一下可以匹配上位機;使用時,只需要先用 InitCana()出始化,然后調用Can_Task()填充數據發送;
/******************************************************************************
* FILENAME : Bsp_Can.c
*
* PURPOSE : Can Initialization & Support Functions.
*
* Author: 電筆小新 Created on: 2025年9月12日
******************************************************************************/
#include "User_Include.h"
#include "Bsp_Can.h"
//==================================================================
// * Variables & Function_Defines
//==================================================================
Uint16 CAN_command0 = 0;
Uint16 CAN_command1 = 0;
CANFRAME CAN_TxBuf;
CANFRAME CAN_RxBuf;
int16 SinTabCnt = 0;
int16 CosTabCnt = 100;
const int16 SinCosTab[400]={
0, 64, 129, 193, 257, 321, 385, 449, 513, 577,
641, 704, 768, 831, 894, 956, 1019, 1081, 1143, 1204,
1266, 1327, 1387, 1448, 1508, 1567, 1627, 1686, 1744, 1802,
1860, 1917, 1973, 2029, 2085, 2140, 2195, 2249, 2302, 2355,
2408, 2459, 2510, 2561, 2611, 2660, 2709, 2757, 2804, 2850,
2896, 2941, 2986, 3030, 3072, 3115, 3156, 3197, 3236, 3276,
3314, 3351, 3388, 3423, 3458, 3492, 3526, 3558, 3589, 3620,
3650, 3678, 3706, 3733, 3759, 3784, 3808, 3832, 3854, 3875,
3896, 3915, 3933, 3951, 3967, 3983, 3997, 4011, 4023, 4035,
4046, 4055, 4064, 4071, 4078, 4083, 4088, 4091, 4094, 4095,
4096, 4095, 4094, 4091, 4088, 4083, 4078, 4071, 4064, 4055,
4046, 4035, 4023, 4011, 3997, 3983, 3967, 3951, 3933, 3915,
3896, 3875, 3854, 3832, 3808, 3784, 3759, 3733, 3706, 3678,
3650, 3620, 3589, 3558, 3526, 3492, 3458, 3423, 3388, 3351,
3314, 3276, 3236, 3197, 3156, 3115, 3072, 3030, 2986, 2941,
2896, 2850, 2804, 2757, 2709, 2660, 2611, 2561, 2510, 2459,
2408, 2355, 2302, 2249, 2195, 2140, 2085, 2029, 1973, 1917,
1860, 1802, 1744, 1686, 1627, 1567, 1508, 1448, 1387, 1327,
1266, 1204, 1143, 1081, 1019, 956, 894, 831, 768, 704,
641, 577, 513, 449, 385, 321, 257, 193, 129, 64,
0, -64, -129, -193, -257, -321, -385, -449, -513, -577,
-641, -704, -768, -831, -894, -956,-1019,-1081,-1143,-1204,
-1266,-1327,-1387,-1448,-1508,-1567,-1627,-1686,-1744,-1802,
-1860,-1917,-1973,-2029,-2085,-2140,-2195,-2249,-2302,-2355,
-2408,-2459,-2510,-2561,-2611,-2660,-2709,-2757,-2804,-2850,
-2896,-2941,-2986,-3030,-3072,-3115,-3156,-3197,-3236,-3276,
-3314,-3351,-3388,-3423,-3458,-3492,-3526,-3558,-3589,-3620,
-3650,-3678,-3706,-3733,-3759,-3784,-3808,-3832,-3854,-3875,
-3896,-3915,-3933,-3951,-3967,-3983,-3997,-4011,-4023,-4035,
-4046,-4055,-4064,-4071,-4078,-4083,-4088,-4091,-4094,-4095,
-4096,-4095,-4094,-4091,-4088,-4083,-4078,-4071,-4064,-4055,
-4046,-4035,-4023,-4011,-3997,-3983,-3967,-3951,-3933,-3915,
-3896,-3875,-3854,-3832,-3808,-3784,-3759,-3733,-3706,-3678,
-3650,-3620,-3589,-3558,-3526,-3492,-3458,-3423,-3388,-3351,
-3314,-3276,-3236,-3197,-3156,-3115,-3072,-3030,-2986,-2941,
-2896,-2850,-2804,-2757,-2709,-2660,-2611,-2561,-2510,-2459,
-2408,-2355,-2302,-2249,-2195,-2140,-2085,-2029,-1973,-1917,
-1860,-1802,-1744,-1686,-1627,-1567,-1508,-1448,-1387,-1327,
-1266,-1204,-1143,-1081,-1019, -956, -894, -831, -768, -704,
-641, -577, -513, -449, -385, -321, -257, -193, -129, -64,
};
//==================================================================
// * FUNCTION: SetGpio_Cana()
// *
// * PURPOSE : Initializes the GPIOs for CANa.
//==================================================================
//CAN的GPIO初始化
//這里采用GPIO30 GPIO31
//--------------------------------------------------------------------
void SetGpio_Cana(void)
{
EALLOW;
GpioCtrlRegs.GPAPUD.bit.GPIO30 = 0; // Enable pull-up for GPIO30 (CANRXA)
GpioCtrlRegs.GPAPUD.bit.GPIO31 = 0; // Enable pull-up for GPIO31 (CANTXA)
GpioCtrlRegs.GPAQSEL2.bit.GPIO30 = 3; // Asynch qual for GPIO30 (CANRXA)
//IO30 IO21配置為CAN外設引腳
GpioCtrlRegs.GPAMUX2.bit.GPIO30 = 1; // Configure GPIO30 for CANRXA operation
GpioCtrlRegs.GPAMUX2.bit.GPIO31 = 1; // Configure GPIO31 for CANTXA operation
EDIS;
}
//==================================================================
// * FUNCTION: SetERegs_Cana()
// *
// * PURPOSE : Initializes the Registers for CANa.
//==================================================================
void SetERegs_Cana(void) // Initialize eCAN-A module
{
/* Create a shadow register structure for the CAN control registers. This is
needed, since only 32-bit access is allowed to these registers. 16-bit access
to these registers could potentially corrupt the register contents or return
false data. */
struct ECAN_REGS ECanaShadow;
EALLOW; // EALLOW enables access to protected bits
/* Configure eCAN RX and TX pins for CAN operation using eCAN regs*/
ECanaShadow.CANTIOC.all = ECanaRegs.CANTIOC.all;
ECanaShadow.CANTIOC.bit.TXFUNC = 1;
ECanaRegs.CANTIOC.all = ECanaShadow.CANTIOC.all;
ECanaShadow.CANRIOC.all = ECanaRegs.CANRIOC.all;
ECanaShadow.CANRIOC.bit.RXFUNC = 1;
ECanaRegs.CANRIOC.all = ECanaShadow.CANRIOC.all;
/* Configure eCAN for HECC mode - (reqd to access mailboxes 16 thru 31) */
// HECC mode also enables time-stamping feature
ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
ECanaShadow.CANMC.bit.SCB = 1; //P35 Select eCAN mode.
ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;
/* Initialize all bits of 'Message Control Register' to zero */
// Some bits of MSGCTRL register come up in an unknown state. For proper operation,
// all bits (including reserved bits) of MSGCTRL must be initialized to zero
ECanaMboxes.MBOX0.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX1.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX2.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX3.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX4.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX5.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX6.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX7.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX8.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX9.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX10.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX11.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX12.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX13.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX14.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX15.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX16.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX17.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX18.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX19.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX20.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX21.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX22.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX23.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX24.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX25.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX26.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX27.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX28.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX29.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX30.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX31.MSGCTRL.all = 0x00000000;
// TAn, RMPn, GIFn bits are all zero upon reset and are cleared again
// as a matter of precaution.
ECanaRegs.CANTA.all = 0xFFFFFFFF; /* Clear all TAn bits */
ECanaRegs.CANRMP.all = 0xFFFFFFFF; /* Clear all RMPn bits */
ECanaRegs.CANGIF0.all = 0xFFFFFFFF; /* Clear all interrupt flag bits */
ECanaRegs.CANGIF1.all = 0xFFFFFFFF;
/* Configure bit timing parameters for eCANA*/
ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
ECanaShadow.CANMC.bit.CCR = 1 ; // Set CCR = 1
ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;
// Wait until the CPU has been granted permission to change the configuration registers
do
{
ECanaShadow.CANES.all = ECanaRegs.CANES.all;
} while(ECanaShadow.CANES.bit.CCE != 1 ); // Wait for CCE bit to be set..
ECanaShadow.CANBTC.all = 0;
//-------------------------自定義的配置------------------------------------------
//P47
/* The following block is only for 60 MHz SYSCLKOUT. (30 MHz CAN module clock Bit rate = 1 Mbps
See Note at end of file. */
//rate Bit =(SYSCLKOUT/2)/(BRP * Bit-time )
//BRP = BRPreg+1
//Bit-time = (TSEG1reg + 1) + (TSEG2reg+ 1) + 1
//配置TQ 和BRP ,
//方案一 TQ為10, 則TSEG1REG = 6, BRP = 5 ,為500K
//方案二,TQ為12,則TSEG1REG = 8, BRP = 4 ,為500K
//500KHz
ECanaShadow.CANBTC.bit.BRPREG = 5;
ECanaShadow.CANBTC.bit.TSEG2REG = 1;
ECanaShadow.CANBTC.bit.TSEG1REG = 6;
ECanaShadow.CANBTC.bit.SAM = 1;
ECanaRegs.CANBTC.all = ECanaShadow.CANBTC.all;
ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
ECanaShadow.CANMC.bit.CCR = 0; // Set CCR = 0
ECanaShadow.CANMC.bit.STM = 0; // 0: normal mode/1: self-test mode
ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;
// Wait until the CPU no longer has permission to change the configuration registers
do
{
ECanaShadow.CANES.all = ECanaRegs.CANES.all;
} while(ECanaShadow.CANES.bit.CCE != 0 ); // Wait for CCE bit to be cleared..
/* Disable all Mailboxes */
ECanaRegs.CANME.all = 0; // Required before writing the MSGIDs
EDIS;
}
/**********************************************************************
* FUNCION : SetMailbox_Cana()
* PURPOSE : Initializes the Mailboxes for Can.
//-----------------------------------------------
//配置發送、接收郵箱等操作
//數據區8個長度字節
//發送郵箱 1到6
//接收郵箱 16, ID為0x0A
//-----------------------------------------------
**********************************************************************/
void SetMailbox_Cana(void)
{
struct ECAN_REGS ECanaShadow;
EALLOW;
ECanaShadow.CANGAM.all = ECanaRegs.CANGAM.all;
ECanaShadow.CANGAM.bit.AMI=1; // Standard and extended frames can be received.
ECanaRegs.CANGAM.all = ECanaShadow.CANGAM.all;
EDIS;
//P59
//In standard identifier mode,if the IDE bit(MSGID.31) =0,the message identifier is storedin bits ID.28:18.
//IDE =0:The RECEIVED message had a standard identifier
//Auto answer mode bit. AAM =0 ; Normal transmit mode
//AME = 1 ;The corresponding acceptance mask is used
//MSGID.31=IDE; MSGID.30=AME; MSGID.29=AAM
// Mailboxs can be written to 16-bits or 32-bits at a time
// Mailboxes can be written to 16-bits or 32-bits at a time
// Write to the MSGID field of TRANSMIT mailboxes MBOX0 - 15
ECanaMboxes.MBOX0.MSGID.all = ( (TXCanId0_Std|0x10000000)<<18); // stand Identifier
ECanaMboxes.MBOX1.MSGID.all = ( (TXCanId1_Std|0x10000000)<<18); // stand Identifier
// Write to the MSGID field of RECEIVE mailboxes MBOX16 - 31
ECanaMboxes.MBOX16.MSGID.all = ((RXCanId0_Std|0x10000000)<<18); // stand Identifier
ECanaMboxes.MBOX17.MSGID.all = ((RXCanId1_Std|0x10000000)<<18); // stand Identifier
// Configure Mailboxes 0-15 as Tx, 16-31 as Rx
// Since this write is to the entire register (instead of a bit
// field) a shadow register is not required.
ECanaRegs.CANMD.all = 0xFFFF0000;
// Specify that 8 bits will be sent/received //8字節數據
ECanaMboxes.MBOX0.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX1.MSGCTRL.bit.DLC = 8;
////////////////////////////////////////////////////////////////////////////////////
EALLOW;
ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
ECanaShadow.CANMC.bit.DBO = 1;
ECanaShadow.CANMC.bit.SCB = 1;//Select eCAN mode
ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;
// Configure Mailboxes 0-15 as Tx, 16-31 as Rx
ECanaRegs.CANMD.all = 0xFFFF0000;
// Since this write is to the entire register (instead of a bit
// field) a shadow register is not required.
ECanaRegs.CANME.all = 0x00030003;
EDIS;
}
//==================================================================
// * FUNCTION: SetInterrupt_Cana()
// *
// * PURPOSE : Initializes the ISR for CANa.
//==================================================================
void SetInterrupt_Cana(void)
{
/* Create a shadow register structure for the CAN control registers. This is
needed, since only 32-bit access is allowed to these registers. 16-bit access
to these registers could potentially corrupt the register contents or return
false data. */
struct ECAN_REGS ECanaShadow;
EALLOW; // EALLOW enables access to protected bits
ECanaShadow.CANMIL.all = ECanaRegs.CANMIL.all;
ECanaShadow.CANMIL.all = 0xFFFFFFFF ; //P76, mailbox interrupts to level 1
ECanaRegs.CANMIL.all = ECanaShadow.CANMIL.all;
ECanaShadow.CANMIM.all = ECanaRegs.CANMIM.all;
ECanaShadow.CANMIM.all =0x00010000 ; //P48,相應的郵箱中斷使能位 Mailbox interrupt is enabled.
ECanaRegs.CANMIM.all = ECanaShadow.CANMIM.all;
//1-32號郵箱中斷在中斷線0上產生
ECanaShadow.CANMIL.all = ECanaRegs.CANMIL.all;
ECanaShadow.CANMIL.all = 0;
ECanaRegs.CANMIL.all = ECanaShadow.CANMIL.all;
//------------中斷配置步驟-----1
//中斷線0使能
ECanaShadow.CANGIM.all = ECanaRegs.CANGIM.all;
ECanaShadow.CANGIM.bit.I0EN = 1;
// ECanaShadow.CANGIM.bit.I1EN = 1;
ECanaRegs.CANGIM.all = ECanaShadow.CANGIM.all;
// TAn, RMPn, GIFn bits are all zero upon reset and are cleared again
// as a matter of precaution.
ECanaRegs.CANTA.all = 0xFFFFFFFF; /* Clear all TAn bits */
ECanaRegs.CANRMP.all = 0xFFFFFFFF; /* Clear all RMPn bits */
ECanaRegs.CANGIF0.all = 0xFFFFFFFF; /* Clear all interrupt flag bits */
ECanaRegs.CANGIF1.all = 0xFFFFFFFF;
//------------中斷配置步驟-----3
// Enable CAN in PIE
PieCtrlRegs.PIEIER9.bit.INTx5 = 1; // Enable INT 9.5 in the PIE
// PieCtrlRegs.PIEIER9.bit.INTx6 = 1; // Enable INT 9.6 in the PIE
//------------中斷配置步驟-----4
IER |= M_INT9; // Enable CPU Interrupt 9
EINT;
ERTM;
EDIS;
}
//==================================================================
// * FUNCTION: InitCana()
// *
// * PURPOSE : Initializes the Enhanced Can modules.
//==================================================================
void InitCana(void)
{
SetGpio_Cana();
SetERegs_Cana();
SetMailbox_Cana();
SetInterrupt_Cana();
}
//==================================================================
// * FUNCTION: sCanHdRead()
// *
// * PURPOSE : Read Can Data From Registers And Save Into Buffer.
//==================================================================
void sCanHdRead(const Uint8 ubMailBox,CANFRAME *pdata)
{
volatile struct MBOX *pMailbox;
pMailbox = &ECanaMboxes.MBOX0 + ubMailBox;
pdata->CanId.all = pMailbox->MSGID.all;
pdata->CanData0 = pMailbox->MDL.word.LOW_WORD;
pdata->CanData1 = pMailbox->MDL.word.HI_WORD;
pdata->CanData2 = pMailbox->MDH.word.LOW_WORD;
pdata->CanData3 = pMailbox->MDH.word.HI_WORD;
}
//==================================================================
// * FUNCTION: sCanHdSend()
// *
// * PURPOSE : Write Can Data Into Registers And Send.
//==================================================================
void sCanHdSend(const Uint8 ubMailBox,const CANFRAME *pdata)
{
struct ECAN_REGS ECanShadow;
volatile struct MBOX *pMailbox;
pMailbox = &ECanaMboxes.MBOX0 + ubMailBox;
/*step3: Load the message to the MSGID Registers of the object*/
pMailbox->MSGID.all= pdata->CanId.all;
/*step4: configure the data length*/
pMailbox->MSGCTRL.bit.DLC = 8;
/*step5: Write the message data to the mail box data field*/
pMailbox->MDL.word.LOW_WORD = pdata->CanData0;
pMailbox->MDL.word.HI_WORD = pdata->CanData1;
pMailbox->MDH.word.LOW_WORD = pdata->CanData2;
pMailbox->MDH.word.HI_WORD = pdata->CanData3;
/* Enable transmit mailbox*/
ECanShadow.CANME.all = ECanaRegs.CANME.all;
ECanShadow.CANME.all |= ((Uint32)1 << ubMailBox);
ECanaRegs.CANME.all = ECanShadow.CANME.all;
ECanShadow.CANTRS.all=0;
ECanShadow.CANTRS.all|= ((Uint32)1 << ubMailBox);
ECanaRegs.CANTRS.all= ECanShadow.CANTRS.all;
ECanShadow.CANTA.all = 0;
ECanShadow.CANTA.all |= ((Uint32)1 << ubMailBox); // Clear all TAn
ECanaRegs.CANTA.all=ECanShadow.CANTA.all;
}
//---------------------------------------------------------------------------
// Can_Task:
//---------------------------------------------------------------------------
void Can_Task(void)
{
SinTabCnt++;
if(SinTabCnt>399)
{
SinTabCnt=0;
}
CosTabCnt++;
if(CosTabCnt>399)
{
CosTabCnt=0;
}
CAN_TxBuf.CanId.all = ((TXCanId0_Std|0x10000000)<<18); // stand Identifier
CAN_TxBuf.CanData0 = SinCosTab[SinTabCnt];
CAN_TxBuf.CanData1 = SinCosTab[CosTabCnt];
CAN_TxBuf.CanData2 = 0x5432;
CAN_TxBuf.CanData3 = 0x9876;
sCanHdSend(0,&CAN_TxBuf);
}
//---------------------------------------------------------------------------
// INT_ISR for Ecana_RX
//---------------------------------------------------------------------------
//// INT9.5
interrupt void ECAN0INTA_ISR(void) // eCAN-A
{
struct ECAN_REGS ECanaShadow;
// Insert ISR Code here
ECanaShadow.CANRMP.all=ECanaRegs.CANRMP.all;
if(ECanaShadow.CANRMP.bit.RMP16==1)
{
ECanaShadow.CANRMP.bit.RMP16=1;
ECanaRegs.CANRMP.all=ECanaShadow.CANRMP.all;
sCanHdRead(16,&CAN_RxBuf);
}
PieCtrlRegs.PIEACK.all = PIEACK_GROUP9; // Must acknowledge the PIE group
}
//==================================================================
// End of file.
//==================================================================