STM32第九节(中级篇):RCC(第三节)—— 使用HSE配置系统时钟并使用MCO输出监控系统时钟

news2024/10/5 18:26:03

前言

        这节课我们开始学习使用HSE配置系统时钟并使用MCO输出监控系统时钟,上节课我们讲了固件库里的系统时钟配置函数,是机器写的,我们现在自己来写一个。

STM32第九节(中级篇):RCC(第三节)—— 使用HSE配置系统时钟并使用MCO输出监控系统时钟

创建固件库文件

        我们先新建两个驱动文件,命名为bsp_rccclkconfig.c文件和bsp_rccclkconfig.h文件。我们这节课使用固件库编程的方式来实现我们的库函数编写。然后将我们所写的文件导入到USER中并初始化文件使之一一对应

编写HSE_SetSysClk函数

        我们想要自己编写一个时钟函数,并以超频的方式输出,那么我们就需要配置HSE时钟(在正常情况下)。我们可以看到,在主函数的模板中,系统时钟已经配置为72MHz,而我们要重新配置我们自己的时钟,就需要先把寄存器复位,然后再编写我们的程序。这个函数编写需要一步一步来,接下来我们就逐步分析如何使用固件库的方式编写代码。

int main(void)
{
	// 来到这里的时候,系统的时钟已经被配置成72M。

复位RCC寄存器

        我们可以在stm32f10x_rcc.h库中找到RCC_DeInit(void)函数,它的作用是初始化RCC寄存器的值(Resets the RCC clock configuration to the default reset state.)。在初始化RCC后我们就可以随心所欲地编写代码了。

	//把RCC寄存器复位到复位值
	RCC_DeInit();

HSE时钟的配置

        我们观察手册可知,我们的时钟树有一个基本的流程,我们先进行HSE时钟的配置。

        在这里,我们需要先对HSE时钟使能,在我们的库函数中找到void RCC_HSEConfig(uint32_t RCC_HSE)函数。我们观察发现,该函数引入了一个参量,是RCC_HSE的一个状态,分为了RCC_HSE_OFF,RCC_HSE_ON,RCC_HSE_Bypass,我们要打开HSE时钟,这里我们选择使用RCC_HSE_ON。

/**
  * @brief  Configures the External High Speed oscillator (HSE).
  * @note   HSE can not be stopped if it is used directly or through the PLL as system clock.
  * @param  RCC_HSE: specifies the new state of the HSE.
  *   This parameter can be one of the following values:
  *     @arg RCC_HSE_OFF: HSE oscillator OFF
  *     @arg RCC_HSE_ON: HSE oscillator ON
  *     @arg RCC_HSE_Bypass: HSE oscillator bypassed with external clock
  * @retval None
  */

         既然我们使能了HSE时钟,那么我们还应该等待HSE使能成功。它这个使能过程有一定的延迟。我们在库函数中找到ErrorStatus RCC_WaitForHSEStartUp(void)函数,并查询其定义类型:

typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrorStatus;

ErrorStatus RCC_WaitForHSEStartUp(void);

        我们可以看到,枚举这个结构体为ErrorStatus,然后定义其值。我们在这里定义为ErrorStatus HSEStatus;然后等待使能成功。

	//把RCC寄存器复位到复位值
	RCC_DeInit();
	
	ErrorStatus HSEStatus;
	
	//使能HSE
	RCC_HSEConfig(RCC_HSE_ON);
	//等待HSE使能成功
	HSEStatus = RCC_WaitForHSEStartUp();

        紧接着我们打开库函数具体函数代码,我们发现该函数是具有返回值的函数(结构体变量类型),然后我们观察,发现如果(RCC_GetFlagStatus(RCC_FLAG_HSERDY) != RESET),则status = SUCCESS,即返回使能结果:

/**
  * @brief  Waits for HSE start-up.
  * @param  None
  * @retval An ErrorStatus enumuration value:
  * - SUCCESS: HSE oscillator is stable and ready to use
  * - ERROR: HSE oscillator not yet ready
  */
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);
    StartUpCounter++;  
  } while((StartUpCounter != HSE_STARTUP_TIMEOUT) && (HSEStatus == RESET));
  
  if (RCC_GetFlagStatus(RCC_FLAG_HSERDY) != RESET)
  {
    status = SUCCESS;
  }
  else
  {
    status = ERROR;
  }  
  return (status);
}

         然后我们判断该返回值是否为SUCCESS,若是,则运行接下来的代码;若否,则使用if——else语句实现编写运行错误的代码。当我们运行成功之后,就要进行下一步:使能预取指及配置总线分频因子。

使能预取指及配置总线分频因子

        在确认为真后,我们在这里就要用到关于FLASH的相关知识来配置使能预取指。我们观察如下代码,我们首先要打开FLASH文件中的FLASH_PrefetchBufferCmd:

/**
  * @brief  Enables or disables the Prefetch Buffer.
  * @note   This function can be used for all STM32F10x devices.
  * @param  FLASH_PrefetchBuffer: specifies the Prefetch buffer status.
  *   This parameter can be one of the following values:
  *     @arg FLASH_PrefetchBuffer_Enable: FLASH Prefetch Buffer Enable
  *     @arg FLASH_PrefetchBuffer_Disable: FLASH Prefetch Buffer Disable
  * @retval None
  */
void FLASH_PrefetchBufferCmd(uint32_t FLASH_PrefetchBuffer)
{
  /* 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;
}

        在打开之后,我们还需要配置FLASH_SetLatency(uint32_t FLASH_Latency)函数,我们选择FLASH_Latency_2: FLASH Two Latency cycles模式。

//使能预取指
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);

        然后我们配置总线分频因子,这也是我们老生常谈的一个话题,我们这里就不过多赘述:

void RCC_HCLKConfig(uint32_t RCC_SYSCLK);
void RCC_PCLK1Config(uint32_t RCC_HCLK);
void RCC_PCLK2Config(uint32_t RCC_HCLK);

//配置总线分频因子
RCC_HCLKConfig(RCC_SYSCLK_Div1);  //72MHz
RCC_PCLK1Config(RCC_HCLK_Div2);		//36MHz
RCC_PCLK2Config(RCC_HCLK_Div1);   //72MHz

配置锁相环时钟

        到了配置锁相环这一步,我们需要选择系统时钟,先配置好锁相环时钟的来源以及配频因子。我们找到RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul)函数,我们发现,该函数我们选择 RCC_PLLSource_HSE_Div1 HSE一分频,然后因为我们要超频工作,所以我们在原有函数参数部分就不再是 void 空类型,而是一个int 类型的参量。

        然后我们就要对PLL时钟进行使能操作,找到RCC_PLLCmd 函数,调整参数为 ENABLE。然后就是等待稳定,和上面的步骤相同。然后就是选择我们的PLLCLK作为系统时钟,使用 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); 函数,然后识别是否真正地使用了PLLCLK。

/**
  * @brief  Returns the clock source used as system clock.
  * @param  None
  * @retval The clock source used as system clock. The returned value can
  *   be one of the following:
  *     - 0x00: HSI used as system clock
  *     - 0x04: HSE used as system clock
  *     - 0x08: PLL used as system clock
  */
uint8_t RCC_GetSYSCLKSource(void)
{
  return ((uint8_t)(RCC->CFGR & CFGR_SWS_Mask));
}

        代码如下:

	if(HSEStatus == SUCCESS)
	{
		//使能预取指
		FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
		FLASH_SetLatency(FLASH_Latency_2);
		
		//配置总线分频因子
		RCC_HCLKConfig(RCC_SYSCLK_Div1);  //72MHz
		RCC_PCLK1Config(RCC_HCLK_Div2);		//36MHz
		RCC_PCLK2Config(RCC_HCLK_Div1);   //72MHz
		
		//配置锁相环时钟
		//配置锁相环时钟来源,配频因子
		RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_x);
		//使能PLL
		RCC_PLLCmd(ENABLE);
		//等待PLL稳定
		while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
		
		//选择系统时钟
		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
		while(RCC_GetSYSCLKSource() != 0x08);

代码展示(CV)

#include "bsp_rccclkconfig.h"

void HSE_SetSysClk(uint32_t RCC_PLLMul_x)
{
	//把RCC寄存器复位到复位值
	RCC_DeInit();
	
	ErrorStatus HSEStatus;
	
	//使能HSE
	RCC_HSEConfig(RCC_HSE_ON);
	//等待HSE使能成功
	HSEStatus = RCC_WaitForHSEStartUp();
	
	if(HSEStatus == SUCCESS)
	{
		//使能预取指
		FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
		FLASH_SetLatency(FLASH_Latency_2);
		
		//配置总线分频因子
		RCC_HCLKConfig(RCC_SYSCLK_Div1);  //72MHz
		RCC_PCLK1Config(RCC_HCLK_Div2);		//36MHz
		RCC_PCLK2Config(RCC_HCLK_Div1);   //72MHz
		
		//配置锁相环时钟
		//配置锁相环时钟来源,配频因子
		RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_x);
		//使能PLL
		RCC_PLLCmd(ENABLE);
		//等待PLL稳定
		while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
		
		//选择系统时钟
		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
		while(RCC_GetSYSCLKSource() != 0x08);
	}else{
		//编写运行错误的代码
	}
}

使用MCO输出监控系统时钟

        我们观察原理图可知,MCO可以控制io口输出,那么我们可以使用MCO输出监控系统时钟。我们找到LED的代码,稍作修改,将接口改为GPIOA,改为GPIO_Pin_8,输出模式改为GPIO_Mode_AF_PP。

