Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
CAN总线
M2354
【NuMaker-M2354试用】CAN总线开发与测试分享【硬件篇】
发布于 2021-12-04 14:52:19 浏览:1119
订阅该版
[tocm] 最近参加了【新唐NuMaker-M2354模块评测任务大挑战】的活动,很幸运的被抽中获得试用机会。😊 由于平时工作中接触CAN总线比较多,故花了几天时间,试用了一下M2354的CAN总线功能,现在把这几天测试过程中总结的经验来分享给大家。我准备写三篇文章来分享,这是第一篇,介绍硬件。废话不多说了,开始上干货。 ### 1.M2354 CAN控制器介绍 在M2354芯片中存在一个CAN控制器,用于控制CAN报文收发控制,还具有32个消息对象,每个消息对象拥有独立的消息缓存,功能非常强大。但是它并不能直接和CAN 总线连接,因为电平不匹配,M2354的CAN接口为TTL电平,CAN总线上为差分信号,为了实现信号转换,我们需要用到CAN收发芯片来实现电平转换。常规的CAN收发芯片为TJA1050,物美价廉,性能稳定,美中不足的是它并非隔离型CAN收发器。由于CAN总线工作环境非常复杂,在某些工况下会受到干扰,所以在实际使用中需要使用隔离CAN收发器,常用的隔离CAN收发器为TD041SCANFD,需要配合隔离电源B0305S-W5SY使用。 ### 2.非隔离CAN BUS电路设计。 使用TJA1050实现,使用5V供电,此处注意,因为根据规定,CAN总线使用差分信号,总线对地为2.5V左右的电压,所以TJA1050只能使用5V,不能使用3.3V供电。具体原理图如下所示。 ![image.png](https://oss-club.rt-thread.org/uploads/20211204/4c41e92a199aaacd102520c531177574.png) 在图中增加了一颗共模电感FL1,用于滤除CAN总线上的公模干扰,另外增加了两个TVS管D2和D3,用于实现CAN总线上的浪涌泄放,保护脆弱的CAN收发芯片。 R1为终端电阻,一般短距离通信并不需要,当CAN总线比较长时,需要增加该终端电阻,否则就会造成无法正常通信的问题。 ### 3.隔离型CAN BUS电路设计。 使用TD041SCANFD+B0305S-W5SY的方案来实现,电路简单可靠,在实际应用中稳定性非常优秀。 ![image.png](https://oss-club.rt-thread.org/uploads/20211204/1a7cda4990a0db4021ff4fe9819500ef.png) TD041SCANFD很特殊,需要使用两路电源,并且时隔离电源,在和单片机连接的一端需要3.3V,在CAN输出端需要5V,所以选用了B0305隔离电源来实现供电。 ### 4.NuMaker-M2354连接CAN收发器 此次使用的为TJA1050方案的非隔离CAN收发器,使用了之前设计的迷你CAN卡的PCB来使用。如图所示。 ![image.png](https://oss-club.rt-thread.org/uploads/20211204/9e5ad7a570edd69a118531b298dbe546.png.webp) 线束颜色 | 左侧| 右侧 -----|-------|----- 红色 | +5V | CAN_H 黑色 | GND | CAN_L 黄色 | TX | 无 绿色 | RX | 无 ![image.png](https://oss-club.rt-thread.org/uploads/20211204/cf8d4e7ee0f80aba195dab4b3acb720d.png) 上图所示的为M2354的所有CAN接口引脚,我们使用PA4和PA5来连接CAN收发器小板。在NuMaker-M2354上所在位置如下图所示。 ![image.png](https://oss-club.rt-thread.org/uploads/20211204/b2b8c51df46c6e1c33f00917dbf402b6.png) 最终的连接如下图所示。 ![image.png](https://oss-club.rt-thread.org/uploads/20211204/b391a93b8654cdc11c31f7e3f4df5271.png.webp) ### 5.硬件测试程序 搭建完硬件环境后,写一个简单的测试程序来检测一下功能。因为现在在家,所以没办法模拟真正的测试环境,所以使用了一台[ZLG USBCAN-II](https://manual.zlg.cn/web/#/55?page_id=2274) 来收发CAN报文。 ```c #include
#include "NuMicro.h" /*---------------------------------------------------------------------------------------------------------*/ /* Global variables */ /*---------------------------------------------------------------------------------------------------------*/ static STR_CANMSG_T rrMsg; void SYS_Init(void) { /*---------------------------------------------------------------------------------------------------------*/ /* Init System Clock */ /*---------------------------------------------------------------------------------------------------------*/ /* Enable HIRC clock */ CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk); /* Wait for HIRC clock ready */ CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk); /* Set core clock to 96MHz */ CLK_SetCoreClock(96000000); /* Enable UART0 module clock */ CLK_EnableModuleClock(UART0_MODULE); /* ENable CAN module clock */ CLK_EnableModuleClock(CAN0_MODULE); /* Select UART0 module clock source as HIRC and UART0 module clock divider as 1 */ CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL2_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1)); /* Update System Core Clock */ SystemCoreClockUpdate(); /*---------------------------------------------------------------------------------------------------------*/ /* Init I/O Multi-function */ /*---------------------------------------------------------------------------------------------------------*/ /* Set multi-function pins for UART0 RXD and TXD */ SYS->GPA_MFPL = (SYS->GPA_MFPL & (~(UART0_RXD_PA6_Msk | UART0_TXD_PA7_Msk))) | UART0_RXD_PA6 | UART0_TXD_PA7; /* Set multi-function pins for CAN0 RXD and TXD */ SYS->GPA_MFPL = (SYS->GPA_MFPL & (~(CAN0_RXD_PA4_Msk | CAN0_TXD_PA5_Msk))) | CAN0_RXD_PA4 | CAN0_TXD_PA5; } void DEBUG_PORT_Init(void) { /*---------------------------------------------------------------------------------------------------------*/ /* Init UART */ /*---------------------------------------------------------------------------------------------------------*/ DEBUG_PORT->LINE = UART_PARITY_NONE | UART_STOP_BIT_1 | UART_WORD_LEN_8; DEBUG_PORT->BAUD = UART_BAUD_MODE2 | UART_BAUD_MODE2_DIVIDER(__HIRC, 115200); } /** * @brief Init CAN driver */ void CAN_Init(CAN_T *tCAN) { if(tCAN == CAN0) { // Enable IP clock CLK->APBCLK0 |= CLK_APBCLK0_CAN0CKEN_Msk; // Reset CAN0 SYS->IPRST1 |= SYS_IPRST1_CAN0RST_Msk; SYS->IPRST1 &= ~SYS_IPRST1_CAN0RST_Msk; } } /** * @brief Disable CAN * @details Reset and clear all CAN control and disable CAN IP */ void CAN_STOP(CAN_T *tCAN) { if(tCAN == CAN0) { /* Disable CAN0 Clock and Reset it */ SYS->IPRST1 |= SYS_IPRST1_CAN0RST_Msk; SYS->IPRST1 &= ~SYS_IPRST1_CAN0RST_Msk; CLK->APBCLK0 &= ~CLK_APBCLK0_CAN0CKEN_Msk; } } void SelectCANSpeed(CAN_T *tCAN) { uint32_t unItem; int32_t i32Err = 0; i32Err = (int32_t)CAN_Open(tCAN, 500000, CAN_BASIC_MODE); } /*----------------------------------------------------------------------------*/ /* Test Function */ /*----------------------------------------------------------------------------*/ void CAN_ShowMsg(STR_CANMSG_T* Msg) { uint8_t i; printf("Read ID=%8X, Type=%s, DLC=%d,Data=", Msg->Id, Msg->IdType ? "EXT" : "STD", Msg->DLC); for(i = 0; i < Msg->DLC; i++) printf("%02X,", Msg->Data[i]); printf("\n\n"); } void CAN_ResetIF(CAN_T *tCAN, uint8_t u8IF_Num) { if(u8IF_Num > 1) return; tCAN->IF[u8IF_Num].CREQ = 0x0; // set bit15 for sending tCAN->IF[u8IF_Num].CMASK = 0x0; tCAN->IF[u8IF_Num].MASK1 = 0x0; // useless in basic mode tCAN->IF[u8IF_Num].MASK2 = 0x0; // useless in basic mode tCAN->IF[u8IF_Num].ARB1 = 0x0; // ID15~0 tCAN->IF[u8IF_Num].ARB2 = 0x0; // MsgVal, eXt, xmt, ID28~16 tCAN->IF[u8IF_Num].MCON = 0x0; // DLC tCAN->IF[u8IF_Num].DAT_A1 = 0x0; // data0,1 tCAN->IF[u8IF_Num].DAT_A2 = 0x0; // data2,3 tCAN->IF[u8IF_Num].DAT_B1 = 0x0; // data4,5 tCAN->IF[u8IF_Num].DAT_B2 = 0x0; // data6,7 } /*----------------------------------------------------------------------------*/ /* Read Rx Msg by Basic Mode Function (Without Message RAM) */ /*----------------------------------------------------------------------------*/ void Test_BasicMode_Rx(CAN_T *tCAN) { STR_CANMSG_T rMsg[5]; int32_t i; CAN_ResetIF(tCAN, 1); tCAN->IF[1].MCON = 0; while(CAN_Receive(tCAN, 0, &rMsg[0]) == FALSE) { } CAN_ShowMsg(&rMsg[0]); return; } int main() { CAN_T *tCAN; tCAN = (CAN_T *) CAN0; SYS_UnlockReg(); SYS_Init(); DEBUG_PORT_Init(); /* Select CAN Multi-Function */ CAN_Init(tCAN); SelectCANSpeed(tCAN); while(1) { Test_BasicMode_Rx(tCAN); } } ``` 这个程序功能为当ZLG USBCAN-I以500Kbps的波特率发送一帧报文后,传输到M2354的CAN接口上,被解析后从串口输出解析的报文。 在ZCANPRO上发送内容如下: ![image.png](https://oss-club.rt-thread.org/uploads/20211204/ad8ed9be5c8aa3eb7f073991b52c2932.png) 在M2354上接收解析的报文内容如下: ![image.png](https://oss-club.rt-thread.org/uploads/20211204/72c6a9dd42e0bfd42063a65a8806c9a5.png) ### 到此硬件篇结束,接下来【下位机篇】开始介绍M2354在RT-THREAD上移植和使用CAN 总线接口,并且加上相关的协议控制,实现一个简单的CAN卡。在【上位机篇】会分享并且开源相关上位机源代码,分享一整套完整的解决方案。
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
xuyu
这家伙很懒,什么也没写!
文章
3
回答
0
被采纳
0
关注TA
发私信
相关文章
1
我也来传一个CANOpen移植,RTT+STM32F107+CanOpenNode
2
谁有STM32裸跑的CANopen程序啊???
3
CAN驱动程序框架
4
CAN驱动接口如何规范一下
5
RTT无法进入线程.Cannot access Memory
6
编译提示arm-none-eabi/bin/ld: cannot find crt0.o: No such file o
7
rtt 2.1.0 正式版 mdk4 bsp/stm32 编译canapp.c错误
8
STM32F10XCAN驱动使用的问题
9
2.1版本stm32f10x分支bxcan驱动波特率设置的bug
10
rtthread2.1.0下,找不到can1设备
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
中断
编译报错
Debug
SFUD
rt_mq_消息队列_msg_queue
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
a1012112796
10
个答案
1
次被采纳
踩姑娘的小蘑菇
4
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
Ryan_CW
4
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
YZRD
2
篇文章
4
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部