大家好、
我正在使用连接到 PCAN USB 的 f28379d。 我要做的是创建一个程序、将消息从 CAN A 发送到 PCAN、并接收从 PCAN 发送到 CAN A 的消息。消息传输部分正常、消息 ID 不会显示在 PCAN 上、其中作为收发数据正确显示在 PCAN 上。 看起来缺少一些寄存器配置、是因为
请确认中提到的原因。
源代码如下所示,此帖子附带了 pcan 屏幕截图。 根据我的设置计算引脚多路复用器、CANA 用于 TX 和 RX。
//######################################################################################################################
//
//文件:CAN_loopback_bitfields.c
//
//标题:演示基本 CAN 设置和使用的示例。
//
//! addtogroup cpu01_example_list
//!
使用位字段的 CAN 外部环回(CAN_loopback_bitFields)
//!
//! 重要说明:位字段标头是否需要编译器 v16.6.0.STS 和更高版本!
//!
//! 该示例使用位域报头、显示了中 CAN 的基本设置
//! 以便在 CAN 总线上发送和接收消息。 CAN
//! 外设配置为发送具有特定 CAN ID 的消息。
//! 然后、使用简单的延迟每秒传输一条消息
//! 用于计时的环路。 发送的消息是一个4字节的消息
//! 包含一个递增模式。
//!
//! 此示例将 CAN 控制器设置为外部环回测试模式。
//! 发送的数据在 CAN0TX 引脚上可见、可通过接收
//! 适当的邮箱配置。
//!
//
//######################################################################################################################
//$TI 发行版:F2837xD 支持库 v3.01.00.00 $
//$Release Date:Mon May 22 15:43:40 CDT 2017 $
//版权所有:
//版权所有(C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/
//
//以源代码和二进制形式重新分发和使用,有无
//如果满足以下条件,则允许进行修改
//满足:
//
//重新分发源代码必须保留上述版权
//注意、此条件列表和以下免责声明。
//
//二进制形式的重新分发必须复制上述版权
//注意、中的条件列表和以下免责声明
//随提供的文档和/或其他材料
//分布。
//
//德州仪器公司的名称和的名称都不是
//其贡献者可用于认可或推广衍生产品
//未经特定的事先书面许可,从该软件下载。
//
//本软件由版权所有者和作者提供
//“原样”以及任何明示或暗示的保证,包括但不包括
//限于对适销性和适用性的暗示保证
//一个特定的目的是免责的。 在任何情况下、版权均不得
//所有者或贡献者应对任何直接、间接、偶然、
//特殊、典型或必然的损害(包括但不包括)
//仅限于采购替代货物或服务;
//数据或利润;或业务中断)
//责任理论,无论是合同责任、严格责任还是侵权行为
//(包括疏忽或其他)以任何方式因使用而产生
//此软件,即使已被告知可能会发生此类损坏。
//$
//######################################################################################################################
//
//包含的文件
//
#include "F28x_Project.h"
//
//定义
//
//#define CAN_MSG_ID 0x1111
#define CAN_MSG_ID 0x0580
#define CAN_TX_MSG_OBJ 1.
#define CAN_RX_MSG_OBJ 2.
#define CAN_MAX_BIT_DIFFERS_(13)//最大 CAN 位时序除数
#define CAN_MIN_BIT_DIMINUSESCULE (5)//最小 CAN 位时序除数
#define CAN_MAX_PRE_DIFFERS_1024 (1024)//最大 CAN 预除数
#define CAN_MIN_PRE_DIMINUSTERINL (1)//最小 CAN 预除数
#define CAN_BTR_BRP_M (0x3F)
#define CAN_BTR_BRPE_M (0xF0000)
//
//全局
//
//unsigned char ucTXMsgData[4]={0x1、0x2、0x3、0x4};// TX 数据
unsigned char ucTXMsgData[8]={0x1、0x2、0x3、0x4、0x5、0x6、0x7、0x8};// TX 数据
unsigned char ucRXMsgData[4]={0、0、0、0};// RX 数据
uint32_t messageSize = sizeof (ucTXMsgData);//消息大小(DLC)
volatile unsigned long msgCount = 0;//一个跟踪的计数器
//发送次数
//成功。
volatile unsigned long errFlag = 0;//一个用于指示某些标志的标志
//发生传输错误。
静态常量 uint16_t canBitValues[]=
{
0x1100、// TSEG2 2、TSEG1 2、SJW 1、除以5
0x1200、// TSEG2 2、TSEG1 3、SJW 1、除以6
0x2240、// TSEG2 3、TSEG1 3、SJW 2、分频7
0x2340、// TSEG2 3、TSEG1 4、SJW 2、8分频
0x3340、// TSEG2 4、TSEG1 4、SJW 2、9分频
0x3440、// TSEG2 4、TSEG1 5、SJW 2、10分频
0x3540、// TSEG2 4、TSEG1 6、SJW 2、分频11
0x3640、// TSEG2 4、TSEG1 7、SJW 2、12分频
0x3740 // TSEG2 4、TSEG1 8、SJW 2、分频13
};
typedef 枚举
{
//! 发送报文对象。
MSG_obj_type_transmit、
//! 接收报文对象。
MSG_OBJ_TYPE_Receive
}
msgObjType;
//
//函数原型
//
uint32_t setCANBitRate (uint32_t sourceClock、uint32_t bitrate);
void setupMessageObject (uint32_t Objid、uint32_t msgid、msgObjType msgType);
void sendCANMessage (uint32_t Objid);
bool getCANMessage (uint32_t Objid);
//
//主函
//
内部
main (空)
{
//
//初始化系统控制:
// PLL、安全装置、启用外设时钟
//此示例函数位于 F2837xD_SYSCTRL.c 文件中。
//
InitSysCtrl();
//
//初始化 GPIO:
//此示例函数位于 F2837xD_GPIO.c 文件和中
//说明了如何将 GPIO 设置为其默认状态。
//
InitGpio();
//默认
#if 0
GPIO_SetupPinMux (30、GPIO_MUX_CPU1、1);//GPIO30 - CANRXA
GPIO_SetupPinMux (31、GPIO_MUX_CPU1、1);//GPIO31 - CANTXA
GPIO_SetupPinOptions (30、GPIO_INPUT、GPIO_异 步);
GPIO_SetupPinOptions (31、GPIO_OUTPUT、GPIO_PushPull);
#endif
GPIO_SetupPinMux (70、GPIO_MUX_CPU1、5);//GPIO70 - CANRXA
GPIO_SetupPinMux (71、GPIO_MUX_CPU1、5);//GPIO71 - CANTXA
GPIO_SetupPinOptions (70、GPIO_INPUT、GPIO_异 步);
GPIO_SetupPinOptions (71、GPIO_OUTPUT、GPIO_PushPull);
//
//初始化 CAN-A 控制器
//
InitCAN();
//
//设置可以关闭 SYSCLKOUT
//
ClkCfgRegs.CLKSRCCTL2.bit.CANABCLKSEL = 0;
//
//设置 CAN 总线的比特率。 此函数设置 CAN
针对标称配置的//总线时序。
//在此示例中、CAN 总线设置为500kHz。
//
//有关的更多信息,请查阅数据表
// CAN 外设时钟。
//
uint32_t status = setCANBitRate (200000000、50000);
//
//如果请求的值太小或太大,则捕获错误
//
if (status =0)
{
errFlag++;
ESTOP0;//在此处停止并处理错误
}
//
//步骤3. 清除所有中断并初始化 PIE 矢量表:
//禁用 CPU 中断
//
Dint;
//
//将 PIE 控制寄存器初始化为默认状态。
//默认状态为禁用所有 PIE 中断和标志
//被清除。
//此函数位于 F2837xD_PIECTRL.c 文件中。
//
InitPieCtrl();
//
//禁用 CPU 中断并清除所有 CPU 中断标志:
//
IER = 0x0000;
IFR = 0x0000;
//
//使用指向 shell 中断的指针初始化 PIE 矢量表
//服务例程(ISR)。
//这将填充整个表,即使是中断也是如此
//在本例中未使用。 这对于调试很有用。
//可以在 F2837xD_DefaultIsr.c 中找到 shell ISR 例程
//此函数可在 F2837xD_PieVect.c 中找到
//
InitPieVectTable();
//
//启用测试模式并选择外部环回
//
CANaRegs.CAN_CTL.bit.Test = 0;
CANaRegs.CAN_TEST.bit.EXL = 0;
//
//初始化将用于发送 CAN 的消息对象
//消息。
//
setupMessageObject (CAN_TX_MSG_obj、CAN_MSG_ID、MSG_OBJ_TYPE_transmit);
//
//启用 CAN 以进行操作。
//
CANaRegs.CAN_CTL.bit.Init = 0;
//
//输入循环以发送消息。 根据、将发送一条新消息
//秒。 4字节的消息内容将被视为无符号
// long 并每次递增1。
//
for (;;)
{
//
//使用对象1发送 CAN 消息(与不一样
// CAN ID、在本例中也是1)。 此函数将导致
//要立即传输的消息。
//
sendCANMessage (CAN_TX_MSG_obj);
msgCount++;
//
//现在等待1秒后再继续
//
DELAY_US (1000*1000);
#if 0
//
//递增发送消息数据中的值。
//
ucTXMsgData[0]+= 0x1;
ucTXMsgData[1]+= 0x1;
ucTXMsgData[2]+= 0x1;
ucTXMsgData[3]+= 0x1;
#endif
}
}
//
// setCANBitRate -根据器件时钟(Hz)设置 CAN 比特率
//和所需的比特率(Hz)
//
uint32_t setCANBitRate (uint32_t sourceClock、uint32_t 比特率)
{
uint32_t 设计位置;
uint32_t canBits;
uint32_t 预分频;
uint32_t regValue;
uint16_t canControlValue;
//
//计算所需的时钟速率。
//
desedRatio = sourceClock/bitrate;
//
//确保所需比率不会太大。 这将强制执行
//要求比特率大于请求的。
//
if ((sourceClock / desedRatio)>位速率)
{
希望+=1;
}
//
//检查所有可能的值以查找匹配的值。
//
while (希望的位置<= CAN_MAX_PRE_DIFFERS_CAN_MAX_BIT_DIFFERS_DIFFERS_CAN_MAX_BIT_DIFFERS_DIFFERS_OUR)
{
//
//循环遍历所有可能的 CAN 位分频器。
//
对于(CANBits = CAN_MAX_BIT_DIFFERS_DIFFERS_IN;
CANBits >= CAN_min_bit_di遮 阳板;
坎比特:-)
{
//
//对于一个给定的 CAN 位分频值、保存预分频值。
//
预分频=需要的 Ratio / canBits;
//
//如果计算出的分频值与所需的时钟比率相匹配
//返回这些比特率并设置 CAN 位时序。
//
if ((preDivide * canBits)==desedRatio)
{
//
//通过添加位时序开始构建位时序值
//在时间份额中。
//
regValue = canBitValues[canBits - CAN_MIN_BIT_DIESS];
//
//要设置位时序寄存器,控制器必须是
//放置
//处于初始化模式(如果尚未),以及配置更改
//位被启用。 应保存寄存器的状态
//这样就可以恢复。
//
canControlValue = CanaRegs.CAN_CTL.ALL;
CANaRegs.CAN_CTL.bit.Init = 1;
CANARegs.CAN_CTL.bit.CCE = 1;
//
//现在添加位速率的预分频器。
//
regValue |=((preDivide-1)& CAN_BTR_BRP_M)|
(((预分频器- 1)<< 10)& CAN_BTR_BRPE_M);
//
//在和中设置时钟位
//预分频器。
//
CanaRegs.CAN_BTR.All = regValue;
//
//恢复保存的 CAN 控制寄存器。
//
CanaRegs.CAN_CTL.ALL = canControlValue;
//
//返回计算出的比特率。
//
return (sourceClock /(preDivide * canBits));
}
}
//
//将除数上移一并重新查看。 只有在极少数情况下才会发生这种情况
//找到该值需要2个以上的循环。
//
需要的信息++;
}
返回0;
}
//
// setupMessageObject -将消息对象设置为发送或接收
//
void setupMessageObject (uint32_t Objid、uint32_t msgid、msgObjType msgType)
{
//
//等待忙位清零。
//
while (CANaRegs.CAN_IF1CMD.bit.BUSY)
{
}
//
//清除并写出寄存器以编程报文对象。
//
CANARegs.CAN_IF1CMD.ALL = 0;
CANaRegs.CAN_IF1MSK.ALL = 0;
CanaRegs.CAN_IF1ARB.all = 0;
CANaRegs.CAN_IF1MCTL.ALL = 0;
//
//设置 Control、Mask 和 ARB 位,以便将它们传送到
//消息对象。
//
CANARegs.CAN_IF1CMD.bit.Control = 1;
CanaRegs.CAN_IF1CMD.bit.ARB = 1;
CANARegs.CAN_IF1CMD.bit.Mask = 1;
CANARegs.CAN_IF1CMD.bit.DIR = 1;
//
//设置发送方向
//
if (msgType = MSG_obj_type_transmit)
{
CANARegs.CAN_IF1ARB.bit.Dir = 1;
}
//
//设置消息 ID (此示例假定11位 ID 掩码)
//StdID
CANaRegs.CAN_IF1ARB.bit.XTD = 0;
CanaRegs.CAN_IF1ARB.bit.ID = msgid;
CANARegs.CAN_IF1ARB.bit.MsgVal = 1;
//
//设置数据长度,因为这是为所有传输设置的。 这是
//也是单次传输,而不是 FIFO 传输,所以将 EOB 位置位。
//
CanaRegs.CAN_IF1MCTL.bit.DLC =消息大小;
CANaRegs.CAN_IF1MCTL.bit.EOB = 1;
//
//将数据传输到消息对象 RAM
//
CANaRegs.CAN_IF1CMD.bit.MSG_NUM = Objid;
}
//
// sendCANMessage -从指定报文对象发送数据
//
空 sendCANMessage (uint32_t Objid)
{
//
//等待忙位清零。
//
while (CANaRegs.CAN_IF1CMD.bit.BUSY)
{
}
//
//将要传输的数据写入数据 A 和数据 B 接口寄存器
//
uint16_t 索引;
for (index = 0;index < messageSize;index++)
{
switch (索引)
{
情况0:
CANARegs.CAN_IF1DATA.bit.Data_0 = ucTXMsgData[index];
中断;
案例1:
CANARegs.CAN_IF1DATA.bit.Data_1 = ucTXMsgData[index];
中断;
案例2:
CANARegs.CAN_IF1DATA.bit.Data_2 = ucTXMsgData[index];
中断;
案例3:
CANARegs.CAN_IF1DATA.bit.Data_3 = ucTXMsgData[index];
中断;
案例4:
CANARegs.CAN_IF1DATB.bit.Data_4 = ucTXMsgData[index];
中断;
情况5:
CANARegs.CAN_IF1DATB.bit.Data_5 = ucTXMsgData[index];
中断;
案例6:
CANARegs.CAN_IF1DATB.bit.Data_6 = ucTXMsgData[index];
中断;
案例7:
CANARegs.CAN_IF1DATB.bit.Data_7 = ucTXMsgData[index];
中断;
}
}
//
//设置写入方向并设置要传输到的数据 A/数据 B
//消息对象
//
CANaRegs.CAN_IF1CMD.ALL = 0x830000;
//
//设置 Tx 请求位
//
CANARegs.CAN_IF1CMD.bit.TXRQST = 1;
//
//将报文对象传输到由指定的报文对象
// Objid。
//
CANaRegs.CAN_IF1CMD.bit.MSG_NUM = Objid;
}
//
// getCANMessage -检查消息对象是否有新数据。
//如果是新数据,则写入数组并返回 true 的数据。
//如果没有新数据,则返回 false。
//
bool getCANMessage (uint32_t Objid)
{
bool 状态;
//
//设置要读取的消息数据 A、数据 B 和控制值
//从报文对象请求数据时。
//
CANARegs.CAN_IF2CMD.ALL = 0;
CANARegs.CAN_IF2CMD.bit.Control = 1;
CANARegs.CAN_IF2CMD.bit.DATA_A = 1;
CANARegs.CAN_IF2CMD.bit.DATA_B = 1;
//
//将报文对象传输到报文对象 IF 寄存器。
//
CANARegs.CAN_IF2CMD.bit.MSG_NUM = Objid;
//
//等待忙位清零。
//
while (CANaRegs.CAN_IF2CMD.bit.BUSY)
{
}
//
//查看是否有可用的新数据。
//
if (CANaRegs.CAN_IF2MCTL.bit.NewDat = 1)
{
//
//从 CAN 寄存器中读出数据。
//
uint16_t 索引;
for (index = 0;index < messageSize;index++)
{
switch (索引)
{
情况0:
ucRXMsgData[index]= CANaRegs.CAN_IF2DATA.bit.Data_0;
中断;
案例1:
ucRXMsgData[index]= CANaRegs.CAN_IF2DATA.bit.Data_1;
中断;
案例2:
ucRXMsgData[index]= CANaRegs.CAN_IF2DATA.bit.Data_2;
中断;
案例3:
ucRXMsgData[index]= CANaRegs.CAN_IF2DATA.bit.Data_3;
中断;
案例4:
ucRXMsgData[index]= CANaRegs.CAN_IF2DATB.bit.Data_4;
中断;
情况5:
ucRXMsgData[index]= CANaRegs.CAN_IF2DATB.bit.Data_5;
中断;
案例6:
ucRXMsgData[index]= CANaRegs.CAN_IF2DATB.bit.Data_6;
中断;
案例7:
ucRXMsgData[index]= CANaRegs.CAN_IF2DATB.bit.Data_7;
中断;
}
}
//
//清除新数据标志
//
CANaRegs.CAN_IF2CMD.bit.TxRqst = 1;
//
//等待忙位清零。
//
while (CANaRegs.CAN_IF2CMD.bit.BUSY)
{
}
//
//将报文对象传输到报文对象 IF 寄存器。
//
CANARegs.CAN_IF2CMD.bit.MSG_NUM = Objid;
状态= true;
}
其他
{
状态= false;
}
退货(状态);
}
//
//文件结束
//