void MCO_GPIO_Config()
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOA,&GPIO_InitStruct);
}

main函数修改

        我们先初始化MCO以及LED,然后使用16倍超频工作模式,找到RCC_MCOConfig(RCC_MCO_SYSCLK);函数,调整参数为RCC_MCO_SYSCLK,实现选择系统时钟(已经配置好)。到这里我们就完成了全部的代码:

#include "stm32f10x.h"   // 相当于51单片机中的  #include <reg51.h>
#include "bsp_led.h"
#include "bsp_rccclkconfig.h"

void Delay(uint32_t count)
{
	for(;count!=0;count--);
}

int main(void)
{
	// 来到这里的时候,系统的时钟已经被配置成72M。
	
	HSE_SetSysClk(RCC_PLLMul_16);
	MCO_GPIO_Config();
	RCC_MCOConfig(RCC_MCO_SYSCLK);
	LED_GPIO_Config();
	
	while(1)
	{
		LED_G(OFF);
		Delay(0xFFFFF);
		
		LED_G(ON);
		Delay(0xFFFFF);
	}
}

小结

        本节课到这里就结束啦,我们学习了 使用HSE配置系统时钟并使用MCO输出监控系统时钟,编写了库函数文件,使用固件库的方式编写程序。希望同学们每天都有所进步!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1528358.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【人工智能】Gitee AI 天数智芯有奖体验开源AI模型,一定能有所收货,快来体验吧

大家好&#xff0c;我是全栈小5&#xff0c;欢迎阅读小5的系列文章。 这是《人工智能》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 目录 前言两大赛道天数智芯1.模型地址2.天数智芯专区3.选择模型4.模型详情页5.部署模型6.成功部署7.执行例子8.移除模型 千模盲…

被大家低估的Excel函数扫地僧choose函数

今天我们要跟大家介绍Excel函数界的又一个世外高手——引用函数CHOOSE。 首先来看下它的基本语法&#xff1a; CHOOSE(索引值,参数1,[参数2],…[参数254]) CHOOSE函数主要用于根据索引值从一组数据中返回相应位置的数值。索引值是介于1到254之间的数字&#xff0c;或者是包含…

2024全网最全的完整的性能测试流程!

完整的性能测试流程 一、准备工作 在什么阶段开展性能测试工作&#xff1f;一般情况下&#xff0c;是在被测系统已完成功能测试、系统趋于稳定的情况下&#xff0c;才会进行性能测试。 1. 组建测试团队 根据被测系统的实际情况&#xff0c;组建一个性能测试团队&#xff0c;团…

[QJS xmake] 非常简单地在Windows下编译QuickJS!

文章目录 前言准备C编译器xmake编译包 工程准备修改版本号第一遍编译第二遍编译效果 前言 quickjs是个很厉害的东西啊&#xff0c;我一直想编译一下的&#xff0c;奈何一直没成功。现在找了点时间成功编译了&#xff0c;写篇文章记录一下。当前版本&#xff1a;2024-1-13 应该…

STM32CubeIDE基础学习-LED闪烁实验

STM32CubeIDE基础学习-LED闪烁实验 文章目录 STM32CubeIDE基础学习-LED闪烁实验前言第1章 硬件介绍第2章 新建工程2.1 基础工程配置部分2.2 工程外设配置部分2.3 生成工程代码部分2.4 输出HEX文件、编译下载 第3章 代码编写3.1 方式1&#xff1a;IO翻转3.2 方式2&#xff1a;调…

“西安大重澳生物科技有限公司”——甄选优质企业品牌入围央媒

西安大重澳生物科技有限公司&#xff0c;一家专注于生物科技研发的企业&#xff0c;自2017年成立以来&#xff0c;致力于开发革命性的肤用肽制剂产品。近日&#xff0c;成功入围央视新媒体直播盛典。在持续的创新与努力下&#xff0c;畅夫泰R畅肤肽品牌已成为备受瞩目的名副其实…

园区配电监测信息系统

园区配电监测信息系统是一款集成了高科技、数据分析和管理的系统&#xff0c;旨在实时监测和控制园区内的电力供应&#xff0c;提高电力使用效率&#xff0c;减少能源浪费&#xff0c;确保电力安全。该系统通过现代通信技术、自动控制技术和计算机技术&#xff0c;实现对园区配…

码云简化版使用教程

码云简化版使用教程 ①创建本地项目 ②在本地项目根目录下创建git相关目录及文件 ③在码云上创建新的仓库 ④在本地项目中配置仓库地址&#xff0c;提交项目内容 下面直接从第二步开始讲解 在本地项目根目录下创建git相关目录及文件 1、打开项目根目录&#xff0c;进入cmd界…

Huggingface 笔记:大模型(Gemma2B,Gemma 7B)部署+基本使用

