STM32CubeMX开发stm32f103rbt6 CAN例程(二)

1、STM32CubeMX配置

 

STM32CubeMX开发stm32f103rbt6 CAN例程(二)_第1张图片

 

STM32CubeMX开发stm32f103rbt6 CAN例程(二)_第2张图片

 

STM32CubeMX开发stm32f103rbt6 CAN例程(二)_第3张图片

 

STM32CubeMX开发stm32f103rbt6 CAN例程(二)_第4张图片

 

2、生成代码查看

STM32CubeMX开发stm32f103rbt6 CAN例程(二)_第5张图片

 

STM32CubeMX开发stm32f103rbt6 CAN例程(二)_第6张图片

 

STM32CubeMX开发stm32f103rbt6 CAN例程(二)_第7张图片

 

3、编写代码

程序下载:http://download.csdn.net/download/white_loong/10137468

 

4、使用CAN分析仪测试(波特率125K)

STM32CubeMX开发stm32f103rbt6 CAN例程(二)_第8张图片

 

问题:

程序CAN收发同时打开例如:

 

1、main() {
     HAL_CAN_Receive_IT();
     HAL_CAN_Transmit_IT();
 }

 HAL_CAN_RxCpltCallback() {
  HAL_CAN_Receive_IT(); // Rearm receive
 }

 HAL_CAN_TxCpltCallback() {
  HAL_CAN_Transmit_IT(); // Rearm transmit
 }

 

 

 

例2:main() {

    HAL_CAN_Receive_IT();
    while(1){
         HAL_CAN_Transmit();
          }
 }
  HAL_CAN_RxCpltCallback() {
    HAL_CAN_Receive_IT(); // Rearm receive
 }

现象:调用HAL_CAN_Receive_IT/HAL_CAN_Transmit_IT函数失败,返回值为HAL_BUSY,之后无法再次接收/发送。

原因分析:

 

分析HAL库程序会发现:

HAL库在操作CAN总线时会进行上锁  __HAL_LOCK(hcan)/解锁 __HAL_LOCK(hcan)的操作,类似于进程线程操作中的互斥锁。

对例2进行分析:

主程序中HAL_CAN_Transmit()进行发送时CAN总线在上锁后解锁前,接收中断触发,进入中断回调函数。但是在再次开接收中断时CAN总线上锁导致,开中断失败。

具体程序如下:

 

