【GD32 MCU 入门教程】GD32 MCU 常见外设介绍(15)CAN 模块介绍

发布者:科技创新实践者最新更新时间:2024-11-04 来源: elecfans关键字:GD32  MCU  CAN  模块 手机看文章 扫描二维码
随时随地手机看文章

输入图片说明

各系列 CAN 功能差异

GD32系列MCU有关CAN外设各系列功能差异如下表GD32各系列MCU CAN外设功能差异表所示。

输入图片说明

15.3.硬件连接说明

CAN 外设硬件连接图

输入图片说明

如图CAN外设硬件连接图所示,为典型的CAN外设硬件连接图:SN65HVD230是收发器,其作用就是把CAN控制器的TTL电平转换成差分信号。发送数据时,控制器把要发送的二进制编码通过CAN_TX线发送到收发器,然后由收发器把这个逻辑电平转换成差分信号,通过差分线CANH、CANL线输出到总线网络。当接收数据时,收发器把总线上收到的CANH、CANL信号转换成逻辑电平,通过CAN_RX输入到控制器。

读者可以根据典型硬件连接图和相应系列的Datasheet设计出自己的硬件连接方式。

15.4.软件配置说明

本小节讲解CAN_Example历程中CAN模块的配置说明,主要包括CAN外设配置、GPIO引脚配置、主函数介绍以及运行结果。本例程主要介绍GD32 MCU各系列CAN模块的数据发送、接收,有关CAN其他功能例程可参考各系列固件库历程。

CAN 外设配置

外设配置如代码清单CAN外设配置所示,在GD32全系列MCU中CAN外设的配置基本相同。GD32标准库提供了CAN初始化结构体及初始化函数来配置CAN外设,其初始化结构体说明如下表CAN参数初始化结构体说明列表和CAN过滤器初始化结构体说明列表所示。需要注意的是本例程需要用到两个开发板,一个发送,一个接收,这可以通过打开宏定义CAN_RECEIVE或CAN_TRANSMIT来决定当前是接收还是发送。

代码清单 CAN 外设配置

