论坛里前辈们的程序见最后,但是有几个问题不懂,请教大家:
1、 FPUEnable();
FPULazyStackingEnable();
FPU的这两句有什么作用?我屏蔽掉也照样可以工作
2、如果想配置为正常模式,不是LOOPBACK模式,是不是应该把寄存器配置的这两句
HWREG(CAN0_BASE + CAN_O_CTL) = HWREG(CAN0_BASE + CAN_O_CTL) | CAN_CTL_TEST;
HWREG(CAN0_BASE + CAN_O_TST) = HWREG(CAN0_BASE + CAN_O_TST) | CAN_TST_LBACK;
修改为:
HWREG(CAN0_BASE + CAN_O_CTL) = HWREG(CAN0_BASE + CAN_O_CTL) | CAN_CTL_TEST;
HWREG(CAN0_BASE + CAN_O_TST) = HWREG(CAN0_BASE + CAN_O_TST) | CAN_TST_BASIC;
看手册还看到说需要把CANIF1CRQ 的BUSY位置1,不知道我理解的对不对?
3、如果我想同时使能CAN0和CAN1,用两个开发板进行通信,一个板子CAN0作为发送,CAN1作为接收,另一个板子相反,是不是同时初始化两个CAN口,就能做这个实验呢?
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "driverlib/pin_map.h"
#include "inc/hw_types.h"
#include "inc/hw_can.h"
#include "inc/hw_ints.h"
#include "driverlib/can.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "utils/uartstdio.h"
#include "driverlib/rom.h"
// 记录所发送的数据包数
volatile uint32_t g_ulMsgCount_TX = 0;
// 记录所接收的数据包数
volatile uint32_t g_ulMsgCount_RX = 0;
// 用于指示在传输过程中是否出现错误以及错误类型
volatile uint32_t g_bErrFlag = 0;
// 是否接收到数据包标志位
volatile uint32_t g_bRXFlag = 0;
unsigned int INT_CNT_ST = 0; // 发送中断计数器
unsigned int INT_CNT_RE = 0; // 接收中断计数器
unsigned int DATA_LOST = 0; // 接收数据丢失标志位
// 延时1s的函数
void
SimpleDelay(void)
{
SysCtlDelay(16000000 / 3); // delay 1s
}
// CAN中断函数
void CANIntHandler(void)
{
uint32_t ulStatus;
// 通过CANIntStatus函数读取中断的状态
ulStatus = CANIntStatus(CAN0_BASE, CAN_INT_STS_CAUSE);
// 如果是控制器状态中断,则说明出现了某种错误
if(ulStatus == CAN_INT_INTID_STATUS)
{
//读取CAN模块所处的状态,并自动清除中断
ulStatus = CANStatusGet(CAN0_BASE, CAN_STS_CONTROL);
// 将g_bErrFlag置1,表示有错误发生
g_bErrFlag = 1;
}
else if(ulStatus == 1)
{
INT_CNT_ST++;
// 数据包发送已经完成,清除中断
CANIntClear(CAN0_BASE, 1);
//发送完一个数据包,计数器g_ulMsgCount_TX增加
g_ulMsgCount_TX++;
// 发送已经完成,清除所有的错误信息
g_bErrFlag = 0;
}
else if(ulStatus==2)
{
INT_CNT_RE++;
// 数据包接收已经完成,清除中断
CANIntClear(CAN0_BASE, 2);
// 接收完一个数据包,计数器g_ulMsgCount_RX增加
g_ulMsgCount_RX++;
// 设置Flag说明接收到的数据包正在等待处理,标志位置位
g_bRXFlag = 1;
// 发送已经完成,清除所有的错误信息
g_bErrFlag = 0;
}
}
// 配置CAN模块,循环发送CAN格式数据包并通过LOOPBACK模式接收
// 运行过程中的信息通过UART向计算机机传输
int main(void)
{
// FPUEnable(); //使能FPU
// FPULazyStackingEnable();
// 定义CAN的发送和接收对象
tCANMsgObject sCANMessage;
tCANMsgObject srCANMessage;
// 定义发送数据存储区和接收数据存储区
// unsigned int uIdx; // 循环显示变量
uint32_t ui32SysClock;
uint8_t ucMsgData[4];
uint8_t ucrMsgData[8];
// uint8_t Datareceive[8];
// 禁用中断,在进行中断配置时要保证中断没被使用
IntMasterDisable();
// 设置系统时钟
ui32SysClock = SysCtlClockFreqSet ( ( SYSCTL_XTAL_25MHZ |
SYSCTL_OSC_MAIN |
SYSCTL_USE_PLL |
SYSCTL_CFG_VCO_480), 120000000);
// CAN0使用PA引脚,使能GPION对应的时钟
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
// 使能CAN0模块的时钟信号
SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0);
//将PA0和PA1两个引脚的功能选择为执行CAN0模块的功能
GPIOPinConfigure(GPIO_PA0_CAN0RX);
GPIOPinConfigure(GPIO_PA1_CAN0TX);
// 对PA0和PA1两个引脚做有关CAN功能的配置
GPIOPinTypeCAN(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
// CAN控制器的初始化
CANInit(CAN0_BASE);
// 利用CANBitRateSet函数将CAN的传输速率设置为1MHz
CANBitRateSet(CAN0_BASE, ui32SysClock, 1000000);
// 寄存器操作,将CAN0模块配置为运行于LOOPBACK模式,直接操作寄存器
HWREG(CAN0_BASE + CAN_O_CTL) = HWREG(CAN0_BASE + CAN_O_CTL) | CAN_CTL_TEST;
HWREG(CAN0_BASE + CAN_O_TST) = HWREG(CAN0_BASE + CAN_O_TST) | CAN_TST_LBACK;
// 使能CAN0模块
CANEnable(CAN0_BASE);
// 使能CAN0模块的中断
IntEnable(INT_CAN0);
//设置可以引起CAN中断的中断源
CANIntEnable(CAN0_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);
//初始化配置message object,即待发送的报文
//配置好报文对象后调用CANMessageSet函数进行设置,报文就可以自动被发送出去
*(uint32_t *)ucMsgData = 0; // 配置发送的数据为0
sCANMessage.ui32MsgID = 1; // 使用1作为发送ID
sCANMessage.ui32MsgIDMask = 0; // 不设置MASK屏蔽
sCANMessage.ui32Flags = MSG_OBJ_TX_INT_ENABLE; //使能发送中断
sCANMessage.ui32MsgLen = sizeof(ucMsgData); //发送数据包大小为4个字节
sCANMessage.pui8MsgData = ucMsgData; // 指向发送数据的指针
// 初始化接收报文,可以接收任何ID的报文对象
srCANMessage.ui32MsgID = 0; // 接收ID位为0
srCANMessage.ui32MsgIDMask = 0; // 不设屏蔽,接收所有东西
srCANMessage.ui32Flags = MSG_OBJ_RX_INT_ENABLE | MSG_OBJ_USE_ID_FILTER; // 使能接收中断和ID过滤
srCANMessage.ui32MsgLen = 8; // 允许最多8个字节的数据
ROM_CANMessageSet(CAN0_BASE, 2 , &srCANMessage, MSG_OBJ_TYPE_RX); // 将message object 2设置为接收报文对象
IntMasterEnable(); // 使能中断
// 发送报文循环,设置每秒发送一个数据包
while(1)
{
CANMessageSet(CAN0_BASE, 1, &sCANMessage, MSG_OBJ_TYPE_TX); //将待发送的报文配置到message object 1中进行发送中断
SimpleDelay(); // 等待1s,过1s后中断已经执行完了
if(g_bErrFlag) // 通过g_bErrFlag变量查看是否出错
{
g_bErrFlag = 1; // 再次置个1吧
}
else
{
// 如果没有出错,则记录已经发送的报文数目
g_ulMsgCount_TX = g_ulMsgCount_TX; // 做一次重复记载
}
(*(uint32_t *)ucMsgData)++; // 每次发送完毕,都将报文中的数据加1
// 接收报文程序,通过g_bRXFlag判断是否有已经接收到是数据包
if (g_bRXFlag)
{
// 建立指向报文数据的缓存区
srCANMessage.pui8MsgData = ucrMsgData;
CANMessageGet(CAN0_BASE, 2 , &srCANMessage,0); // 将message object2 中的信息读取到srCANMessage接收对象中
g_bRXFlag=0; // 方便下一次接收中断后的处理
if(srCANMessage.ui32Flags & MSG_OBJ_DATA_LOST) // 如果出现数据丢失等错误,标志位提示
{
DATA_LOST = 1;
}
/*
// 输出报文中的数据内容,没什么用了
for(uIdx=0; uIdx<srCANMessage.ui32MsgLen; uIdx++)
{
Datareceive[uIdx] = ucrMsgData[uIdx]; // 再次赋值给一个新的数组
}
// 输出所有已收到的报文数目
g_ulMsgCount_RX = g_ulMsgCount_RX;
*/
}
}
}
Maka Luo:
guang xiao
论坛里前辈们的程序见最后,但是有几个问题不懂,请教大家:
1、 FPUEnable();
FPULazyStackingEnable();
FPU的这两句有什么作用?我屏蔽掉也照样可以工作
这个代码只是使能M4F内核浮点运算单元,不使能当然可以工作,只是做部分算法效率没那么高。
2、如果想配置为正常模式,不是LOOPBACK模式,是不是应该把寄存器配置的这两句
HWREG(CAN0_BASE + CAN_O_CTL) = HWREG(CAN0_BASE + CAN_O_CTL) | CAN_CTL_TEST; HWREG(CAN0_BASE + CAN_O_TST) = HWREG(CAN0_BASE + CAN_O_TST) | CAN_TST_LBACK;
修改为:
HWREG(CAN0_BASE + CAN_O_CTL) = HWREG(CAN0_BASE + CAN_O_CTL) | CAN_CTL_TEST;HWREG(CAN0_BASE + CAN_O_TST) = HWREG(CAN0_BASE + CAN_O_TST) | CAN_TST_BASIC;
看手册还看到说需要把CANIF1CRQ 的BUSY位置1,不知道我理解的对不对?
3、如果我想同时使能CAN0和CAN1,用两个开发板进行通信,一个板子CAN0作为发送,CAN1作为接收,另一个板子相反,是不是同时初始化两个CAN口,就能做这个实验呢?
#include <stdint.h>#include <stdbool.h>#include "inc/hw_memmap.h"#include "driverlib/pin_map.h"#include "inc/hw_types.h"#include "inc/hw_can.h"#include "inc/hw_ints.h"#include "driverlib/can.h"#include "driverlib/interrupt.h"#include "driverlib/sysctl.h"#include "driverlib/gpio.h"#include "utils/uartstdio.h"#include "driverlib/rom.h"
// 记录所发送的数据包数volatile uint32_t g_ulMsgCount_TX = 0;// 记录所接收的数据包数volatile uint32_t g_ulMsgCount_RX = 0;// 用于指示在传输过程中是否出现错误以及错误类型volatile uint32_t g_bErrFlag = 0;// 是否接收到数据包标志位volatile uint32_t g_bRXFlag = 0;unsigned int INT_CNT_ST = 0; // 发送中断计数器unsigned int INT_CNT_RE = 0; // 接收中断计数器unsigned int DATA_LOST = 0; // 接收数据丢失标志位
// 延时1s的函数voidSimpleDelay(void){
SysCtlDelay(16000000 / 3); // delay 1s}
// CAN中断函数
void CANIntHandler(void){ uint32_t ulStatus; // 通过CANIntStatus函数读取中断的状态 ulStatus = CANIntStatus(CAN0_BASE, CAN_INT_STS_CAUSE); // 如果是控制器状态中断,则说明出现了某种错误 if(ulStatus == CAN_INT_INTID_STATUS) { //读取CAN模块所处的状态,并自动清除中断 ulStatus = CANStatusGet(CAN0_BASE, CAN_STS_CONTROL); // 将g_bErrFlag置1,表示有错误发生 g_bErrFlag = 1; } else if(ulStatus == 1) { INT_CNT_ST++; // 数据包发送已经完成,清除中断 CANIntClear(CAN0_BASE, 1); //发送完一个数据包,计数器g_ulMsgCount_TX增加 g_ulMsgCount_TX++; // 发送已经完成,清除所有的错误信息 g_bErrFlag = 0; } else if(ulStatus==2) { INT_CNT_RE++; // 数据包接收已经完成,清除中断 CANIntClear(CAN0_BASE, 2); // 接收完一个数据包,计数器g_ulMsgCount_RX增加 g_ulMsgCount_RX++; // 设置Flag说明接收到的数据包正在等待处理,标志位置位 g_bRXFlag = 1; // 发送已经完成,清除所有的错误信息 g_bErrFlag = 0; }}
// 配置CAN模块,循环发送CAN格式数据包并通过LOOPBACK模式接收// 运行过程中的信息通过UART向计算机机传输
int main(void){
// FPUEnable(); //使能FPU// FPULazyStackingEnable();
// 定义CAN的发送和接收对象 tCANMsgObject sCANMessage; tCANMsgObject srCANMessage;
// 定义发送数据存储区和接收数据存储区// unsigned int uIdx; // 循环显示变量 uint32_t ui32SysClock; uint8_t ucMsgData[4]; uint8_t ucrMsgData[8];// uint8_t Datareceive[8];
// 禁用中断,在进行中断配置时要保证中断没被使用 IntMasterDisable(); // 设置系统时钟 ui32SysClock = SysCtlClockFreqSet ( ( SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000);
// CAN0使用PA引脚,使能GPION对应的时钟 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); // 使能CAN0模块的时钟信号 SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0); //将PA0和PA1两个引脚的功能选择为执行CAN0模块的功能 GPIOPinConfigure(GPIO_PA0_CAN0RX); GPIOPinConfigure(GPIO_PA1_CAN0TX); // 对PA0和PA1两个引脚做有关CAN功能的配置 GPIOPinTypeCAN(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1); // CAN控制器的初始化 CANInit(CAN0_BASE); // 利用CANBitRateSet函数将CAN的传输速率设置为1MHz CANBitRateSet(CAN0_BASE, ui32SysClock, 1000000);
// 寄存器操作,将CAN0模块配置为运行于LOOPBACK模式,直接操作寄存器 HWREG(CAN0_BASE + CAN_O_CTL) = HWREG(CAN0_BASE + CAN_O_CTL) | CAN_CTL_TEST; HWREG(CAN0_BASE + CAN_O_TST) = HWREG(CAN0_BASE + CAN_O_TST) | CAN_TST_LBACK; // 使能CAN0模块 CANEnable(CAN0_BASE);
// 使能CAN0模块的中断 IntEnable(INT_CAN0);
//设置可以引起CAN中断的中断源 CANIntEnable(CAN0_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);
//初始化配置message object,即待发送的报文 //配置好报文对象后调用CANMessageSet函数进行设置,报文就可以自动被发送出去
*(uint32_t *)ucMsgData = 0; // 配置发送的数据为0 sCANMessage.ui32MsgID = 1; // 使用1作为发送ID sCANMessage.ui32MsgIDMask = 0; // 不设置MASK屏蔽 sCANMessage.ui32Flags = MSG_OBJ_TX_INT_ENABLE; //使能发送中断 sCANMessage.ui32MsgLen = sizeof(ucMsgData); //发送数据包大小为4个字节 sCANMessage.pui8MsgData = ucMsgData; // 指向发送数据的指针
// 初始化接收报文,可以接收任何ID的报文对象 srCANMessage.ui32MsgID = 0; // 接收ID位为0 srCANMessage.ui32MsgIDMask = 0; // 不设屏蔽,接收所有东西 srCANMessage.ui32Flags = MSG_OBJ_RX_INT_ENABLE | MSG_OBJ_USE_ID_FILTER; // 使能接收中断和ID过滤 srCANMessage.ui32MsgLen = 8; // 允许最多8个字节的数据 ROM_CANMessageSet(CAN0_BASE, 2 , &srCANMessage, MSG_OBJ_TYPE_RX); // 将message object 2设置为接收报文对象
IntMasterEnable(); // 使能中断
// 发送报文循环,设置每秒发送一个数据包 while(1) {
CANMessageSet(CAN0_BASE, 1, &sCANMessage, MSG_OBJ_TYPE_TX); //将待发送的报文配置到message object 1中进行发送中断
SimpleDelay(); // 等待1s,过1s后中断已经执行完了
if(g_bErrFlag) // 通过g_bErrFlag变量查看是否出错 { g_bErrFlag = 1; // 再次置个1吧 } else { // 如果没有出错,则记录已经发送的报文数目 g_ulMsgCount_TX = g_ulMsgCount_TX; // 做一次重复记载 }
(*(uint32_t *)ucMsgData)++; // 每次发送完毕,都将报文中的数据加1
// 接收报文程序,通过g_bRXFlag判断是否有已经接收到是数据包 if (g_bRXFlag) { // 建立指向报文数据的缓存区 srCANMessage.pui8MsgData = ucrMsgData; CANMessageGet(CAN0_BASE, 2 , &srCANMessage,0); // 将message object2 中的信息读取到srCANMessage接收对象中 g_bRXFlag=0; // 方便下一次接收中断后的处理
if(srCANMessage.ui32Flags & MSG_OBJ_DATA_LOST) // 如果出现数据丢失等错误,标志位提示 { DATA_LOST = 1; }/* // 输出报文中的数据内容,没什么用了 for(uIdx=0; uIdx<srCANMessage.ui32MsgLen; uIdx++) { Datareceive[uIdx] = ucrMsgData[uIdx]; // 再次赋值给一个新的数组 } // 输出所有已收到的报文数目 g_ulMsgCount_RX = g_ulMsgCount_RX;*/ } }}
Engineer:
回复 Maka Luo:
第二问题,今天试验过了,如果把寄存器改为TEST 和BASIC模式,就无法进入发送中断了,我的发送中断完成计数器一直为0,看来不正确。或者是不写寄存器吗?
只能通过LBACK模式才能发送数据?
pei gong:
回复 Maka Luo:
您好,请教您个问题。目前我使用CAN0同时作为发送和接收处理,接收设置为:可以接收总线上的所有CAN信息,发送目前是只发送ID为1的数据,但是我想实现这样的功能:不管接收到的总线上CAN信息的帧ID是多少,发送的ID能够根据帧ID的不同来发送数据,那么在程序中对不同设置的帧ID接收如何做处理?
谢谢您!