资讯动态

RTThread学习记录13——关于要使用一个外设,RTThread与cubemx到底要怎么配合?

发布时间:2026/10/2 13:57:03 来源:尧图企业网站定制
一、遇到的问题我学习RTThread到IO设备模型时先是学习了怎么使用UART和PIN设备再学习了ADC和PWM这种外包型外设就遇到一个疑惑为什么突然到初始化ADC时就要使用到cubemx生成代码了为什么生成代码之后要放到board.c?为什么UART和PIN设备就不需要呢还有我最近也在搞RTThread相关的项目就遇到一个问题就是我按照我的理解我用到了pwm我需要线在RTThread里打开pwm然后在board.h里面#define要用到的pwm及其通道然后使用cubemx生成pwm的引脚和时钟硬件初始化代码再把这些代码粘贴到board.c里面去但是我就遇到了一个问题就是编译的时候报错提示pwm的引脚和时钟硬件初始化代码重复定义了这和我之前遇到的情况完全不一样之前学习到pwm时也是类似的操作这次却出问题为什么呢。后面我用DeepSeekv4.1Flash让它带我看懂底层逻辑我才搞懂。二、为什么 UART 和 PIN 不用 CubeMX,而 ADC 和 PWM 要用首先我们要明白大部分的外设要使用分成底层驱动方向和软件驱动方向底层驱动就类似于配置某个外设的时钟和引脚偏向硬件和底层的驱动/初始化而软件驱动方向就类似于设置这个参数的初始值、配置相关的调用这个外设的函数等等偏向代码层面不太涉及直接控制硬件寄存器。所以UART和PIN外设不需要cubemx配置是因为在RTThread中UART和PIN外设是直接被完全配置的而ADC和PWM外设的底层驱动对硬件引脚和时钟的初始化也就是HAL_xxx_MspPostInit()和HAL_xxx_MspInit()这2个函数RTThread是没有配置的RTThread只配置了软件驱动cubemx负责底层驱动。为什么要怎么做三、为什么官方教程需要复制那2个函数其本意是什么前面我们知道RTThread要用一个外设需要两个方向的驱动但是在硬件引脚和时钟方面的初始化RTThread有2种方式。第一种就是非常简单直接的比如你要初始化定时器3的PWM通道是4那就找到初始化定时器3的PWM通道为4的时钟及其硬件引脚的代码也就是下面的代码把它粘贴到board.c里面这样就能让RTThread自己初始化硬件引脚和时钟了。void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* htim_pwm) { if(htim_pwm-InstanceTIM3) { /* USER CODE BEGIN TIM3_MspInit 0 */ /* USER CODE END TIM3_MspInit 0 */ /* Peripheral clock enable */ __HAL_RCC_TIM3_CLK_ENABLE(); /* USER CODE BEGIN TIM3_MspInit 1 */ /* USER CODE END TIM3_MspInit 1 */ } } void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim) { GPIO_InitTypeDef GPIO_InitStruct {0}; if(htim-InstanceTIM3) { /* USER CODE BEGIN TIM3_MspPostInit 0 */ /* USER CODE END TIM3_MspPostInit 0 */ __HAL_RCC_GPIOB_CLK_ENABLE(); /**TIM3 GPIO Configuration PB1 ------ TIM3_CH4 */ GPIO_InitStruct.Pin GPIO_PIN_1; GPIO_InitStruct.Mode GPIO_MODE_AF_PP; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOB, GPIO_InitStruct); /* USER CODE BEGIN TIM3_MspPostInit 1 */ /* USER CODE END TIM3_MspPostInit 1 */ } }其实这种方式也就是和board.h里面的指示意思一样就是需要你自己找到初始化这个外设的底层驱动函数这样RTThread就能自己脱离cubemx使用外设了。缺点就是这个初始化底层的代码需要自己找要么ai要么查资料。但是最方便的方式其实就是使用cubemx生成某个外设的全套初始化代码包括初始化这个外设的时钟、这个外设的硬件引脚这个外设的初始值设置这个外设其他的管理函数等等.....但是RTThread其实只需要初始化这个外设的时钟、初始化这个外设的硬件引脚的代码其他的初始化RTThread自己能搞定所以就需要RTThread排除掉cubemx生成的无用的东西不让无用的代码参与编译然后把初始化这个外设的时钟、初始化这个外设的硬件引脚的代码复制粘贴到board.c里面这样就能正常使用一个外设了这才是board.h里那4个步骤的本意四、cubemx到底有什么用为什么RTThread需要用到cubemxcubemx对于RTThread目前我总结出有2个作用。1.RTThread独立不依赖cubemx首先cubemx能帮助RTThread生成外设的底层初始化的代码也就是HAL_xxx_MspPostInit()和HAL_xxx_MspInit()这2个函数省得RTThread又去找。就像上面举的例子就是cubemx生成代码RTThread取自己需要的就行不依赖cubemx。2.RTThread配合cubemx依赖于cubemx其次就是直接由cubemx接管所以的硬件初始化简单来说就是不管什么外设UART、PWM、PIN、ADC等等全部在cubemx里面配置好参数通道模式等等直接生成代码由cubemx接管外设的初始化。RTThread只需要在RTThread-setting里面打开要用到外设就行此时RTThread就是深度依赖于cubemx了。五、为什么之前能成功现在不行关键在于RTThread屏蔽的代码有哪些和cubemx生成代码放哪里的问题。在以前使用cubemx开发时我们会经常要勾选Generate peripheral initialization as a pair of .c/.h files per peripheral目的是为了把每个外设的初始化文件xxx.c/xxx.h分开放不要全部放到stm32f1xx_hal_msp.c文件里能够方便我们管理。在RTThreadRTThread恰好屏蔽的代码文件就包括每个外设自己的的初始化文件xxx.c/xxx.h而不会屏蔽stm32f1xx_hal_msp.c这个文件因为里面还包含的是整个板子HAL库及底层硬件的初始化代码RTThread不能屏蔽同时在cubemx眼里你不勾选Generate peripheral initialization as a pair of .c/.h files per peripheral意思就是要把所有外设的初始化代码包含了HAL_xxx_MspPostInit()和HAL_xxx_MspInit()这2个函数及该外设的初始值、模式、通道初始化放到stm32f1xx_hal_msp.c这个文件里这样因为RTThread没有屏蔽stm32f1xx_hal_msp.c这个文件就会调用里面对该外设的底层驱动初始化的代码也就是HAL_xxx_MspPostInit()和HAL_xxx_MspInit()这2个函数这也是第四个问题里RTThread依赖cubemx的实现原理就是cubemx在生成代码时不勾选然后把外设所有的初始化代码放一起让RTThread自己调用。那么RTThread不依赖cubemx自己初始化外设的原理就和上面相反了就是勾选Generate peripheral initialization as a pair of .c/.h files per peripheral让外设的初始化代码分别存放这样我们需要用到哪个外设就直接去对于外设的初始化代码把里面的HAL_xxx_MspPostInit()和HAL_xxx_MspInit()函数复制粘贴出来放到board.c里面就行了。cubemx在这单纯只是一个代码生成器没有其他作用了。所以总的来说为什么我之前的项目能成功但是现在却不行了成功的原因就是我之前的项目勾选了RTThread就自动屏蔽掉cubemx生成的代码了然后我就按照board.h里面指示的复制HAL_xxx_MspPostInit()和HAL_xxx_MspInit()这2个函数到board.c里面完全符合流程和原理就没出现问题。失败的原因有2个我一开始遇到的问题是说HAL_xxx_MspPostInit()和HAL_xxx_MspInit()这2个函数重复定义了是因为我在cubemx里面没有勾选然后我又把HAL_xxx_MspPostInit()和HAL_xxx_MspInit()这2个函数复制到board.c里面导致RTThread在编译时发现HAL_xxx_MspPostInit()和HAL_xxx_MspInit()这2个函数定义了两次就报了这个错。第二个问题就是六、总结与拓展总的来说这次有加深了我对于IO设备从应用上的理解DeepSeek确实也是一个很好的自学工具让我很快理解了教程里一带而过但是深有其意的细节之处它还给我拓展了很多的知识。拓展部分关于弱定义函数RT-Thread 里像 ADC、PWM这类外设,执行和他们有关的库函数时会去找一个固定名字的配套初始化函数来开时钟、配引脚。一般cubemx生成的代码在RTThread里都会被加载成弱定义函数比如_weak int main()函数就是典型例子cubemx也会生成main函数但是会加上_weak前缀表示是弱定义这样就只会执行RTThread里面的main()函数了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