你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

用C++写单片机程序STM32F103+自建固件库+FreeRTOS gcc编译器  

[复制链接]
freemancn 发布时间:2019-8-17 18:13
用C++写单片机程序 STM32F103 + 自建固件库 + FreeRTOS 用gcc编译器和newlib(1篇)


       作为论坛的新人,先自我介绍一下。本人有10年的Win平台开发经验,从VS6.0一直用到VS2019,主要使用C#构建程序。在安徽某大学任教C语言程序设计7年,C语言自然是滚花烂熟。由于工作需要或者说是个人爱好,转战单片机。刚开始学习也是51+Keil用C语言开发,既然是学习实现的功能并不复杂,编写的代码量也不大,但还是体会到什么是一夜回到解放前。Keil的代码自动完成功能太弱鸡,如果做正式的项目效率会非常低。当时也只是想想而已,因为知道自己并不会去做实际的项目。之后当然就是学习STM32了,选择STM32主要是看中了中文资料多,学习人数多学习氛围好。STM32十足让我惊叹,比51复杂N倍的体系架构,超多的片上外设,还有如此低廉的价格。深入学习后发现还是Keil+C语言,至少市面上99%的学习都是基于这一框架的。非常的失望,非常的不适应。因为之前用C#开发Win应用,肯定是面向对象的开发思路,因为.NET Framework(相当于STM32的固件库)就是OO(面相对象)设计的,这么多年用下来,也深深的体会到OO的优势。不光是程序设计思路,还有就是IDE(集成开发环境)对开发者的重要性。我独自开发的Win应用最大的有10万行代码,我可以很轻松的构建,还能很轻松的完成代码维护,这里的代码维护指的是修订BUG,优化功能,增加功能,版本迭代等等。


       STM32F103的主频已有72MHz,复杂的系统架构,超多的片上外设。想要喂饱这个MCU或者说是发挥出它强大的功能,肯定是需要大量代码的。当代码数量达到一定规模,自然要面对代码结构的问题。用Keil+C可以做,完成需要的功能肯定没有问题,而且现在绝大多数人都在这么做。但是C语言是面相过程的语言,对代码结构毫无帮助,毫无益处,因为无计可施。达到一定规模后,代码逻辑估计只有设计者很清楚,别人要想看懂是一件很耗费时间的事情。导致这一结果的原因是有大量的宏,更可怕的是宏嵌套、使用全局变量,这个变量会被多少函数共享,在什么时候会被改变分析起来很头疼、大量的函数,这些函数在语言层面是相互独立的,但逻辑上可能是有联系的,在语言级并没有这种逻辑关系的表达。就像官方的HAL库,我读起来想死的心都有。不是我读不懂而是读懂这些我付出的时间代价太大,要在OO思路下,这个要轻松N倍。时间就是金钱,效率就是生命。官方的HAL库其实就是想实现一个硬件抽象层,让开发者对于不同型号的MCU有一个统一的应用层开发界面,提高代码的移植性,缩短开发周期。想法是好的,做法是失败的,因为HAL库还是再用C语言编写,硬是用C语言套OO思路,代码恶心到极致。这也就是STD库还是有人在用的原因。如果使用真OO就可以把逻辑上有关联的函数组织到一起,将一些全局变量限定在部分函数中共享,其实这就OO中的封装,是语言层面提供的支持。还有要吐槽的地方就是IDE,VS的代码自动完成功能真的很好用,只要你按下任何按键都会出现提示列表,按下空格自动填充你还没有输入的内容,还有参数列表的提示。带来的好处就是,我不需要记住所有函数的名称和参数列表,我只要有一个模糊的映像,输入代码的时候IDE协助我完成。让我专注于逻辑思路,代码只是完成逻辑思路的工具而已。对语言再熟悉,对函数再熟悉,没有一个好的逻辑思路仍然写不出优秀的应用。不光是代码自动完成,还有代码着色,代码折叠,代码重构等等IDE功能,对于开发真的是不可或缺。Keil可能也有这方面的支持,但和其它一些IDE相比真的太弱了。再次重申一遍,时间就是金钱,效率就是生命。Keil+C可以吐槽的地方还有很多很多,我可以给你说一整天,我并不想开吐槽大会,只是想告诉大家其实可以有更好的选择。


      说一下代码效率问题,这可能是大家非常关注的地方。绝大多数人会认为C++的时间效率不如C,但是你要知道C++是C的超集,使用C++开发并不是什么地方都必须C++,你任然可以写C函数,任然可以写嵌入汇编代码。C++的效率损失主要是函数调用,C语言中会将参数压栈,而C++对象函数除了压栈参数以外还要压栈一个this指针,多一个32位的变量而已。表面上看是多了一个参数,但事实上呢?C语言函数可能需要4个参数,而对象函数的这个this指针却能代表这4个参数,因为C++通过这个this指针去访问私有变量,而这些私有变量恰恰是C函数的那4个参数。以上的说明可能过于抽象,你现在未必需要知道细节,你只要明白一点,效率的损失不是绝对的,有时却是一种效率的提升。再高级一点的效率损失来自于多态。在C99里面已有函数参数的多态支持,即使相同函数名但参数不同,调用时根据给定参数自动选择对应的函数。这种多态在C++里面也是存在的,但这种多态是在编译时完成的,对运行效率毫无影响。而虚函数多态的效率损失才是重点,当使用基类指针指向一个子类并调用虚函数,实际运行的时候会确定实际对象的类型去调用不同版本的虚函数,这需要在运行时查找虚函数表来完成,多了一个查找的过程,在内存中多了一份虚函数表。但是这种特性有助于实现一个优秀的代码结构或设计思路,用纯C可能实现不了或者实现了效率也未必比C++来的高效,而代码的逻辑和结构肯定没有C++的优雅,构建的速度也没有C++来的快。对于虚函数的采用是选择性的,没有什么项目在任何位置都需要虚函数。而一些普通的代码,例如:int a, b; a = 10; b = a + 200; if、for......不管是用C还是C++生成的汇编代码都是一致的。第二是空间效率,上面也分析了时间效率,所以空间效率可能有所损失,但也不是绝对的。当你用到一些特性的时候,执行的代码量必然增加,所以固件的体积肯定会有所增加。C++还有个STL库,里面实现了很多基础类,这些基础类可以直接使用或者进行再封装。当你使用这个库时,固件体积会极速增加。对于一些Flash只有64K或更小的MCU,可能有点紧张。但对于更大容量的Flash完全就不是问题了。使用这个库的好处就是,更少的BUG,更快的构建速度。这也是选择性的,你可以根据实际情况自由选择。而C语言中的常用库,例如printf、abs、floor等在C++中也是可以用的,且不会因为你是C++这些库函数就发生变化。总结起来就是可能会带来一些效率的损失,这些损失大部分是选择性的,当你选择牺牲性能的同时会得到C语言无法实现的功能,得到优雅的代码,得到清晰的逻辑,得到快速的构建。对于当今的MCU性能的损失往往都是可以接受的,你能不能喂饱单片机反而是个问题。当你在C++中需要极致性能的时候,你任然可以像C语言一样,该干嘛干嘛。


       互联网上可以找到的资料实在是少之又少,断断续续搞了2年,现在已经完整构建了整个环境,打算写一个连载。这是第一篇,主要是阐述这种开发环境的优势。后面将陆续给大家分享开发环境的搭建,为什么要自建固件库,如何自建固件库,FreeRTOS如何与C++联合使用,newlib中如何实现printf重定向到串口,以及在实践过程中遇到的各种零碎的问题。随着芯片科技的不断进步,MCU性能的进一步加强,我相信这种环境将是未来的主流。也希望一些技术大牛不要再保守秘密了,把真正的技术都分享出来,彻底提升MCU编程。目前我已在用这个环境做实际的项目了,下面给一张开发环境的截图。能回复的回复一下啊,让我有写完整篇的动力。
