[活动专区]【杰发科技AC7840x测评】+ CAN收发测试

测试下开发板的CAN收发功能。

一、硬件部分

1.1、CAN收发器电路
 



1.2、CAN接口
CAN接口连接到PE4和PE5端口
 



1.3、芯片端口映射
PE4和PE5映射到CAN0
 



二、程序部分

2.1、can.c

复制

#include "ac7840x.h"

#include "gpio_drv.h"

#include "can_drv.h"

#include "can/can.h"

#include "osif.h"

#include "clock_config.h"



/* ============================================  Define  ============================================ */

#define CAN_SOURCE_CLOCK             (60UL)         /* 时钟源选择60M */

#define CAN_MSG_HANDLE_DIRECT        (1UL)          /* 是否处理消息, 1 是, 0 否 */

#define CAN_TIME_STAMP_ENABLE        (0UL)          /* 使能/失能CAN时间戳, 1 使能, 0 失能 */



/* ===========================================  Typedef  ============================================ */

typedef struct

{

    uint32_t recvCount;                              /* 接收消息计数 */

    uint32_t sendCount;                              /* 发送消息计数*/

} can_cur_node_t;



/* ==========================================  Variables  =========================================== */

/*  

 *  波特率和采样点计算公式:

 *  tSeg1 = (S_SEG_1 + 2); tSeg2 = (S_SEG_2 + 1).

 *  BandRate = (SRC_CLK / (S_PRESC + 1) / ((S_SEG_1 + 2) + (S_SEG_2 + 1))), SRC_CLK 为CAN模块时钟源

 *  SamplePoint = (tSeg1 / (tSeg1 + tSeg2)).

 */

#if (CAN_SOURCE_CLOCK == 80UL)  /*时钟源为80M*/

static const can_time_segment_t s_canBitrate[CAN_BITRATE_NUM] =

{

    {0x1C, 0x09, 0x09, 0x01},  /*   1M, 75% */

    {0x26, 0x09, 0x09, 0x01},  /* 800K, 80% */

    {0x1C, 0x09, 0x09, 0x03},  /* 500K, 75% */

    {0x1C, 0x09, 0x09, 0x07},  /* 250K, 75% */

    {0x1C, 0x09, 0x09, 0x0F},  /* 125K, 75% */

    {0x1C, 0x09, 0x09, 0x13},  /* 100K, 75% */

    {0x1C, 0x09, 0x09, 0x27},  /*  50K, 75% */

};



#elif (CAN_SOURCE_CLOCK == 60UL) /*时钟源为60M*/

static const can_time_segment_t s_canBitrate[CAN_BITRATE_NUM] =

{

    {0x0D, 0x04, 0x04, 0x02},  /*   1M, 75% */

    {0x12, 0x04, 0x04, 0x02},  /* 800K, 80% */

    {0x1C, 0x09, 0x09, 0x02},  /* 500K, 75% */

    {0x1C, 0x09, 0x09, 0x05},  /* 250K, 75% */

    {0x1C, 0x09, 0x09, 0x0B},  /* 125K, 75% */

    {0x1C, 0x09, 0x09, 0x0E},  /* 100K, 75% */

    {0x1C, 0x09, 0x09, 0x1D},  /*  50K, 75% */

};



#elif (CAN_SOURCE_CLOCK == 48UL) /* 时钟源为48M*/

static const can_time_segment_t s_canBitrate[CAN_BITRATE_NUM] =

{

    {0x22, 0x0B, 0x0B, 0x00},  /*   1M, 75% */

    {0x16, 0x05, 0x05, 0x01},  /* 800K, 80% */

    {0x22, 0x0B, 0x0B, 0x01},  /* 500K, 75%*/

    {0x22, 0x0B, 0x0B, 0x03},  /* 250K, 75% */

    {0x22, 0x0B, 0x0B, 0x07},  /* 125K, 75% */

    {0x22, 0x0B, 0x0B, 0x09},  /* 100K, 75% */

    {0x22, 0x0B, 0x0B, 0x13},  /*  50K, 75% */

};



#elif (CAN_SOURCE_CLOCK == 24UL) /* 时钟源为24M*/

static const can_time_segment_t s_canBitrate[CAN_BITRATE_NUM] =

{

    {0x10, 0x05, 0x05, 0x00},  /*   1M, 75% */

    {0x16, 0x05, 0x05, 0x00},  /* 800K, 80% */

    {0x10, 0x05, 0x05, 0x01},  /* 500K, 75% */

    {0x10, 0x05, 0x05, 0x03},  /* 250K, 75% */

    {0x10, 0x05, 0x05, 0x07},  /* 125K, 75% */

    {0x10, 0x05, 0x05, 0x09},  /* 100K, 75% */

    {0x10, 0x05, 0x05, 0x13},  /*  50K, 75% */

};



