嵌入式作業6.3 CAN 匯流排程式設計

一只心耳發表於2024-06-13

2個或以上同學相互連線,利用CAN通訊,向對方傳送帶有本人姓名的資訊。連線方式:按基本原理性電路(不帶收發器晶片)連線,參考教材圖10-1。

程式程式碼

can.c:

//======================================================================
// 檔名稱:can.c
// 功能概要:uart底層驅動構件原始檔
// 版權所有:蘇州大學嵌入式系統與物聯網研究所(sumcu.suda.edu.cn)
// 更新記錄:2021-02-03 V1.0  JJL
//======================================================================
#include "can.h"

CAN_TypeDef *CAN_ARR[] = {(CAN_TypeDef *)CAN1_BASE};         // CAN暫存器陣列,包含一個指向CAN1_BASE地址的指標
IRQn_Type table_irq_can[2] = {CAN1_RX0_IRQn, CAN1_RX1_IRQn}; // 中斷請求號陣列,包含 CAN1 的兩個接收中斷請求號

uint8_t can_send_once(uint8_t canNo, uint32_t DestID, uint16_t len, uint8_t *buff);
uint8_t CAN_HWInit(uint8_t CANChannel);
uint8_t CAN_SWInit_Entry(uint8_t canNo);
void CAN_SWInit_CTLMode(uint8_t canNo);
void CAN_SWInit_BT(uint8_t canNo, uint32_t CANMode, uint32_t Prescaler);
uint8_t CAN_SWInit_Quit(uint8_t canNo);
uint8_t CANFilterConfig(uint8_t canNo, uint32_t canID, uint32_t FilterBank, uint32_t Can_Rx_FifoNo, uint8_t IsActivate, uint32_t FilterMode, uint32_t FilterScale);

//=====================================================================
// 函式名稱:can_init
// 函式返回:無
// 引數說明:canNo:模組號,本晶片只有CAN_1
//		    canID:自身CAN節點的唯一標識,例如按照CANopen協議給出
//          BitRate:位速率
// 功能概要:初始化CAN模組
//=====================================================================
void can_init(uint8_t canNo, uint32_t canID, uint32_t BitRate)
{
    // 宣告Init函式使用的區域性變數
    uint32_t CANMode;
    uint32_t CANFilterBank;
    uint32_t CANFiltermode;
    uint32_t CAN_Filterscale;

    // 給Init函式使用的區域性變數賦初值
    CANMode = CAN_MODE_NORMAL;               // 設定CAN的工作模式為正常模式
    CANFilterBank = CANFilterBank0;          // 設定過濾器組編號為0
    CANFiltermode = CAN_FILTERMODE_IDMASK;   // 設定過濾器模式為掩碼模式
    CAN_Filterscale = CAN_FILTERSCALE_32BIT; // 設定過濾器比例為單32位過濾器

    // (1)CAN匯流排硬體初始化
    CAN_HWInit(CAN_CHANNEL);
    // (2)CAN匯流排進入軟體初始化模式
    CAN_SWInit_Entry(canNo);
    // (3)CAN匯流排模式設定
    CAN_SWInit_CTLMode(canNo);
    // (4)CAN匯流排位時序配置
    CAN_SWInit_BT(canNo, CANMode, BitRate);
    // (5)CAN匯流排過濾器初始化
    CANFilterConfig(canNo, canID, CANFilterBank, CAN_RX_FIFO0, 1, CANFiltermode, CAN_Filterscale);
    // (6)CAN匯流排退出軟體初始化模式,進入正常模式
    CAN_SWInit_Quit(canNo);
}