void can_config(void) { #if defined (GD32F30X_CL) ||(GD32F4XX) ||(GD32F20X_CL)||(GD32F10X_HD) can_parameter_struct can_parameter; can_filter_parameter_struct can_filter_parameter; can_struct_para_init(CAN_INIT_STRUCT, &can_parameter); can_struct_para_init(CAN_FILTER_STRUCT, &can_filter_parameter); /* initialize CAN register */ can_deinit(CAN0); /* initialize CAN parameters */ can_parameter.time_triggered = DISABLE; can_parameter.auto_bus_off_recovery = DISABLE; can_parameter.auto_wake_up = DISABLE; can_parameter.no_auto_retrans = DISABLE; can_parameter.rec_fifo_overwrite = DISABLE; can_parameter.trans_fifo_order = DISABLE; can_parameter.working_mode = CAN_NORMAL_MODE; can_parameter.resync_jump_width = CAN_BT_SJW_1TQ; can_parameter.time_segment_1 = CAN_BT_BS1_5TQ; can_parameter.time_segment_2 = CAN_BT_BS2_4TQ; can_parameter.prescaler = 12; /* initialize CAN */ can_init(CAN0, &can_parameter); /* initialize filter */ can_filter_parameter.filter_number = 0; can_filter_parameter.filter_mode = CAN_FILTERMODE_MASK; can_filter_parameter.filter_bits = CAN_FILTERBITS_32BIT; can_filter_parameter.filter_list_high = 0x0000; can_filter_parameter.filter_list_low = 0x0000; can_filter_parameter.filter_mask_high = 0x0000; can_filter_parameter.filter_mask_low = 0x0000; can_filter_parameter.filter_fifo_number = CAN_FIFO0; can_filter_parameter.filter_enable = ENABLE; can_filter_init(&can_filter_parameter); #if defined (CAN_RECEIVE) #if defined (GD32F10X_HD) nvic_irq_enable(USBD_LP_CAN0_RX0_IRQn,0,0); #else nvic_irq_enable(CAN0_RX0_IRQn,0,0); #endif /* enable can receive FIFO0 not empty interrupt */ can_interrupt_enable(CAN0, CAN_INT_RFNE0); #endif #elif defined (GD32E10X) can_parameter_struct can_parameter; can_struct_para_init(CAN_INIT_STRUCT, &can_parameter); /* initialize CAN register */ can_deinit(CAN0); /* initialize CAN parameters */ can_parameter.time_triggered = DISABLE; can_parameter.auto_bus_off_recovery = DISABLE; can_parameter.auto_wake_up = DISABLE; can_parameter.auto_retrans = DISABLE; can_parameter.rec_fifo_overwrite = DISABLE; can_parameter.trans_fifo_order = DISABLE; can_parameter.working_mode = CAN_NORMAL_MODE; /* initialize CAN */ can_init(CAN0, &can_parameter); /* config CAN0 baud rate */ can_frequency_set(CAN0, DEV_CAN_BAUD_RATE); /* initialize filter */ can_filter_mask_mode_init(DEV_CAN_ID, DEV_CAN_MASK, CAN_EXTENDED_FIFO0, 0); #if defined (CAN_RECEIVE) /* configure CAN0 NVIC */ nvic_irq_enable(CAN0_RX0_IRQn, 0, 0); /* enable can receive FIFO0 not empty interrupt */ can_interrupt_enable(CAN0, CAN_INTEN_RFNEIE0); #endif #elif defined (GD32F1X0) can_parameter_struct can_parameter; can_filter_parameter_struct can_filter_parameter; /* initialize CAN register */ can_deinit(CAN1); /* initialize CAN parameters */ can_parameter.time_triggered = DISABLE; can_parameter.auto_bus_off_recovery = DISABLE; can_parameter.auto_wake_up = DISABLE; can_parameter.no_auto_retrans = DISABLE; can_parameter.rec_fifo_overwrite = DISABLE; can_parameter.trans_fifo_order = DISABLE; can_parameter.working_mode = CAN_NORMAL_MODE; can_parameter.resync_jump_width = CAN_BT_SJW_1TQ; can_parameter.time_segment_1 = CAN_BT_BS1_4TQ; can_parameter.time_segment_2 = CAN_BT_BS2_3TQ; can_parameter.prescaler = 18; /* initialize CAN */ can_init(CAN1, &can_parameter); /* initialize filter */ can_filter_parameter.filter_number = 15; can_filter_parameter.filter_mode = CAN_FILTERMODE_MASK; can_filter_parameter.filter_bits = CAN_FILTERBITS_32BIT; can_filter_parameter.filter_list_high = 0x0000; can_filter_parameter.filter_list_low = 0x0000; can_filter_parameter.filter_mask_high = 0x0000; can_filter_parameter.filter_mask_low = 0x0000; can_filter_parameter.filter_fifo_number = CAN_FIFO0; can_filter_parameter.filter_enable = ENABLE; can_filter_init(&can_filter_parameter); #if defined (CAN_RECEIVE) /* configure CAN1 NVIC */ nvic_irq_enable(CAN1_RX0_IRQn,0,0); can_interrupt_enable(CAN1, CAN_INTEN_RFNEIE0); #endif #endif }


CAN 参数初始化结构体说明列表

输入图片说明

CAN 过滤器初始化结构体说明列表

输入图片说明

GPIO 引脚配置

GPIO引脚配置如代码清单CAN例程GPIO引脚配置所示。GD32F10X、GD32F30X、GD32F20X、GD32E10X系列用到remap功能,因此需要打开AF时钟。使用GD32F1X0时,例程中是使用CAN1来进行收发。需要注意的是,发送时,不需要打开CAN0的时钟,但是接收时需要打开CAN0的时钟。

代码清单 CAN 例程 GPIO 引脚配置

void can_gpio_config(void) { #if defined (GD32F4XX) /* enable CAN0 clock */ rcu_periph_clock_enable(RCU_CAN0); rcu_periph_clock_enable(RCU_GPIOB); /* configure CAN0 GPIO */ gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8); gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_8); gpio_af_set(GPIOB, GPIO_AF_9, GPIO_PIN_8); gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_9); gpio_af_set(GPIOB, GPIO_AF_9, GPIO_PIN_9); #elif defined (GD32E10X) || (GD32F30X_CL) ||(GD32F10X_HD) /* enable CAN0 clock */ rcu_periph_clock_enable(RCU_CAN0); rcu_periph_clock_enable(RCU_GPIOD); rcu_periph_clock_enable(RCU_AF); /* configure CAN0 GPIO */ gpio_init(GPIOD,GPIO_MODE_IPU,GPIO_OSPEED_50MHZ,GPIO_PIN_0); gpio_init(GPIOD,GPIO_MODE_AF_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_1); #if defined (GD32F10X_HD) gpio_pin_remap_config(GPIO_CAN_FULL_REMAP,ENABLE); #else gpio_pin_remap_config(GPIO_CAN0_FULL_REMAP,ENABLE); #endif #elif defined (GD32F20X_CL) /* enable CAN0 clock */ rcu_periph_clock_enable(RCU_CAN0); rcu_periph_clock_enable(RCU_GPIOB); rcu_periph_clock_enable(RCU_AF); /* configure CAN0 GPIO */ gpio_init(GPIOB,GPIO_MODE_IPU,GPIO_OSPEED_50MHZ,GPIO_PIN_8); gpio_init(GPIOB,GPIO_MODE_AF_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_9); gpio_pin_remap_config(GPIO_CAN0_PARTIAL_REMAP,ENABLE); #elif defined (GD32F1X0) //only GD32F170 and GD32F190 have CAN, GD32F130 and GD32F150 don't have /* enable CAN clock */ #if defined (CAN_RECEIVE) rcu_periph_clock_enable(RCU_CAN0); #endif rcu_periph_clock_enable(RCU_CAN1); rcu_periph_clock_enable(RCU_GPIOB); /* configure CAN1 GPIO */ gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_12); gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_12); gpio_af_set(GPIOB, GPIO_AF_9, GPIO_PIN_12); gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_13); gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13); gpio_af_set(GPIOB, GPIO_AF_9, GPIO_PIN_13); #endif }


主函数配置

主函数配置如代码清单主函数配置所示。本例程需要两个开发板,一个作为发送,一个作为接收,这可以通过使用宏定义CAN_RECEIVE和CAN_TRANSMIT来实现。如果作为接收,那么主函数的开始会把can_receive_flag设置为RESET,并初始化LED2。LED2作为通讯的指示灯,如果通讯成功,就点亮LED2,否则就不点亮。can_receive_flag状态的改变在中断里实现,如果成功接收到数据,就会进入中断,在中断里把can_receive_flag设置为SET。主函数接下来对CAN的GPIO以及CAN模块进行初始化。完成后,如果是作为发送方,程序需要设置需要发送的数据。有关发送结构体参数的说明,请见下表CAN发送消息初始化结构体说明列表。

代码清单主函数配置

int main(void) { #if defined (CAN_RECEIVE) can_receive_flag = RESET; LED2_init(); #endif /* GPIO config */ can_gpio_config(); /* CAN config */ can_config(); #if defined (CAN_TRANSMIT) /* initialize transmit message */ #if defined (GD32E10X) || (GD32F30X_CL) || (GD32F10X_HD) || (GD32F4XX) || (GD32F20X_CL) can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &g_transmit_message); #endif g_transmit_message.tx_sfid = 0x00; g_transmit_message.tx_efid = DEV_CAN_ID; g_transmit_message.tx_ft = CAN_FT_DATA; g_transmit_message.tx_ff = CAN_FF_EXTENDED; g_transmit_message.tx_dlen = 4; g_transmit_message.tx_data[0] = 0xaa; g_transmit_message.tx_data[1] = 0xbb; g_transmit_message.tx_data[2] = 0xcc; g_transmit_message.tx_data[3] = 0xdd; #if defined (GD32E10X) || (GD32F30X_CL) || (GD32F10X_HD) || (GD32F4XX) || (GD32F20X_CL) can_message_transmit(CAN0, &g_transmit_message); #elif defined (GD32F1X0) can_message_transmit(CAN1, &g_transmit_message); #endif #endif #if defined (CAN_RECEIVE) while(can_receive_flag == RESET); if((g_receive_message.rx_data[0] == 0xaa) && (g_receive_message.rx_data[1] == 0xbb)&& (g_receive_message.rx_data[2] == 0xcc) && (g_receive_message.rx_data[3] == 0xdd)) { LED2_ON(); } else { LED2_OFF(); } #endif while(1); }


CAN 发送消息初始化结构体说明列表

输入图片说明

运行结果

本例程需要用到两个开发板,用杜邦线把两个开发板的CAN_H、CAN_L分别连接起来。打开CAN_Example例程,选择好对应开发板的芯片工程后,先屏蔽掉CAN_RECEIVE,不屏蔽CAN_TRANSMIT ,编译后把程序下载到一号开发板上。然后换一块开发板,屏蔽掉CAN_TRANSMIT,不屏蔽CAN_RECEIVE,编译后把程序下载到二号开发板上。接下来按下二号开发板的复位键,然后再按下一号开发板的复位键,此时会看到二号开发板的LED2被点亮,这表明通讯成功。

15.5.CAN 使用注意事项

(1) 使用F10X、F20X、F30X、F1X0、E10X、F403接收数据时如果出现接收两帧数据会丢失一包的情况,这是由于手动多调用一次清缓存的操作导致的。因此,软件中无需调用can_fifo_release函数;

(2) 使用F10X、F20X、F1X0时,会出现CAN离线后无法自动恢复,这是由于CAN模块的离线自动恢复功能与CAN协议定义的离线恢复序列存在一定理解误差造成的。该状况可以通过使能离线中断,在离线中断内重新初始化CAN模块来规避;

(3) GD32F170和GD32F190的CAN0内置PHY,其CANH和CANL口的耐压范围为VSS-0.3到VSS+7.5,内置的PHY不支持12V和24V系统。当使用CAN0时,建议硬件上按照下图CAN0引脚连接图连接。

CAN0 引脚连接图

输入图片说明

[1] [2]
关键字:GD32  MCU  CAN  模块 引用地址:【GD32 MCU 入门教程】GD32 MCU 常见外设介绍(15)CAN 模块介绍

上一篇:【GD32 MCU 入门教程】GD32 MCU 常见外设介绍(1)RCU 时钟介绍
下一篇:【GD32 MCU 入门教程】GD32 MCU 常见外设介绍(3)NVIC 介绍

推荐阅读最新更新时间:2026-02-26 10:42

GD32 MCU 入门教程】GD32 MCU 常见外设介绍(8)SPI 模块介绍
串行外设接口(Serial Peripheral Interface,缩写为 SPI) 提供了基于SPI 协议的数据发送和接收功能, 可以工作于主机或从机模式。 SPI 接口支持具有硬件 CRC 计算和校验的全双工和单工模式。 8.1.SPI 基础知识 SPI 物理层 SPI接口采用主从模式(Master Slave)架构;支持一主一从模式和一主多从模式,但不支持多主模式。它是一种同步高速全双工的通信总线,总体结构如下图常见的SPI通讯系统所示。 一个主机连接四个从机,其中一个SPI总线一般有四个信号分为: SCLK:时钟信号,由主机产生并控制。 MOSI:主机数据输出,从机数据输入。 MISO:主机数据输入,从机数据输出。
[单片机]
【<font color='red'>GD32</font> <font color='red'>MCU</font> 入门教程】<font color='red'>GD32</font> <font color='red'>MCU</font> <font color='red'>常见</font><font color='red'>外设</font>介绍(8)SPI <font color='red'>模块</font>介绍
GD32 MCU 入门教程】GD32 MCU 常见外设介绍(11)PMU 模块介绍
11.1.PMU 简介 PMU即电源管理单元,它有三个电源域,包括VDD/VDDA域、1.1V/1.2V域和备份域。电源管理单元在常规芯片提供了三种省电模式,包括睡眠模式、深度睡眠模式和待机模式;在低功耗芯片中,电源管理单元提供了十种省电模式,包括运行模式,运行模式 1,运行模式 2,睡眠模式,睡眠模式 1,睡眠模式 2,深度睡眠模式,深度睡眠模式 1,深度睡眠模式 2 和待机模式。这些模式能减少电源能耗,且使得应用程序可以在CPU运行时间要求、速度和功耗的相互冲突中获得最佳折衷。 11.2.PMU 功能 三个电源域:备份域、 VDD/VDDA域和1.1V/1.2V电源域; 三种省电模式(常规芯片):睡眠模式、深度睡眠模式和待
[单片机]
【<font color='red'>GD32</font> <font color='red'>MCU</font> 入门教程】<font color='red'>GD32</font> <font color='red'>MCU</font> <font color='red'>常见</font><font color='red'>外设</font>介绍(11)PMU <font color='red'>模块</font>介绍
GD32 MCU 入门教程】GD32 MCU 常见外设介绍(9)FWDG 模块介绍
9.1.FWDG 简介 本章我们主要分析独立看门狗(FWDG)的功能框图和它的应用。独立看门狗用通俗一点的话来解释就是一个12位的递减计数器,当计数器的值从某个值一直减到0的时候,系统就会产生一个复位信号,即FWDGTRSTF。如果在计数没减到0之前,刷新了计数器的值的话,那么就不会产生复位信号,这个动作就是我们经常说的喂狗。看门狗功能由 VDD 电压域供电,在停止模式和待机模式下仍能工作。独立看门狗定时器有独立的时钟源(IRC40K) 。 即使主时钟失效, FWDGT依然 能保持正常工作状态, 适用于需要独立环境且对计时精度要求不高的场合。 9.2.GD32 FWDG 外设原理简介 因篇幅有限,本文无法详细介绍GD32所有系列F
[单片机]
【<font color='red'>GD32</font> <font color='red'>MCU</font> 入门教程】<font color='red'>GD32</font> <font color='red'>MCU</font> <font color='red'>常见</font><font color='red'>外设</font>介绍(9)FWDG <font color='red'>模块</font>介绍
有关STM32外设配置的几个常见问题
在做STM32开发应用的过程中,常常会遇到这样那样的问题,其中相当部分问题是与各外设及相关GPIO的配置有关的。就这方面的问题,这里一起总结交流下。 目前的STM32芯片是基于ARM内核的可编程微处理器,我们可以简单地把内核以外的东西统称为外设,比方 TIMER、UART、SPI、USB、I2C、存储器等功能模块。以32F427芯片功能框图为例,那些红圈上的都是。 好,我们直接切入主题。围绕外设的配置,我们遇到的问题,大致可以分为两大类。 一、时钟问题,就这方面的问题又可以细分为几小点。 1.1 时钟没打开就使用。 这个不难理解,就是相关外设的时钟没有打开。比如UART5的时钟没有打开,SPI的时钟没打开
[单片机]
有关STM32<font color='red'>外设</font>配置的几个<font color='red'>常见</font>问题
单片机和MCP2510的CAN息线通信模块设计
CAN(Controller Area Network)总线,即控制器局域网。由于具有高性能、高可靠性以及独特的设计,CAN总线越来越受到人们的重视。德国的Bosch公司最初为汽车监控和控制系统设计了CAN总线,现在,其应用已面向过程工业、机械工业、纺织工业、农用机械、机器人、数控机床、医疗器械及传感器等领域发展。CAN总线已经形成国际标准,并已经公认为是最有前途的现场总线之一。CAN总线规范已经被国际标准化组织制订为国际标准ISOll898,并得到众多半导体器件厂商的支持,推出各种集成有CAN协议的产品。CAN总线系统智能节点是网络上报文的接收和发送站,一般由单片机和CAN控制器或二者合二为一组成。 MCP2510是Micro
[单片机]
单片机和MCP2510的CAN息线通信模块设计
  CAN(Controller Area Network)总线,即控制器局域网。由于具有高性能、高可靠性以及独特的设计,CAN总线越来越受到人们的重视。德国的Bosch公司最初为汽车监控和控制系统设计了CAN总线,现在,其应用已面向过程工业、机械工业、纺织工业、农用机械、机器人、数控机床、医疗器械及传感器等领域发展。CAN总线已经形成国际标准,并已经公认为是最有前途的现场总线之一。CAN总线规范已经被国际标准化组织制订为国际标准ISOll898,并得到众多半导体器件厂商的支持,推出各种集成有CAN协议的产品。CAN总线系统智能节点是网络上报文的接收和发送站,一般由单片机和CAN控制器或二者合二为一组成。   M
[工业控制]
<font color='red'>单片机</font>和MCP2510的<font color='red'>CAN</font>息线通信<font color='red'>模块</font>设计
单片机和MCP2510的CAN总线通信模块设计
CAN(Controller Area Network)总线,即控制器局域网。由于具有高性能、高可靠性以及独特的设计,CAN总线越来越受到人们的重视。德国的Bosch公司最初为汽车监控和控制系统设计了CAN总线,现在,其应用已面向过程工业、机械工业、纺织工业、农用机械、机器人、数控机床、医疗器械及传感器等领域发展。CAN总线已经形成国际标准,并已经公认为是最有前途的现场总线之一。CAN总线规范已经被国际标准化组织制订为国际标准ISO11898,并得到众多半导体器件厂商的支持,推出各种集成有CAN协议的产品。CAN总线系统智能节点是网络上报文的接收和发送站,一般由单片机和CAN控制器或二者合二为一组成。 MCP25l0是Micro
[工业控制]
GD32 MCU 移植教程】9、从 STM32F10x 系列移植到 GD32F30x 系列
1.本文简介 GD32F30x 系列 MCU 是基于 Arm® Cortex®-M4 处理器的 32 位通用微控制器,与 STM32F10x 系列 MCU 保持高度兼容。本文主要从以下三个方面进行介绍:硬件资源对比、外设及性能对比以及从 STM32F10x 移植到 GD32F30x 的移植步骤,旨在让开发者能够快速从 STM32F10x 移植到 GD32F30x,缩短研发周期,加快产品开发进度。 2.GD32F30x vs STM32F10x 硬件资源对比 GD32F30x 和 STM32F10x 硬件引脚对比如表 2-1. GD32F30x 和 STM32F10xpin 对比所示,由该表可知,GD32F30x 与 STM32
[单片机]
【<font color='red'>GD32</font> <font color='red'>MCU</font> 移植教程】9、从 STM32F10x 系列移植到 GD32F30x 系列
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved