> 技术文档 > CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

本文讲述如何通过简单操作就可以把CanFestival库移植到STM32 F4芯片上,作为Slave设备。使用启明欣欣的工控板来做实验。


一 硬件连接

观察CAN报文需要专门的设备,本人从某宝上买了一个兼容PCAN的开源小板子,二十几块钱,通过USB接到电脑后就可以使用PCAN-View打开进行监控,非常方便,同时还带开关控制的120欧姆终端电阻,缺点是有时不太稳定,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

这个小板子还需要通过CAN线和启明欣欣板子上的CAN口进行连接,如下图,这里连接的是CAN2,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

工控板需要单独供电,不能依靠下载器的电,否则无法正常运行。最后打开小板子上的120欧姆电阻,开关拨到ON那一端就可以了。

PS:PCAN-View可以去PeakCAN官网下载,是免费软件;CAN线得是双绞线,H对H,L对L进行连接。


二 搭建CAN基础工程

硬件搭建好之后,先搭建一个CAN的基础工程,验证是否可以收发CAN消息,为后续移植打下基础。这里使用STM32CubeMX来操作。

打开STM32CubeMX,芯片选择STM32F407ZGT6,选好后创建工程。

配置时钟

在新界面里的Pinout & Configuration里选择RCC,然后高速时钟和低速时钟都选择Crystal/Ceramic Resonator

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

PS:启明欣欣的板子,其外部接了2个晶振,一个8M,一个32.768K,前者用于高速时钟,后者用于低速时钟,如果低速时钟没有外接晶振,那么就选disable。

此时点击Clock Configuration

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

然后按照红框里的步骤一个个更改,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

第4步输入频率168后回车,CubeMX会自动调整,非常方便。另外,可以看到低速时钟LSE的输入频率是32.768K,这个也可以修改,需要结合实际。

这里要注意一下:配置完毕后APB1外设时钟是42M,APB1定时器时钟是84M,后面要用到。

设置SYS

回到Pinout & Configuration,然后点击SYS,右侧的选项按照如下进行选择,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

PS:由于没有使用操作系统,所以这里的Timebase Source选择SysTick

开启CAN2

启明欣欣的CAN2对应的是PB12和PB13,其中PB12是RX,PB13是TX,先在Pinout view里右下角的搜索框中输入PB12,然后回车,就可以找到PB12,会闪烁,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

点击该引脚,功能选择CAN2_RX,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

同理找到PB13,将其设置为CAN2_TX,设置OK后会发现CAN2已经自动使能了。

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

这里设置一下CAN的通信速率,本教程使用500K,设置如上图红框,

  • Prescaler设置为6
  • Time Quanta in Bit Segment 1设置为7
  • Time Quanta in Bit Segment 2设置为6
  • ReSynchronization Jump Width设置为1

经过上述设置后,CAN的波特率就变成500K了。

设置原理:前面配置时钟时,APB1的外设时钟是42M,而CAN是属于APB1的外设,这样经过Prescaler的变频后就变成42M/6=7M,也就是7000K,然后除以(Time Quanta in Bit Segment 1 + Time Quanta in Bit Segment 2 + ReSynchronization Jump Width * 1),也就是7000K/14=500K

芯片手册上的波特率的计算原理如下,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

可以看出上述配置并不是唯一选择,只要根据原理让波特率是500K就可以了。

最后是开启CAN2的接收中断,如下红框,勾选CAN2 RX0中断,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

PS:RX0和RX1分别对应2个内部接收FIFO,这里选择FIFO0,后面会讲到如何设置

生成Keil工程

配置完毕,最后生成工程。

点击Project Manager,然后在Project里对红框标注的地方进行自定义修改

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

接着是Code Generator,按照如下勾选,也可以根据自己需要进行修改

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

设置完毕后点击右上角的GENERATE CODE来生成Keil工程

PS:Keil现在有社区版,个人使用是免费的,不用去破解了。

验证CAN通信

打开生成的Keil工程,然后先做以下配置,

  • 编译器使用V6版本

    CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

    如果使用的是老版的Keil,可能还得用V5版本的编译器

  • 取消勾选Browse Information,节约编译时间

    CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

  • 编译优化选项选择O1或O0,优化选项过高可能会造成调试时无法打断点

    CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

配置好之后,编译一下,保证工程可以顺利编译完成。

剩下是修改代码,主要参考这篇文章,不过该作者用的CAN1,这里再写一遍,在USER CODE BEGIN 4下面添加函数CANFilter_Config(),用于配置CAN2的过滤器,

