Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RT-Thread Studio
STM32H750VB
STM32H750 在RT-Thread Studio上配置CANFD驱动普通CAN模式控制大疆M3508电机
发布于 2023-03-26 18:21:51 浏览:1408
订阅该版
[tocm] 本文旨在RT-Thread Studio上配置rtthread CANFD驱动来控制M3508电机,不涉及任何原理 开发环境:RT-Thread Studio v2.2.6 rtthread版本:v4.1.1 硬件平台:FK750M1-VBT6 # 一、创建并配置项目 ## 创建 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230326/f4b4c201f5ebd5de2f28018eb74fb233.png.webp) ## 修改时钟 利用STM32CUBEMX生成SystemClock_Config()函数,将drv_clk.c里的system_clock_config()内容替换, 并修改board.h里的时钟源 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230326/f5d67accabb67917b1703f24bd06b64e.png.webp) ```c void system_clock_config(int target_freq_mhz) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Supply configuration update enable */ HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY); /** Configure the main internal regulator output voltage */ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0); while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {} /** Configure LSE Drive Capability */ HAL_PWR_EnableBkUpAccess(); __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.LSEState = RCC_LSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 5; RCC_OscInitStruct.PLL.PLLN = 192; RCC_OscInitStruct.PLL.PLLP = 2; RCC_OscInitStruct.PLL.PLLQ = 12; RCC_OscInitStruct.PLL.PLLR = 2; RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2; RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; RCC_OscInitStruct.PLL.PLLFRACN = 0; 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_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) { Error_Handler(); } } ``` ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230326/1c26bb84b4a9e4fe22aa383a8d58fb50.png.webp) # 二、添加FDCAN设备 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230326/b4c9c824abd8cf6adac6336bf3975e5c.png.webp) 并将stm32h7xx_hal_conf.h里#define HAL_FDCAN_MODULE_ENABLED的注释取消 在board.h里添加#define BSP_USING_CAN #define BSP_USING_FDCAN #define BSP_USING_FDCAN1 从RT-ThreadStudio\repo\Extract\Board_Support_Packages\RealThread\STM32H750-RT-ART-Pi\1.3.0\libraries\drivers里复制drv_fdcan.c和drv_fdcan.h添加到自己的工程(*注意:要在RT-Thread SDK管理器里下载STM32H750-RT-ART-PI的包才有*) 这时我们编译一下,没有报错 # 三、CubeMX配置FDCAN1 我们查看[大疆C型教程文档](https://github.com/RoboMaster/Development-Board-C-Examples/blob/master/RoboMaster%E5%BC%80%E5%8F%91%E6%9D%BFC%E5%9E%8B%E5%B5%8C%E5%85%A5%E5%BC%8F%E8%BD%AF%E4%BB%B6%E6%95%99%E7%A8%8B%E6%96%87%E6%A1%A3.pdf),得到和电机通讯所需要的波特率为1Mbps,前面配置H7输入FDCAN的时钟为80MHz,根据计算(80M/NPre/(1+NTSeg1+NTSeg2) = 80M/1/(1+63+16) = 1Mbit/s得到参数如下 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230326/b53a1115a7394536ad88fed008681e41.png.webp) 生成代码,将配置函数复制到board.c内 ```c FDCAN_HandleTypeDef hfdcan1; /* FDCAN1 init function */ void MX_FDCAN1_Init(void) { /* USER CODE BEGIN FDCAN1_Init 0 */ /* USER CODE END FDCAN1_Init 0 */ /* USER CODE BEGIN FDCAN1_Init 1 */ /* USER CODE END FDCAN1_Init 1 */ hfdcan1.Instance = FDCAN1; hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC; hfdcan1.Init.Mode = FDCAN_MODE_NORMAL; hfdcan1.Init.AutoRetransmission = DISABLE; hfdcan1.Init.TransmitPause = DISABLE; hfdcan1.Init.ProtocolException = DISABLE; hfdcan1.Init.NominalPrescaler = 1; hfdcan1.Init.NominalSyncJumpWidth = 8; hfdcan1.Init.NominalTimeSeg1 = 63; hfdcan1.Init.NominalTimeSeg2 = 16; hfdcan1.Init.DataPrescaler = 1; hfdcan1.Init.DataSyncJumpWidth = 8; hfdcan1.Init.DataTimeSeg1 = 63; hfdcan1.Init.DataTimeSeg2 = 16; hfdcan1.Init.MessageRAMOffset = 0; hfdcan1.Init.StdFiltersNbr = 0; hfdcan1.Init.ExtFiltersNbr = 0; hfdcan1.Init.RxFifo0ElmtsNbr = 0; hfdcan1.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_8; hfdcan1.Init.RxFifo1ElmtsNbr = 0; hfdcan1.Init.RxFifo1ElmtSize = FDCAN_DATA_BYTES_8; hfdcan1.Init.RxBuffersNbr = 0; hfdcan1.Init.RxBufferSize = FDCAN_DATA_BYTES_8; hfdcan1.Init.TxEventsNbr = 0; hfdcan1.Init.TxBuffersNbr = 0; hfdcan1.Init.TxFifoQueueElmtsNbr = 0; hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; hfdcan1.Init.TxElmtSize = FDCAN_DATA_BYTES_8; if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN FDCAN1_Init 2 */ /* USER CODE END FDCAN1_Init 2 */ } void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* fdcanHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; if(fdcanHandle->Instance==FDCAN1) { /* USER CODE BEGIN FDCAN1_MspInit 0 */ /* USER CODE END FDCAN1_MspInit 0 */ /** Initializes the peripherals clock */ PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_FDCAN; PeriphClkInitStruct.FdcanClockSelection = RCC_FDCANCLKSOURCE_PLL; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { Error_Handler(); } /* FDCAN1 clock enable */ __HAL_RCC_FDCAN_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); /**FDCAN1 GPIO Configuration PD0 ------> FDCAN1_RX PD1 ------> FDCAN1_TX */ GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); /* USER CODE BEGIN FDCAN1_MspInit 1 */ /* USER CODE END FDCAN1_MspInit 1 */ } } void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef* fdcanHandle) { if(fdcanHandle->Instance==FDCAN1) { /* USER CODE BEGIN FDCAN1_MspDeInit 0 */ /* USER CODE END FDCAN1_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_FDCAN_CLK_DISABLE(); /**FDCAN1 GPIO Configuration PD0 ------> FDCAN1_RX PD1 ------> FDCAN1_TX */ HAL_GPIO_DeInit(GPIOD, GPIO_PIN_0|GPIO_PIN_1); /* USER CODE BEGIN FDCAN1_MspDeInit 1 */ /* USER CODE END FDCAN1_MspDeInit 1 */ } } ``` 引脚根据自己的实际情况选择 # 四、修改rtthread驱动文件 修改drv_fdcan.c文件,使用什么波特率就改什么 ```c static const _stm32_fdcan_NTconfig_t st_CanNTconfig[]= /*baud brp sjw tseg1 tseg2*/ { {CAN1MBaud, 1,8,63,16}, {CAN800kBaud, 10,8,20,4}, {CAN500kBaud, 20,8,15,4}, {CAN250kBaud, 20,8,35,4}, {CAN125kBaud, 40,8,35,4}, {CAN100kBaud, 40,8,44,5}, {CAN50kBaud, 80,8,44,5}, {CAN20kBaud, 200,8,44,5}, {CAN10kBaud, 400,8,44,5} }; ``` ```c static int rt_hw_can_init(void) { struct can_configure config; config.baud_rate = CAN1MBaud; //修改此处 config.msgboxsz = 48; config.sndboxnumber = 1; config.mode = RT_CAN_MODE_NORMAL; config.privmode = RT_CAN_MODE_NOPRIV; config.ticks = 50; /* config default filter */ FDCAN_FilterTypeDef sFilterConfig; sFilterConfig.IdType = FDCAN_STANDARD_ID; sFilterConfig.FilterIndex = 0; sFilterConfig.FilterType = FDCAN_FILTER_MASK; sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; sFilterConfig.FilterID1 = 0; sFilterConfig.FilterID2 = 0; #ifdef BSP_USING_FDCAN1 st_DrvCan1.FilterConfig = sFilterConfig; st_DrvCan1.device.config = config; /* register FDCAN1 device */ rt_hw_can_register(&st_DrvCan1.device, st_DrvCan1.name, &_can_ops, &st_DrvCan1); #endif /* BSP_USING_FDCAN1 */ #ifdef BSP_USING_FDCAN2 st_DrvCan2.FilterConfig = sFilterConfig; st_DrvCan2.device.config = config; /* register FDCAN1 device */ rt_hw_can_register(&st_DrvCan2.device, st_DrvCan2.name, &_can_ops, &st_DrvCan2); #endif /* BSP_USING_FDCAN2 */ return 0; } ``` 编译一遍,有报错 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230326/a205f14022b9d0ed20f0763b437aa312.png.webp) 我们找到错误,从相邻的RT_CAN_MODE_NORMAL go过去,发现是名字错误,修改即可 在can.h里添加#include "rt-thread/components/drivers/include/ipc/completion.h" 再次编译,无报错,至此所有配置已完成,可以正常使用 # 五、访问 CAN 设备 运行以下代码 ```c #define CAN_DEV_NAME "fdcan1" /* CAN 设备名称 */ rt_device_t can_dev; /* CAN 设备句柄 */ can_dev = rt_device_find(CAN_DEV_NAME); if (!can_dev) { rt_kprintf("find %s failed!\n", CAN_DEV_NAME); return RT_ERROR; } rt_kprintf("find %s success!\n", CAN_DEV_NAME); /* 以中断接收及发送方式打开 CAN 设备 */ rt_device_open(can_dev, (RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX)); /* 设置 CAN 通信的波特率为1 MBit/s*/ if(rt_device_control(can_dev, RT_CAN_CMD_SET_BAUD, (void *)CAN1MBaud) != RT_EOK) { rt_kprintf("config %s failed!\n", CAN_DEV_NAME); return RT_ERROR; } ``` ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230326/50f5e1ba3a38f25c3f1cb4e60b67eb04.png.webp) 可以发现fdcan1已经挂载到can总线下,下一步就是给电调发送信号 新建can_motor.c文件 ```c #include "can_motor.h" #define ABS(x) ( (x>0) ? (x) : (-x) ) //绝对值函数 rt_device_t can_dev; /* CAN 设备句柄 */ int can_init(void){ //rtthread can含有一个bug---若can设备突然断开,整个程序就会卡死即发送失败后等待重传---待修复 /* 查找 CAN 设备 */ can_dev = rt_device_find(CAN_DEV_NAME); if (!can_dev) { rt_kprintf("find %s failed!\n", CAN_DEV_NAME); return RT_ERROR; } rt_kprintf("find %s success!\n", CAN_DEV_NAME); /* 以中断接收及发送方式打开 CAN 设备 */ rt_device_open(can_dev, (RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX)); /* 设置 CAN 通信的波特率为1 MBit/s*/ if(rt_device_control(can_dev, RT_CAN_CMD_SET_BAUD, (void *)CAN1MBaud) != RT_EOK) { rt_kprintf("config %s failed!\n", CAN_DEV_NAME); return RT_ERROR; } return RT_EOK; } struct rt_can_msg t_msg; //左前,右前,左后,右后 此函数内用到了Function[rt_completion_wait],因此不能放到中断里执行 //11.05 利用rt_hw_interrupt_disable关闭中断,可以放到定时器里执行 void set_moto_current(rt_device_t can_dev,rt_int16_t left_f_value, rt_int16_t right_f_value,rt_int16_t left_b_value, rt_int16_t right_b_value) { t_msg.ide=RT_CAN_STDID; t_msg.rtr=RT_CAN_DTR; t_msg.len=8; t_msg.id=0x200; t_msg.data[0] = (left_f_value >> 8); t_msg.data[1] = left_f_value; t_msg.data[2] = (right_f_value >> 8); t_msg.data[3] = right_f_value; t_msg.data[4] = (left_b_value >> 8); t_msg.data[5] = left_b_value; t_msg.data[6] = (right_b_value >> 8); t_msg.data[7] = right_b_value; rt_device_write(can_dev, 0, &t_msg, sizeof(t_msg)); } ``` can_motor.h文件 ```c #define CAN_DEV_NAME "fdcan1" /* CAN 设备名称 */ #define motor_num 4 //电机数量 extern rt_device_t can_dev; int can_init(void); void set_moto_current(rt_device_t can_dev,rt_int16_t left_f_value, rt_int16_t right_f_value,rt_int16_t left_b_value, rt_int16_t right_b_value); ``` 使用set_moto_current函数可以给四个电调发送电流值,读取电调发送的信息请参照[大疆例程](https://github.com/RoboMaster/Development-Board-C-Examples/blob/master/14.CAN/application/CAN_receive.c)和[CAN 设备](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/can/can)补全,接下来的事就是如何利用PID进行速度闭环,网上资料很多,不多阐述。 # 六、参考 [【ART-PI】使用STM32H750的隐藏2MB ROM](https://blog.csdn.net/FightingDragon/article/details/124469160) [STM32H750 更好用的CANFD 用例详解](https://blog.csdn.net/weifengdq/article/details/114000726) [STM32H7 FDCAN兼容普通CAN使用 基于CubeMX配置](https://blog.csdn.net/Fairchild_1947/article/details/122877178) [CAN 设备](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/can/can) [ART PI 的FDCAN 终于调通了](https://club.rt-thread.org/ask/article/44d8605771b1907e.html) [RoboMaster开发板C型嵌入式软件教程文档](https://github.com/RoboMaster/Development-Board-C-Examples/blob/master/RoboMaster%E5%BC%80%E5%8F%91%E6%9D%BFC%E5%9E%8B%E5%B5%8C%E5%85%A5%E5%BC%8F%E8%BD%AF%E4%BB%B6%E6%95%99%E7%A8%8B%E6%96%87%E6%A1%A3.pdf)
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
djjznb
这家伙很懒,什么也没写!
文章
1
回答
2
被采纳
0
关注TA
发私信
相关文章
1
rt_thread studio 啥时候能用呢
2
RT_Thread使用反馈帖子
3
RTT studio 下的 AT指令问题。
4
什么时候RTT Sdudio支持Ubuntu,Deepin和UOS操作系统
5
rt thread Studio 关于J-LINK下载问题
6
RT-Thread studio 调试设置问题
7
RTT-Studio 如何设置调试配置参数?
8
rt_thread studio 软件包配置
9
RT-Studio目前只能开发STM32的项目吗?
10
rtt studio 生成hex名字修改
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
SFUD
msh
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1443
个答案
289
次被采纳
张世争
805
个答案
174
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
4
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部