STM32启动流程

发布者:和谐共融最新更新时间:2024-10-16 来源: cnblogs关键字: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 */

[1] [2]
关键字:STM32  启动流程 引用地址:STM32启动流程

上一篇:stm32常见错误与工程模板
下一篇:STM32自定义printf实现多串口互用

推荐阅读最新更新时间:2024-11-10 11:36

应用笔记 | 看似无法唤醒的一种异常现象分析
1. 引言 STM32 G0 系列产品具有丰富的外设和强大的处理性能以及良好的低功耗特性,被广泛用于各类工业产品中,包括一些需要低功耗需求的应用。 2.问题描述 用户使用STM32G0B1 作为汽车多媒体音响控制器的控制芯片,用来作为收音机频道存贮和各种检测控制。在实验室条件下模拟汽车频繁打火的情形进行测试,连续工作72 小时实验中,进入STOP 模式后,会出现无法再继续运行的情况(屏幕没有显示输出,外部中断无反应)。 3. 问题重现 通常调查问题时采取调试监控的方式。但是用户产品是在检测外部掉电时,测外部电压(汽车ACC 电源,轿车12V)下降后,立刻进入低功耗模式,然后通过RTC 和外部中断(PC13 下降沿触发
[单片机]
应用笔记 | 看似无法唤醒的一种异常现象分析
STM32入门学习笔记之MPU6050传感器解析实验1
19.1 MPU6050简介 19.1.1 芯片概述 MPU6050是InvenSense公司推出的一款6轴运动处理芯片,内置3轴陀螺仪及3轴速度传感器,内置两组I2C接口,其中一组用于通信,另一组则用于连接外部磁力传感器,采用自带的数字运动处理器DMP(Digital Motion Processor),通过主I2C接口,直接读取完整的9轴融合演算数据。MPU6050检测轴及其检测方向如下图所示。 19.1.2 引脚介绍 MPU6050采用QFN-24封装,端口描述如下表所示。 引脚编号 引脚名称 功能 1 CLKIN 外部参考时钟输入,如果不使用直接接地 2 NC 空引脚 3 NC 空引脚 4 NC 空
[单片机]
<font color='red'>STM32</font>入门学习笔记之MPU6050传感器解析实验1
STM32 上使用 printf 输出函数
如果要实现在串口 或者 LCD 上显示,必须重定义标准库函数里调用的与输出设备相关的函数。 如果使用 printf 输出到串口,需要将 fputc 里面的输出指向串口,这一过程就叫重定向。 那么如何让 STM32 使用 printf 函数呢?只需要将 fputc 里面的输 出指向 STM32 串口即可。 int fputc(int ch,FILE *p) //函数默认的,在使用 printf 函数时自动调用 { USART_SendData(USART1,(u8)ch); while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); return ch;
[单片机]
<font color='red'>STM32</font> 上使用 printf 输出函数
STM32中GPIO的8中模式详解
一、推挽输出:可以输出高、低电平,连接数字器件;推挽结构一般是指两个三极管分别受两个互补信号的控制,总是在一个三极管导通的时候另一个截止。高低电平由IC的电源决定。 推挽电路是两个参数相同的三极管或MOSFET,以推挽方式存在于电路中,各负责正负半周的波形放大任务,电路工作时,两只对称的功率开关管每次只有一个导通,所以导通损耗小、效率高。输出既可以向负载灌电流,也可以从负载抽取电流。推拉式输出级既提高电路的负载能力,又提高开关速度。 二、开漏输出:输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行。适合于做电流型的驱动,其吸收电流的能力相对强(一般20mA以内)。开漏形式的电路有以下几个特点:
[单片机]
STM32学习笔记——按键输入
隔了好久才写这第二篇,期间重感冒,身体难受大约十天,今天重新写,又踩了好多的坑。 1:首先,按键实验是GPIO口的另一应用,上一次的跑马灯实验是将GPIO口作为输出,此次按键实验是将GPIO口作为输入。 和跑马灯实验实验一样,要启用GPIO口,第一步要做的就是使能GPIO所在的时钟总线,具体库函数操作为:RCC_APB2PeriphClockCmd(GPIOA,ENABLE); 2:接下来说说GPIO作为输入时和输入的不同: (1):首先需要了解按键是低电平有效还是高电平有效,因为此处需要配置GPIO口的输入模式。大家都知道GPIO口有四种输入模式,四种输出模式(具体请看我的第一篇笔记)。我使用的是STM32F10
[单片机]
<font color='red'>STM32</font>学习笔记——按键输入
C语言宏定义的使用原理
使用STM32开发的朋友不知道是否有发现过这样的一些宏定义? 如下: #if defined (__CC_ARM) #pragma anon_unions #endif 看到上面的语句一开始确实搞不懂为什么要写这些东西,通过上网去查询,才搞明白这其中的使用原理。 上面的代码段我们可以看到两部分的内容: 1) __CC_ARM 2) #pragma anon_unions 这两个都有啥用呢? 待我一一道来! 1、__CC_ARM 是 ARM 编译中的宏选项 __CC_ARM 是一个编译器的选项,在ARM开发中根据开发环境的不同,有好几个可选的宏选项。
[单片机]
STM32——JLINK下载器刷固件
在使用JLINK下载器期间,出现JLINK突然不能使用,指示灯不亮,曾以为板子烧坏,多次出现此故障后,故此上网寻查,一探究竟。 刚上百度,发现众人也有此现象。 原因:山寨版的jlink会出现固件丢失。 解决方法:重新刷固件。 刷固件方法: 链接:http://pan.baidu.com/s/1pLAvwj5 密码:myt1 不同版本JLINK,刷固件引脚位置可能不同,无须担心,多尝试几次,直至成功!
[单片机]
STM32让printf通过串口打印及自定义printf函数
在嵌入式系统中,通过串口打印log是非常重要的调试手段,但是直接调用底层驱动打印信息非常不方便,在c语言中一般使用printf打印基本的显示信息,而默认printf的结果不会通过串口发送,所以需要对printf的输出进行重定向。 有时候需要同时从多个串口输出信息,如果仍然想通过printf函数输出信息,就需要自己写printf的实现。 一. 初始化端口和配置 对串口用到的GPIO进行配置,并对串口的参数进行初始化。 二. 宏定义并实现具体的发送函数 代码在编译时首先判断__GNUC__有无定义,之后将PUTCHAR_PROTOTYPE替换成具体的定义。在keil5中,使用fputc函数,所以其实
[单片机]
<font color='red'>STM32</font>让printf通过串口打印及自定义printf函数
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved