加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入
  • 正文
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

STM32 CAN快速配置(HAL庫(kù)版本)

04/02 07:38
7428
閱讀需 18 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

控制器局域網(wǎng)總線(CAN,Controller Area Network)是一種用于實(shí)時(shí)應(yīng)用的串行通訊協(xié)議總線,它可以使用雙絞線來(lái)傳輸信號(hào),是世界上應(yīng)用最廣泛的現(xiàn)場(chǎng)總線之一。CAN協(xié)議用于汽車中各種不同元件之間的通信,以此取代昂貴而笨重的配電線束。該協(xié)議的健壯性使其用途延伸到其他自動(dòng)化和工業(yè)應(yīng)用。CAN協(xié)議的特性包括完整性的串行數(shù)據(jù)通訊、提供實(shí)時(shí)支持、傳輸速率高達(dá)1Mb/s、同時(shí)具有11位的尋址以及檢錯(cuò)能力。

特別說(shuō)明:關(guān)于CAN總線協(xié)議和硬件電路等問(wèn)題,這里不做介紹,網(wǎng)上的資料非常多,不懂的同學(xué)請(qǐng)自行查閱。

1 軟件編程

1.1 初始化

初始化主要分成三部分:引腳設(shè)置,CAN參數(shù)設(shè)置和CAN濾波器設(shè)置。

1.1.1 引腳設(shè)置

把CAN_H和CAN_L兩個(gè)引腳配置成復(fù)用功能即可。
注:如果CAN控制芯片的S引腳連接到STM32的話,還得初始化這個(gè)引腳,S引腳可以配置成高速模式或靜音模式。

參考代碼:
注:該代碼可以通過(guò)STM32CubeMX生成

/**
* @brief CAN MSP Initialization
* This function configures the hardware resources used in this example
* @param hcan: CAN handle pointer
* @retval None
*/
void HAL_CAN_MspInit(CAN_HandleTypeDef* hcan)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hcan->Instance==CAN1)
  {/* USER CODE END CAN1_MspInit 0 */
    /* Peripheral clock enable */
    HAL_RCC_CAN1_CLK_ENABLED++;
    if(HAL_RCC_CAN1_CLK_ENABLED==1){
      __HAL_RCC_CAN1_CLK_ENABLE();
    }

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**CAN1 GPIO Configuration
    PA11     ------> CAN1_RX
    PA12     ------> CAN1_TX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* CAN1 interrupt Init */
    HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 0, 0);    // CAN接收中斷
    HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
  }
}
1.1.2 CAN參數(shù)設(shè)置

HAL庫(kù)的CAN初始化有幾個(gè)重要參數(shù),都存放在幾個(gè)結(jié)構(gòu)體里面(如:CAN_HandleTypeDef,CAN_InitTypeDef),具體的結(jié)構(gòu)體定義可以在HAL庫(kù)查看。
說(shuō)明:CAN參數(shù)需要根據(jù)自己實(shí)際的需求來(lái)配。

我這里著重講解一下CAN波特率的配置。

CAN波特率 = CAN時(shí)鐘頻率 / 分頻系數(shù) / (TimeSeg1 + TimeSeg2 + 1)。

其中,CAN時(shí)鐘頻率不是固定不變的,它取決于CAN所掛載的總線時(shí)鐘。
比如STM32F1,系統(tǒng)時(shí)鐘最大72M,APB1的總線時(shí)鐘最大36M,而CAN控制器的時(shí)鐘是掛在APB1的,所以CAN的時(shí)鐘頻率也等于APB1的時(shí)鐘。
如果換作其他型號(hào)的MCU,CAN外設(shè)不一定是掛載到APB1上面的,時(shí)鐘也不一定是36M,比如F4系列,APB1的時(shí)鐘是可以配成42M的,因此,這個(gè)要根據(jù)實(shí)際情況來(lái)配置。

參考代碼:
注:該代碼可以通過(guò)STM32CubeMX生成