#elif (CAN_SOURCE_CLOCK == 8UL) /*时钟源为8M*/

static const can_time_segment_t s_canBitrate[CAN_BITRATE_NUM] =

{

    {0x04, 0x01, 0x01, 0x00},  /*   1M,75% */

    {0x06, 0x01, 0x01, 0x00},  /* 800K, 80% */

    {0x0A, 0x03, 0x03, 0x00},  /* 500K,75% */

    {0x0A, 0x03, 0x03, 0x01},  /* 250K,75% */

    {0x0A, 0x03, 0x03, 0x03},  /* 125K,75% */

    {0x0D, 0x04, 0x03, 0x03},  /* 100K,75% */

    {0x0D, 0x04, 0x03, 0x07},  /*  50K,75% */

};

#endif



static const can_filter_config_t s_canFilterList[16] =  /* 过滤器配置*/

{

    {0x00000001, 0x00000000, CAN_MSG_ID_BOTH},         /* 只接收ID 0x0000_0001和0x001的数据 */

    {0x00000002, 0x00000000, CAN_MSG_ID_STD},          /* 只接收ID 0x002的标准帧数据 */

    {0x00000013, 0x00000000, CAN_MSG_ID_EXT},          /* 只接收ID 0x0000_0013的扩展帧数据 */

    {0x00000124, 0x00000000, CAN_MSG_ID_BOTH},         /* 只接收ID 0x0000_0124和0x124的数据 */

    {0x00000050, 0x1FFFFF0F, CAN_MSG_ID_BOTH},         /* 可接收ID 0xXXXX_XX5X 或 0xX5X的数据,X为任意值 */

    {0x00000060, 0x1FFFFF0F, CAN_MSG_ID_BOTH},         /* 可接收ID 0xXXXX_XX6X 或 0xX6X的数据,X为任意值 */

    {0x00000007, 0x1FFFFFF0, CAN_MSG_ID_BOTH},         /* 可接收ID 0xXXXX_XXX7 或 0xXX7的数据,X为任意值 */

    {0x00000008, 0x1FFFFFF0, CAN_MSG_ID_BOTH},         /* 可接收ID 0xXXXX_XXX8 或 0xXX8的数据,X为任意值 */



    {0x00000009, 0x1FFFFFF0, CAN_MSG_ID_STD},          /* 可接收ID 0xXX9的标准帧数据,X为任意值 */

    {0x0000000a, 0x1FFFFFF0, CAN_MSG_ID_EXT},          /* 可接收ID 0xXXXX_XXXa的扩展帧数据,X为任意值 */

    {0x00000700, 0x1FFFF0FF, CAN_MSG_ID_BOTH},         /* 可接收ID 0xXXXX_X7XX 或 0x7XX的数据,X为任意值 */

    {0x0000c000, 0x1FFF0FFF, CAN_MSG_ID_EXT},          /* 可接收ID 0xXXXX_CXXX 的扩展帧数据,X为任意值 */

    {0x000d0000, 0x1FF0FFFF, CAN_MSG_ID_EXT},          /* 可接收ID 0xXXXX_DXXX 的扩展帧数据,X为任意值 */

    {0x00e00000, 0x1F0FFFFF, CAN_MSG_ID_EXT},          /* 可接收ID 0xXXEX_XXXX 的扩展帧数据,X为任意值 */

    {0x0f000000, 0x10FFFFFF, CAN_MSG_ID_EXT},          /* 可接收ID 0xXXXX_XXXX 的扩展帧数据,X为任意值 */

    {0x10000000, 0x0FFFFFFF, CAN_MSG_ID_EXT},          /* 可接收ID 0xXXXX_XXXX 的扩展帧数据,X为任意值 */

};



static can_cur_node_t s_canCurNode[CAN_INSTANCE_MAX] = {0}; /* 接收信息*/



/*!

 * [url=home.php?mod=space&uid=247401]@brief[/url] GPIO 初始化

 *

 * @param[in] instance: CAN 模块通道

 * [url=home.php?mod=space&uid=266161]@return[/url] none

 */

void CAN_InitGPIO(uint8_t instance)