IED.jpg


收藏 5 评论31 发布时间:2019-8-17 18:13

举报

31个回答
freemancn 回答时间:2020-11-19 21:43:03
mylovemcu 发表于 2020-11-13 14:08
老师去哪了  怎么不更新了  搞一个库上来学习一下
想看看你的顶层库怎么写的  我现在也在用C++  底层库太费 ...

分享一个

#ifndef RCC_HPP_
#define RCC_HPP_

#include "STM32F103.h"

namespace MCU
{
        namespace STM32F103
        {
                struct RegisterRCC
                {
                        volatile union
                        {
                                volatile uint32_t Value;
                        
                                volatile struct
                                {
                                        volatile uint32_t HSION : 1;
                                        volatile const uint32_t HSIRDY : 1;
                                        volatile uint32_t RESERVED1 : 1;
                                        volatile uint32_t HSITRIM : 5;
                                        volatile const uint32_t HSICAL : 8;
                                        volatile uint32_t HSEON : 1;
                                        volatile const uint32_t HSERDY : 1;
                                        volatile uint32_t HSEBYP : 1;
                                        volatile uint32_t CSSON : 1;
                                        volatile uint32_t RESERVDE2 : 4;
                                        volatile uint32_t PLLON : 1;
                                        volatile const uint32_t PLLRDY : 1;
                                        volatile uint32_t RESERVDE3 : 6;
                                }Bit;
                        }CR;

