一、硬件准备

使用的是STM32F103C8T6,TJA1050模块,外部电源(一般的STM32F103开发板上的5V电源不可用,可以使用STLINK上面的5v电源)

二、CubeMX创建工程

2.1 配置时钟

配置RCC,选择外部晶振

选择Debug模式为Serial Wire

配置时钟树,选择72MHz,按回车键确认即可

2.2 配置定时器

CanOpenNode需要定时处理或发送心跳,这里用的是定时器2,配置为1ms中断,即72-1,1000-1,需要在NVIC 中开启TIM2中断

2.3 配置CAN和串口1

CAN的波特率设置为500K,同时需要在GPIO中设置PA11为上拉模式


开启串口1,由于CanOpenNode库中使用了printf,必须要开启重定向,否则CAN无法发送报文,波特率默认为115200即可

2.4 生成代码

需要将Heap Size调整为0x2000

三、下载源代码

主要需要下载两个源代码
CANopenNodeCanOpenSTM32
CANopenNode是整个协议栈的核心,而CanOpenSTM32是将CANopenNode的核心协议栈,无缝移植到STM32系列微控制器上的“成品”。它让开发者无需关心底层移植细节,就能在STM32上快速实现CANopen通信。


根目录下新建一个文件夹CanOpenNode,将下载的CANopenNode-master复制到CanOpenNode文件夹下,并仅保留如下文件

将另一个CanOpenSTM32-master内部的CANopenNode_STM32文件夹也复制到CanOpenNode文件夹下。
还有一个数据字典编辑器CANopenEditor,这个可以让你通过图形化界面快速配置OD,下载binary.zip,找到EDSEditor.exe运行即可,本次不涉及,感兴趣的网上很多教程

四、代码实现

添加文件路径、勾选Use MicroLIB
添加头文件

#include "CO_app_STM32.h"
#include "OD.h"
#include <stdio.h>
#include <string.h>

CANopenNodeSTM32 CANopenNode;


配置canopennode,绑定定时器2,心跳发送时间,手动开启CAN,默认不开启,这里可以把系统的HAL_CAN_Start取消,放在这

void system_init(void)
{
    /* 初始化CANopen */
    CANopenNode.CANHandle = &hcan;                /* 使用CAN接口 */
    CANopenNode.HWInitFunction = MX_CAN_Init;     /* 初始化CAN */
    CANopenNode.timerHandle = &htim2;             /* 使用的定时器句柄 */
    CANopenNode.desiredNodeID = 1;                /* Node-ID */
    OD_PERSIST_COMM.x1017_producerHeartbeatTime = 1000;
    canopen_app_init(&CANopenNode);
    HAL_CAN_Start(&hcan);
    HAL_TIM_Base_Start_IT(&htim2);
}


开启TIM2中断

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim == CANopenNode.timerHandle)
    {
        canopen_app_interrupt();
    }
}

Alt
开启重定向,添加#include <stdio.h>

int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
    return ch;
}

过滤器配置,如果用的是CAN-USB可以不配置过滤器,要配置的话,可以放在HAL_CAN_Start前面

void can_device_init(void)
{
    CAN_FilterTypeDef can_filter; /*过滤器设置*/

    can_filter.FilterBank = 0;
    /*使用的过滤器编号。使用一个CAN,则可选0~13;使用两个CAN可选0~27*/
    can_filter.FilterMode = CAN_FILTERMODE_IDMASK;
    /*过滤器模式选择。掩码模式填写CAN_FILTERMODE_IDMASK,
                      列表模式填写CAN_FILTERMODE_IDLIST */
    can_filter.FilterScale = CAN_FILTERSCALE_32BIT;
    /*过滤器位宽,32位是CAN_FILTERSCALE_32BIT,
                  16位是CAN_FILTERSCALE_16BIT */
    can_filter.FilterIdHigh = 0x0000;
    /*过滤器验证码ID高16位,参数值:0~0xFFFF*/
    can_filter.FilterIdLow = 0x0000;
    /*过滤器验证码ID低16位,参数值:0~0xFFFF*/
    can_filter.FilterMaskIdHigh = 0x0000;
    /*过滤器掩码ID高16位,参数值:0~0xFFFF*/
    can_filter.FilterMaskIdLow = 0x0000;
    /*过滤器掩码ID低16位,参数值:0~0xFFFF*/
    can_filter.FilterFIFOAssignment = CAN_FilterFIFO0;
    /*将通过的报文放入哪个FIFOx中,填写FIFO(x)*/
    can_filter.SlaveStartFilterBank = 0;
    /*can2开始的过滤器*/
    can_filter.FilterActivation = ENABLE;
    /*是否使能过滤器,DISABLE 或 ENABLE */

    HAL_CAN_ConfigFilter(&hcan, &can_filter);
    while (HAL_CAN_ConfigFilter(&hcan, &can_filter) != HAL_OK)
        ;
    /*配置can1过滤器并等待至配置完成*/
}

在主循环中加上canopen_app_process();

canopen_app_process();

五、物理接线

注意STM32和RX要接TJA1050的RX,这个和串口不一样。TJA1050的5v电源要额外供电,要共地。
alt

效果

由于CANopenNode底层使用CAN协议,所以可以用正常的CAN接收报文

        CAN_RxHeaderTypeDef rxHeader;
        uint8_t rxData[8];
        if (HAL_CAN_GetRxMessage(&hcan2, CAN_RX_FIFO0, &rxHeader, rxData) == HAL_OK)
        {
            printf("%02X ", rxHeader.StdId);
            for (int i = 0; i < rxHeader.DLC; i++)
            {
                printf("%02X ", rxData[i]);
            }
            printf("\r\n");
        }
        HAL_Delay(500);

alt
StdId是701(0x700 + Node ID),Node ID是1,05代表当前为Operational(操作)状态。

Logo

免费领 150 小时云算力,进群参与显卡、AI PC 幸运抽奖

更多推荐