HAL_StatusTypeDef HAL_CAN_Transmit(CAN_HandleTypeDef* hcan, uint32_t Timeout)
{
  uint32_t transmitmailbox = CAN_TXSTATUS_NOMAILBOX;
  uint32_t tickstart = 0;

  /* Check the parameters */
  assert_param(IS_CAN_IDTYPE(hcan->pTxMsg->IDE));
  assert_param(IS_CAN_RTR(hcan->pTxMsg->RTR));
  assert_param(IS_CAN_DLC(hcan->pTxMsg->DLC));
 
  /* Process locked */
  __HAL_LOCK(hcan);
 
  if(hcan->State == HAL_CAN_STATE_BUSY_RX)
  {
    /* Change CAN state */
    hcan->State = HAL_CAN_STATE_BUSY_TX_RX;
  }
  else
  {
    /* Change CAN state */
    hcan->State = HAL_CAN_STATE_BUSY_TX;
  }
 
  /* Select one empty transmit mailbox */
  if (HAL_IS_BIT_SET(hcan->Instance->TSR, CAN_TSR_TME0))
  {
    transmitmailbox = 0;
  }
        else if (HAL_IS_BIT_SET(hcan->Instance->TSR, CAN_TSR_TME1))
                {
                    transmitmailbox = 1;
                    }
                else if (HAL_IS_BIT_SET(hcan->Instance->TSR, CAN_TSR_TME2))
                            {
                        transmitmailbox = 2;
                        }
                        else
                            {
                            transmitmailbox = CAN_TXSTATUS_NOMAILBOX;
                            }

  if (transmitmailbox != CAN_TXSTATUS_NOMAILBOX)
  {
    /* Set up the Id */
    hcan->Instance->sTxMailBox[transmitmailbox].TIR &= CAN_TI0R_TXRQ;
    if (hcan->pTxMsg->IDE == CAN_ID_STD)
    {
      assert_param(IS_CAN_STDID(hcan->pTxMsg->StdId));  
      hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->StdId << CAN_TI0R_STID_BIT_POSITION) |
                                                           hcan->pTxMsg->RTR);
    }
    else
    {
      assert_param(IS_CAN_EXTID(hcan->pTxMsg->ExtId));
      hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->ExtId << CAN_TI0R_EXID_BIT_POSITION) |
                                                           hcan->pTxMsg->IDE |
                                                           hcan->pTxMsg->RTR);
    }
    
    /* Set up the DLC */
    hcan->pTxMsg->DLC &= (uint8_t)0x0000000F;
    hcan->Instance->sTxMailBox[transmitmailbox].TDTR &= (uint32_t)0xFFFFFFF0;
    hcan->Instance->sTxMailBox[transmitmailbox].TDTR |= hcan->pTxMsg->DLC;

    /* Set up the data field */
    WRITE_REG(hcan->Instance->sTxMailBox[transmitmailbox].TDLR, ((uint32_t)hcan->pTxMsg->Data[3] << CAN_TDL0R_DATA3_BIT_POSITION) |
                                                                ((uint32_t)hcan->pTxMsg->Data[2] << CAN_TDL0R_DATA2_BIT_POSITION) |
                                                                ((uint32_t)hcan->pTxMsg->Data[1] << CAN_TDL0R_DATA1_BIT_POSITION) |
                                                                ((uint32_t)hcan->pTxMsg->Data[0] << CAN_TDL0R_DATA0_BIT_POSITION)  );
    WRITE_REG(hcan->Instance->sTxMailBox[transmitmailbox].TDHR, ((uint32_t)hcan->pTxMsg->Data[7] << CAN_TDL0R_DATA3_BIT_POSITION) |
                                                                ((uint32_t)hcan->pTxMsg->Data[6] << CAN_TDL0R_DATA2_BIT_POSITION) |
                                                                ((uint32_t)hcan->pTxMsg->Data[5] << CAN_TDL0R_DATA1_BIT_POSITION) |
                                                                ((uint32_t)hcan->pTxMsg->Data[4] << CAN_TDL0R_DATA0_BIT_POSITION)  );
    /* Request transmission */
    SET_BIT(hcan->Instance->sTxMailBox[transmitmailbox].TIR, CAN_TI0R_TXRQ);
 
    /* Get timeout */
    tickstart = HAL_GetTick();   
 
    /* Check End of transmission flag */
    while(!(__HAL_CAN_TRANSMIT_STATUS(hcan, transmitmailbox)))
    {
      /* Check for the Timeout */
      if(Timeout != HAL_MAX_DELAY)
      {
        if((Timeout == 0) || ((HAL_GetTick()-tickstart) > Timeout))
        {
          hcan->State = HAL_CAN_STATE_TIMEOUT;
          
          /* Process unlocked */
          __HAL_UNLOCK(hcan);
          
          return HAL_TIMEOUT;
        }
      }
    }
    if(hcan->State == HAL_CAN_STATE_BUSY_TX_RX)
    {
      /* Change CAN state */
      hcan->State = HAL_CAN_STATE_BUSY_RX;
      
      /* Process unlocked */
      __HAL_UNLOCK(hcan);
    }
    else
    {
      /* Change CAN state */
      hcan->State = HAL_CAN_STATE_READY;
    }
    
    /* Process unlocked */
    __HAL_UNLOCK(hcan);
    
    /* Return function status */
    return HAL_OK;
  }
  else
  {
    /* Change CAN state */
    hcan->State = HAL_CAN_STATE_ERROR;
    
    /* Process unlocked */
    __HAL_UNLOCK(hcan);

    /* Return function status */
    return HAL_ERROR;
  }
}




 

 