                        volatile union
                        {
                                volatile uint32_t Value;
                        
                                volatile struct
                                {
                                        volatile uint32_t SW : 2;
                                        volatile const uint32_t SWS : 2;
                                        volatile uint32_t HPRE : 4;
                                        volatile uint32_t PPRE1 : 3;
                                        volatile uint32_t PPRE2 : 3;
                                        volatile uint32_t ADCPRE : 2;
                                        volatile uint32_t PLLSRC : 1;
                                        volatile uint32_t PLLXTPRE : 1;
                                        volatile uint32_t PLLMUL : 4;
                                        volatile uint32_t USBPRE : 1;
                                        volatile uint32_t RESERVED1 : 1;
                                        volatile uint32_t MCO : 3;
                                        volatile uint32_t RESERVED2 : 5;
                                }Bit;
                        }CFGR;
               
                        volatile union
                        {
                                volatile uint32_t Value;
                        
                                volatile struct
                                {
                                        volatile const uint32_t LSIRDYF : 1;
                                        volatile const uint32_t LSERDYF : 1;
                                        volatile const uint32_t HSIRDYF : 1;
                                        volatile const uint32_t HSERDYF : 1;
                                        volatile const uint32_t PLLRDYF : 1;
                                        volatile const uint32_t PLL2RDYF : 1;
                                        volatile const uint32_t PLL3RDYF : 1;
                                        volatile const uint32_t CSSF : 1;
                                        volatile uint32_t LSIRDYIE : 1;
                                        volatile uint32_t LSERDYIE : 1;
                                        volatile uint32_t HSIRDYIE : 1;
                                        volatile uint32_t HSERDYIE : 1;
                                        volatile uint32_t PLLRDYIE : 1;
                                        volatile const uint32_t PLL2RDYE : 1;
                                        volatile const uint32_t PLL3RDYE : 1;
                                        volatile uint32_t RESERVED1 : 1;
                                        volatile uint32_t LSIRDYC : 1;
                                        volatile uint32_t LSERDYC : 1;
                                        volatile uint32_t HISRDYC : 1;
                                        volatile uint32_t HSERDYC : 1;
                                        volatile uint32_t PLLRDYC : 1;
                                        volatile uint32_t PLL2RDYC : 1;
                                        volatile uint32_t PLL3RDYC : 1;
                                        volatile uint32_t CSSC : 1;
                                        volatile uint32_t RESERVED2 : 8;
                                }Bit;
                        }CIR;
               
                        volatile union
                        {
                                volatile uint32_t Value;
                        
                                volatile struct
                                {
                                        volatile uint16_t AFIORST : 1;
                                        volatile uint16_t RESERVED1 : 1;
                                        volatile uint16_t IOPARST : 1;
                                        volatile uint16_t IOPBRST : 1;
                                        volatile uint16_t IOPCRST : 1;
                                        volatile uint16_t IOPDRST : 1;
                                        volatile uint16_t IOPERST : 1;
                                        volatile uint16_t IOPFRST : 1;
                                        volatile uint16_t IOPGRST : 1;
                                        volatile uint16_t ADC1RST : 1;
                                        volatile uint16_t ADC2RST : 1;
                                        volatile uint16_t TIM1RST : 1;
                                        volatile uint16_t SPI1RST : 1;
                                        volatile uint16_t TIM8RST : 1;
                                        volatile uint16_t USART1RST : 1;
                                        volatile uint16_t ADC3RST : 1;
                                        volatile uint16_t RESERVED2 : 16;
                                }Bit;
                        }APB2RSTR;
               
