1、CAN時鐘
GD32F303主時鐘頻率最大是120Mhz,然后APB1時鐘最大是60Mhz,APB2時鐘最大是120Mhz,CAN掛載在APB1總線上面
所以一般CAN的時鐘頻率是60Mhz,這個頻率和后面配置波特率有關
2、GD32F303時鐘配置
首先我們知道芯片有幾個時鐘
HXTAL:高速外部時鐘;
LXTAL:低速外部時鐘;
IRC8M:高速內部時鐘;
IRC40K:低速內部時鐘;
代碼配置時鐘時我們要確定時選擇內部晶振還是外部晶振,他們配置頻率都不一樣,例如下面的宏定義可以配置不同的時鐘頻率
比如? 如果定義了__SYSTEM_CLOCK_120M_PLL_IRC8M宏定義,那么芯片時鐘采用內部晶振8Mhz,然后主時鐘頻率是120Mhz
如果定義了__SYSTEM_CLOCK_120M_PLL_HXTAL宏定義,那么芯片時鐘采用外部晶振時鐘,這個晶振一般都是8Mhz,但是針對不同的系列有所不一樣,比如GD32F303RET6的外部晶振就是12Mhz,然后使能__SYSTEM_CLOCK_120M_PLL_HXTAL宏定義之后他的主時鐘頻率不是120Mhz,看代碼可知? ?(12/2)*30不等于120Mhz,所以時鐘的頻率需要確定好,下面這個代碼只適配外部晶振是8Mhz的。
3、CAN的波特率配置
首先我們需要知道波特率的計算公式,其中的PCLK就是CAN掛載總線APB1的時鐘,一般為60Mhz,如果我們配置為下面的參數,及代表著CAN的波特率為250kbits。
/* baudrate 250Kbps */can_parameter.resync_jump_width=CAN_BT_SJW_1TQ;can_parameter.time_segment_1 = CAN_BT_BS1_14TQ;can_parameter.time_segment_2 = CAN_BT_BS2_1TQ;can_parameter.prescaler = 15;
4、CAN通信代碼
can.c
//can.c文件
#include "can.h"
#include "led.h"void gd32_can_init(void)
{can_parameter_struct can_parameter;can_filter_parameter_struct can_filter;/* initialize CAN register */can_deinit(CAN0);/* enable CAN clock */rcu_periph_clock_enable(RCU_CAN0);rcu_periph_clock_enable(RCU_GPIOA);//使能時鐘gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ,GPIO_PIN_11);gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_12);//IO復用為CAN功能/* configure CAN0 NVIC */nvic_irq_enable(CAN0_RX1_IRQn,0,0); //中斷配置can_struct_para_init(CAN_INIT_STRUCT, &can_parameter);can_struct_para_init(CAN_FILTER_STRUCT, &can_filter);//初始化參數/* baudrate 250Kbps */can_parameter.time_segment_1 = CAN_BT_BS1_14TQ;can_parameter.time_segment_2 = CAN_BT_BS2_1TQ;can_parameter.prescaler = 15;/* initialize CAN */can_init(CAN0, &can_parameter);can_filter.filter_fifo_number = CAN_FIFO1;can_filter.filter_enable = ENABLE;can_filter_init(&can_filter);/* enable can receive FIFO0 not empty interrupt */can_interrupt_enable(CAN0, CAN_INT_RFNE1|CAN_INT_TME);}/*CAN通信數據發送can_frame---要發送的數據發送成功返回0,失敗返回1
*/
uint8_t gd32_can_send(can_trasnmit_message_struct can_frame)
{ uint8_t ret=0;ret = can_message_transmit(CAN0,&can_frame);if(ret == CAN_NOMAILBOX){return 1;}return 0;
}/*CAN出錯--重啟CAN
*/
void gd32_can_error(void)
{if( can_flag_get(CAN0, CAN_FLAG_MTE2) != RESET ||can_flag_get(CAN0, CAN_FLAG_MTE0) != RESET ||can_flag_get(CAN0, CAN_FLAG_MTE1) != RESET || can_flag_get(CAN0, CAN_FLAG_PERR) != RESET ||can_flag_get(CAN0, CAN_FLAG_WERR) != RESET){can_flag_clear(CAN0, CAN_FLAG_MTE0);can_flag_clear(CAN0, CAN_FLAG_MTE1);can_flag_clear(CAN0, CAN_FLAG_MTE2);can_flag_clear(CAN0, CAN_FLAG_PERR);can_flag_clear(CAN0, CAN_FLAG_WERR);can_wakeup(CAN0);gd32_can_init();}
}/*CAN接收中斷函數
*/
void CAN0_RX1_IRQHandler(void)
{can_receive_message_struct can_mes;memset(&can_mes,0,sizeof(can_mes)); can_message_receive(CAN0, CAN_FIFO1, &can_mes); LED1_ON();
}
can.h
#ifndef __CAN_H
#define __CAN_H#include "gd32f30x.h"
#include "string.h"void gd32_can_init(void);
uint8_t gd32_can_send(can_trasnmit_message_struct can_frame);
void gd32_can_error(void);#endif
main.c
//CAN初始化gd32_can_init();transmit_message.tx_sfid = 0x7ab;transmit_message.tx_efid = 0x00;transmit_message.tx_ft = CAN_FT_DATA;//幀的類型:數據幀或者遙控幀transmit_message.tx_ff = CAN_FF_STANDARD;//幀的格式:標準幀或者拓展幀transmit_message.tx_dlen = 8;//數據長度小于8transmit_message.tx_data[0] = 0x55;transmit_message.tx_data[1] = 0x55;transmit_message.tx_data[2] = 0x55;transmit_message.tx_data[3] = 0x55;transmit_message.tx_data[4] = 0x55;transmit_message.tx_data[5] = 0x55;transmit_message.tx_data[6] = 0x55;transmit_message.tx_data[7] = 0x55;gd32_can_send(transmit_message);
5、USBCAN-II+的指示燈含義
如果sys 亮綠燈,則代表驅動安裝成功,如果亮紅燈,則表示驅動安裝失敗
如果CAN0或者CAN1的綠燈常亮,說明開始通信
6、CAN通信失敗原因可能
(1)波特率和上位機沒有一一配對
(2) CAN的時鐘頻率配置問題
(3)CANtest上位機如果一直出現打開設備失敗,則選擇使用ZCanPro上位機
(4)可以使用示波器掛一下單片機的兩個輸出引腳,是否有波形發出,如果有,說明軟件發出了數據,然后掛載另一邊,檢查芯片是否有問題
7、USBCAN-II+驅動下載
驅動下載 (zlg.cn)