Everyone:
I am learning the CAN module.This is my program.When it is debugged, the flag about sending data doesn't be equal to be 1,so it can't be sent successfully.
main.c:
CANInit(CAN module be initialized)
uint8 CANInit(uint8 CANChannel,uint32 baudrateKHz,uint8 selfLoop,uint8 idMask)
{
int8 i;
CAN_MemMapPtr CANBaseAdd;
//使能FlexCAN外部时钟
OSC0_CR |= OSC_CR_ERCLKEN_MASK | OSC_CR_EREFSTEN_MASK;//*晶振提供外部时钟
//通过模块号选择模块基地址
if(CANChannel == 0)
CANBaseAdd = CAN0_BASE_PTR;
else if(CANChannel == 1)
CANBaseAdd = CAN1_BASE_PTR;
//使能CAN模块时钟
if(CANBaseAdd == CAN0_BASE_PTR)
SIM_SCGC6 |= SIM_SCGC6_FLEXCAN0_MASK;//使能CAN0的时钟模块
else
SIM_SCGC3 |= SIM_SCGC3_FLEXCAN1_MASK;//使能CAN1的时钟模块
/*
//使能CAN中断
if(CANChannel == 0)//使能CAN0的中断
{
NVICICPR0 = (NVICICPR0 & ~(0x07<<29)) | (0x07<<29);//清除挂载在FlexCAN0的中断
NVICISER0 = (NVICISER0 & ~(0x07<<29)) | (0x07<<29);//使能FlexCAN0中断
NVICICPR1 = (NVICICPR1 & ~(0x1F<<0)) | (0x1F);//清除挂载在FlexCAN0的中断
NVICISER1 = (NVICISER1 & ~(0x1F<<0)) | (0x1F);//使能FlexCAN0中断
}
else //使能CAN1的中断
{
NVICICPR1 = (NVICICPR1 & ~(0xFF<<5)) | (0xFF<<5);//清除挂载在FlexCAN1的中断
NVICISER1 = (NVICISER1 & ~(0xFF<<5)) | (0xFF<<5);//使能FlexCAN1中断
}
*/
//配置CAN_RX/TX复用引脚功能
if(CANChannel == 0)
{
PORTE_PCR24 = PORT_PCR_MUX(2) | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK; //上拉 *PORT PCR寄存器的设置
PORTE_PCR25 = PORT_PCR_MUX(2) | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK; //上拉
}
else
{
PORTC_PCR17 = PORT_PCR_MUX(2) | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK; //Tx上拉
PORTC_PCR16 = PORT_PCR_MUX(2) | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK; //Rx上拉
}
//选择时钟源,外设时钟48MHz,内部时钟:12MHz
CAN_CTRL1_REG(CANBaseAdd) |= CAN_CTRL1_CLKSRC_MASK;//选择内部时钟
// CAN_CTRL1_REG(CANBaseAdd) &=~CAN_CTRL1_CLKSRC_MASK;//应该是外部时钟源吧?
CAN_MCR_REG(CANBaseAdd) |= CAN_MCR_FRZ_MASK; //使能冻结模式
CAN_MCR_REG(CANBaseAdd) &= ~CAN_MCR_MDIS_MASK;//使能CAN模块
//确认已退出冻结模式
while((CAN_MCR_LPMACK_MASK & CAN_MCR_REG(CANBaseAdd)));
//软件复位
CAN_MCR_REG(CANBaseAdd) ^= CAN_MCR_SOFTRST_MASK;
//等待复位完成
while(CAN_MCR_SOFTRST_MASK & CAN_MCR_REG(CANBaseAdd));
//等待进入冻结模式
while(!(CAN_MCR_FRZACK_MASK & CAN_MCR_REG(CANBaseAdd)));
// Set local priority
CAN_MCR_REG(CANBaseAdd)|=CAN_MCR_LPRIOEN_MASK;
//将16个邮箱缓冲区内容清0
for(i=0;i<16;i++)
{
CANBaseAdd->MB[i].CS = 0x00000000;
CANBaseAdd->MB[i].ID = 0x00000000;
CANBaseAdd->MB[i].WORD0 = 0x00000000;
CANBaseAdd->MB[i].WORD1 = 0x00000000;
}
//接收邮箱过滤IDE比较,RTR不比较
CAN_CTRL2_REG(CANBaseAdd) &= ~CAN_CTRL2_EACEN_MASK;//0 Rx Mailbox filter’s IDE bit is always compared and RTR is never compared despite mask bits.
//远程请求帧产生
CAN_CTRL2_REG(CANBaseAdd) &= ~CAN_CTRL2_RRS_MASK; //0 Remote Response Frame is generated.
//邮箱首先从接收FIFO队列匹配然后再在邮箱中匹配
CAN_CTRL2_REG(CANBaseAdd) &= ~CAN_CTRL2_MRP_MASK;//0 Matching starts from Rx FIFO and continues on Mailboxes
//使用一个32位过滤器
CAN_MCR_REG(CANBaseAdd) |= (CAN_MCR_REG(CANBaseAdd) & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0);
//设置波特率
if(SetCANBand(CANChannel,baudrateKHz) == 1)//若设置错误
return 1;
//模式选择:回环模式或正常模式
//采用正常模式,即注释以下程序
// if(1==selfLoop)
// CAN_CTRL1_REG(CANBaseAdd) |= CAN_CTRL1_LPB_MASK;//使用回环模式
//初始化掩码寄存器
if(1==idMask)//屏蔽ID
{
CAN_RXMGMASK_REG(CANBaseAdd) = 0x1FFFFFFF;
CAN_RX14MASK_REG(CANBaseAdd) = 0x1FFFFFFF;
CAN_RX15MASK_REG(CANBaseAdd) = 0x1FFFFFFF;
}
else//不屏蔽ID
{
CAN_RXMGMASK_REG(CANBaseAdd) = 0x0;
CAN_RX14MASK_REG(CANBaseAdd) = 0x0;
CAN_RX15MASK_REG(CANBaseAdd) = 0x0;
}
//如果单独掩码功能使能,为每个队列初始化单独的掩码寄存器
if(CAN_MCR_REG(CANBaseAdd) & CAN_MCR_IRMQ_MASK)
{
for(i = 0; i < NUMBER_OF_MB ; i++)
{
CANBaseAdd->RXIMR[i] = 0x1FFFFFFFL;
}
}
//只有在冻结模式下才能配置,配置完推出冻结模式
CAN_MCR_REG(CANBaseAdd) &= ~(CAN_MCR_HALT_MASK);
//等待直到退出冻结模式
while( CAN_MCR_REG(CANBaseAdd) & CAN_MCR_FRZACK_MASK);
//等到不在冻结模式,休眠模式或者停止模式
while((CAN_MCR_REG(CANBaseAdd) & CAN_MCR_NOTRDY_MASK));
return 0;
}
CANSendData(Send Data)
uint8 CANSendData(uint8 CANChannel,uint16 iMB, uint32 id,uint8 length,uint8 Data[])
{
int16 i,wno,bno;
uint32 word[2] = {0};
CAN_MemMapPtr CANBaseAdd;
if(CANChannel == 0)
CANBaseAdd = CAN0_BASE_PTR;
else if(CANChannel == 1)
CANBaseAdd = CAN1_BASE_PTR;
//缓冲区和数据长度设置错误
if(iMB >= NUMBER_OF_MB || length >8)
return 1; //超出范围
//转换8个字节转换成32位的word存储
wno = (length-1)>>2;//是否超过4字节
bno = (length-1)%4; //
if(wno > 0) //长度大于4(即发送数据超过4字节)
{
word[0] = (
(Data[0]<<24)
| (Data[1]<<16)
| (Data[2]<< 8)
| Data[3]
);
}
for(i=0;i<=bno;i++)
word[wno] |= Data[(wno<<2)+i] << (24-(i<<3));
///////////////////////////////////////////////////////
// ID 格式
// B31 30 29 28 27 26 ... 11 10 9 8 7 6 5 4 3 2 1 0
// | | | |
// | | |------------------------------------|
// | | |--> 29 位 ID
// | |
// | |--> RTR 1: 远程帧, 0: 数据帧
// |
// |-------> IDE 1 : 扩展ID, 0: 标准ID
///////////////////////////////////////////////////////
//通过id判断帧类型——扩展帧
wno = (id & CAN_MSG_IDE_MASK)>>CAN_MSG_IDE_BIT_NO; //IDE
//通过id判断帧类型——远程帧
bno = (id & CAN_MSG_TYPE_MASK)>>CAN_MSG_TYPE_BIT_NO;//RTR
//获得ID位数
i = wno? 0: FLEXCAN_MB_ID_STD_BIT_NO;
//以下四步骤为发送过程
CANBaseAdd->MB[iMB].CS = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_INACTIVE)//缓冲区写激活代码
| (wno<<FLEXCAN_MB_CS_IDE_BIT_NO)//缓冲区写IDE位
| (bno<<FLEXCAN_MB_CS_RTR_BIT_NO)//缓冲区写RTR位
| FLEXCAN_MB_CS_LENGTH(length); //缓冲区写数据长度
//缓冲区写ID
CANBaseAdd->MB[iMB].ID = (1 << FLEXCAN_MB_ID_PRIO_BIT_NO) //传输的优先级
| ((id & ~(CAN_MSG_IDE_MASK|CAN_MSG_TYPE_MASK))<<i);
//缓冲区写内容
CANBaseAdd->MB[iMB].WORD0 = word[0];
CANBaseAdd->MB[iMB].WORD1 = word[1];
//延迟
for(i = 0;i < 100;i++);
//通过制定的发送代码开始发送
CANBaseAdd->MB[iMB].CS = (CANBaseAdd->MB[iMB].CS & ~(FLEXCAN_MB_CS_CODE_MASK))
| FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_ONCE);//写激活代码
//限时等待发送完成(如果使用中断则限时等待语句可删除)
i=0;
GPIOA_PTOR|=GPIO_PDOR_PDO(GPIO_PIN(29));//指示灯的亮、暗状态切换
while(!(CANBaseAdd->IFLAG1 & (1<<iMB)))
{
if((i++)>0x1000)
return 1;
}
//清报文缓冲区中断标志
CANBaseAdd->IFLAG1 = (1<<iMB);
GPIOA_PTOR&=~GPIO_PDOR_PDO(GPIO_PIN(28));//指示灯的亮、暗状态切换
return 0;
}
Hi Minmin Zhengzheng,
I recommend you refer to the "Typical Usage" of CAN_LDD in KDS3.2 ide , you can find them at here:
Hope it help! Have a nice day.
Best Regards,
Robin
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
----------------------------------------------------------------------------------------------------------------------
Yes. You can use it.
The usage of CAN_LDD is the same. You can create a Processor Expert project and refer that example.
Below information may help you know about the Processor Expert.
video
Processor Expert What You Need to Know
Processor Expert® Code Model (CodeWarrior®) - Code Walkthrough
document:
飞思卡尔单片机快速上手指南 6.2.3 处理器专家(PE)的使用
It's difficult for me to learn the Processor Expert. I am a beginner. The teacher told me to use the CAN module to transimit data immediately instead of learning others. So I program the CAN procedure by myself according to other demo in Codewarrior10.7.Can you help me figure out my program?
Hi Minmim
In case of difficulties you can also use the uTasker Open Source project for K60F120 and dual-CAN.
Documented at http://www.utasker.com/docs/uTasker/uTaskerCAN.PDF
Video at https://youtu.be/Ha8cv_XEvco
IDE-independent and requires no code generators or porting.
If you are new to CAN also beware that you need another active node on the CAN bus to correctly send messages - also ensure correct bus terminations.
Regards
Mark
http://www.utasker.com/kinetis.html
http://www.utasker.com/kinetis/TWR-K60F120M.html
hi:
what's the uTasker Open Source project for K60F120? I am useing the Codewarrior 10.7. And the PDF doesn't have complete procedure demo. I am still in trouble.
Hi Minmim
The uTasker project includes Codewarrior support - see https://youtu.be/uBbiw36Caq4 which explains how to use it.
Regards
Mark