                        volatile union
                        {
                                volatile uint32_t Value;
                        
                                volatile struct
                                {
                                        volatile uint32_t TIM2RST : 1;
                                        volatile uint32_t TIM3RST : 1;
                                        volatile uint32_t TIM4RST : 1;
                                        volatile uint32_t TIM5RST : 1;
                                        volatile uint32_t TIM6RST : 1;
                                        volatile uint32_t TIM7RST : 1;
                                        volatile uint32_t RESERVED1 : 2;
                                        volatile uint32_t RESERVED2 : 3;
                                        volatile uint32_t WWDGRST : 1;
                                        volatile uint32_t RESERVED3 : 2;
                                        volatile uint32_t SPI2RST : 1;
                                        volatile uint32_t SPI3RST : 1;
                                        volatile uint32_t RESERVED4 : 1;
                                        volatile uint32_t USART2RST : 1;
                                        volatile uint32_t USART3RST : 1;
                                        volatile uint32_t USART4RST : 1;
                                        volatile uint32_t USART5RST : 1;
                                        volatile uint32_t I2C1RST : 1;
                                        volatile uint32_t I2C2RST : 1;
                                        volatile uint32_t USBRST : 1;
                                        volatile uint32_t RESERVED5 : 1;
                                        volatile uint32_t CANRST : 1;
                                        volatile uint32_t RESERVED6 : 1;
                                        volatile uint32_t BKPRST : 1;
                                        volatile uint32_t PWRRST : 1;
                                        volatile uint32_t DACRST : 1;
                                        volatile uint32_t RESERVED7 : 2;
                                }Bit;
                        }APB1RSTR;
               
                        volatile union
                        {
                                volatile uint32_t Value;
                        
                                volatile struct
                                {
                                        volatile uint16_t DMA1EN : 1;
                                        volatile uint16_t DMA2EN : 1;
                                        volatile uint16_t SRAMEN : 1;
                                        volatile uint16_t RESERVED1 : 1;
                                        volatile uint16_t FLITFEN : 1;
                                        volatile uint16_t RESERVED2 : 1;
                                        volatile uint16_t CRCEN : 1;
                                        volatile uint16_t RESERVED3 : 1;
                                        volatile uint16_t FSMCEN : 1;
                                        volatile uint16_t RESERVED4 : 1;
                                        volatile uint16_t SDIOEN : 1;
                                        volatile uint16_t RESERVED5 : 5;
                                        volatile uint16_t RESERVED6 : 16;
                                }Bit;
                        }AHBENR;
               
                        volatile union
                        {
                                volatile uint32_t Value;
                        
                                volatile struct
                                {
                                        volatile uint16_t AFIOEN : 1;
                                        volatile uint16_t RESERVED1 : 1;
                                        volatile uint16_t IOPAEN : 1;
                                        volatile uint16_t IOPBEN : 1;
                                        volatile uint16_t IOPCEN : 1;
                                        volatile uint16_t IOPDEN : 1;
                                        volatile uint16_t IOPEEN : 1;
                                        volatile uint16_t IOPFEN : 1;
                                        volatile uint16_t IOPGEN : 1;
                                        volatile uint16_t ADC1EN : 1;
                                        volatile uint16_t ADC2EN : 1;
                                        volatile uint16_t TIM1EN : 1;
                                        volatile uint16_t SPI1EN : 1;
                                        volatile uint16_t TIM8EN : 1;
                                        volatile uint16_t USART1EN : 1;
                                        volatile uint16_t ADC3EN : 1;
                                        volatile uint16_t RESERVED2 : 16;
                                }Bit;
                        }APB2ENR;
               
                        volatile union
                        {
                                volatile uint32_t Value;
                        
                                volatile struct
                                {
                                        volatile uint32_t TIM2EN : 1;
                                        volatile uint32_t TIM3EN : 1;
                                        volatile uint32_t TIM4EN : 1;
                                        volatile uint32_t TIM5EN : 1;
                                        volatile uint32_t TIM6EN : 1;
                                        volatile uint32_t TIM7EN : 1;
                                        volatile uint32_t RESERVED1 : 2;
                                        volatile uint32_t RESERVED2 : 3;
                                        volatile uint32_t WWDGEN : 1;
                                        volatile uint32_t RESERVED3 : 2;
                                        volatile uint32_t SPI2EN : 1;
                                        volatile uint32_t SPI3EN : 1;
                                        volatile uint32_t RESERVED4 : 1;
                                        volatile uint32_t USART2EN : 1;
                                        volatile uint32_t USART3EN : 1;
                                        volatile uint32_t USART4EN : 1;
                                        volatile uint32_t USART5EN : 1;
                                        volatile uint32_t I2C1EN : 1;
                                        volatile uint32_t I2C2EN : 1;
                                        volatile uint32_t USBEN : 1;
                                        volatile uint32_t RESERVED5 : 1;
                                        volatile uint32_t CANEN : 1;
                                        volatile uint32_t RESERVED6 : 1;
                                        volatile uint32_t BKPEN : 1;
                                        volatile uint32_t PWREN : 1;
                                        volatile uint32_t DACEN : 1;
                                        volatile uint32_t RESERVED7 : 2;
                                }Bit;
                        }APB1ENR;
               