/**
  * @brief CAN1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_CAN_Init(void)
{
  // CAN波特率 = CAN時(shí)鐘頻率 / Prescaler / (TimeSeg1 + TimeSeg2 + 1)
  // 例: 500kbps = 36MHz / 9 / (3 + 4 + 1)   36MHz為該例程APB1的總線時(shí)鐘
  /* USER CODE END CAN1_Init 1 */

  hcan.Instance = CAN1;                     // 配置CAN1
  hcan.Init.Prescaler = 9;                  // 預(yù)分頻系數(shù)
  hcan.Init.Mode = CAN_MODE_NORMAL;         // 正常CAN模式        
  hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;    // 重同步跳躍寬度,CAN_SJW_1TQ~CAN_SJW_4TQ             
  hcan.Init.TimeSeg1 = CAN_BS1_3TQ;         // TimeSeg1        
  hcan.Init.TimeSeg2 = CAN_BS2_4TQ;         // TimeSeg2        
  hcan.Init.TimeTriggeredMode = DISABLE;    // 非時(shí)間觸發(fā)通信模式             
  hcan.Init.AutoBusOff = DISABLE;           // 軟件自動(dòng)離線管理      
  hcan.Init.AutoWakeUp = DISABLE;           // 睡眠模式通過(guò)軟件喚醒(清除CAN->MCR的SLEEP位)      
  hcan.Init.AutoRetransmission = DISABLE;   // 禁止報(bào)文自動(dòng)重傳               
  hcan.Init.ReceiveFifoLocked = DISABLE;    // FIFO報(bào)文不鎖定,新的覆蓋舊的              
  hcan.Init.TransmitFifoPriority = DISABLE; // 優(yōu)先級(jí)由報(bào)文標(biāo)識(shí)符決定                 
  if (HAL_CAN_Init(&hcan) != HAL_OK)
  {
    Error_Handler();
  }
}
1.1.3 CAN濾波器設(shè)置

CAN濾波器的主要作用是篩選CAN接收的數(shù)據(jù),只有滿足設(shè)定規(guī)則的數(shù)據(jù)才會(huì)被接收,否則會(huì)被過(guò)濾掉。

參考代碼:

void CAN_Config(void)
{
  CAN_FilterTypeDef  sFilterConfig;

  /* Configure the CAN Filter */
  sFilterConfig.FilterBank = 0;                      // 過(guò)濾器編號(hào),使用一個(gè)CAN,則可選0-13;使用兩個(gè)CAN可選0-27
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;  // 過(guò)濾器模式,掩碼模式或列表模式
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 過(guò)濾器位寬
  sFilterConfig.FilterIdHigh = 0x0000;               // 過(guò)濾器驗(yàn)證碼ID高16位,0-0xFFFF
  sFilterConfig.FilterIdLow = 0x0000;                // 過(guò)濾器驗(yàn)證碼ID低16位,0-0xFFFF
  sFilterConfig.FilterMaskIdHigh = 0x0000;           // 過(guò)濾器掩碼ID高16位,0-0xFFFF
  sFilterConfig.FilterMaskIdLow = 0x0000;            // 過(guò)濾器掩碼ID低16位,0-0xFFFF
  sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // FIFOx,0或1
  sFilterConfig.FilterActivation = ENABLE;           // 使能過(guò)濾器
  sFilterConfig.SlaveStartFilterBank = 14;           // 從過(guò)濾器編號(hào),0-27,對(duì)于單CAN實(shí)例該參數(shù)沒(méi)有意義

  if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
  {
    /* Filter configuration Error */
  }

  /* Start the CAN peripheral */
  if (HAL_CAN_Start(&hcan) != HAL_OK)
  {
    /* Start Error */
  }

  /* Activate CAN RX notification */
  if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
  {
    /* Notification Error */
  }
}

1.2 CAN發(fā)送

CAN發(fā)送需要先配置發(fā)送參數(shù),我這里為了方便測(cè)試,直接固定發(fā)送標(biāo)準(zhǔn)幀,ID也是固定的。
實(shí)際使用時(shí)可以再增加一個(gè)ID的入?yún)ⅲ@樣會(huì)更靈活一點(diǎn)。

參考代碼:

/****************************************************************************
* 名    稱: uint8_t CAN_Send_Msg(uint8_t* msg, uint8_t len)
* 功    能:can發(fā)送一組數(shù)據(jù)(固定格式:ID為0X12,標(biāo)準(zhǔn)幀,數(shù)據(jù)幀)
* 入口參數(shù):len:數(shù)據(jù)長(zhǎng)度(最大為8)				     
           msg:數(shù)據(jù)指針,最大為8個(gè)字節(jié).
* 返回參數(shù):0,成功;
           其他,失敗;
* 說(shuō)    明:       
****************************************************************************/		
uint8_t CAN_Send_Msg(uint8_t* msg, uint8_t len)
{	
  uint8_t i=0;
  uint8_t message[8];
  uint32_t TxMailbox;
  CAN_TxHeaderTypeDef CAN_TxHeader;

  // 設(shè)置發(fā)送參數(shù)
  CAN_TxHeader.StdId = 0x12;                 // 標(biāo)準(zhǔn)標(biāo)識(shí)符(12bit)
  CAN_TxHeader.ExtId = 0x12;                 // 擴(kuò)展標(biāo)識(shí)符(29bit)
  CAN_TxHeader.IDE = CAN_ID_STD;             // 使用標(biāo)準(zhǔn)幀
  CAN_TxHeader.RTR = CAN_RTR_DATA;           // 數(shù)據(jù)幀
  CAN_TxHeader.DLC = len;                    // 發(fā)送長(zhǎng)度      
  CAN_TxHeader.TransmitGlobalTime = DISABLE;

  // 裝載數(shù)據(jù)
  for(i = 0; i < len; i++)
  {
    message[i] = msg[i];
  }

  // 發(fā)送CAN消息
  if(HAL_CAN_AddTxMessage(&hcan, &CAN_TxHeader, message, &TxMailbox) != HAL_OK) 
  {
    return 1;
  }
  while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan) != 3) 
  {

  }
  return 0;	
}

1.3 CAN接收

接收部分只要開(kāi)啟了Rx中斷,在CAN控制器收到消息時(shí)會(huì)調(diào)用RxFifo的回調(diào)函數(shù),此時(shí)我們?cè)谶@里讀取數(shù)據(jù)并根據(jù)實(shí)際情況做相應(yīng)的處理即可。

參考代碼:

/*******************************************************************************
* Function Name  : HAL_CAN_RxFifo0MsgPendingCallback
* Description    : 消息接收回調(diào)函數(shù)
* Input          : hcan
* Output         : None
* Return         : None
****************************************************************************** */
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{// 收到CAN數(shù)據(jù)會(huì)觸發(fā)接收中斷,進(jìn)入該回調(diào)函數(shù)
  uint32_t i;
  uint8_t RxData[8];
  CAN_RxHeaderTypeDef CAN_RxHeader; 
  
  if(HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &CAN_RxHeader, RxData) == HAL_OK)
  {
    // 串口打印接收結(jié)果
    printf("GetRxMessage, CANID:0x%0X, Data:", CAN_RxHeader.StdId);
    for(i = 0;i < CAN_RxHeader.DLC; i++)
    {
      printf("%02x ", RxData[i]);
    }
    // 把接收的數(shù)據(jù)用CAN再發(fā)回去
    CAN_Send_Msg(RxData, CAN_RxHeader.DLC);
  }
}

2 運(yùn)行測(cè)試

使用USB-CAN工具測(cè)試發(fā)送:
在這里插入圖片描述

消息窗口如下:
在這里插入圖片描述
可以看到,上位機(jī)發(fā)送了一條CAN數(shù)據(jù),CANID為0x01,接著就收到了STM32回的一條數(shù)據(jù),CANID為0x12(因?yàn)槲掖a固定寫(xiě)死了ID為0x12)。

同樣的,通過(guò)串口也能看到STM32收到的CAN數(shù)據(jù),如下圖所示:
在這里插入圖片描述
還有一些其他測(cè)試,比如收發(fā)不同長(zhǎng)度,切換擴(kuò)展幀等等,這里就不展示了,感興趣的同學(xué)可以自己改參數(shù)試試。

結(jié)論:CAN收發(fā)正常。

結(jié)束語(yǔ)

好了,關(guān)于如何通過(guò)STM32如何配置和使用CAN就講到這里,如果你有什么問(wèn)題或者有更好的方法,歡迎在評(píng)論區(qū)留言。

推薦器件

更多器件
器件型號(hào) 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊(cè) ECAD模型 風(fēng)險(xiǎn)等級(jí) 參考價(jià)格 更多信息
KSZ8081RNACA 1 Microchip Technology Inc DATACOM, ETHERNET TRANSCEIVER, QCC24

ECAD模型

下載ECAD模型
$0.77 查看
NC7SZ74K8X 1 Fairchild Semiconductor Corporation D Flip-Flop, LVC/LCX/Z Series, 1-Func, Positive Edge Triggered, 1-Bit, Complementary Output, CMOS, PDSO8, 3.10 MM, MO-187CA, US-8
$0.56 查看
S25FL512SAGBHIC13 1 Cypress Semiconductor Flash, 128MX4, PBGA24, FBGA-24
暫無(wú)數(shù)據(jù) 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