CanFestival移植到STM32G4

文章目錄

  • 一、準備工作
  • 二、軟件配置
  • 三、移植CanFestival
  • 參考

一、準備工作

1、獲取Canfestival源碼
2、Python下載
3、wxPython下載
4、CanFestival字典生成
5、安裝參考
Python2.7.15及wxPython2.8百度云盤下載地址:https://pan.baidu.com/s/1bRS403m4B31m4ovSJ-_HwA
提取碼:38sn

二、軟件配置

FDCAN 500K@2M配置
在這里插入圖片描述

    /** Bit timing & sampling* Tq = (BRP+1)/Fcan if DIV8 = 0* Tq = 8*(BRP+1)/Fcan if DIV8 = 1* TSync = 1.Tq* TSeg1 = (TSEG1+1)*Tq                >= 3Tq* TSeg2 = (TSEG2+1)*Tq                >= 2Tq* Bit Time = TSync + TSeg1 + TSeg2    >= 8Tq** Resynchronization:** Tsjw = (SJW + 1)*Tq* TSeg1 >= Tsjw + Tprop* TSeg2 >= Tsjw*/

在這里插入圖片描述
可以通過 KVASER Bit Timing Calculator for CANFD 這個網站在線計算.
CANFD關鍵代碼:

FDCAN_FilterTypeDef sFilterConfig2;
FDCAN_RxHeaderTypeDef RxHeader2;
FDCAN_TxHeaderTypeDef TxHeader2;void fdcan2_config(void)
{sFilterConfig2.IdType = FDCAN_STANDARD_ID;sFilterConfig2.FilterIndex = 0;sFilterConfig2.FilterType = FDCAN_FILTER_RANGE;sFilterConfig2.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;sFilterConfig2.FilterID1 = 0x00;sFilterConfig2.FilterID2 = 0x7FF;if (HAL_FDCAN_ConfigFilter(&hfdcan2, &sFilterConfig2) != HAL_OK){Error_Handler();}sFilterConfig2.IdType = FDCAN_EXTENDED_ID;sFilterConfig2.FilterIndex = 0;sFilterConfig2.FilterType = FDCAN_FILTER_RANGE;sFilterConfig2.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;sFilterConfig2.FilterID1 = 0x00;sFilterConfig2.FilterID2 = 0x1FFFFFFF;if (HAL_FDCAN_ConfigFilter(&hfdcan2, &sFilterConfig2) != HAL_OK){Error_Handler();}/* Configure global filter on both FDCAN instances:Filter all remote frames with STD and EXT IDReject non matching frames with STD ID and EXT ID */if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan2, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK){Error_Handler();}/* Activate Rx FIFO 0 new message notification on both FDCAN instances */if (HAL_FDCAN_ActivateNotification(&hfdcan2, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK){Error_Handler();}if (HAL_FDCAN_ActivateNotification(&hfdcan2, FDCAN_IT_BUS_OFF, 0) != HAL_OK){Error_Handler();}/* Configure and enable Tx Delay Compensation, required for BRS mode.TdcOffset default recommended value: DataTimeSeg1 * DataPrescalerTdcFilter default recommended value: 0 */HAL_FDCAN_ConfigTxDelayCompensation(&hfdcan2, hfdcan2.Init.DataPrescaler * hfdcan2.Init.DataTimeSeg1, 0);HAL_FDCAN_EnableTxDelayCompensation(&hfdcan2);HAL_FDCAN_Start(&hfdcan2);
}void HAL_FDCAN_ErrorStatusCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t ErrorStatusITs)
{if(hfdcan->Instance == FDCAN2) {MX_FDCAN2_Init();fdcan2_config();} 
}//RxHeader1.DataLength => can_dlc
//0x00000 => 0 
//0x10000 => 1 
//0x20000 => 2 
//0x30000 => 3 
//0x40000 => 4 
//0x50000 => 5 
//0x60000 => 6 
//0x70000 => 7 
//0x80000 => 8 
//0x90000 => 12
//0xA0000 => 16
//0xB0000 => 20
//0xC0000 => 24
//0xD0000 => 32
//0xE0000 => 48
//0xF0000 => 64
uint8_t dlc2len[]={0,1,2,3,4,5,6,7,8,12,16,20,24,32,48,64};
uint8_t RxData2[100];
uint8_t TxData2[64];
uint8_t can_dlc2len(uint32_t RxHeader_DataLength)
{return dlc2len[RxHeader_DataLength>>16];
}uint8_t cnt = 0;
uint8_t brs[] = {'-', 'B'};
uint8_t esi[] = {'-', 'E'};
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
{if((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != 0) {      HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader2, RxData2);if (hfdcan->Instance == FDCAN2) { usb_printf("fdcan2, ");} }usb_printf("0x%8X, %02d, %c, %c:",RxHeader2.Identifier, can_dlc2len(RxHeader2.DataLength), brs[RxHeader2.BitRateSwitch>>20 & 0x1],esi[RxHeader2.ErrorStateIndicator>>31 & 0x1]);for(cnt = 0; cnt < can_dlc2len(RxHeader2.DataLength); cnt++) {usb_printf(" %02X", RxData2[cnt]);}usb_printf("\n\r");}FDCAN_SendFailTypeDef fdcan2_send_fail = {0};
void fdcan2_transmit(uint32_t can_id, uint32_t DataLength, uint8_t tx_data[])
{TxHeader2.Identifier = can_id;TxHeader2.IdType = FDCAN_EXTENDED_ID;if(can_id < 0x800) {  //exactly not rightTxHeader2.IdType = FDCAN_STANDARD_ID;}TxHeader2.TxFrameType = FDCAN_DATA_FRAME;TxHeader2.DataLength = DataLength;TxHeader2.ErrorStateIndicator = FDCAN_ESI_ACTIVE;TxHeader2.BitRateSwitch = FDCAN_BRS_ON;TxHeader2.FDFormat = FDCAN_FD_CAN;TxHeader2.TxEventFifoControl = FDCAN_NO_TX_EVENTS;TxHeader2.MessageMarker = 0;	//marker++;	//Tx Event FIFO Useif(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan2, &TxHeader2, tx_data) != HAL_OK) {fdcan2_send_fail.flag = 1;memcpy(&fdcan2_send_fail.TxHeader, &TxHeader2, sizeof(FDCAN_TxHeaderTypeDef));memcpy(fdcan2_send_fail.TxData, tx_data, can_dlc2len(DataLength));} 
}uint32_t count = 0;uint32_t cnt_100us = 0;uint32_t cnt_500us = 0;uint8_t tim4_flag = 0;
void canfd_test(void)
{for(uint8_t i = 0; i < 64; i++) {TxData2[i] = i;}if(count < 1000) {TxData2[0] = count >> 8 & 0xFF;TxData2[1] = count & 0xFF;++cnt_100us;cnt_500us = cnt_100us / 5;if(cnt_500us && (cnt_100us%5==0) ) {switch(cnt_500us) {case 1: fdcan2_transmit(0x123, FDCAN_DLC_BYTES_64, TxData2); fdcan2_transmit(0x124, FDCAN_DLC_BYTES_64, TxData2);fdcan2_transmit(0x125, FDCAN_DLC_BYTES_64, TxData2); break;case 4: fdcan2_transmit(0x12345678, FDCAN_DLC_BYTES_64, TxData2); break;case 5: fdcan2_transmit(0x12345679, FDCAN_DLC_BYTES_64, TxData2); break;case 6: fdcan2_transmit(0x1234567A, FDCAN_DLC_BYTES_64, TxData2); break;case 7: /* next send */ break;case 8: break;case 20: ++count; cnt_100us = 0; break; //10ms}} else {  //fail retransmission onceif(fdcan2_send_fail.flag) {fdcan2_transmit(fdcan2_send_fail.TxHeader.Identifier, fdcan2_send_fail.TxHeader.DataLength,fdcan2_send_fail.TxData);fdcan2_send_fail.flag = 0;}}}}

通訊可收發即可。

三、移植CanFestival

步驟一
在新建好的工程目錄下新建文件夾Canopen,再在Canopen下新建文件夾driver、inc和src,再在inc文件夾下面新建stm32文件夾(我這里主要以移植到stm32為例說明,如果是移植到VC或其他平臺下,這里也可以命名為其他名字,如vc)。
步驟二
將CanFestival-3-10\src目錄下的dcf.c、emcy.c、lifegrd.c、lss.c、nmtMaster.c、nmtSlave.c、objacces.c、pdo.c、sdo.c、states.c、sync.c、timer.c共12個文件拷貝到CanFestival\src目錄下;
將CanFestival-3-10\include目錄下的所有.h文件共19個文件全部拷貝到CanFestival\inc目錄下,
再把CanFestival-3-10\examples\AVR\Slave目錄下的ObjDict.h文件拷貝過來,一共20個;
將CanFestival-3-10\include\AVR目錄下的applicfg.h、canfestival.h、config.h、timerscfg.h共4個頭文件拷貝到canfestival\inc\stm32目錄下;
將CanFestival-3-10\objdictgen\MySlave目錄下的slave.c、slave.h拷貝到canfestival\driver目錄下,并在該目錄下新建stm32_canfestival.c文件。(這里的MySlave是自己新建的,用于保存通過對象字典編輯工具生成的eds等文件)
步驟三
將CanFestival\src目錄下的所有.c文件添加到工程;將canfestival\driver目錄下的stm32_canfestival.c文件添加到工程;
如果實現的是從設備,再將canfestival\driver目錄下的TestSlave.c文件添加到工程,如果實現的是主設備,則將TestMaster.c文件添加到工程;
步驟四
將文件目錄canfestival\inc、canfestival\inc\stm32、canfestival\driver等路徑添加到工程包含路徑。
步驟五:
在stm32_canfestival.c中包含頭文件#include “canfestival.h”,并定義如下函數:

void setTimer(TIMEVAL value)
{
}
TIMEVAL getElapsedTime(void)
{return 1;
}
unsigned char canSend(CAN_PORT notused, Message *m)
{return 1;
}

可以先定義一個空函數,等到編譯都通過了之后,再往里面添加內容,這幾個函數都是定義來供canfestival源碼調用的,如果找不到這幾個函數編譯就會報錯。
步驟六:
通過以上幾步,所有的文件都弄齊了,但是編譯一定會出現報錯,注釋或刪除掉config.h文件中的如下幾行就能編譯通過:

include <inttypes.h>
#include <avr\io.h>
#include <avr\interrupt.h>
#include <avr/pgmspace.h>
#include <avr\sleep.h>
#include <avr\wdt.h>

如果還有其他報錯,那有可能是因為不同源碼版本、不同平臺、不同人遇到的錯誤也會不相同,這里的過程只能做一定的參考,不一定完全相同,需要根據編譯出錯提示來進行修改對應地方,一般都是有些函數沒聲明或者某個頭文件沒有包含或者包含了一些不必要的頭文件而該文件不存在或者是一些變量類型不符合需定義之類的。
在這里插入圖片描述
如果提示:

error:  #3092: anonymous unions are only supported in --gnu mode, or when enabled with #pragma anon_unions

解決方法:
在這里插入圖片描述
勾選GUN extensions。
步驟七
解決了所有的編譯錯誤后,接下來實現剛才定義的3個空函數:

/*** @brief  Set timer for nex alarm* @param  value: timer value* @retval None*/
void setTimer(TIMEVAL value)
{// 獲取當前定時器值UNS32 timer = Bsp_Canopen_GetTimer();// 計算已經過去的時間elapsed_time += timer - last_counter_val;// 設置下一次定時器值last_counter_val = CANOPEN_TIM_PERIOD - value;// 設置定時器Bsp_Canopen_SetTimer(last_counter_val);
}/*** @brief  Return the elapsed time to tell the Stack how much time is spent since the last call.* @param  None* @retval The elapsed time*/
TIMEVAL getElapsedTime(void)
{uint32_t timer = Bsp_Canopen_GetTimer(); // Copy the value of the running timerif (timer < last_counter_val)timer += CANOPEN_TIM_PERIOD;TIMEVAL elapsed = timer - last_counter_val + elapsed_time;return elapsed;
}/*** @brief  Can send* @param  notused: not used*         m: message point* @retval 0:successful -1:failed*/
unsigned char canSend(CAN_PORT notused, Message *m)
{// 調用fdcan2_transmit函數發送消息return fdcan1_transmit(m->cob_id, m->len, m->data);
}void CAN_DispatchRcv_Cbk(FDCAN_ReceivedFailTypeDef *RxMsg) {// 定義一個靜態變量msg,用于存儲接收到的消息static Message msg;// 如果接收到的消息標志位為1,則返回if (RxMsg->flag) {return; }// 如果接收到的消息是標準ID,則將消息ID賦值給msg.cob_idif (RxMsg->RxHeader.IdType == FDCAN_STANDARD_ID) {msg.cob_id = RxMsg->RxHeader.Identifier & 0x7FF; } else {// 如果接收到的消息是擴展ID,則將消息ID賦值給msg.cob_id,并將最高位設置為1msg.cob_id = RxMsg->RxHeader.Identifier | 0x80000000; }// 將消息類型設置為數據幀msg.rtr = 0;// 將接收到的消息長度賦值給msg.len//msg.len = (UNS8)can_dlc2len(RxMsg->RxHeader.DataLength);msg.len = (UNS8)RxMsg->RxHeader.DataLength;// 將接收到的消息數據賦值給msg.datamemcpy(msg.data, RxMsg->RxData, msg.len);// 禁用TIM4中斷// HAL_NVIC_DisableIRQ(TIM4_IRQn);// 調用canDispatch函數,將接收到的消息傳遞給slave_DatacanDispatch(&slave_Data, &msg);// 使能TIM4中斷// HAL_NVIC_EnableIRQ(TIM4_IRQn);
}/*** @brief  Timer ISR* @param  None* @retval None*/
void TIMx_Dispatch_Cbk(void)
{last_counter_val = 0;elapsed_time = 0;TimeDispatch();
}void CANopen_App_Init(CO_Data *d)
{	setNodeId(d, (UNS8)CAN_NodeID);setState(d, Initialisation);setState(d, Pre_operational);setState(d, Operational);
}

其中:

#define CANOPEN_TIM_PERIOD  0xffffextern void canfd_test(void);
extern void TIMx_Dispatch_Cbk(void);
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) 
{if(htim->Instance == TIM4) {TIMx_Dispatch_Cbk();}
}/*** @brief  * @param  None* @retval void*/
inline uint32_t Bsp_Canopen_GetTimer(void)
{return __HAL_TIM_GET_COUNTER(&htim4);
}/*** @brief  * @param  None* @retval void*/
inline void Bsp_Canopen_SetTimer(uint32_t value)
{__HAL_TIM_SET_COUNTER(&htim4, value);
}

步驟八
完善canfd收發函數

typedef struct {uint8_t flag;FDCAN_TxHeaderTypeDef TxHeader;uint8_t TxData[64];
} FDCAN_SendFailTypeDef;typedef struct {uint8_t flag;FDCAN_RxHeaderTypeDef RxHeader;uint8_t RxData[64];
} FDCAN_ReceivedFailTypeDef;FDCAN_FilterTypeDef sFilterConfig1;
FDCAN_RxHeaderTypeDef RxHeader1;
FDCAN_TxHeaderTypeDef TxHeader1;void fdcan1_config(void)
{sFilterConfig1.IdType = FDCAN_STANDARD_ID;sFilterConfig1.FilterIndex = 0;sFilterConfig1.FilterType = FDCAN_FILTER_RANGE;sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;sFilterConfig1.FilterID1 = 0x00;sFilterConfig1.FilterID2 = 0x7FF;if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig1) != HAL_OK){Error_Handler();}sFilterConfig1.IdType = FDCAN_EXTENDED_ID;sFilterConfig1.FilterIndex = 0;sFilterConfig1.FilterType = FDCAN_FILTER_RANGE;sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;sFilterConfig1.FilterID1 = 0x00;sFilterConfig1.FilterID2 = 0x1FFFFFFF;if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig1) != HAL_OK){Error_Handler();}/* Configure global filter on both FDCAN instances:Filter all remote frames with STD and EXT IDReject non matching frames with STD ID and EXT ID */if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK){Error_Handler();}/* Activate Rx FIFO 0 new message notification on both FDCAN instances */if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK){Error_Handler();}if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_BUS_OFF, 0) != HAL_OK){Error_Handler();}/* Configure and enable Tx Delay Compensation, required for BRS mode.TdcOffset default recommended value: DataTimeSeg1 * DataPrescalerTdcFilter default recommended value: 0 */HAL_FDCAN_ConfigTxDelayCompensation(&hfdcan1, hfdcan1.Init.DataPrescaler * hfdcan1.Init.DataTimeSeg1, 0);HAL_FDCAN_EnableTxDelayCompensation(&hfdcan1);HAL_FDCAN_Start(&hfdcan1);
}void HAL_FDCAN_ErrorStatusCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t ErrorStatusITs)
{if(hfdcan->Instance == FDCAN1) {MX_FDCAN1_Init();fdcan1_config();} 
}//RxHeader1.DataLength => can_dlc
//0x00000 => 0 
//0x10000 => 1 
//0x20000 => 2 
//0x30000 => 3 
//0x40000 => 4 
//0x50000 => 5 
//0x60000 => 6 
//0x70000 => 7 
//0x80000 => 8 
//0x90000 => 12
//0xA0000 => 16
//0xB0000 => 20
//0xC0000 => 24
//0xD0000 => 32
//0xE0000 => 48
//0xF0000 => 64
uint8_t dlc2len[]={0,1,2,3,4,5,6,7,8,12,16,20,24,32,48,64};
uint8_t RxData1[100];
uint8_t TxData1[64];
uint8_t can_dlc2len(uint16_t data_length) {// 提取 DLC 的 4 位(例如:DLC 位于位 16-19)uint8_t dlc = (data_length >> 16) & 0x0F;  // 確保 dlc 在 0-15 范圍內return (dlc < 16) ? dlc2len[dlc] : 0;      // 邊界檢查
}uint8_t cnt = 0;
uint8_t brs[] = {'-', 'B'};
uint8_t esi[] = {'-', 'E'};
extern void CAN_DispatchRcv_Cbk(FDCAN_ReceivedFailTypeDef *RxMsg) ;
// 接收回調函數
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) {if (hfdcan->Instance == FDCAN1 && (RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE)) {FDCAN_RxHeaderTypeDef RxHeader1;uint8_t RxData1[64];FDCAN_ReceivedFailTypeDef RxMsg = {0};if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1) != HAL_OK) {Error_Handler();  // 自定義錯誤處理return;}// 提取數據長度//uint8_t data_len = can_dlc2len(RxHeader1.DataLength);uint8_t data_len = RxHeader1.DataLength;if (data_len > 64) {return;  // 無效長度處理}// 填充接收消息結構體RxMsg.RxHeader.Identifier = RxHeader1.Identifier;RxMsg.RxHeader.DataLength = data_len;RxMsg.RxHeader.BitRateSwitch = (RxHeader1.BitRateSwitch) ? 1 : 0;RxMsg.RxHeader.ErrorStateIndicator = (RxHeader1.ErrorStateIndicator) ? 1 : 0;memcpy(RxMsg.RxData, RxData1, data_len);// 調試輸出#ifdef CAN_DEBUGLogCanFrame(&RxMsg);  // 封裝調試函數#endif// 分發消息CAN_DispatchRcv_Cbk(&RxMsg);}
}FDCAN_SendFailTypeDef fdcan1_send_fail = {0};
uint8_t fdcan1_transmit(uint32_t can_id, uint32_t DataLength, uint8_t tx_data[])
{// 定義一個FDCAN_TxHeaderTypeDef類型的變量TxHeader1,并初始化為0FDCAN_TxHeaderTypeDef TxHeader1={0};// 判斷can_id的高位是否為1,如果是,則表示為擴展ID,否則為標準IDif ((can_id & 0x80000000) == 0) { // 設置為標準IDTxHeader1.IdType = FDCAN_STANDARD_ID;// 將can_id的低11位賦值給TxHeader1.Identifiercan_id &= 0x7FF;} else {                       // 設置為擴展IDTxHeader1.IdType = FDCAN_EXTENDED_ID;// 將can_id的低29位賦值給TxHeader1.Identifiercan_id &= 0x1FFFFFFF;}// 設置標識符TxHeader1.Identifier = can_id;// 設置幀類型為數據幀TxHeader1.TxFrameType = FDCAN_DATA_FRAME;// 設置數據長度TxHeader1.DataLength = DataLength;// 設置錯誤狀態指示器為活動狀態TxHeader1.ErrorStateIndicator = FDCAN_ESI_ACTIVE;// 設置比特率切換為開啟TxHeader1.BitRateSwitch = FDCAN_BRS_ON;// 設置為FD格式TxHeader1.FDFormat = FDCAN_FD_CAN;// 設置為不使用Tx Event FIFOTxHeader1.TxEventFifoControl = FDCAN_NO_TX_EVENTS;// 設置消息標記為0TxHeader1.MessageMarker = 0;	//marker++;	//Tx Event FIFO Use// 將數據添加到Tx Event FIFO隊列中if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader1, tx_data) != HAL_OK) {// 如果添加失敗,則設置發送失敗標志fdcan1_send_fail.flag = 1;// 將TxHeader1的值復制到fdcan1_send_fail.TxHeader中memcpy(&fdcan1_send_fail.TxHeader, &TxHeader1, sizeof(FDCAN_TxHeaderTypeDef));// 將tx_data的值復制到fdcan1_send_fail.TxData中memcpy(fdcan1_send_fail.TxData, tx_data, can_dlc2len(DataLength));// 返回0return 0;} // 返回1return 1;
}uint32_t count = 0;uint32_t cnt_100us = 0;uint32_t cnt_500us = 0;uint8_t tim4_flag = 0;
void canfd_test(void)
{for(uint8_t i = 0; i < 64; i++) {TxData1[i] = i;}if(count < 1000) {TxData1[0] = count >> 8 & 0xFF;TxData1[1] = count & 0xFF;++cnt_100us;cnt_500us = cnt_100us / 5;if(cnt_500us && (cnt_100us%5==0) ) {switch(cnt_500us) {case 1: fdcan1_transmit(0x123, FDCAN_DLC_BYTES_64, TxData1); fdcan1_transmit(0x124, FDCAN_DLC_BYTES_64, TxData1);fdcan1_transmit(0x125, FDCAN_DLC_BYTES_64, TxData1); break;case 4: fdcan1_transmit(0x12345678, FDCAN_DLC_BYTES_64, TxData1); break;case 5: fdcan1_transmit(0x12345679, FDCAN_DLC_BYTES_64, TxData1); break;case 6: fdcan1_transmit(0x1234567A, FDCAN_DLC_BYTES_64, TxData1); break;case 7: /* next send */ break;case 8: break;case 20: ++count; cnt_100us = 0; break; //10ms}} else {  //fail retransmission onceif(fdcan1_send_fail.flag) {fdcan1_transmit(fdcan1_send_fail.TxHeader.Identifier, fdcan1_send_fail.TxHeader.DataLength,fdcan1_send_fail.TxData);fdcan1_send_fail.flag = 0;}}}}

初始化

HAL_TIM_Base_Start_IT(&htim4);
fdcan1_config();
CANopen_App_Init(&slave_Data);

修改timerscfg.h

// The timer is incrementing every 10 us.
#define MS_TO_TIMEVAL(ms) ((ms) * 100U)
#define US_TO_TIMEVAL(us) ((us)/10)

根據實際修改,由于TIM4的時基100KHz(160Mhz/1600),也就是10us
經測試NMT的Boot_up (節點上線報文)、NMT 心跳報文 、NMT節點狀態切換、SDO快速讀、SDO快速寫、SDO錯誤、PDO、節點守護均正常。

參考

【1】CanOpen協議【CanFestival】移植方法 支持VC、QT、STM32:https://bbs.21ic.com/icview-878522-1-1.html
【2】CANopen協議【CANFestival】移植方法:
https://www.cnblogs.com/ChYQ/p/5719469.html#:~:text=%E6%8E%A5%E4%B8%8B%E6%9D%A5%E5%BC%80%E5%A7%8B%E7%A7%BB%E6%A4%8D%EF%BC%9A%20%E6%AD%A5%E9%AA%A4%E4%B8%80%EF%BC%9A,%E5%9C%A8%E6%96%B0%E5%BB%BA%E5%A5%BD%E7%9A%84%E5%B7%A5%E7%A8%8B%E7%9B%AE%E5%BD%95%E4%B8%8B%E6%96%B0%E5%BB%BA%E6%96%87%E4%BB%B6%E5%A4%B9CanFestival%EF%BC%8C%E5%86%8D%E5%9C%A8CanFestival%E4%B8%8B%E6%96%B0%E5%BB%BA%E6%96%87%E4%BB%B6%E5%A4%B9driver%E3%80%81inc%E5%92%8Csrc%EF%BC%8C%E5%86%8D%E5%9C%A8inc%E6%96%87%E4%BB%B6%E5%A4%B9%E4%B8%8B%E9%9D%A2%E6%96%B0%E5%BB%BA%20stm32%E6%96%87%E4%BB%B6%E5%A4%B9%EF%BC%88%E6%88%91%E8%BF%99%E9%87%8C%E4%B8%BB%E8%A6%81%E4%BB%A5%E7%A7%BB%E6%A4%8D%E5%88%B0stm32%E4%B8%BA%E4%BE%8B%E8%AF%B4%E6%98%8E%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%98%AF%E7%A7%BB%E6%A4%8D%E5%88%B0VC%E6%88%96%E5%85%B6%E4%BB%96%E5%B9%B3%E5%8F%B0%E4%B8%8B%EF%BC%8C%E8%BF%99%E9%87%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E5%91%BD%E5%90%8D%E4%B8%BA%E5%85%B6%E4%BB%96%E5%90%8D%E5%AD%97%EF%BC%8C%E5%A6%82vc%EF%BC%89%E3%80%82
【3】STM32無系統移植CanFestival小白教程:https://blog.csdn.net/weixin_43072093/article/details/115245443
【4】CANOPEN 學習(一) CANFestival 字典工具 環境搭建:https://blog.csdn.net/mobei1983/article/details/110879850?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-110879850-blog-115245443.pc_relevant_multi_platform_whitelistv1_exp2&spm=1001.2101.3001.4242.1&utm_relevant_index=3
【5】CanFestival字典生成:https://blog.csdn.net/lushoumin/article/details/92841982
【6】基于STM32F4的CANOpen移植教程(超級詳細)_月落三千雪的博客-程序員秘密_canopen stm32:https://cxymm.net/article/qq_37662088/123261908
【7】驅動器使用 —— DS402狀態切換(個人筆記):https://blog.csdn.net/weixin_43455581/article/details/103661372
【8】基于STM32F4的CANOpen移植教程(超級詳細):
https://blog.csdn.net/qq_37662088/article/details/123261908
【9】CanFestival移植到STM32 F4芯片(基于HAL庫):
https://www.iotword.com/32673.html
【10】B站CANopen視頻
https://www.bilibili.com/video/BV1LF411E7KJ/?spm_id_from=333.1387.collection.video_card.click&vd_source=5f570a9f261c43941608688d2d31a4c5
【11】CANopen FD:
https://www.can-cia.org/can-knowledge/canopen-fd-the-art-of-embedded-networking
【12】STM32 CAN使用記錄:FDCAN基礎通訊:https://blog.csdn.net/Naisu_kun/article/details/132830048
【13】STM32G474_FDCAN的普通CAN模式使用(寄存器開發):https://shequ.stmicroelectronics.cn/thread-637235-1-1.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/84309.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/84309.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/84309.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

iOS性能調優實戰:借助克魔(KeyMob)與常用工具深度洞察App瓶頸

在日常iOS開發過程中&#xff0c;性能問題往往是最令人頭疼的一類Bug。尤其是在App上線前的壓測階段或是處理用戶反饋的高發期&#xff0c;開發者往往需要面對卡頓、崩潰、能耗異常、日志混亂等一系列問題。這些問題表面上看似偶發&#xff0c;但背后往往隱藏著系統資源調度不當…

第十三章 RTC 實時時鐘

第十三章 RTC 實時時鐘 目錄 第十三章 RTC 實時時鐘 1 RTC簡介 1.1 主要特性 2 功能描述 2.1 概述 2.2 復位過程 2.3 讀RTC寄存器 2.4 配置RTC寄存器 2.5 RTC標志的設置 3 RTC寄存器描述 3.1 RTC控制寄存器高位(RTC_CRH) 3.2 RTC控制寄存器低位(RTC_CRL) 3.3 RTC預…

618來了,推薦京東云服務器

2核2G3M,49元/1年,348元/3年 2核4G5M,149元/1年,518元/3年 4核8G5M,368元/1年,1468元/3年 8核16G5M,1258元/1年,3498元/3年 8核32G10M,1498元/1年,4268元/3年 活動地址&#xff1a;https://3.cn/2hT-F6AX

數據庫邏輯刪除,唯一性約束究極解決方案

文章目錄 一、寫在前面二、解決方案1、業務邏輯層面控制2、物理刪除數據歸檔3、is_delete !0的都認為是刪除&#xff08;推薦&#xff09;4、MySQL 函數索引&#xff08;表達式索引&#xff09;&#xff08;需 MySQL 8.0&#xff09;&#xff08;推薦&#xff09;5、部分索引&a…

3-存儲系統

一-基本概念 二-主存儲器 三-主存儲器與CPU的連接 四-外部存儲器 五-高速緩沖存儲器 六-虛擬存儲器

華為0528筆試

第三題 題目 給定一個二維數組 mountainMap 表示一座山的地圖&#xff0c;數組中的每個元素 mountainMap[x][y] 代表坐標 (x, y) 處山的高度。登山員從山底出發&#xff0c;爬到山峰。 山底的含義&#xff1a;mountainMap中高度為0的坐標點。 山峰的含義&#xff1a;mountain…

Redis的過期策略和淘汰策略

Redis的過期策略和淘汰策略 想象一下周末的大型超市&#xff1a;生鮮區的酸奶貼著"今日特價"標簽&#xff0c;促銷員定時檢查這些商品的保質期&#xff1b;而倉庫管理員正根據"先進先出"原則整理貨架&#xff0c;確保商品不會過期積壓。這種高效的商品管理…

laravel8+vue3.0+element-plus搭建方法

創建 laravel8 項目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安裝 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …

【HarmonyOS 5】 影視與直播詳以及 開發案例

&#x1f3a5; ?一、超高清低延遲直播? ?4K/8K硬解能力?&#xff1a;通過鴻蒙媒體引擎實現15Mbps碼率視頻流穩定解碼&#xff0c;華為Pura X實測端到端延遲<80ms?分布式渲染?&#xff1a;支持手機拍攝→智慧屏導播→平板監看的工作流協同&#xff0c;設備間傳輸延遲&…

Tunna工具實戰:基于HTTP隧道的RDP端口轉發技術

工具概述 Tunna是一款利用HTTP/HTTPS隧道進行TCP通信的滲透測試工具&#xff0c;由SECFORCE團隊開發并開源。該工具主要應用于需要繞過防火墻限制的場景&#xff0c;通過Webshell實現內網服務的端口轉發&#xff0c;特別適合在僅開放80/443端口的環境中建立TCP連接。 項目地址…

c# Autorest解析

AutoRest 工具生成用于訪問 RESTful Web 服務的客戶端庫。AutoRest 的輸入是使用 OpenAPI 規范格式描述 REST API 的規范。OpenAPI(f.k.a Swagger)規范代碼生成器。支持 C#、PowerShell、Go、Java、Node.js、TypeScript、Python。 安裝 AutoRest 在 Windows、MacOS 或 Linux …

高中數學聯賽模擬試題精選學數學系列第24套幾何題

⊙ O 1 \odot O_1 ⊙O1? 和 ⊙ O 2 \odot O_2 ⊙O2? 交于 A A A, B B B. Y Y Y 是 ⊙ O 1 \odot O_1 ⊙O1? 上一點, Z Z Z 是 ⊙ O 2 \odot O_2 ⊙O2? 上一點&#xff0c; Y Z YZ YZ 通過 A A A. 過 Y Y Y 的 ⊙ O 1 \odot O_1 ⊙O1? 的切線和過 Z Z Z 的 ⊙…

【QT】INI格式文件讀寫類IniApi封裝

【QT】INI文件讀寫類IniApi封裝 前言實現INI文件寫入方法INI文件讀取方法 測試 前言 INI格式文件是一種純文本格式&#xff0c;使用方括[]定義節&#xff08;Section&#xff09;&#xff0c;每個節下包含鍵值對&#xff0c;如下圖所示。該格式文件簡單易讀易編輯。而且在所有…

ABAP設計模式之---“童子軍法則(The Boy Scout Rule)”

法則介紹 The Boy Scout Rule&#xff0c;中文一般翻譯為“童子軍法則”&#xff0c;是一個簡單卻非常有意義的軟件開發原則&#xff0c;它最早由軟件開發大師 Robert C. Martin (Uncle Bob) 在他的《Clean Code》一書中提出。 這條法則的核心思想非常簡單&#xff1a; “確保…

BaikalDB 架構演進實錄:打造融合向量化與 MPP 的 HTAP 查詢引擎

導讀 BaikalDB作為服務百度商業產品的分布式存儲系統&#xff0c;支撐了整個廣告庫海量物料的存儲和OLTP事務處理。隨著數據不斷增長&#xff0c;離線計算時效性和資源需求壓力突顯&#xff0c;基于同一份數據進行OLAP處理也更為經濟便捷&#xff0c;BaikalDB如何在OLTP系統內…

【抖音小程序】通用交易系統-下單問題整理

在通用交易系統中&#xff0c;支付流程如下 1、服務端-預下單&#xff1a;生成參數與簽名信息&#xff08;此過程不需要與抖音平臺對接&#xff09; 參考 生成下單參數與簽名_抖音開放平臺 2、小程序用戶端&#xff1a;根據返回的參數與簽名&#xff0c;拉起抖音支付&#x…

模型參數、模型存儲精度、參數與顯存

模型參數量衡量單位 M&#xff1a;百萬&#xff08;Million&#xff09; B&#xff1a;十億&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 參數存儲精度 模型參數是固定的&#xff0c;但是一個參數所表示多少字節不一定&#xff0c;需要看這個參數以什么…

EurekaServer 工作原理

一、核心工作流程 二、核心組件解析 1. 自動配置引擎 入口&#xff1a;EnableEurekaServer 引入 EurekaServerMarkerConfiguration&#xff0c;創建標記Bean Marker觸發條件&#xff1a;EurekaServerAutoConfiguration 檢測到 Marker 存在時激活關鍵Bean初始化&#xff1a; …

Playwright 與 Selenium:自動化測試的兩大主流工具對比

《Playwright 與 Selenium&#xff1a;自動化測試的兩大主流工具對比》 *Playwright 和 Selenium 是自動化測試領域的兩大主流工具&#xff0c;二者在架構設計、功能特性和適用場景上存在顯著差異&#xff0c;以下是核心對比&#xff1a; 一、架構與設計理念 維度Playwright…

網絡編程(Modbus進階)

思維導圖 Modbus RTU&#xff08;先學一點理論&#xff09; 概念 Modbus RTU 是工業自動化領域 最廣泛應用的串行通信協議&#xff0c;由 Modicon 公司&#xff08;現施耐德電氣&#xff09;于 1979 年推出。它以 高效率、強健性、易實現的特點成為工業控制系統的通信標準。 包…