打印
[STM32F4]

STMF4系列HAL库使用双CAN配置及注意事项

[复制链接]
633|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
时钟配置如图所示


使用特权

评论回复
沙发
paotangsan|  楼主 | 2021-8-4 15:13 | 只看该作者
CAN配置
           CAN外设是挂载在APB1_PCLK1时钟上的,APB1_PCLK1是42M。CAN的最大速率是1MHZ,本实验配置为500KHZ。波特率配置计算方法:

CAN波特率 = APB1_PCLK1/分频/(tq1 + tq2 + rjw)
本实验波特率 = 42MHZ/4分频/(14 + 6 + 1) = 0.5MHZ = 500KHZ


  使能CAN接收中断


配置CAN的IO,此步骤必须!!要不然HAL库函数MX_CAN_Init初始化会失败!!

CAN2和CAN1是同样的配置,这里不再贴CAN2的配置图了。


使用特权

评论回复
板凳
paotangsan|  楼主 | 2021-8-4 15:14 | 只看该作者
STM32外设CAN过滤器说明

STM32CUBEMX生成的代码默认是没有设置ID筛选器的,所以需要手动添加过滤器代码。下面一张图,STM32的过滤器组:

STM32F407ZG有28组筛选器,一组筛选器有两个32位的寄存器,筛选器组可配置为四种模式:


1个32位筛选器-标识符掩码模式,这时候筛选器组的两个32位寄存器一个用来存放ID,另一个用来存放ID的掩码

两个32位筛选器-标识符列表模式,这时候筛选器组的两个32位寄存器都用来存放ID

两个16位筛选器-标识符掩码模式,这时候筛选器组被分成了4个16位的寄存器,分别存放ID高16位+掩码高16位,ID低16位+掩码低16位

四个16位筛选-标识符列表模式,这时候筛选器组被分成了4个16位的寄存器,都存放ID的高16位和低16位



使用特权

评论回复
地板
paotangsan|  楼主 | 2021-8-4 15:14 | 只看该作者
贴上我的配置代码,:


#define CAN1_FILTER_MODE_MASK_ENABLE 1        ///< CAN1过滤器模式选择:=1:屏蔽位模式  =0:屏蔽列表模式
#define CAN2_FILTER_MODE_MASK_ENABLE 1  ///< CAN2过滤器模式选择:=1:屏蔽位模式  =0:屏蔽列表模式

#define CAN1_BASE_ID  0x10F00266                ///< 主CAN过滤ID
#define CAN2_BASE_ID  0x10F0F126                ///< 从CAN过滤ID

#define CAN1_FILTER_BANK  0             ///< 主CAN过滤器组编号
#define CAN2_FILTER_BANK  14            ///< 从CAN过滤器组编号

/// CAN过滤器寄存器位宽类型定义
typedef union
{
    __IO uint32_t value;
    struct
    {
        uint8_t REV : 1;                        ///< [0]    :未使用
        uint8_t RTR : 1;                        ///< [1]    : RTR(数据帧或远程帧标志位)
        uint8_t IDE : 1;                        ///< [2]    : IDE(标准帧或扩展帧标志位)
        uint32_t EXID : 18;                        ///< [21:3] : 存放扩展帧ID
        uint16_t STID : 11;                        ///< [31:22]: 存放标准帧ID
    } Sub;
} CAN_FilterRegTypeDef;

// CAN_FMR寄存器位宽类型定义
typedef union
{
        __IO uint32_t value;
        struct
        {
                uint8_t FINIT : 1;
                uint8_t RESERVER_0 : 7;
                uint8_t CAN2SB : 6;
                uint32_t RESERVER_1 : 18;
        }Sub;
}FMR_TypeDef;