1 部署 1.1 申请权限 在huggingface的gemma界面&#xff0c;点击“term”以申请gemma访问权限 https://huggingface.co/google/gemma-7b 然后接受条款 1.2 添加hugging对应的token 如果直接用gemma提供的代码&#xff0c;会出现如下问题&#xff1a; from transformers i…

邮箱验证码api接口申请流程?有哪些条件?

邮箱验证码API服务如何选择&#xff1f;怎么正确设置邮箱验证码&#xff1f; 邮箱验证码API接口在保障用户账号安全、提高用户体验方面发挥着至关重要的作用。AokSend将详细介绍邮箱验证码API接口的申请流程&#xff0c;帮助您顺利集成这一功能&#xff0c;增强应用的安全性。…

【ADF4351】使用FPGA进行SPI寄存器配置、使用FPGA计算各个频率的频点,ADF4351配置程序

简介 特性 输出频率范围&#xff1a;35 MHz至4,400 MHz 小数N分频频率合成器和整数N分频频率合成器 具有低相位噪声的VCO 可编程的1/2/4/8/16/32/64分频输出 典型抖动&#xff1a;0.3 ps rms EVM(典型值&#xff0c;2.1 GHz)&#xff1a; 0.4% 电源&#xff1a;3.0 V至3.6 V …

基于spring boot框架的发艺美发店管理系统

摘 要 系统根据现有的管理模块进行开发和扩展&#xff0c;采用面向对象的开发的思想和结构化的开发方法对发艺美发店管理的现状进行系统调查。采用结构化的分析设计&#xff0c;该方法要求结合一定的图表&#xff0c;在模块化的基础上进行系统的开发工作。在设计中采用“自下而…

算法详解——选择排序和冒泡排序

一、选择排序 选择排序算法的执行过程是这样的&#xff1a;首先&#xff0c;算法遍历整个列表以确定最小的元素&#xff0c;接着&#xff0c;这个最小的元素被置换到列表的开头&#xff0c;确保它被放置在其应有的有序位置上。接下来&#xff0c;从列表的第二个元素开始&#x…

Java进阶 Maven基础

资料格式 配置文件 com.itheima Java代码 Statement stat con.createStatement(); 示例 com.itheima 命令 mvn test - Maven简介 传统项目管理状态分析 Maven 是什么 Maven的本质是一个项目管理工具&#xff0c;将项目开发过程抽象成一个项目对象模型&#xff08;POM&…

如何使用phpStudy在Windows系统部署静态站点并实现无公网IP远程访问

文章目录 使用工具1. 本地搭建web网站1.1 下载phpstudy后解压并安装1.2 打开默认站点&#xff0c;测试1.3 下载静态演示站点1.4 打开站点根目录1.5 复制演示站点到站网根目录1.6 在浏览器中&#xff0c;查看演示效果。 2. 将本地web网站发布到公网2.1 安装cpolar内网穿透2.2 映…

文献速递:深度学习乳腺癌诊断---使用深度学习改善乳腺癌组织学分级

Title 题目 Improved breast cancer histological grading using deep learning 使用深度学习改善乳腺癌组织学分级 01 文献速递介绍 乳腺癌组织学分级是乳腺癌中一个确立的临床变量&#xff0c;它包括来自三个方面的信息&#xff0c;即小管形成程度、核多态性和有丝分裂计…

java数据结构与算法刷题-----LeetCode1005. K 次取反后最大化的数组和(这就不是简单题)

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 卷来卷去&#xff0c;把简单题都卷成中等题了 文章目录 1. 排序后从小到大…

免费录屏软件无水印推荐,录制视频更轻松(3款)

随着互联网技术的快速发展&#xff0c;录制屏幕成为人们日常生活中日益重要的需求。无论是制作教学视频、直播分享&#xff0c;还是录制游戏过程&#xff0c;一款好用且免费的录屏软件都是不可或缺的。然而&#xff0c;许多录屏软件在录制过程中会添加水印&#xff0c;影响了录…

电脑如何直接压缩图片?这几个方法帮你解决

在许多社交媒体平台上&#xff0c;上传照片时经常需要进行大小调整&#xff0c;这是因为较大的照片文件可能会占用更多的存储空间&#xff0c;并且在传输过程中需要更长的时间。通过图片压缩可以减小文件大小&#xff0c;提高上传速度&#xff0c;并节省存储空间&#xff0c;那…

大学老师不会告诉你的网安证书?

前言 在大学中&#xff0c;有很多安全专业的师傅们&#xff0c;一直有问&#xff1a; “计算机xxx级有用吗&#xff1f;” “软考初级有用吗&#xff1f;” “xxx资格证有用吗&#xff1f;” 甚至有一些来讲这些整数的&#xff0c;以“我们这个专业以后就业需要的证书....…