{

    if (0U == instance)

    {

        GPIO_DRV_SetMuxModeSel(PORTE, 4U, PORT_MUX_ALT5);           /* CAN0_RX */

        GPIO_DRV_SetMuxModeSel(PORTE, 5U, PORT_MUX_ALT5);           /* CAN0_TX */

        GPIO_DRV_SetMuxModeSel(PORTE, 10U, PORT_MUX_ALT5);          /* 配置收发器standby功能*/

    }

    else if (1U == instance)

    {

        GPIO_DRV_SetMuxModeSel(PORTC, 6U, PORT_MUX_ALT3);           /* CAN1_RX */

        GPIO_DRV_SetMuxModeSel(PORTC, 7U, PORT_MUX_ALT3);           /* CAN1_TX */

        GPIO_DRV_SetMuxModeSel(PORTE, 6U, PORT_MUX_ALT5);           /* 配置收发器standby功能*/

    }

    else if (2U == instance)

    {

        GPIO_DRV_SetMuxModeSel(PORTC, 16U, PORT_MUX_ALT3);          /* CAN2_RX */

        GPIO_DRV_SetMuxModeSel(PORTC, 17U, PORT_MUX_ALT3);          /* CAN2_TX */

        GPIO_DRV_SetMuxModeSel(PORTC, 15U, PORT_MUX_ALT5);          /* 配置收发器standby功能 */

    }

    else if (3U == instance)

    {

        GPIO_DRV_SetMuxModeSel(PORTC, 12U, PORT_MUX_ALT5);          /* CAN3_RX */

        GPIO_DRV_SetMuxModeSel(PORTC, 13U, PORT_MUX_ALT5);          /* CAN3_TX */

        GPIO_DRV_SetMuxModeSel(PORTC, 11U, PORT_MUX_ALT5);          /* 配置收发器standby功能 */

    }

}



/*!

 * @brief CAN_GetNormalBitrate 获取波特率

 *

 * @param[in] index: 波特率索引

 * @return 波特率配置

 */

static can_time_segment_t CAN_GetNormalBitrate(can_bitrate_t index)

{

    can_time_segment_t bitrate = {0};



    if (index < CAN_BITRATE_NUM)

    {

        bitrate = s_canBitrate[index];

    }



    return bitrate;

}



/*!

 * @brief CAN_HandleMsg 接收数据处理

 *

 * @param[in] instance: CAN 模块通道

 * @param[in] msgInfo: 接收数据

 * @return none

 */

static void CAN_HandleMsg(uint8_t instance, const can_msg_info_t *msgInfo)

{

    uint8_t i = 0;



    s_canCurNode[instance].recvCount++;             /* 节点信息更新 */

#if CAN_MSG_HANDLE_DIRECT                           /* 处理数据*/

    if (msgInfo->IDE)

    {

        printf("CAN[%d] RecvCount:%06d ID:%08x DLC:%d", instance, s_canCurNode[instance].recvCount, msgInfo->ID, msgInfo->DLC);

    }

    else

    {

        printf("CAN[%d] RecvCount:%06d  ID:%03x DLC:%d", instance, s_canCurNode[instance].recvCount, msgInfo->ID, msgInfo->DLC);

    }

    if ((0 == msgInfo->RTR) && msgInfo->DLC)

    {

        printf("\r\tData: ");

        for (i = 0; (i < msgInfo->DLC) && (i < 8); i++)

        {

            printf(" %02x", msgInfo->DATA[i]);

        }

    }

    printf("\r\n");

#endif

}



/*!

 * @brief CAN_EventCallback 中断回调函数, 可通过CAN_IRQHandler了解参数具体含义

 *

 * @param[in] instance: CAN 模块通道

 * @param[in] event: 中断事件

 * @param[in] koer: 错误类型

 * @return 0: none

 */

void CAN_EventCallback(uint8_t instance, uint32_t event, uint32_t koer)

{

    can_msg_info_t recvMsg = {0};

    uint8_t recvData[8] = {0};



    if (event & (uint32_t)CAN_EVENT_BUS_ERROR)         /* 发生错误后,打印错误消息,仅用于调试 */

    {

        printf("CAN[%d]e: EVEN: %x  KOER: %x\r\n", instance, event, koer);

    }



    if (event & (uint32_t)CAN_EVENT_RECEIVE_DONE)      /* 接收数据*/

    {

        while (CAN_DRV_GetRbufStatus(instance))

        {

            recvMsg.DATA = recvData;                   /* 为接收数据索引中的数据域分配空间, 如果未给接收数据索引的数据域分配空间,直操作会触发Haltfault */

            if (!CAN_DRV_Receive(instance, &recvMsg))

            {

                CAN_HandleMsg(instance, &recvMsg);

            }

        }

    }

}







void init_can(void)

