硬汉嵌入式论坛

 找回密码
 立即注册
查看: 6471|回复: 7
收起左侧

[有问必答] 关于CAN通信中总线上存在多个节点时的返回ACK

[复制链接]

14

主题

11

回帖

53

积分

初级会员

积分
53
发表于 2020-9-9 18:41:27 | 显示全部楼层 |阅读模式
最近在用STM32F407调试CAN通信,关于返回ACK有一个疑问
我用两个节点,分别收发数据,然后用示波器查看波形,我发现不管接收节点的ID是否与发送ID相符,都会有返回ACK。发送节点我是用HAL_CAN_AddTxMessage这个函数发送的,不管ID是否相符,都会返回HAL_OK。
但是如果我的接收节点断电,那么就没有返回ACK了。
那么我是不是可以这样认为,在总线上有多个节点的时候,即便当前的发送节点发送成功了,我也不能保证正确ID的节点接收到了数据,因为可能正确ID的节点已经掉电了,而这个返回ACK是其他ID不相符的节点返回的。
那么为了保证数据传输,是不是也需要像串口通信一样,有返回机制?

第一次使用CAN通信,对于原理了解的不是很透彻,希望能得到大家的回答
回复

使用道具 举报

0

主题

160

回帖

160

积分

初级会员

积分
160
发表于 2020-9-9 19:27:24 | 显示全部楼层
CAN的ACK是CAN的硬件层自动发送的,如果需要节点响应 则需要向总线发一段报文表示收到···
回复

使用道具 举报

31

主题

76

回帖

169

积分

初级会员

积分
169
发表于 2020-9-28 10:05:22 | 显示全部楼层
我也有这样的疑问,目前还是和串口一样处理了,楼主有答案了吗
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107778
QQ
发表于 2020-9-29 05:06:26 | 显示全部楼层
特别注意,函数HAL_CAN_AddTxMessage的返回值仅仅是表示这个函数可用,与底层CAN是否成功没有任何关系
  1. /**
  2.   * @brief  Add a message to the first free Tx mailbox and activate the
  3.   *         corresponding transmission request.
  4.   * @param  hcan pointer to a CAN_HandleTypeDef structure that contains
  5.   *         the configuration information for the specified CAN.
  6.   * @param  pHeader pointer to a CAN_TxHeaderTypeDef structure.
  7.   * @param  aData array containing the payload of the Tx frame.
  8.   * @param  pTxMailbox pointer to a variable where the function will return
  9.   *         the TxMailbox used to store the Tx message.
  10.   *         This parameter can be a value of @arg CAN_Tx_Mailboxes.
  11.   * @retval HAL status
  12.   */
  13. HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, CAN_TxHeaderTypeDef *pHeader, uint8_t aData[], uint32_t *pTxMailbox)
  14. {
  15.   uint32_t transmitmailbox;
  16.   HAL_CAN_StateTypeDef state = hcan->State;
  17.   uint32_t tsr = READ_REG(hcan->Instance->TSR);

  18.   /* Check the parameters */
  19.   assert_param(IS_CAN_IDTYPE(pHeader->IDE));
  20.   assert_param(IS_CAN_RTR(pHeader->RTR));
  21.   assert_param(IS_CAN_DLC(pHeader->DLC));
  22.   if (pHeader->IDE == CAN_ID_STD)
  23.   {
  24.     assert_param(IS_CAN_STDID(pHeader->StdId));
  25.   }
  26.   else
  27.   {
  28.     assert_param(IS_CAN_EXTID(pHeader->ExtId));
  29.   }
  30.   assert_param(IS_FUNCTIONAL_STATE(pHeader->TransmitGlobalTime));

  31.   if ((state == HAL_CAN_STATE_READY) ||
  32.       (state == HAL_CAN_STATE_LISTENING))
  33.   {
  34.     /* Check that all the Tx mailboxes are not full */
  35.     if (((tsr & CAN_TSR_TME0) != 0U) ||
  36.         ((tsr & CAN_TSR_TME1) != 0U) ||
  37.         ((tsr & CAN_TSR_TME2) != 0U))
  38.     {
  39.       /* Select an empty transmit mailbox */
  40.       transmitmailbox = (tsr & CAN_TSR_CODE) >> CAN_TSR_CODE_Pos;

  41.       /* Check transmit mailbox value */
  42.       if (transmitmailbox > 2U)
  43.       {
  44.         /* Update error code */
  45.         hcan->ErrorCode |= HAL_CAN_ERROR_INTERNAL;

  46.         return HAL_ERROR;
  47.       }

  48.       /* Store the Tx mailbox */
  49.       *pTxMailbox = (uint32_t)1 << transmitmailbox;

  50.       /* Set up the Id */
  51.       if (pHeader->IDE == CAN_ID_STD)
  52.       {
  53.         hcan->Instance->sTxMailBox[transmitmailbox].TIR = ((pHeader->StdId << CAN_TI0R_STID_Pos) |
  54.                                                            pHeader->RTR);
  55.       }
  56.       else
  57.       {
  58.         hcan->Instance->sTxMailBox[transmitmailbox].TIR = ((pHeader->ExtId << CAN_TI0R_EXID_Pos) |
  59.                                                            pHeader->IDE |
  60.                                                            pHeader->RTR);
  61.       }

  62.       /* Set up the DLC */
  63.       hcan->Instance->sTxMailBox[transmitmailbox].TDTR = (pHeader->DLC);

  64.       /* Set up the Transmit Global Time mode */
  65.       if (pHeader->TransmitGlobalTime == ENABLE)
  66.       {
  67.         SET_BIT(hcan->Instance->sTxMailBox[transmitmailbox].TDTR, CAN_TDT0R_TGT);
  68.       }

  69.       /* Set up the data field */
  70.       WRITE_REG(hcan->Instance->sTxMailBox[transmitmailbox].TDHR,
  71.                 ((uint32_t)aData[7] << CAN_TDH0R_DATA7_Pos) |
  72.                 ((uint32_t)aData[6] << CAN_TDH0R_DATA6_Pos) |
  73.                 ((uint32_t)aData[5] << CAN_TDH0R_DATA5_Pos) |
  74.                 ((uint32_t)aData[4] << CAN_TDH0R_DATA4_Pos));
  75.       WRITE_REG(hcan->Instance->sTxMailBox[transmitmailbox].TDLR,
  76.                 ((uint32_t)aData[3] << CAN_TDL0R_DATA3_Pos) |
  77.                 ((uint32_t)aData[2] << CAN_TDL0R_DATA2_Pos) |
  78.                 ((uint32_t)aData[1] << CAN_TDL0R_DATA1_Pos) |
  79.                 ((uint32_t)aData[0] << CAN_TDL0R_DATA0_Pos));

  80.       /* Request transmission */
  81.       SET_BIT(hcan->Instance->sTxMailBox[transmitmailbox].TIR, CAN_TI0R_TXRQ);

  82.       /* Return function status */
  83.       return HAL_OK;
  84.     }
  85.     else
  86.     {
  87.       /* Update error code */
  88.       hcan->ErrorCode |= HAL_CAN_ERROR_PARAM;

  89.       return HAL_ERROR;
  90.     }
  91.   }
  92.   else
  93.   {
  94.     /* Update error code */
  95.     hcan->ErrorCode |= HAL_CAN_ERROR_NOT_INITIALIZED;

  96.     return HAL_ERROR;
  97.   }
  98. }
复制代码


回复

使用道具 举报

3

主题

1266

回帖

1275

积分

至尊会员

积分
1275
发表于 2020-9-29 15:19:00 | 显示全部楼层
这个你看CAN2.0AB的标准,就知道了。 ACK的作用是啥,本着这个问题去看下,就明白了。
回复

使用道具 举报

3

主题

1266

回帖

1275

积分

至尊会员

积分
1275
发表于 2020-9-29 15:21:20 | 显示全部楼层
从协议所描述的内容来看,我们不难得出一个结论:CAN是一种基于广播的通讯方式,为了保证总线上的每一个节点(处于normal mode)都能正确的接收到报文,报文的发送者要求每一个接收节点在报文发送结束前,也就是ACK slot的时间内,作出应答,即要求接收的节点都在这个时间发送一个“显性”位。发送者在发送的同时,会监视总线上的数据,如果与发送的娄据不一致,则表示发送失败或自己失去仲裁,立即停止发送或转入接收模式。如果有一个节点在ACK SLOT的时间内发送“显性”位,则发送者认为此次发送报文成功;如果发送者检测到ACK SLOT为隐性位,则表示没有节点填充ACK SLOT,则发送者会检测到这个隐性位而知道发送失败,此条报文需要重发。所以,当总线上只有一个节点的时候,或是只有一个节点可以收发数据的时候,这个节点是发不出去数据的,因为它所发出的数据帧中的ACK SLOT没有另外一个节点来填充,将永远是隐性位,这个节点会一直重发数据直到发送成功或发送被取消。
(注:一:总线上只有一个节点而且它向外发送了数据。它确实不会收到任何ACK,它会变成“error passive”但是它不会变成BUS off。why?请参考CAN specificaton 2.0-partB-Fault_Confinement--rule3--exception1二:其它检测到CRC错误的节点不会马上发送错误帧,而是在ACK delimiter之后才发送。请参考CAN specificaton 2.0-partB-Error_Signalling)
回复

使用道具 举报

3

主题

1266

回帖

1275

积分

至尊会员

积分
1275
发表于 2020-9-29 15:23:57 | 显示全部楼层
我们认为,发送者在发数据的时候,CANTX在发送数据,而CANRX同时也在接收数据,当发送者发送ACK为隐性时,接收到的ACK SLOT一定要是显性才会正确。那么,当有节点正确接收到了数据,在ACK SLOT填上显性位后,接收错误的节点这时候会如何呢?接收错误的节点就会马上发送错误帧,一般是发送连续的6个0或1,根据CAN的位填充原理,当有五个连续的0或1出现时,为了传送中的同步,必须插入一个反相位的BIT作为填充位,如果连续出现6个或以上的相同信号,则此次传送错误,数据将被丢弃。故当发送者收到这个错误帧后,便会知道发送出错,并试图重发数据。
回复

使用道具 举报

29

主题

514

回帖

606

积分

金牌会员

积分
606
QQ
发表于 2020-10-17 16:20:05 | 显示全部楼层
开放的CAN通信,自己私用可以定义广播码,主机通信地址范围,从机通信地址范围。报文的头就用来确定握手通信来往的依据。具体功能再接着匹配功能字符,最后再对接数据。
Releasing your creativity
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-6-13 22:19 , Processed in 0.167427 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表