1、STM32CubeMX配置
2、生成代码查看
3、编写代码
程序下载:http://download.csdn.net/download/white_loong/10137468
4、使用CAN分析仪测试(波特率125K)
问题:
程序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;
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』