void CANFilter_Config(void){ CAN_FilterTypeDef sFilterConfig; sFilterConfig.FilterBank = 0; // CAN过滤器编号,范围0-27 sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; // CAN过滤器模式,掩码模式或列表模式,这里选择掩码模式 sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // CAN过滤器尺度,16位或32位,这里选择32位 sFilterConfig.FilterIdHigh = 0x0000; // 32位下,存储要过滤ID的高16位 sFilterConfig.FilterIdLow = 0x0000; // 32位下,存储要过滤ID的低16位 sFilterConfig.FilterMaskIdHigh = 0x0000; // 掩码模式下,存储的是过滤器掩码的高16位 sFilterConfig.FilterMaskIdLow = 0x0000; // 掩码模式下,存储的是过滤器掩码的低16位 sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 报文通过过滤器的匹配后,存储到哪个FIFO,这里选择FIFO0 sFilterConfig.FilterActivation = CAN_FILTER_ENABLE; // 激活过滤器 sFilterConfig.SlaveStartFilterBank = 0; if (HAL_CAN_ConfigFilter(&hcan2, &sFilterConfig) != HAL_OK) { Error_Handler(); }}

选择FilterBank 0,配置成掩码模式,选择FIFO0来接收CAN报文(这个和前面选择RX0中断保持一致,如果使用FIFO1,那么前面就要勾选RX1中断)。掩码ID是全0,表示允许接收所有报文,芯片手册介绍如下,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

PS:如果只想接收指定报文,那么就要配置掩码ID为非0,具体可以参考芯片手册。

然后添加CAN2的使能函数,

void CAN_Start_Init(void){ if (HAL_CAN_Start(&hcan2) != HAL_OK) { Error_Handler(); } if (HAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) { Error_Handler(); }}

还有发送函数,这个用来测试发送,

void CAN2_Send_Test(void){ uint32_t TxMailbox; uint8_t data[4] = {0x01, 0x02, 0x03, 0x04}; CAN_TxHeaderTypeDef TxMessage; TxMessage.IDE = CAN_ID_STD; // 设置ID类型,标准帧还是扩展帧,这里选择标准帧 TxMessage.StdId = 0x111; // 设置ID号 TxMessage.RTR = CAN_RTR_DATA; // 设置传输数据帧 TxMessage.DLC = 4;  // 设置数据长度 if (HAL_CAN_AddTxMessage(&hcan2, &TxMessage, data, &TxMailbox) != HAL_OK) { Error_Handler(); }}

最后是CAN2接收中断的回调函数,用来测试接收,

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan){ uint8_t data[8] = {0, 0, 0, 0, 0, 0, 0, 0}; HAL_StatusTypeDef status; CAN_RxHeaderTypeDef RxMessage; if (hcan == &hcan2) { status = HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxMessage, data); if (HAL_OK == status) { ; // to do something } }}

添加好之后,在USER CODE BEGIN PFP下添加函数声明,接收中断的回调函数不用声明,

/* USER CODE BEGIN PFP */void CANFilter_Config(void);void CAN_Start_Init(void);void CAN2_Send_Test(void);/* USER CODE END PFP */

然后在main函数里调用这些函数,每隔1s发送一次CAN报文,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

再次编译并烧录到板子里,然后重启运行,此时在PCAN-View上可以看到CAN报文,说明发送没问题,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

接着验证接收,此时先进入debug模式,然后在CAN接收中断里打个断点,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

使用PCAN-View来创建一条随意报文,数据是0x9988,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

然后点击OK进行保存,最后选中创建的报文按空格进行发送,此时会进入断点,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

把data数组添加到Keil的Watch窗口中,然后单步走一步,可以看到data数组里有数据了,如下,正是之前发送的报文数据,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival


三 移植CanFestival

有了第二节的基础工程后,本节讲述如何移植CanFestival,适用于STM32 F4系列芯片。

对象字典的配置

首先规划一下Slave设备的对象字典,具体如下,

  • 每隔3s发送一次心跳报文
  • 添加对象0x2000_00 (u8类型), 0x2001_00 (u16类型), 0x2002_00 (u32类型), 0x2003_00 (i32类型),0x2004_00 (i16类型),0x2005_00 (Visible String类型),总共6个对象
  • RPDO1:对应0x2000_00,0x2001_00和0x2002_00
  • TPDO1:对应0x2003_00,每隔500ms发一次

这里使用objdictgen来进行编辑,其地址是https://github.com/happybruce/objdictgen,经过本人优化后可以使用Python3启动。
PS:这个编辑器原本是在CanFestival里自带的,本人把其独立出来了。

双击objdictedit.py打开编辑器,然后在File下点击New,在弹出的界面里进行以下设置,
CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

点击OK,进入新的主界面,然后根据下述步骤进行配置,

配置心跳报文

接着在0x1000-0x1029里找到0x1017,将其值设置为3000 (其单位是毫秒,16进制是0xBB8)
CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

添加对象

在0x2000-0x5FFF里添加之前提到的6个对象,
CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

配置RPDO1

设置RPDO1的映射,该对象索引是0x1600,如下,对应0x2000_00, 0x2001_00和0x2002_00
CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

设置RPDO1的通信参数,该对象索引是0x1400,这里只配置COB ID和Inhibit Time (10ms)
CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

当设备收到COB ID的为NodeId+0x200的报文,就会把报文里包含的值存入对应的对象里。

配置TPDO1

设置TPDO1的映射,该对象索引是0x1A00,如下,对应0x2003_00
CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

设置TPDO1的通信参数,该对象索引是0x1800,如下,
CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

COB ID是nodeid+0x180,传输类型是254,即0xFE,定时时间是500ms,即0x1F4

这样对象字典就配置好了。最后保存工程,并生成对应的代码,点击File->Build Dictionary生成slavedic.c和slavedic.h
CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

这2个文件暂时留着备用

开启定时器

打开CubeMX工程,然后开启TIM3,时钟源选择内部时钟,预分频系数输入839,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

为什么是839呢?CanFestival对定时器的要求是counter每隔10us加1,也就是100KHz,而前面配置时钟时定时器的时钟频率是84MHz,如果以100KHz为单位,那么84M就等于840x100K, 那么为了达到100KHz的频率,预分频系数就是840-1=839

最后打开定时器中断,
CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

移植

首先使用git clone下载CanFestival,

git clone https://github.com/happybruce/CanFestival.gitcd CanFestivalgit checkout develop

这个Github地址是本人的仓库,已经对代码进行了优化。

在工程目录Core下添加以下目录结构,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

然后做以下拷贝,

  • 把CanFestival/src目录下的红框标注的文件拷贝到Core/CanFestival/src/下,红叉的不要拷贝

    CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

  • 把CanFestival/include目录下的以下文件拷贝到Core/CanFestival/inc/下,还有cm4目录也拷贝过来,

    CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

  • 把CanFestival/drivers/cm4目录下的cm4.h和cm4.c拷贝到Core/CanFestival/drv下

  • 把CanFestival/examples/CM4/od/下的slavedic.c和slavedic.h拷贝到Core/CanFestival/slavedic下

拷贝完毕后打开Keil工程,点击以下按钮,

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

然后添加三个组及其对应的源文件,注意这里不需要添加头文件,后面给头文件设置搜索目录即可

CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival

添加完毕后点击OK,然后添加搜索目录,如下图2个步骤,
CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival
在弹出界面里填入以下目录,
CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival
最后点击OK,这样工程就配置好了。

main.c内容如下,

/* USER CODE BEGIN Header *//** ****************************************************************************** * @file  : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2024 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** *//* USER CODE END Header *//* Includes ------------------------------------------------------------------*/#include \"main.h\"#include \"can.h\"#include \"tim.h\"#include \"gpio.h\"/* Private includes ----------------------------------------------------------*//* USER CODE BEGIN Includes */#include \"canfestival.h\"#include \"slavedic.h\"/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*//* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*//* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*//* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/void SystemClock_Config(void);/* USER CODE BEGIN PFP */void CANFilter_Config(void);void CAN_Start_Init(void);void CAN1_Send_Test(void);/* USER CODE END PFP *//* Private user code ---------------------------------------------------------*//* USER CODE BEGIN 0 *//* USER CODE END 0 *//** * @brief The application entry point. * @retval int */int main(void){ /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_CAN2_Init(); MX_TIM3_Init(); /* USER CODE BEGIN 2 */ initTimer(); // 初始化定时器 canInit(&slavedic_ObjDictData, 500000); // 设置速率为500K HAL_TIM_Base_Start_IT(&htim3); CANFilter_Config(); CAN_Start_Init(); setNodeId(&slavedic_ObjDictData, 1); // 设置Canopen id为1 setState(&slavedic_ObjDictData, Initialisation); // NMT状态设置为Initialisation setState(&slavedic_ObjDictData, Pre_operational); // NMT状态设置为Pre_operational setState(&slavedic_ObjDictData, Operational); // NMT状态设置为Operational /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { HAL_Delay(1000); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */}/** * @brief System Clock Configuration * @retval None */void SystemClock_Config(void){ RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 4; RCC_OscInitStruct.PLL.PLLN = 168; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { Error_Handler(); }}/* USER CODE BEGIN 4 */// static CAN_TxHeaderTypeDef TxMessage; //CAN发�?�的消息的消息头// static CAN_RxHeaderTypeDef RxMessage; //CAN接收的消息的消息�???void CANFilter_Config(void){ CAN_FilterTypeDef sFilterConfig; sFilterConfig.FilterBank = 0; //CAN过滤器编号,范围0-27 sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //CAN过滤器模式,掩码模式或列表模�??? sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //CAN过滤器尺度,16位或32�??? sFilterConfig.FilterIdHigh = 0x000 << 5; //32位下,存储要过滤ID的高16�??? sFilterConfig.FilterIdLow = 0x0000; //32位下,存储要过滤ID的低16�??? sFilterConfig.FilterMaskIdHigh = 0x0000; //掩码模式下,存储的是掩码 sFilterConfig.FilterMaskIdLow = 0x0000; sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; //报文通过过滤器的匹配后,存储到哪个FIFO sFilterConfig.FilterActivation = CAN_FILTER_ENABLE; //�???活过滤器 sFilterConfig.SlaveStartFilterBank = 0; if (HAL_CAN_ConfigFilter(&hcan2, &sFilterConfig) != HAL_OK) { Error_Handler(); }}void CAN_Start_Init(void){ if (HAL_CAN_Start(&hcan2) != HAL_OK) { Error_Handler(); } if (HAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) { Error_Handler(); }}void CAN1_Send_Test(void){ uint32_t TxMailbox; CAN_TxHeaderTypeDef TxMessage; uint8_t data[4] = {0x01, 0x02, 0x03, 0x04}; TxMessage.IDE = CAN_ID_STD; //设置ID类型 TxMessage.StdId = 0x111; //设置ID�??? TxMessage.RTR = CAN_RTR_DATA; //设置传�?�数据帧 TxMessage.DLC = 4;  //设置数据长度 if (HAL_CAN_AddTxMessage(&hcan2, &TxMessage, data, &TxMailbox) != HAL_OK) { Error_Handler(); } }// void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)// {// uint8_t data[8] = {0, 0, 0, 0, 0, 0, 0, 0};// HAL_StatusTypeDef status;// CAN_RxHeaderTypeDef RxMessage; // if (hcan == &hcan2)// { // status = HAL_CAN_GetRxMessage(&hcan2, CAN_RX_FIFO0, &RxMessage, data);// if (HAL_OK == status)// {// // printf(\"--->Data Receieve!\\r\\n\");// // printf(\"RxMessage.StdId is %#x\\r\\n\", RxMessage.StdId);// // printf(\"data[0] is 0x%02x\\r\\n\", data[0]);// // printf(\"data[1] is 0x%02x\\r\\n\", data[1]);// // printf(\"data[2] is 0x%02x\\r\\n\", data[2]);// // printf(\"data[3] is 0x%02x\\r\\n\", data[3]);// // printf(\"<---\\r\\n\");// __nop(); // }// }// }/* USER CODE END 4 *//** * @brief This function is executed in case of error occurrence. * @retval None */void Error_Handler(void){ /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */}#ifdef USE_FULL_ASSERT/** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */void assert_failed(uint8_t *file, uint32_t line){ /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf(\"Wrong parameters value: file %s on line %d\\r\\n\", file, line) */ /* USER CODE END 6 */}#endif /* USE_FULL_ASSERT */

然后编译,烧录到板子上运行,如下,可以看到TPDO1每隔500毫秒发一次
CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival
由前面配置可知,TPDO1对应0x2003_00,这里通过PCAN view来发送SDO去修改这个对象值,
CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival
发送完后,可以看出TPDO1发出的值就变了,变成我们通过SDO写的值
CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival
然后通过PCAN View发一个RPDO1给板子,
CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival
发完之后通过SDO去读取0x2000_00, 0x2001_00和0x2002_00的值,如下,可以看出与RPDO1发出的值相等
CanFestival移植到STM32 F4芯片(基于HAL库)_stm32 canfestival


四 总结

本文讲述了如何把CanFestival移植到STM32 F4系列芯片上,由于本人优化了CanFestival库,所以移植起来比较简单。

了解过程后,对于master或移植到CM3、CM0都很容易了。