/// 设置CAN1的过滤器(主CAN)
static void CAN1_Filter_Config(void)
{
        CAN_FilterTypeDef sFilterConfig;
    CAN_FilterRegTypeDef IDH = {0};
    CAN_FilterRegTypeDef IDL = {0};

        IDH.Sub.IDE  = 0;                                                                // 标准帧
        IDH.Sub.STID = 0;                                                                // 标准帧ID值
    IDH.Sub.EXID = (CAN1_BASE_ID >> 16) & 0xFFFF;        // 扩展帧高16位ID值
       
        IDL.Sub.IDE  = 1;                                                                // 扩展帧
        IDL.Sub.STID = 0;                                                                // 标准帧ID值
    IDL.Sub.EXID = (CAN1_BASE_ID & 0xFFFF);                        // 扩展帧低16位ID值

        sFilterConfig.FilterBank           = CAN1_FILTER_BANK;                                                                // 设置过滤器组编号
#if CAN1_FILTER_MODE_MASK_ENABLE
    sFilterConfig.FilterMode           = CAN_FILTERMODE_IDMASK;                                                        // 屏蔽位模式
#else
        sFilterConfig.FilterMode           = CAN_FILTERMODE_IDLIST;                                                        // 列表模式
#endif
    sFilterConfig.FilterScale          = CAN_FILTERSCALE_32BIT;                                                        // 32位宽
    sFilterConfig.FilterIdHigh         = IDH.value;                                                                                // 标识符寄存器一ID高十六位,放入扩展帧位
    sFilterConfig.FilterIdLow          = IDL.value;                                                                                // 标识符寄存器一ID低十六位,放入扩展帧位
    sFilterConfig.FilterMaskIdHigh     = IDH.value;                                                                                // 标识符寄存器二ID高十六位,放入扩展帧位
    sFilterConfig.FilterMaskIdLow      = IDL.value;                                                                                // 标识符寄存器二ID低十六位,放入扩展帧位
    sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;                                                                        // 过滤器组关联到FIFO0
    sFilterConfig.FilterActivation     = ENABLE;                                                                                // 激活过滤器
    sFilterConfig.SlaveStartFilterBank = CAN2_FILTER_BANK;                                                                // 设置CAN2的起始过滤器组(对于单CAN的CPU或从CAN此参数无效;对于双CAN的CPU此参数为从CAN的起始过滤器组编号)
    if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
    {
        Error_Handler();
    }
        {
                FMR_TypeDef regval = {0};
                regval.value = hcan1.Instance->FMR;
                printf("------ CAN1:> FMR:0x%0X  CAN2SB:0x%X  \r\n", regval.value, regval.Sub.CAN2SB);
        }
}

/// 设置CAN2的过滤器(从CAN)
static void CAN2_Filter_Config(void)
{
        CAN_FilterTypeDef sFilterConfig;
    CAN_FilterRegTypeDef IDH = {0};
    CAN_FilterRegTypeDef IDL = {0};

        IDH.Sub.IDE  = 0;
        IDH.Sub.STID = 0;
    IDH.Sub.EXID = (CAN2_BASE_ID >> 16) & 0xFFFF;
       
        IDL.Sub.IDE  = 1;
        IDL.Sub.STID = 0;
    IDL.Sub.EXID = (CAN2_BASE_ID & 0xFFFF);

    sFilterConfig.FilterBank           = CAN2_FILTER_BANK;                                                                // 设置过滤器组编号
#if CAN2_FILTER_MODE_MASK_ENABLE
    sFilterConfig.FilterMode           = CAN_FILTERMODE_IDMASK;                                                        // 屏蔽位模式
#else
        sFilterConfig.FilterMode           = CAN_FILTERMODE_IDLIST;                                                        // 列表模式
#endif
    sFilterConfig.FilterScale          = CAN_FILTERSCALE_32BIT;                                                        // 32位宽
    sFilterConfig.FilterIdHigh         = IDH.value;                                                                                // 标识符寄存器一ID高十六位,放入扩展帧位
    sFilterConfig.FilterIdLow          = IDL.value;                                                                                // 标识符寄存器一ID低十六位,放入扩展帧位
    sFilterConfig.FilterMaskIdHigh     = IDH.value;                                                                                // 标识符寄存器二ID高十六位,放入扩展帧位
    sFilterConfig.FilterMaskIdLow      = IDL.value;                                                                                // 标识符寄存器二ID低十六位,放入扩展帧位
    sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;                                                                        // 过滤器组关联到FIFO0
    sFilterConfig.FilterActivation     = ENABLE;                                                                                // 激活过滤器
    sFilterConfig.SlaveStartFilterBank = 28;                                                                                        // 无效
    if (HAL_CAN_ConfigFilter(&hcan2, &sFilterConfig) != HAL_OK)
    {
        Error_Handler();
    }
        {
                FMR_TypeDef regval = {0};
                regval.value = hcan2.Instance->FMR;
                printf("------ CAN2:> FMR:0x%0X  CAN2SB:0x%X  \r\n", regval.value, regval.Sub.CAN2SB);
        }
}

/// CAN初始化
void CAN_Init(void)
{
    MX_CAN1_Init();                                                                                                                                                // 初始化CNA1
    CAN1_Filter_Config();                                                                                                                                // 初始化CNA1过滤器
    HAL_CAN_Start(&hcan1);                                                                                                                                // 启动CAN1
    HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);                                        // 激活CAN1 FIFO0

    MX_CAN2_Init();
    CAN2_Filter_Config();
    HAL_CAN_Start(&hcan2);
    HAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO0_MSG_PENDING);
}