HAL_StatusTypeDef HAL_CAN_Receive_IT(CAN_HandleTypeDef* hcan, uint8_t FIFONumber)
{
  /* Check the parameters */
  assert_param(IS_CAN_FIFO(FIFONumber));
 
  if((hcan->State == HAL_CAN_STATE_READY) || (hcan->State == HAL_CAN_STATE_BUSY_TX))
  {
    /* Process locked */
    __HAL_LOCK(hcan);
 
    if(hcan->State == HAL_CAN_STATE_BUSY_TX)
    {
      /* Change CAN state */
      hcan->State = HAL_CAN_STATE_BUSY_TX_RX;
    }
    else
    {
      /* Change CAN state */
      hcan->State = HAL_CAN_STATE_BUSY_RX;
    }
    
    /* Set CAN error code to none */
    hcan->ErrorCode = HAL_CAN_ERROR_NONE;
    
    /* Enable interrupts: */
    /*  - Enable Error warning Interrupt */
    /*  - Enable Error passive Interrupt */
    /*  - Enable Bus-off Interrupt */
    /*  - Enable Last error code Interrupt */
    /*  - Enable Error Interrupt */
    /*  - Enable Transmit mailbox empty Interrupt */
    __HAL_CAN_ENABLE_IT(hcan, CAN_IT_EWG |
                              CAN_IT_EPV |
                              CAN_IT_BOF |
                              CAN_IT_LEC |
                              CAN_IT_ERR |
                              CAN_IT_TME  );

    /* Process unlocked */
    __HAL_UNLOCK(hcan);

    if(FIFONumber == CAN_FIFO0)
    {
      /* Enable FIFO 0 message pending Interrupt */
      __HAL_CAN_ENABLE_IT(hcan, CAN_IT_FMP0);
    }
    else
    {
      /* Enable FIFO 1 message pending Interrupt */
      __HAL_CAN_ENABLE_IT(hcan, CAN_IT_FMP1);
    }
    
  }
  else
  {
    return HAL_BUSY;
  }
 
  /* Return function status */
  return HAL_OK;
}

 

相关定义:

 

typedef struct
{
  CAN_TypeDef                 *Instance;  /*!< Register base address          */
  CAN_InitTypeDef             Init;       /*!< CAN required parameters        */
  CanTxMsgTypeDef*            pTxMsg;     /*!< Pointer to transmit structure  */
  CanRxMsgTypeDef*            pRxMsg;     /*!< Pointer to reception structure */
  HAL_LockTypeDef             Lock;       /*!< CAN locking object             */
  __IO HAL_CAN_StateTypeDef   State;      /*!< CAN communication state        */
  __IO uint32_t               ErrorCode;  /*!< CAN Error code                 */  
}CAN_HandleTypeDef;

 

 

 

 

 #define __HAL_LOCK(__HANDLE__)                                           \
                                do{                                        \
                                    if((__HANDLE__)->Lock == HAL_LOCKED)  \
                                    {                                      \
                                       return HAL_BUSY;                    \
                                    }                                      \
                                    else                                   \
                                    {                                      \
                                       (__HANDLE__)->Lock = HAL_LOCKED;    \
                                    }                                      \
                                  }while (0)

  #define __HAL_UNLOCK(__HANDLE__)                                          \
                                  do{                                       \
                                      (__HANDLE__)->Lock = HAL_UNLOCKED;   \
                                    }while (0)

 

 

 

 

对例2解决(例1可参照):

1、对CAN状态进行判断(推荐使用)

若已经加锁,先解锁,操作,再加锁

if((CanHandle)->Lock == HAL_LOCKED){                                     
              __HAL_UNLOCK(CanHandle);        

        HAL_CAN_Receive_IT(); // Rearm receive

              (CanHandle )->Lock = HAL_LOCKED
            }   
                else{       

       HAL_CAN_Receive_IT(); // Rearm receive

                }
        } 

2、直接对寄存器进行操作

 

 HAL_CAN_RxCpltCallback() {
   __HAL_CAN_ENABLE_IT();
 }

 

 

你可能感兴趣的:(STM32)