各系列 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 引腳連接圖
上一篇:【GD32 MCU 入門教程】GD32 MCU 常見外設介紹(1)RCU 時鐘介紹
下一篇:【GD32 MCU 入門教程】GD32 MCU 常見外設介紹(3)NVIC 介紹
推薦閱讀最新更新時間:2025-04-24 15:51






設計資源 培訓 開發板 精華推薦
- CK_LINK Lite2.30
- DC237A,用于 LT1506 單片 4A 開關 5V 至 15V 輸入 3.3V 輸出的演示板
- SiM3L1xxLCD-B-DK,統一開發平臺(UDP)依賴于SiM3L1XX LCD MCU卡
- 【訓練營_進階班】基于阿里云的智能插座
- 時鐘控制/2相雙極型步進電機驅動IC —— TB62269FTG
- ESP8266
- 微型、薄款 10A 負載點穩壓器參考設計
- 具有基本抑制功能的 LF60CDT-TR 6V 極低壓降穩壓器的典型應用
- LTC3616 -6A、4MHz 單片式同步降壓型 DC/DC 轉換器的典型應用
- LTM4627EV 演示板,高效 40A 多相降壓電源
- 高通攜手中國“汽車朋友圈”亮相2025上海車展: 加速駕駛輔助普惠,推動艙駕創新升級
- 工業市場正在快速回暖,德州儀器如何重塑電力電子市場?
- 特斯拉:美國交付的Model Y/3電池包已實現100%美國生產
- 地平線與博世深化合作,攜手為多家車企提供輔助駕駛產品
- 強化中國市場戰略布局,德州儀器正靈活應對全球關稅挑戰
- Molex莫仕通過本地合作和創新加強支持中國汽車行業
- 貿澤開售Texas Instruments適用于高分辨率AR HUD的 全新DLP4620S-Q1 0.46"汽車數字微鏡器件
- ROHM推出高功率密度的新型SiC模塊,將實現車載充電器小型化!
- 用上車規級UFS 4.0,讓出行變得高效且可靠
- 車載測試技術解析:聚焦高帶寬、多通道同步采集與協議分析