//=====================================================================
// 函式名稱:can_send
// 函式返回:0=正常,1=錯誤
// 引數說明:canNo:模組號,本晶片只有CAN_1
//          DestID:目標CAN節點的唯一標識,例如按照CANopen協議給出
//          len:待傳送資料的位元組數
//          buff:待傳送資料傳送緩衝區首地址
// 功能概要:CAN模組傳送資料
//=====================================================================
uint8_t can_send(uint8_t canNo, uint32_t DestID, uint16_t len, uint8_t *buff)
{
    // 檢查目標ID是否超過29位擴充套件識別符號的最大值
    if (DestID > 0x1FFFFFFFU)
        return 1;

    uint8_t send_length; // 傳送長度

    // 迴圈處理待傳送的資料,每次傳送最多8個位元組
    for (int i = len; i > 0; i = i - 8)
    {
        // 計算當前傳送的資料長度,如果剩餘長度大於8,則傳送8個位元組,否則傳送剩餘長度
        send_length = (i > 8) ? 8 : i;
        // 呼叫 can_send_once 函式傳送資料
        if (can_send_once(canNo, DestID, send_length, buff + len - i) == 1)
        {
            return 1;
        }
    }
    return 0;
}

//=====================================================================
// 函式名稱:can_recv
// 函式返回:接收到的位元組數
// 引數說明:canNo:模組號,本晶片只有CAN_1
//          buff:接收到的資料存放的記憶體區首地址
// 功能概要:在CAN模組接收中斷中呼叫本函式接收已經到達的資料
//=====================================================================
uint8_t can_recv(uint8_t canNo, uint8_t *buff)
{
    uint8_t len;                    // 收到的資料長度
    uint32_t RxFifo = CAN_RX_FIFO0; // 設定接收FIFO為FIFO0(先進先出佇列)

    // (1)判斷哪個郵箱收到了報文資訊
    //  檢查FIFO0是否有待處理訊息
    if (RxFifo == CAN_RX_FIFO0)
    {
        // 檢查FIFO0訊息掛起位,如果沒有訊息,返回1表示錯誤
        if ((CAN_ARR[canNo - 1]->RF0R & CAN_RF0R_FMP0) == 0U)
        {
            return 1;
        }
    }
    else
    {
        // 檢查FIFO1訊息掛起位,如果沒有訊息,返回1表示錯誤
        if ((CAN_ARR[canNo - 1]->RF1R & CAN_RF1R_FMP1) == 0U)
        {
            return 1;
        }
    }

    // (2)獲取資料長度
    //  從接收FIFO的郵箱中獲取資料長度
    len = (CAN_RDT0R_DLC & CAN_ARR[canNo - 1]->sFIFOMailBox[RxFifo].RDTR) >> CAN_RDT0R_DLC_Pos;

    // (3)獲取資料幀中的資料
    //  從接收FIFO的郵箱中讀取資料幀的每個位元組,並儲存到緩衝區buff中
    buff[0] = (uint8_t)((CAN_RDL0R_DATA0 & CAN_ARR[canNo - 1]->sFIFOMailBox[RxFifo].RDLR) >> CAN_RDL0R_DATA0_Pos);
    buff[1] = (uint8_t)((CAN_RDL0R_DATA1 & CAN_ARR[canNo - 1]->sFIFOMailBox[RxFifo].RDLR) >> CAN_RDL0R_DATA1_Pos);
    buff[2] = (uint8_t)((CAN_RDL0R_DATA2 & CAN_ARR[canNo - 1]->sFIFOMailBox[RxFifo].RDLR) >> CAN_RDL0R_DATA2_Pos);
    buff[3] = (uint8_t)((CAN_RDL0R_DATA3 & CAN_ARR[canNo - 1]->sFIFOMailBox[RxFifo].RDLR) >> CAN_RDL0R_DATA3_Pos);
    buff[4] = (uint8_t)((CAN_RDH0R_DATA4 & CAN_ARR[canNo - 1]->sFIFOMailBox[RxFifo].RDHR) >> CAN_RDH0R_DATA4_Pos);
    buff[5] = (uint8_t)((CAN_RDH0R_DATA5 & CAN_ARR[canNo - 1]->sFIFOMailBox[RxFifo].RDHR) >> CAN_RDH0R_DATA5_Pos);
    buff[6] = (uint8_t)((CAN_RDH0R_DATA6 & CAN_ARR[canNo - 1]->sFIFOMailBox[RxFifo].RDHR) >> CAN_RDH0R_DATA6_Pos);
    buff[7] = (uint8_t)((CAN_RDH0R_DATA7 & CAN_ARR[canNo - 1]->sFIFOMailBox[RxFifo].RDHR) >> CAN_RDH0R_DATA7_Pos);

    // (4)清除標誌位,等待接收下一幀資料
    //  清除對應FIFO的訊息掛起標誌位,以便接收下一幀資料
    if (RxFifo == CAN_RX_FIFO0)
    {
        SET_BIT(CAN_ARR[canNo - 1]->RF0R, CAN_RF0R_RFOM0);
    }
    else
    {
        SET_BIT(CAN_ARR[canNo - 1]->RF1R, CAN_RF1R_RFOM1);
    }

    return len; // 返回接收到的資料長度
}

//=====================================================================
// 函式名稱:CAN_enable_re_int
// 函式返回:無
// 引數說明:canNo:模組基地址號,Can_Rx_FifoNo:中斷使用的郵箱號
// 功能概要:CAN接收中斷開啟
//=====================================================================
void can_enable_recv_int(uint8_t canNo)
{
    uint8_t Can_Rx_FifoNo;
    Can_Rx_FifoNo = CAN_RX_FIFO0; // 設定接收FIFO編號為FIFO0

    // 判斷接收FIFO編號,如果為FIFO0,設定相應的中斷使能位
    if (Can_Rx_FifoNo == CAN_RX_FIFO0)
        SET_BIT(CAN_ARR[canNo - 1]->IER, CAN_IER_FMPIE0); // 設定FIFO0訊息掛起中斷使能位
    else
        SET_BIT(CAN_ARR[canNo - 1]->IER, CAN_IER_FMPIE1); // 設定FIFO1訊息掛起中斷使能位

    // 啟用相應的中斷請求
    NVIC_EnableIRQ(table_irq_can[Can_Rx_FifoNo]);
}

//=====================================================================
// 函式名稱:can_disable_recv_int
// 函式返回:無
// 引數說明:canNo:模組號,本晶片只有CAN_1
// 功能概要:關閉CAN接收中斷
//=====================================================================
void can_disable_recv_int(uint8_t canNo)
{
    uint8_t Can_Rx_FifoNo;
    Can_Rx_FifoNo = CAN_RX_FIFO0;
    if (Can_Rx_FifoNo == CAN_RX_FIFO0)
        CLEAR_BIT(CAN_ARR[canNo - 1]->IER, CAN_IER_FMPIE0); // 清除FIFO0訊息掛起中斷使能位
    else
        CLEAR_BIT(CAN_ARR[canNo - 1]->IER, CAN_IER_FMPIE1); // 清除FIFO1訊息掛起中斷使能位

    // 禁用相應的中斷請求
    NVIC_DisableIRQ(table_irq_can[Can_Rx_FifoNo]);
}

//=====================================================================
// 函式名稱:can_send_once
// 函式返回:0=正常,1=錯誤
// 引數說明:canNo:模組號,本晶片只有CAN_1
//          DestID:目標CAN節點的唯一標識,例如按照CANopen協議給出
//          len:待傳送資料的位元組數
//          buff:待傳送資料傳送緩衝區首地址
// 功能概要:CAN模組傳送一次資料
//=====================================================================
uint8_t can_send_once(uint8_t canNo, uint32_t DestID, uint16_t len, uint8_t *buff)
{
    // (1)定義Can傳送函式所需要用到的變數
    uint32_t transmit_mailbox;                        // 用於儲存可用的傳送郵箱
    uint32_t register_tsr;                            // 用於儲存傳送狀態暫存器的值
    uint32_t rtr;                                     // 幀型別(資料幀)
    rtr = CAN_RTR_DATA;                               // 設定為資料幀
    register_tsr = READ_REG(CAN_ARR[canNo - 1]->TSR); // 讀取傳送狀態暫存器的值

    // (2)判斷3個郵箱中是否有空閒郵箱,若有,選取其中一個進行傳送,選取順序為1,2,3
    if (((register_tsr & CAN_TSR_TME0) != 0U) ||
        ((register_tsr & CAN_TSR_TME1) != 0U) ||
        ((register_tsr & CAN_TSR_TME2) != 0U))
    {
        transmit_mailbox = (register_tsr & CAN_TSR_CODE) >> CAN_TSR_CODE_Pos; // 獲取空閒郵箱編號
        if (transmit_mailbox > 2U)                                            // 如果編號大於2,返回錯誤
        {
            return 1;
        }

        // (2.1)判斷並設定傳送幀為標準幀還是擴充套件幀
        if (DestID <= 0x7FFU) // 如果目標ID在標準ID範圍內
        {
            CAN_ARR[canNo - 1]->sTxMailBox[transmit_mailbox].TIR = ((DestID << CAN_TI0R_STID_Pos) | CAN_ID_STD | rtr); // 設定標準幀ID和幀型別
        }
        else // 如果目標ID在擴充套件ID範圍內
        {
            CAN_ARR[canNo - 1]->sTxMailBox[transmit_mailbox].TIR = ((DestID << CAN_TI0R_EXID_Pos) | CAN_ID_EXT | rtr); // 設定擴充套件幀ID和幀型別
        }

        // (2.2)設定傳送幀的資料長度
        CAN_ARR[canNo - 1]->sTxMailBox[transmit_mailbox].TDTR = len; // 設定資料長度
        // SET_BIT(CAN_ARR[canNo-1]->sTxMailBox[transmit_mailbox].TDTR, CAN_TDT0R_TGT);

        // (2.3)設定傳送幀的資料
        //  設定高位資料
        WRITE_REG(CAN_ARR[canNo - 1]->sTxMailBox[transmit_mailbox].TDHR,
                  ((uint32_t)buff[7] << CAN_TDH0R_DATA7_Pos) |
                      ((uint32_t)buff[6] << CAN_TDH0R_DATA6_Pos) |
                      ((uint32_t)buff[5] << CAN_TDH0R_DATA5_Pos) |
                      ((uint32_t)buff[4] << CAN_TDH0R_DATA4_Pos));
        // 設定低位資料
        WRITE_REG(CAN_ARR[canNo - 1]->sTxMailBox[transmit_mailbox].TDLR,
                  ((uint32_t)buff[3] << CAN_TDL0R_DATA3_Pos) |
                      ((uint32_t)buff[2] << CAN_TDL0R_DATA2_Pos) |
                      ((uint32_t)buff[1] << CAN_TDL0R_DATA1_Pos) |
                      ((uint32_t)buff[0] << CAN_TDL0R_DATA0_Pos));

        // (2.4)傳送Can資料包
        SET_BIT(CAN_ARR[canNo - 1]->sTxMailBox[transmit_mailbox].TIR, CAN_TI0R_TXRQ); // 請求傳送資料
        return 0;
    }
    else // 如果沒有空閒郵箱
    {
        return 1;
    }
}

//=====================================================================
// 函式名稱:CAN_HWInit
// 函式返回:0=正常,1=錯誤
// 引數說明:CANChannel:硬體引腳組號,共有3組,分別為PTA11&PTA12(CAN_CHANNEL0),PTB8&PTB9(CAN_CHANNEL1),PTD0&PTD1(2)
// 功能概要:CAN模組引腳初始化
//=====================================================================
uint8_t CAN_HWInit(uint8_t CANChannel)
{
    // 檢查CANChannel的合法性,必須在0到2之間
    if (CANChannel < 0 || CANChannel > 2)
    {
        return 1;
    }

    // 根據CANChannel的值進行不同的引腳初始化
    if (CANChannel == 0)
    {
        RCC->APB1ENR1 |= RCC_APB1ENR1_CAN1EN; // 啟用CAN1時鐘
        RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN;  // 啟用GPIOA時鐘
                                              // 配置PA11和PA12為複用功能模式
        GPIOA->MODER &= ~(GPIO_MODER_MODE11 | GPIO_MODER_MODE12);
        GPIOA->MODER |= (GPIO_MODER_MODE11_1 | GPIO_MODER_MODE12_1);
        // 配置PA11和PA12為CAN複用功能(AF9)
        GPIOA->AFR[1] &= ~(GPIO_AFRH_AFSEL11 | GPIO_AFRH_AFSEL12);
        GPIOA->AFR[1] |= (GPIO_AFRH_AFSEL11_0 | GPIO_AFRH_AFSEL11_3) | (GPIO_AFRH_AFSEL12_0 | GPIO_AFRH_AFSEL12_3);
    }
    else if (CANChannel == 1)
    {
        RCC->APB1ENR1 |= RCC_APB1ENR1_CAN1EN;
        RCC->AHB2ENR |= RCC_AHB2ENR_GPIOBEN;
        GPIOB->MODER &= ~(GPIO_MODER_MODE8 | GPIO_MODER_MODE9);
        GPIOB->MODER |= (GPIO_MODER_MODE8_1 | GPIO_MODER_MODE9_1);
        GPIOB->AFR[1] &= ~(GPIO_AFRH_AFSEL8 | GPIO_AFRH_AFSEL9);
        GPIOB->AFR[1] |= ((GPIO_AFRH_AFSEL8_0 | GPIO_AFRH_AFSEL8_3) |
                          (GPIO_AFRH_AFSEL9_0 | GPIO_AFRH_AFSEL9_3));
    }
    else
    {
        RCC->APB1ENR1 |= RCC_APB1ENR1_CAN1EN;
        RCC->AHB2ENR |= RCC_AHB2ENR_GPIODEN;
        GPIOD->MODER &= ~(GPIO_MODER_MODE0 | GPIO_MODER_MODE1);
        GPIOD->MODER |= (GPIO_MODER_MODE0_1 | GPIO_MODER_MODE1_1);
        GPIOD->AFR[0] &= ~(GPIO_AFRL_AFSEL0 | GPIO_AFRL_AFSEL1);
        GPIOD->AFR[0] |= ((GPIO_AFRL_AFSEL0_0 | GPIO_AFRL_AFSEL0_3) |
                          (GPIO_AFRL_AFSEL1_0 | GPIO_AFRL_AFSEL1_3));
    }
    return 0;
}

//=====================================================================
// 函式名稱:CAN_SWInit_Entry
// 函式返回:0=正常,1=錯誤
// 引數說明:canNo:模組基地址號,本晶片只有CAN_1,
// 功能概要:進入初始化模式
//=====================================================================
uint8_t CAN_SWInit_Entry(uint8_t canNo)
{
    int i;

    // 取消睡眠模式,確保CAN模組不在睡眠狀態
    CLEAR_BIT(CAN_ARR[canNo - 1]->MCR, CAN_MCR_SLEEP);

    // 取消睡眠模式,確保CAN模組不在睡眠狀態
    i = 0;
    while ((CAN_ARR[canNo - 1]->MSR & CAN_MSR_SLAK) != 0U)
    {
        // 如果等待時間過長
        if (i++ > 0x30000)
        {
            return 1;
        }
    }

    // 進入初始化模式
    SET_BIT(CAN_ARR[canNo - 1]->MCR, CAN_MCR_INRQ);

    // 等待確認進入初始化模式
    i = 0;
    while ((CAN_ARR[canNo - 1]->MSR & CAN_MSR_INAK) == 0U)
    {
        if (i++ > 0x30000)
        {
            return 1;
        }
    }
    return 0;
}

//=====================================================================
// 函式名稱:CAN_SWInit_CTLMode
// 函式返回:無
// 引數說明:canNo:模組基地址號,本晶片只有CAN_1,
// 功能概要:CAN匯流排模式設定
//=====================================================================
void CAN_SWInit_CTLMode(uint8_t canNo)
{
    CLEAR_BIT(CAN_ARR[canNo - 1]->MCR, CAN_MCR_TTCM); // 清除時間觸發通訊模式
    CLEAR_BIT(CAN_ARR[canNo - 1]->MCR, CAN_MCR_ABOM); // 清除自動離線管理模式
    CLEAR_BIT(CAN_ARR[canNo - 1]->MCR, CAN_MCR_AWUM); // 清除自動喚醒模式
    SET_BIT(CAN_ARR[canNo - 1]->MCR, CAN_MCR_NART);   // 設定無自動重傳模式
    CLEAR_BIT(CAN_ARR[canNo - 1]->MCR, CAN_MCR_RFLM); // 清除接收FIFO鎖定模式
    CLEAR_BIT(CAN_ARR[canNo - 1]->MCR, CAN_MCR_TXFP); // 清除傳送FIFO優先順序模式
}

//=====================================================================
// 函式名稱:CAN_SWInit_CTLMode
// 函式返回:無
// 引數說明:canNo:模組基地址號,本晶片只有CAN_1,
//			CANMode:CAN匯流排工作模式,分別為正常模式(CAN_MODE_NORMAL)、迴環模式(CAN_MODE_LOOPBACK)、
//										    靜默模式(CAN_MODE_SILENT)以及迴環與靜默組合模式(CAN_MODE_SILENT_LOOPBACK)
// 功能概要:CAN匯流排位時序配置
//=====================================================================
void CAN_SWInit_BT(uint8_t canNo, uint32_t CANMode, uint32_t Prescaler)
{
    // 配置位時序和工作模式,預分頻器值、同步跳轉寬度為1個時間量、時間段1、時間段2、CAN匯流排工作模式
    CAN_ARR[canNo - 1]->BTR |= ((uint32_t)(Prescaler - 1) | CAN_SJW_1TQ | CAN_BTR_TS1_1 | CAN_BTR_TS1_0 | CAN_BTR_TS2_2 | CANMode);
}

//=====================================================================
// 函式名稱:CAN_SWInit_Quit
// 函式返回:0=正常,1=錯誤
// 引數說明:canNo:模組基地址號
// 功能概要:退出初始化模式,進入正常模式
//=====================================================================
uint8_t CAN_SWInit_Quit(uint8_t canNo)
{
    int i;
    // 清除初始化請求位,退出初始化模式
    CLEAR_BIT(CAN_ARR[canNo - 1]->MCR, CAN_MCR_INRQ);

    // 等待確認退出初始化模式
    i = 0;
    while ((CAN_ARR[canNo - 1]->MSR & CAN_MSR_INAK) != 0U)
    {
        if (i++ > 0x30000)
        {
            return 1;
        }
    }
    return 0;
}