{

        uint8_t instance = 0U;

        can_user_config_t canCfg = {0};

        can_bitrate_t bitrateIndex = CAN_BITRATE_500K;                 /* 低速波特率设置 */

        can_transmit_buff_t type = CAN_TRANSMIT_SECONDARY;             /* 发送缓存设置 */



        canCfg.filterNum = 0U;                                         /* 过滤器数量 */

        canCfg.canMode = CAN_NORMAL_MODE;                              /* 正常模式 */

        canCfg.interruptEn = true;                                     /* 使能中断*/

        canCfg.tsMode = CAN_TSMODE_FIFO;                               /* 选择FIFO模式*/

        canCfg.tsAmount = CAN_TRANSMIT_SEC_ALL;                        /* TSALL*/

        canCfg.tpss = false;                                           /* 失能PTB单次发送 */

        canCfg.tsss = false;                                           /* 失能STB单次发送 */

        canCfg.rom = CAN_ROM_OVER_WRITE;                               /* 缓冲区溢出后,新数据会覆盖旧数据*/

        canCfg.errorWarningLimit = 0x0BU;                              /* 错误警告限制,当 TECNT|RECTN 超过这个限制,会触发EIF错误中断 */

#if CAN_TIME_STAMP_ENABLE

        canCfg.timeStampEn = true;                                     /* 时间戳使能 */

        canCfg.timeStampClkSrc = CAN_TIME_STAMP_CLK_SRC_EXT;           /* 时间戳时钟源选择 */

        canCfg.timeStampClkDiv = CAN_TIME_STAMP_CLK_DIV_8;             /* 时间戳时钟源分频 */

        canCfg.timeStampPos = CAN_TIME_STAMP_SOF;                      /* 时间区采样位置选择 */

#endif

        canCfg.dmaRecvEn = false;                                      /* 不使用DMA */

        canCfg.memEccEn = false;                                       /* 失能ECC */

        canCfg.wakeupIntEn = false;                                    /* 失能唤醒功能 */

        canCfg.busOffRecDisable = false;                               /* 失能自动总线关闭恢复, busoff产生后, 会遵循ISO 11898-规范 */

        canCfg.interruptMask = CAN_IRQ_ALL_ENABLE_MSK;                 /* 使能所有中断*/

        canCfg.bitrate = CAN_GetNormalBitrate(bitrateIndex);           /* 低速波特率配置*/

        canCfg.filterList = (can_filter_config_t *)s_canFilterList;    /* 过滤器配置*/

        canCfg.callback = (can_callback_t)CAN_EventCallback;

        CAN_InitGPIO(instance);                                        /* CAN模块IO口初始化 */

        CAN_DRV_Init(instance, &canCfg);                                                  /* CAN模块初始化 */

        

}



void can_senddat(uint8_t *dat)

{

    int32_t ret = 1;

    static can_msg_info_t s_sendMsg = {0};

    static uint8_t sendData[8] = {0};



    if (!CAN_DRV_IsTransmitBusy(0, CAN_TRANSMIT_SECONDARY))

    {

        s_sendMsg.ID = 0x220;                        /* CAN ID*/

        s_sendMsg.IDE = 0;                           /* 标准帧*/

        s_sendMsg.RTR = 0;                           /* 非远程帧*/

        s_sendMsg.DLC = 8;                           /* 数据长度*/

        s_sendMsg.DATA = sendData;                   /* 分配空间*/

        s_sendMsg.DATA[0] = dat[0];                    /* 填充数据*/

        s_sendMsg.DATA[1] = dat[1];

        s_sendMsg.DATA[2] = dat[2];

        s_sendMsg.DATA[3] = dat[3];

        s_sendMsg.DATA[4] = dat[4];

        s_sendMsg.DATA[5] = dat[5];

        s_sendMsg.DATA[6] = dat[6];

        s_sendMsg.DATA[7] = dat[7];

        if (STATUS_SUCCESS == CAN_DRV_Send(0, &s_sendMsg, CAN_TRANSMIT_SECONDARY))

        {

            s_canCurNode[0].sendCount++;      /* 节点信息更新 */

            ret = 0;

        }

    }



    return ret;

}











2.2、main.c

复制

#include "ac7840x.h"

#include "clock_config.h"

#include "debugout_ac7840x.h"

#include "osif.h"

#include "led/led.h"

#include "key/key.h"

#include "adc/adc.h"

#include "spi/spi.h"

#include "ch376s.h"

#include "can/can.h"



uint8_t can_txbuf[8];



void SystemClock_Config(void)

{

    CKGEN_SYS_Init(g_clockManConfigsArr, CLOCK_MANAGER_CONFIG_CNT,

                   g_clockManCallbacksArr, CLOCK_MANAGER_CALLBACK_CNT);

    CKGEN_DRV_UpdateConfiguration(0, CLOCK_MANAGER_POLICY_AGREEMENT);

}



int main(void)

{

        uint8_t i=0;

        SystemClock_Config();

        init_led();

        init_key();

        init_adc();

        InitDebug();

        init_can();



        while (1)

        {

                i++;

                can_txbuf[0]=i;

                can_senddat(can_txbuf);

                led3_on();

                OSIF_TimeDelay(100);

                led3_off();

                OSIF_TimeDelay(100);

                //ADC_TriggerTest();

        }

}



三、运行结果

3.1、CAN接收测试
打开CAN调试卡,收到开发板发送的数据
 



3.2、CAN接收测试
串口打印CAN接收到的数据


---------------------
作者:tlled
链接:https://bbs.21ic.com/icview-3350900-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值