STM32芯片命名规则:
。。。。
所以stm32 CB为48引脚,128k闪存。
stm32寄存器:
。。。。
1、stm32初始化流程
void RCC_Configuration(void)
{
/* RCC system reset(for debug purpose) */
RCC_DeInit(); //时钟控制寄存器全部恢复默认值
/* Enable HSE */
RCC_HSEConfig(RCC_HSE_ON); //外部高速时钟源开启(8M晶振)
/* Wait till HSE is ready */
HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待外部时钟HSE就绪
if(HSEStartUpStatus == SUCCESS) //如果时钟启动成功
{
/* HCLK = SYSCLK */
RCC_HCLKConfig(RCC_SYSCLK_Div1); //定义AHB设备时钟为系统时钟1分频,AHB,系统时钟不分频
/* PCLK2 = HCLK */
RCC_PCLK2Config(RCC_HCLK_Div1); //定义AHB2设备时钟为HCLK时钟1分频
/* PCLK1 = HCLK/2 */
RCC_PCLK1Config(RCC_HCLK_Div2); //定义AHB1设备时钟为HCLK时钟2分频
/* Flash 2 wait state */
FLASH_SetLatency(FLASH_Latency_2); //设定内部FLASH的的延时周期为2周期
/* Enable Prefetch Buffer */
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //使能FLASH预存取缓冲区
/* PLLCLK = 8MHz * 9 = 72 MHz */
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //配置PLL时钟为外部高速时钟的9倍频,8MHz * 9 = 72 MHz
/* Enable PLL */
RCC_PLLCmd(ENABLE); //使能PLL时钟
/* Wait till PLL is ready */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) //等待PLL时钟设置完成准备就绪
{
}
/* Select PLL as system clock source */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //使用PLL时钟作为系统时钟源
/* Wait till PLL is used as system clock source */
while(RCC_GetSYSCLKSource() != 0x08) //返回系统所用时钟源确认为外部高速晶振,8M晶振。
{
}
}
}
void RCC_DeInit(void)
{
/* Set HSION bit,打开内部8M的HSI时钟 */
RCC->CR |= (uint32_t)0x00000001; //RCC结构体为RCC_TypeDef
/* Reset SW[1:0], HPRE[3:0], PPRE1[2:0], PPRE2[2:0], ADCPRE[1:0] and MCO[2:0] bits */
/*SW=00,SWS=00,设置HSI为系统时钟
*HPRE=0000,AHB,即SYSCLK不分频
*PPRE1=000,AHB1(PCLK1)不分频
*PPRE2=000,AHB2 (PCLK2)不分频
*ADCPRE=00,PCLK2 两分频后作为ADC时钟
*MCO=000,没有时钟输出*/
RCC->CFGR &= (uint32_t)0xF8FF0000;
/* Reset HSEON, CSSON and PLLON bits */
/*HSEON=0,关闭HSE振荡器
CSSON=0,关闭时钟检测器
PLLON=0,PLL关闭*/
RCC->CR &= (uint32_t)0xFEF6FFFF;
/* Reset HSEBYP bit */
/*HSEBYP=0,外部4-16M振荡器没旁路*/
RCC->CR &= (uint32_t)0xFFFBFFFF;
/* Reset PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE bits */
/*PLLSRC=0,HSI经过2分频后作为PLL输入时钟
PLLXTPRE=0.HSE不分频
PLLMUL=0000,PLL 2倍频输出
USBPRE=0,PLL 1.5倍分频后作为USB时钟*/
RCC->CFGR &= (uint32_t)0xFF80FFFF;
/* Disable all interrupts */
//关闭所有时钟中断
RCC->CIR = 0x00000000;
}
#define RCC ((RCC_TypeDef *) RCC_BASE)
#define RCC_BASE (AHBPERIPH_BASE + 0x1000) //RCC_BASE = 0x40021000
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000) //AHBPERIPH_BASE = 0x40020000
#define PERIPH_BASE ((uint32_t)0x40000000) //PERIPH_BASE = 0x40000000
//所以RCC_BASE = 0x40021000,由上面寄存器表可知这个是复位和时钟控制器RCC
typedef struct
{
__IO uint32_t CR;
__IO uint32_t CFGR;
__IO uint32_t CIR;
__IO uint32_t APB2RSTR;
__IO uint32_t APB1RSTR;
__IO uint32_t AHBENR;
__IO uint32_t APB2ENR;
__IO uint32_t APB1ENR;
__IO uint32_t BDCR;
__IO uint32_t CSR;
} RCC_TypeDef;
这个结构体根据寄存器定义,如下图所示
总结:RCC_DeInit(); 所做的工作就是在系统初始的时候关闭HSE时钟,打开HSI作为时钟,并关闭时钟中断
void RCC_HSEConfig(uint32_t RCC_HSE)
{
/* Check the parameters */
/*不做实质上的操作*/
assert_param(IS_RCC_HSE(RCC_HSE));
/* Reset HSEON and HSEBYP bits before configuring the HSE ------------------*/
/* Reset HSEON bit */
/*#define CR_HSEON_Reset ((uint32_t)0xFFFEFFFF)
#define CR_HSEBYP_Reset ((uint32_t)0xFFFBFFFF)
设置HSE之前需要复位HSEON,HSEBYP,这两位写0*/
RCC->CR &= CR_HSEON_Reset;
/* Reset HSEBYP bit */
RCC->CR &= CR_HSEBYP_Reset;
/* Configure HSE (RCC_HSE_OFF is already covered by the code section above) */
switch(RCC_HSE)
{
/*RCC_HSE= RCC_HSE_ON,所以执行这条
#define CR_HSEON_Set ((uint32_t)0x00010000),开启HSE振荡器*/
case RCC_HSE_ON:
/* Set HSEON bit */
RCC->CR |= CR_HSEON_Set;
break;
case RCC_HSE_Bypass:
/* Set HSEBYP and HSEON bits */
RCC->CR |= CR_HSEBYP_Set | CR_HSEON_Set;
break;
default:
break;
}
}
总结:打开HSE时钟
ErrorStatus RCC_WaitForHSEStartUp(void)
{
__IO uint32_t StartUpCounter = 0;
ErrorStatus status = ERROR;
FlagStatus HSEStatus = RESET;
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC_GetFlagStatus(RCC_FLAG_HSERDY); //#define RCC_FLAG_HSERDY ((uint8_t)0x31)
StartUpCounter++;
} while((HSEStatus == RESET) && (StartUpCounter != HSEStartUp_TimeOut));
if (RCC_GetFlagStatus(RCC_FLAG_HSERDY) != RESET)
{
status = SUCCESS;
}
else
{
status = ERROR;
}
return (status);
}
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)
{
uint32_t tmp = 0;
uint32_t statusreg = 0;
FlagStatus bitstatus = RESET;
/* Check the parameters */
assert_param(IS_RCC_FLAG(RCC_FLAG));
/* Get the RCC register index */
tmp = RCC_FLAG >> 5; //RCC_FLAG = 0x31,tmp = 1
if (tmp == 1) /* The flag to check is in CR register */
{
statusreg = RCC->CR; // 读取RCC->CR寄存器
}
else if (tmp == 2) /* The flag to check is in BDCR register */
{
statusreg = RCC->BDCR;
}
else /* The flag to check is in CSR register */
{
statusreg = RCC->CSR;
}
/* Get the flag position */
tmp = RCC_FLAG & FLAG_Mask; //tmp = 0x31 & 1f = 0x11
if ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET) //检测RCC->HSERDY,如果HSE准备好了,则bitstatus = SET,(RESET = 0, SET = !RESET)
{
bitstatus = SET;
}
else
{
bitstatus = RESET;
}
/* Return the flag status */
return bitstatus;
}
总结:等待HSE时钟准备完毕,HSE准备完毕则返回SUCCES
void RCC_HCLKConfig(uint32_t RCC_SYSCLK) //RCC_SYSCLK = RCC_SYSCLK_Div1 #define RCC_SYSCLK_Div1 ((uint32_t)0x00000000)
{
uint32_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_RCC_HCLK(RCC_SYSCLK));
tmpreg = RCC->CFGR;
/* Clear HPRE[3:0] bits,RCC->CFGR->HPRE清零,表示SYSCLK不分频 */
tmpreg &= CFGR_HPRE_Reset_Mask; //#define CFGR_HPRE_Reset_Mask ((uint32_t)0xFFFFFF0F)
/* Set HPRE[3:0] bits according to RCC_SYSCLK value ,*/
tmpreg |= RCC_SYSCLK; //RCC_SYSCLK = RCC_SYSCLK_Div1 #define RCC_SYSCLK_Div1 ((uint32_t)0x00000000)
/* Store the new value */
RCC->CFGR = tmpreg;
}
void RCC_PCLK2Config(uint32_t RCC_HCLK) //#define RCC_HCLK_Div1 ((uint32_t)0x00000000), RCC_HCLK = RCC_HCLK_Div1
{
uint32_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_RCC_PCLK(RCC_HCLK));
tmpreg = RCC->CFGR;
/* Clear PPRE2[2:0] bits */
tmpreg &= CFGR_PPRE2_Reset_Mask; //#define CFGR_PPRE2_Reset_Mask ((uint32_t)0xFFFFC7FF)
/* Set PPRE2[2:0] bits according to RCC_HCLK value */
tmpreg |= RCC_HCLK << 3;
/* Store the new value */
RCC->CFGR = tmpreg;
}
void RCC_PCLK1Config(uint32_t RCC_HCLK) //RCC_HCLK = #define RCC_HCLK_Div2 ((uint32_t)0x00000400)
{
uint32_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_RCC_PCLK(RCC_HCLK));
tmpreg = RCC->CFGR;
/* Clear PPRE1[2:0] bits ,PPRE1清零*/
tmpreg &= CFGR_PPRE1_Reset_Mask; //#define CFGR_PPRE1_Reset_Mask ((uint32_t)0xFFFFF8FF)
/* Set PPRE1[2:0] bits according to RCC_HCLK value */
tmpreg |= RCC_HCLK; //2分频
/* Store the new value */
RCC->CFGR = tmpreg;
}
void FLASH_SetLatency(uint32_t FLASH_Latency) //#define FLASH_Latency_2 ((uint32_t)0x00000002)
{
uint32_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_FLASH_LATENCY(FLASH_Latency));
/* Read the ACR register */
tmpreg = FLASH->ACR;
/* Sets the Latency value */
tmpreg &= ACR_LATENCY_Mask; //#define ACR_LATENCY_Mask ((uint32_t)0x00000038)
tmpreg |= FLASH_Latency; //2个等待状态
/* Write the ACR register */
FLASH->ACR = tmpreg;
}
void FLASH_PrefetchBufferCmd(uint32_t FLASH_PrefetchBuffer) // //#define FLASH_PrefetchBuffer_Enable ((uint32_t)0x00000010)
{
/* Check the parameters */
assert_param(IS_FLASH_PREFETCHBUFFER_STATE(FLASH_PrefetchBuffer));
/* Enable or disable the Prefetch Buffer */
FLASH->ACR &= ACR_PRFTBE_Mask;
FLASH->ACR |= FLASH_PrefetchBuffer;
}
void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul) //#define RCC_PLLSource_HSE_Div1 ((uint32_t)0x00010000), #define RCC_PLLMul_9 ((uint32_t)0x001C0000)
{
uint32_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_RCC_PLL_SOURCE(RCC_PLLSource));
assert_param(IS_RCC_PLL_MUL(RCC_PLLMul));
tmpreg = RCC->CFGR;
/* Clear PLLSRC, PLLXTPRE and PLLMUL[3:0] bits ,清零LLSRC, PLLXTPRE and PLLMUL[3:0]*/
tmpreg &= CFGR_PLL_Mask; //#define CFGR_PLL_Mask ((uint32_t)0xFFC0FFFF)
/* Set the PLL configuration bits ,HSE作为PLL时钟输入,PLL 9倍输出,即,如果HSE = 8M,则PLL = 72M*/
tmpreg |= RCC_PLLSource | RCC_PLLMul; // RCC_PLLSource = ((uint32_t)0x00010000),RCC_PLLMul = ((uint32_t)0x001C0000)
/* Store the new value */
RCC->CFGR = tmpreg;
}
void RCC_PLLCmd(FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_FUNCTIONAL_STATE(NewState));
*(__IO uint32_t *) CR_PLLON_BB = (uint32_t)NewState; //?????
}
#define CR_PLLON_BB (PERIPH_BB_BASE + (CR_OFFSET * 32) + (PLLON_BitNumber * 4)),
#define PERIPH_BB_BASE ((uint32_t)0x42000000),
#define CR_OFFSET (RCC_OFFSET + 0x00)
#define RCC_OFFSET (RCC_BASE - PERIPH_BASE)
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
#define PLLON_BitNumber 0x18
所以 CR_PLLON_BB = 0x42000000 +0x21000*32 + 0x18 * 4 = 0x42000000 + 0x420000 + 0x60 = 0x42420060
void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource) //#define RCC_SYSCLKSource_PLLCLK ((uint32_t)0x00000002)
{
uint32_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_RCC_SYSCLK_SOURCE(RCC_SYSCLKSource));
tmpreg = RCC->CFGR;
/* Clear SW[1:0] bits */
tmpreg &= CFGR_SW_Mask;
/* Set SW[1:0] bits according to RCC_SYSCLKSource value */
tmpreg |= RCC_SYSCLKSource;
/* Store the new value */
RCC->CFGR = tmpreg;
}
设置PLL输出作为系统时钟