This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

请教TM4C129X的CAN模块的编程,正常模式的模式写法,不使用LOOPBACK模式?

论坛里前辈们的程序见最后,但是有几个问题不懂,请教大家:

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;
*/
}
}
}

  • 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的函数
    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;
    */
    }
    }
    }

    其它问题我需要研究一下再回复

  • 第二问题,今天试验过了,如果把寄存器改为TEST 和BASIC模式,就无法进入发送中断了,我的发送中断完成计数器一直为0,看来不正确。或者是不写寄存器吗?

    只能通过LBACK模式才能发送数据?

  • 您好,请教您个问题。目前我使用CAN0同时作为发送和接收处理,接收设置为:可以接收总线上的所有CAN信息,发送目前是只发送ID为1的数据,但是我想实现这样的功能:不管接收到的总线上CAN信息的帧ID是多少,发送的ID能够根据帧ID的不同来发送数据,那么在程序中对不同设置的帧ID接收如何做处理?

    谢谢您!