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;
}
分享一个
#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++配上这个开发环境生产力大大提高,代码的可复用性也大大提高.另外,我的项目已经投产了.
还更新吗,能出一期环境搭建的教程吗,配一个Demo工程