//=====================================================================
// 函式名稱: CANFilterConfig
// 函式返回:0=正常,1=錯誤
// 引數說明: canNo:模組基地址號,
//		    canID:自身CAN節點的唯一標識,例如按照CANopen協議給出
//		    Can_Rx_FifoNo:中斷使用的郵箱號,
//			IsActivate:是否啟用過濾器
//			CANFilterBank:CAN匯流排過濾器組選擇,共有28個,(CANFilterBank0~CANFilterBank27)
//			CANFiltermode:CAN匯流排過濾器模式,分別為掩碼模式(CAN_FILTERMODE_IDMASK)和列表模式(CAN_FILTERMODE_IDLIST)
//			CAN_Filterscale:CAN匯流排過濾器位數,分別為32位(CAN_FILTERSCALE_32BIT)和16位(CAN_FILTERSCALE_16BIT)
// 功能概要:CAN接收中斷開啟
//=====================================================================
uint8_t CANFilterConfig(uint8_t canNo, uint32_t CanID, uint32_t FilterBank, uint32_t Can_Rx_FifoNo, uint8_t IsActivate, uint32_t FilterMode, uint32_t FilterScale)
{
    // 定義過濾器ID和掩碼的高低位變數,以及過濾器編號位掩碼
    uint32_t FilterIdHigh, FilterIdLow, FilterMaskIdHigh, FilterMaskIdLow, filternbrbitpos;

    // 如果CanID是標準ID(11位),將其左移至標準ID位置
    if (CanID <= 0x7FFU)
        CanID = CanID << CAN_TI0R_STID_Pos;

    // 將CanID的高低位分割出來
    FilterIdHigh = (CanID >> 16) & 0xFFFF;
    FilterIdLow = (CanID & 0xFFFF);
    // 設定過濾器掩碼,高位和低位
    FilterMaskIdHigh = 0xFFE0;
    FilterMaskIdLow = 0x0000;
    // 計算過濾器編號位掩碼
    filternbrbitpos = (uint32_t)1 << (FilterBank & 0x1FU);

    // 設定過濾器初始化模式 (FINIT=1),在此模式下可以進行過濾器初始化
    SET_BIT(CAN_ARR[canNo - 1]->FMR, CAN_FMR_FINIT);
    CLEAR_BIT(CAN_ARR[canNo - 1]->FA1R, filternbrbitpos); // 關閉過濾器

    // 配置過濾器的縮放模式
    if (FilterScale == CAN_FILTERSCALE_16BIT)
    {
        // 配置為16位模式
        CLEAR_BIT(CAN_ARR[canNo - 1]->FS1R, filternbrbitpos);
        CAN_ARR[canNo - 1]->sFilterRegister[FilterBank].FR1 =
            ((0x0000FFFFU & (uint32_t)FilterMaskIdLow) << 16U) |
            (0x0000FFFFU & (uint32_t)FilterIdLow);
        CAN_ARR[canNo - 1]->sFilterRegister[FilterBank].FR2 =
            ((0x0000FFFFU & (uint32_t)FilterMaskIdHigh) << 16U) |
            (0x0000FFFFU & (uint32_t)FilterIdHigh);
    }
    if (FilterScale == CAN_FILTERSCALE_32BIT)
    {
        // 配置為32位模式
        SET_BIT(CAN_ARR[canNo - 1]->FS1R, filternbrbitpos);
        CAN_ARR[canNo - 1]->sFilterRegister[FilterBank].FR1 =
            ((0x0000FFFFU & (uint32_t)FilterIdHigh) << 16U) |
            (0x0000FFFFU & (uint32_t)FilterIdLow);
        CAN_ARR[canNo - 1]->sFilterRegister[FilterBank].FR2 =
            ((0x0000FFFFU & (uint32_t)FilterMaskIdHigh) << 16U) |
            (0x0000FFFFU & (uint32_t)FilterMaskIdLow);
    }

    // 設定過濾器模式
    if (FilterMode == CAN_FILTERMODE_IDMASK)
    {
        CLEAR_BIT(CAN_ARR[canNo - 1]->FM1R, filternbrbitpos);
    }
    else
    {
        SET_BIT(CAN_ARR[canNo - 1]->FM1R, filternbrbitpos);
    }

    // 配置過濾器關聯的FIFO
    if (Can_Rx_FifoNo == CAN_FILTER_FIFO0)
    {
        CLEAR_BIT(CAN_ARR[canNo - 1]->FFA1R, filternbrbitpos);
    }
    else
    {
        SET_BIT(CAN_ARR[canNo - 1]->FFA1R, filternbrbitpos);
    }

    // 啟用或停用過濾器
    if (IsActivate == 1)
    {
        SET_BIT(CAN_ARR[canNo - 1]->FA1R, filternbrbitpos);
    }
    
    // 退出過濾器初始化模式 (FINIT=0)
    CLEAR_BIT(CAN_ARR[canNo - 1]->FMR, CAN_FMR_FINIT);

    return 0;
}

相關文章