                        volatile union
                        {
                                volatile uint32_t Value;
                        
                                volatile struct
                                {
                                        volatile uint32_t LSEON : 1;
                                        volatile const uint32_t LSERDY : 1;
                                        volatile uint32_t LSEBYP : 1;
                                        volatile uint32_t RESERVED1 : 5;
                                        volatile uint32_t RTCSEL : 2;
                                        volatile uint32_t RESERVED2 : 5;
                                        volatile uint32_t RTCEN : 1;
                                        volatile uint32_t BDRST : 1;
                                        volatile uint32_t RESERVED3 : 7;
                                        volatile uint32_t RESERVED4 : 8;
                                }Bit;
                        }BDCR;
               
                        volatile union
                        {
                                volatile uint32_t Value;
                        
                                volatile struct
                                {
                                        volatile uint32_t LSION : 1;
                                        volatile const uint32_t LSIRDY : 1;
                                        volatile uint32_t RESERVED1 : 6;
                                        volatile uint32_t RESERVED2 : 8;
                                        volatile uint32_t RESERVED3 : 8;
                                        volatile uint32_t RMVF : 1;
                                        volatile uint32_t RESERVED4 : 1;
                                        volatile uint32_t PINRSTF : 1;
                                        volatile uint32_t PORRSTF : 1;
                                        volatile uint32_t SFTRSTF : 1;
                                        volatile uint32_t IWDGRSTF : 1;
                                        volatile uint32_t WWDGRSTF : 1;
                                        volatile uint32_t LPWRRSTF : 1;
                                }Bit;
                        }CSR;
                };
        
                enum RCC_PLL_MUL
                {
                        RCC_PLL_MUL2  = 0b0000,
                        RCC_PLL_MUL3  = 0b0001,
                        RCC_PLL_MUL4  = 0b0010,
                        RCC_PLL_MUL5  = 0b0011,
                        RCC_PLL_MUL6  = 0b0100,
                        RCC_PLL_MUL7  = 0b0101,
                        RCC_PLL_MUL8  = 0b0110,
                        RCC_PLL_MUL9  = 0b0111,
                        RCC_PLL_MUL10 = 0b1000,
                        RCC_PLL_MUL11 = 0b1001,
                        RCC_PLL_MUL12 = 0b1010,
                        RCC_PLL_MUL13 = 0b1011,
                        RCC_PLL_MUL14 = 0b1100,
                        RCC_PLL_MUL15 = 0b1101,
                        RCC_PLL_MUL16 = 0b1110,
                };
               
                enum RCC_PLL_XTPRE
                {
                        RCC_PLL_XTPRE_DIV1 = 0b0,
                        RCC_PLL_XTPRE_DIV2 = 0b1,
                };
               
                enum RCC_PLL_SRC
                {
                        RCC_PLL_SRC_HSI_DIV2 = 0b0,
                        RCC_PLL_SRC_HSE      = 0b1,
                };
               
                enum RCC_HPRE
                {
                        RCC_HPRE_DIV1   = 0b0000,
                        RCC_HPRE_DIV2   = 0b1000,
                        RCC_HPRE_DIV4   = 0b1001,
                        RCC_HPRE_DIV8   = 0b1010,
                        RCC_HPRE_DIV16  = 0b1011,
                        RCC_HPRE_DIV64  = 0b1100,
                        RCC_HPRE_DIV128 = 0b1101,
                        RCC_HPRE_DIV256 = 0b1110,
                        RCC_HPRE_DIV512 = 0b1111,
                };
               
                enum RCC_PPRE
                {
                        RCC_PPRE_DIV1  = 0b000,
                        RCC_PPRE_DIV2  = 0b100,
                        RCC_PPRE_DIV4  = 0b101,
                        RCC_PPRE_DIV8  = 0b110,
                        RCC_PPRE_DIV16 = 0b111,
                };
               
