打印
[其他ST产品]

STR712F CAN通信碰到一个问题

[复制链接]
2667|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
john_light|  楼主 | 2009-7-21 17:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
实验细节
编译器 :IAR EWARM EV V4.42
程序  :IAR环境所带STR712F例子并稍作改动
其它工具:ZLG USBCAN-II测试仪

问题描述
CAN通信收发均完成并按程序流程动作,8字节的CAN数据也正确。唯独帧ID和程序不符。
如0x12345678在测试仪端接收为0x19E2468A,而0x11111111对应0x04462222。

现在怀疑是例子程序中拼装CAN帧过程存在BUG,待查。
沙发
john_light|  楼主 | 2009-7-21 18:04 | 只看该作者

不解

在CAN_SendMessage函数中对ID的拼装:
      // extended ID
    CAN->sMsgObj[0].A1R = EXT_FIXED_ID_ARB_L(pCanMsg->Id);
    CAN->sMsgObj[0].A2R = (CAN->sMsgObj[0].A2R & 0xE000) | EXT_FIXED_ID_ARB_H(pCanMsg->Id);

看来要查一下手册说明了……

使用特权

评论回复
板凳
john_light|  楼主 | 2009-7-22 11:02 | 只看该作者

在网上搜索到一位em_zhuzhu网友的发言

作者: em_zhuzhu 于 2007-1-25 19:24:00 发布:   这个是软件封装的问题
实际上
void CAN_SetRxMsgObj(********)
{
    if (idType == CAN_STD_ID)
    {
      CANx->sMsgObj[msg_if].M1R = 0;
      CANx->sMsgObj[msg_if].M2R = STD_RANGE_ID_MSK(idLow, idHigh);

      CANx->sMsgObj[msg_if].A1R = 0;
      CANx->sMsgObj[msg_if].A2R = CAN_A2R_MSGVAL |STD_RANGE_ID_ARB(idLow, idHigh);
      }
        .......
}
#define RANGE_ID_MSK(range_start, range_end)    (~((range_end) - (range_start)))
#define RANGE_ID_ARB(range_start, range_end)    ((range_start) & (range_end))

#define STD_RANGE_ID_MSK(range_start, range_end)    ((u16)((RANGE_ID_MSK((range_start), (range_end)) & 0x7FF) << 2))
#define STD_RANGE_ID_ARB(range_start, range_end)    ((u16)(RANGE_ID_ARB((range_start), (range_end)) << 2))
实际上地址过滤就是设置MSK和ID(总裁)。两者一起合作来过滤地址。

而ST采用的供给用户的软件算法是这样的:
MSR:~(idhigh - idlow);为1的位则对应该位的ID位必须对应,不对应则过滤
ID:(idhigh & idlow);ID总裁作用
可以看出,用户其实是必须设定了ID位,再通过MSR来确定ID的哪几位用作匹配。
实际上它是不能完全起作用的,
举例说明:
用户设定:
  idhigh:0x3FF
  idlow: 0x100
  那么:MSR:为10100000000
        ID: 为00100000000
  所以实际的匹配为为第9和第11位:0x1xxxxxxxx(x表任意值)
  但是可以发现其实,这是有漏洞的,即0x2xx的地址段也包含在用户需要的地址段中,
但是它却会被过滤掉,因为第9位被确定为了1,而0x2xx的第9位为0。
所以实际的接收地址为0x100~0x1FF和
                      0x300~0x3FF两段。

所以,在使用提供函数设置地址过滤的时候,最好自己推算一下。

另外,如果设置唯一地址时,只需要ID放地址然后将MSR置全1即可,可以不需要用ST提供的函数。

使用特权

评论回复
地板
john_light|  楼主 | 2009-7-22 11:17 | 只看该作者

ST有关CAN ID的算法真让我一头雾水

在我这样的傻瓜看来,对STR71x库函数的使用只要按要求填数据便可。

CAN的报文结构在STR71x库中定义为:
typedef struct
{
    int IdType;
    u32 Id;
    u8 Dlc;
    u8 Data[8];
} canmsg;

我认为,如果要发送一个ID为0x12345678的扩展帧,8字节数据为0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07

那么,准备好往一个canmsg结构变量填
{ CAN_EXT_ID, 0x12345678, 8, { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }即可。

可是经CAN_SendMessage函数一处理,ID都面目全非了。


u32 CAN_SendMessage(u32 msgobj, canmsg* pCanMsg)
{
  while (CAN->sMsgObj[0].CRR & CAN_CRR_BUSY);

/*  if (CAN->sMsgObj[0].COMR & CAN_CRQ_BUSY) */
/*    return 0;    // message interface 0 not free */

  CAN->SR &= ~CAN_SR_TXOK;

  /* read the Arbitration and Message Control */
  CAN->sMsgObj[0].CMR = CAN_CMR_ARB | CAN_CMR_CONTROL;

  CAN->sMsgObj[0].CRR = 1 + msgobj;

  while (CAN->sMsgObj[0].CRR & CAN_CRR_BUSY);

  /* update the contents needed for transmission */
  CAN->sMsgObj[0].CMR =   CAN_CMR_WRRD
                      | CAN_CMR_ARB
                      | CAN_CMR_CONTROL
                      | CAN_CMR_DATAA
                      | CAN_CMR_DATAB;

  if ((CAN->sMsgObj[0].A2R & CAN_A2R_XTD) == 0)
  {
      /* standard ID */
    CAN->sMsgObj[0].A1R = 0;
    CAN->sMsgObj[0].A2R = (CAN->sMsgObj[0].A2R & 0xE000) | STD_FIXED_ID_ARB(pCanMsg->Id);
  }
  else
  {
      // extended ID
    CAN->sMsgObj[0].A1R = EXT_FIXED_ID_ARB_L(pCanMsg->Id);
    CAN->sMsgObj[0].A2R = (CAN->sMsgObj[0].A2R & 0xE000) | EXT_FIXED_ID_ARB_H(pCanMsg->Id);
  }

  CAN->sMsgObj[0].MCR = (CAN->sMsgObj[0].MCR & 0xFEF0) | CAN_MCR_NEWDAT | CAN_MCR_TXRQST | pCanMsg->Dlc;

  CAN->sMsgObj[0].DA1R = ((u16)pCanMsg->Data[1]<<8) | pCanMsg->Data[0];
  CAN->sMsgObj[0].DA2R = ((u16)pCanMsg->Data[3]<<8) | pCanMsg->Data[2];
  CAN->sMsgObj[0].DB1R = ((u16)pCanMsg->Data[5]<<8) | pCanMsg->Data[4];
  CAN->sMsgObj[0].DB2R = ((u16)pCanMsg->Data[7]<<8) | pCanMsg->Data[6];

  CAN->sMsgObj[0].CRR = 1 + msgobj;

  return 1;
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

34

主题

1094

帖子

2

粉丝