/**
* CAN数据传输
* @param  buf    待发送的数据
* @param  len    数据长度
* @param  number CAN编号,=0:CAN1,=1:CAN2
* @return        0:成功  other:失败
*/
uint8_t CAN_Transmit(const void* buf, uint32_t len, uint8_t number)
{
    uint32_t txmailbox = 0;
    uint32_t offset = 0;
    CAN_TxHeaderTypeDef hdr;

    hdr.IDE = CAN_ID_EXT;                                                                                                        // ID类型:扩展帧
    hdr.RTR = CAN_RTR_DATA;                                                                                                        // 帧类型:数据帧
    hdr.StdId = 0;                                                                                                                        // 标准帧ID,最大11位,也就是0x7FF
    hdr.ExtId = number == 0 ? CAN1_BASE_ID : CAN2_BASE_ID;                                        // 扩展帧ID,最大29位,也就是0x1FFFFFFF
    hdr.TransmitGlobalTime = DISABLE;

    while (len != 0)
    {
        hdr.DLC = len > 8 ? 8 : len;                        // 数据长度
        if (HAL_CAN_AddTxMessage(number == 0 ? &hcan1 : &hcan2, &hdr, ((uint8_t *)buf) + offset, &txmailbox) != HAL_OK)
            return 1;
        offset += hdr.DLC;
        len -= hdr.DLC;
    }
    return 0;
}

uint8_t CAN1_RX_STA = 0;                ///< CAN1数据接收标志:[7]:数据 [6:0]:未使用
uint8_t CAN2_RX_STA = 0;                ///< CAN2数据接收标志:[7]:数据 [6:0]:未使用

uint8_t CAN1_RX_BUF[8];                        ///< CAN1数据接收缓存
uint8_t CAN2_RX_BUF[8];                        ///< CAN2数据接收缓存

uint8_t CAN1_TX_BUF[8];                        ///< CAN1数据发送缓存
uint8_t CAN2_TX_BUF[8];                        ///< CAN2数据发送缓存

/**
* CAN FIFO0 数据接收中断回调函数
* @param hcan CAN句柄
*/
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
    static CAN_RxHeaderTypeDef CAN_RX_HDR;

    // CAN1数据接收
    if (hcan->Instance == hcan1.Instance)
    {
        // 数据已经处理
        if ((CAN1_RX_STA & 0x80) == 0)
        {
            // 清空缓存
            memset(CAN1_RX_BUF, 0, 8);

            // 接收数据
            if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &CAN_RX_HDR, CAN1_RX_BUF) == HAL_OK)                // 获得接收到的数据头和数据
            {
                CAN1_RX_STA |= 0x80;                                                                                                                                // 标记接收到数据
                HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING);                                        // 再次使能FIFO0接收中断
            }
        }
    }

    // CAN2数据接收
    else if (hcan->Instance == hcan2.Instance)
    {
        // 数据已经处理
        if ((CAN2_RX_STA & 0x80) == 0)
        {
            // 清空缓存
            memset(CAN2_RX_BUF, 0, 8);

            // 接收数据
            if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &CAN_RX_HDR, CAN2_RX_BUF) == HAL_OK)                // 获得接收到的数据头和数据
            {
                CAN2_RX_STA |= 0x80;                                                                                                                                // 标记接收到数据
                HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING);                                        // 再次使能FIFO0接收中断
            }
        }
    }
}

///< CAN数据处理函数
inline void CAN_RecvHandler(void)
{
    // CAN1有数据收到
    if (CAN1_RX_STA & 0x80)
    {
                int i = 0;
                memcpy(CAN1_TX_BUF, CAN1_RX_BUF, sizeof(CAN1_RX_BUF));                // 拷贝出数据
                CAN1_RX_STA = 0;                                                                                        // 重置CAN1接收状态
                for(i = 0; i != 8; i++)
                {
                        printf("CAN1_TX_BUF[%d]:0x%X\r\n", i, CAN1_TX_BUF);
                }
                printf("\r\n\r\n");
    }

    // CAN2有数据收到
    if (CAN2_RX_STA & 0x80)
    {
                int i = 0;
                memcpy(CAN2_TX_BUF, CAN2_RX_BUF, sizeof(CAN2_RX_BUF));                // 拷贝出数据
                CAN2_RX_STA = 0;                                                                                        // 重置CAN1接收状态
                for(i = 0; i != 8; i++)
                {
                        printf("CAN2_TX_BUF[%d]:0x%X\r\n", i, CAN2_TX_BUF);
                }
                printf("\r\n\r\n");
    }
}


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

51

主题

4079

帖子

0

粉丝