                enum RCC_SW
                {
                        RCC_SW_HSI = 0b00,
                        RCC_SW_HSE = 0b01,
                        RCC_SW_PLL = 0b10,
                };
               
                class CRCC
                {
                public:
                        //保存外部晶体频率 在EnableHSE方法中初始化 用于计算系统频率
                        static uint32_t HSE;
                        
                        volatile struct RegisterRCC *pRegister = (volatile struct RegisterRCC *)(RCC_BASE);
                        
                        //开启外部高速时钟并等待时钟就绪,如果时钟不能就绪则一直等待
                        //HSE:晶体频率 单位:Hz
                        void EnableHSE(uint32_t HSE)
                        {
                                CRCC::HSE = HSE;
                                
                                this->pRegister->CR.Bit.HSEON = 1;
                                while(!this->pRegister->CR.Bit.HSERDY);
                        }
                        
                        //设置PLL参数,必须在PLL关闭的状态下
                        void SetPLL(RCC_PLL_MUL MUL, RCC_PLL_XTPRE XTPRE, RCC_PLL_SRC SRC)
                        {
                                this->pRegister->CFGR.Bit.PLLMUL = MUL;
                                this->pRegister->CFGR.Bit.PLLXTPRE = XTPRE;
                                this->pRegister->CFGR.Bit.PLLSRC = SRC;
                        }
                        
                        //开启PLL时钟并等待时钟就绪,如果时钟不能就绪则一直等待
                        void EnablePLL(void)
                        {
                                this->pRegister->CR.Bit.PLLON = 1;
                                while(!this->pRegister->CR.Bit.PLLRDY);
                        }
                        
                        //切换系统时钟源并等待切换就绪,如果切换不能就绪则一直等待
                        void SetSysClkSource(RCC_SW SW)
                        {
                                this->pRegister->CFGR.Bit.SW = SW;
                                while(this->pRegister->CFGR.Bit.SWS != SW);
                        }
                        
                        //获取系统时钟频率 单位:Hz
                        uint32_t GetSYSCLK(void)
                        {
                                if(this->pRegister->CFGR.Bit.SWS == RCC_SW_HSI)
                                {
                                        //系统时钟为HSI
                                        return 8000000;
                                }
                                else if(this->pRegister->CFGR.Bit.SWS == RCC_SW_HSE)
                                {
                                        //系统时钟为HSE
                                        return CRCC::HSE;
                                }
                                else if(this->pRegister->CFGR.Bit.SWS == RCC_SW_PLL)
                                {
                                        //系统时钟为PLL
                                        uint32_t SRC, XTPRE, MUL;
                                       
                                        if(this->pRegister->CFGR.Bit.PLLSRC == RCC_PLL_SRC_HSI_DIV2)
                                        {
                                                //PPL输入时钟源为HSI/2
                                                SRC = 8000000;
                                                XTPRE = 2;
                                        }
                                        else
                                        {
                                                //PLL输入时钟源为HSE
                                                SRC = CRCC::HSE;
                                                
                                                if(this->pRegister->CFGR.Bit.PLLXTPRE == RCC_PLL_XTPRE_DIV1)
                                                {
                                                        //PLL输入时钟源为HSE/2
                                                        XTPRE = 1;
                                                }
                                                else
                                                {
                                                        //PLL输入时钟源为HSE/2
                                                        XTPRE = 2;
                                                }
                                        }
                                       
                                        switch((uint32_t)this->pRegister->CFGR.Bit.PLLMUL)
                                        {
                                                case RCC_PLL_MUL2: MUL = 2; break;
                                                case RCC_PLL_MUL3: MUL = 3; break;
                                                case RCC_PLL_MUL4: MUL = 4; break;
                                                case RCC_PLL_MUL5: MUL = 5; break;
                                                case RCC_PLL_MUL6: MUL = 6; break;
                                                case RCC_PLL_MUL7: MUL = 7; break;
                                                case RCC_PLL_MUL8: MUL = 8; break;
                                                case RCC_PLL_MUL9: MUL = 9; break;
                                                case RCC_PLL_MUL10: MUL = 10; break;
                                                case RCC_PLL_MUL11: MUL = 11; break;
                                                case RCC_PLL_MUL12: MUL = 12; break;
                                                case RCC_PLL_MUL13: MUL = 13; break;
                                                case RCC_PLL_MUL14: MUL = 14; break;
                                                case RCC_PLL_MUL15: MUL = 15; break;
                                                case RCC_PLL_MUL16: MUL = 16; break;
                                                default: MUL = 16; break;
                                        }
                                       
                                        return SRC / XTPRE * MUL;
                                }
                                else
                                        return 8000000;
                        }
                        
                        //获取AHB总线频率 单位:Hz
                        uint32_t GetHCLK(void)
                        {
                                uint32_t Prescaler;
                                
                                switch((uint32_t)this->pRegister->CFGR.Bit.HPRE)
                                {
                                        case RCC_HPRE_DIV1: Prescaler = 1; break;
                                        case RCC_HPRE_DIV2: Prescaler = 2; break;
                                        case RCC_HPRE_DIV4: Prescaler = 4; break;
                                        case RCC_HPRE_DIV8: Prescaler = 8; break;
                                        case RCC_HPRE_DIV16: Prescaler = 16; break;
                                        case RCC_HPRE_DIV64: Prescaler = 64; break;
                                        case RCC_HPRE_DIV128: Prescaler = 128; break;
                                        case RCC_HPRE_DIV256: Prescaler = 256; break;
                                        case RCC_HPRE_DIV512: Prescaler = 512; break;
                                        default: Prescaler = 1; break;
                                }
                                
                                return this->GetSYSCLK() / Prescaler;
                        }
                        
                        //获取APB1总线频率 单位:Hz
                        uint32_t GetPCLK1(void)
                        {
                                uint32_t Prescaler;
                                
                                switch((uint32_t)this->pRegister->CFGR.Bit.PPRE1)
                                {
                                        case RCC_PPRE_DIV1:        Prescaler = 1; break;
                                        case RCC_PPRE_DIV2:        Prescaler = 2; break;
                                        case RCC_PPRE_DIV4: Prescaler = 4; break;
                                        case RCC_PPRE_DIV8: Prescaler = 8; break;
                                        case RCC_PPRE_DIV16: Prescaler = 16; break;
                                        default: Prescaler = 1; break;
                                }
                                
                                return this->GetHCLK() / Prescaler;
                        }
                        
                        //获取APB2总线频率 单位:Hz
                        uint32_t GetPCLK2(void)
                        {
                                uint32_t Prescaler;
                                
                                switch((uint32_t)this->pRegister->CFGR.Bit.PPRE2)
                                {
                                        case RCC_PPRE_DIV1: Prescaler = 1; break;
                                        case RCC_PPRE_DIV2: Prescaler = 2; break;
                                        case RCC_PPRE_DIV4: Prescaler = 4; break;
                                        case RCC_PPRE_DIV8: Prescaler = 8; break;
                                        case RCC_PPRE_DIV16: Prescaler = 16; break;
                                        default: Prescaler = 1; break;
                                }
                                
                                return this->GetHCLK() / Prescaler;
                        }
                };
               
                uint32_t CRCC::HSE = 0;
        }
}

#endif // !RCC_HPP_

这是对RCC的封装,其实对寄存器的封装只是C++写单片机的小问题.还有几个问题要解决.
第一:如何把中断连接到任何对象的方法,这个问题本质就是如何利用指针调用对象方法,实现后可以更好的发挥面向对象的多态思路,实现一些高灵活度的编程.我用模板类实现了一个类似C#中的委托对象,然后利用这个对象还可以实现类似C#中的事件,完成消息的多播.当然这是需要付出代价的,这个模板类要用到虚函数表,经过实测这个消耗是可以接受的,多1us左右吧.这个模板类的实现具体可以用Bing国际版搜索FastDelegate.
第二:如何new和delete,这个必须通过OS实现.我使用FreeRTOS,然后全局重载new和delete运算符到pvPortMalloc和pvPortFree.不过能定义声明的对象尽量定义声明,不要频繁new和delete因为FreeRTOS的内存管理还是很弱鸡的.实现的目的只是为了提高程序的灵活度.让一些代码可以更快地适配一些硬件.我通常都是只new不delete

为了更好更快地更换MCU,应该定义一个HAL层,里面全是虚基类,抽象类似但又不同的硬件.然后顶层基于HAL开发,底层继承HAL的虚基类并做具体实现.不过虚基类又牵涉虚函数表,会有性能损失.在对性能要求高的地方还是针对不同的硬件进行直接控制.

为了更好的进行C++编程,我用gcc编译器.使用这个编译器时一定要注意,编译优化可能导致运行结果不正确,我通常是用O2或Os,一些特殊的函数还需要标记为O0.开发环境是Visual Studio 2019(个人版 免费) + VisualGDB(我买了正版).VisualGDB V5.5R2这个版本真是超级好用,自动完成,代码着色,代码格式化都是杠杠的.这个环境中在线仿真是ST-Link 2 + OpenOCD,可以设置端点,可以实时读取寄存器值,等等.

总之,C++配上这个开发环境生产力大大提高,代码的可复用性也大大提高.另外,我的项目已经投产了.



freemancn 回答时间:2019-9-18 21:55:48
redstone8415 发表于 2019-9-15 11:03
做嵌入式的基本上都是从电子硬件转入的! window编程能力非常有限!计算机基础也不扎实,
C#,C++面向对象 ...


我不是去开发一个IDE,而是用了别人很少用的IDE并且完全实现了我的想法。现在正在用这个IDE以及C++在做一个USB键盘(实际的产品)的项目。其实主要的动机来源于对USB的开发,真的是太复杂了不用C++很难解耦和重用。现在USB键盘已经接近尾声了,等我忙完我会继续写贴教大家怎么搭建开发环境,分享一些在C++过程中的心得。提前透露一下,我的键盘的USB枚举过程比海盗船K70快很多,K70是266ms完成,我键盘是176ms完成。海盗船单次获取设备描述耗时88us,我的键盘是61us,那些国产方案的键盘更是要230us左右。我购买一台USB协议分析仪测量的。虽然这个过程快一点对用户并没有什么卵用,但是说明使用C++程序效率并不会降低。
redstone8415 回答时间:2019-9-15 11:03:00
做嵌入式的基本上都是从电子硬件转入的! window编程能力非常有限!计算机基础也不扎实,
C#,C++面向对象被以前的那些所谓嵌入式大佬批得体无完肤!让他们得以在嵌入式上守住一片天地。
而C#,和C++也缺少实际的应用实例(嵌入式),而真正的即懂C#,C++又懂嵌入式的人,几乎没有!
老师望你在嵌入式C#,C++上开辟一片天地。
还有!老师要实现你的愿景!可能需要一个团队,一个人可能难以完成!也可以把它做成一个项目,才可能有持续下去的源源动力。
个人认为: 关键在于有足够多的实际应用(嵌入式的各个功能)实例服众。
奏奏奏 回答时间:2019-8-17 19:21:03
哦,支持一下这位老师。
Kevin_G 回答时间:2019-8-17 21:18:13
支持这位老师,期待革命性的变革。现在MCU性能越来越强大,使用C语言及Keil越来越吃力。
不知道ST自己的IDE(STM32CubeIDE)也是使用GCC编译器,不知道对楼主改用C++开发是否有用。
STMWoodData 回答时间:2019-8-18 13:19:44
提示: 作者被禁止或删除 内容自动屏蔽
pythonworld 回答时间:2019-8-18 18:08:31
楼主可以了解一下mbed,是用c++的。
294479435@qq.co 回答时间:2019-8-19 15:08:51
楼主分析的KEIL+C确实是经典,我也想试试C++,期待楼主后期大作
啊泽 回答时间:2019-8-19 20:08:15
支持大佬,干翻官方库
zbxiaowu 回答时间:2019-8-20 17:18:15
支持大佬
generalcircuits 回答时间:2019-8-22 11:20:07
支持老师,VS确实比keil好用
sq0101 回答时间:2019-8-22 11:41:16
楼主,mbed和vs code了解下吧,又会给你打开新的大门
haocheng996 回答时间:2019-8-22 13:59:17
支持一下
lornis 回答时间:2019-8-22 15:35:18
想法非常非常的好,支持你这样做。当面对大的项目的时候,这样做就会从容很多。
jingwang 回答时间:2019-8-23 09:15:19
支持
tanic 回答时间:2019-8-23 09:41:01
感觉C和C++混合编程,官方底层SDK还是没必要修改的。
然后单片机项目主要是UI花费时间重复代码多,应用逻辑的话其实还好。
我整过一个2W行的单片机项目,2/3的代码量花在UI上了,
123下一页

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版