【STM32】时钟设置函数(寄存器版)

一、STM32时钟设置函数移植

1.时钟模块回顾

一个疑问

前面代码并没有设置时钟为什么可以直接使用。

2.时钟树

3.时钟树分析

1.内部晶振(HSI)

内部晶振不稳定,当我们上电后,会自动产生振动,自动产生时钟,但是晶振不稳定。

不经过PPLMUL,默认使用8MHZ。所以如果我们想要72MHZ,则需要使用外部晶振

  2.外部晶振(HSE)

当接上外部晶振,当接通电源之后,不用软件操作,会自动产生振动。可以进行分频等操作。

从外部接上外部晶振的时候,我们需要等待一段时间,让其稳定后,才开始工作。(所以要进行判断)

3.PLLMUL

当上电后,经过他时,要等待一段时间,让其稳定后,才可以开始工作。(所以我们有一个寄存器专门用来判断其是否准备好开始工作,当我们去读取到其准备好了才可以进行下一步)

二、代码移植

#ifndef __CLOCK_H__
#define __CLOCK_H__#include "gpio.h"// 寄存器宏定义
// RCC寄存器基地址为0x40021000
#define RCC_BASE	0x40021000			// RCC部分寄存器的基地址
#define RCC_CR		(RCC_BASE + 0x00)	// RCC_CR的地址
#define RCC_CFGR	(RCC_BASE + 0x04)#define FLASH_ACR	0x40022000// 用C语言来访问寄存器的宏定义
#define rRCC_CR		(*((volatile unsigned int *)RCC_CR))
#define rRCC_CFGR	(*((volatile unsigned int *)RCC_CFGR))
#define rFLASH_ACR	(*((volatile unsigned int *)FLASH_ACR))// 函数作用:时钟源切换到HSE并且使能PLL,将主频设置为72MHz
void Set_SysClockTo72M(void);#endif

1.复位RCC_CR寄存器

#define rRCC_APB2ENR     (*((unsigned int *)RCC_APB2ENR))

RCC->CR就相当于rRCC_APB2ENR

	//复位RCC_CR寄存器rRCC_CR=0x00000083;

2.开启外部时钟(就是开启外部晶振)

&:将某一些位置0

|:将某一些位置1

	//开启外部时钟(外部晶振)//第一步:先置0【将bit16清零】rRCC_CR &= ~(1<<16);//关闭HSEON//第二步:在置1rRCC_CR |= (1<<16);//打开HSEON,让HSE开始工作

3.检测外部时钟开启是否成功(HSEREDY)

do while十分适合检测是否超时!!!!!!!

	do{//检测HSEREAY(bit17)是否为1,1表示准备好Rcc_CR_HSE_Ready=rRCC_CR&(1<<17);//取出bit17faultTime++;}while((faultTime<0x0fffffff) && (Rcc_CR_HSE_Ready==0))//跳出do-while 1)要么超时2)要么准好了

4.当准备好进入下一步

5.Flash的设置

		rFLASH_ACR |= 0x10;rFLASH_ACR &= (~0x03);rFLASH_ACR |= (0x02);

6.对其进行预分频

		//HPRE【AHB】:对应bit4-bit7:不分频(000)//PPRE1【APB1】:对应bit8-bit10:进行二分频(100)//PPRE2【APB2】:对应bit11-bit13:不分频(000)//AHB和APB2未分频,APB1被2分频//所以最终:AHB和APB2都是72MHZ,APB1是36MHZ//第一步:先置0rRCC_CFGR=(~((0x0f<<4) | (0x07<<8) | (0x07<<11)));//等价于:rRCC_CFGR=(~(0x3ff<<4));//第二步:置1rRCC_CFGR=(((0x0<<4) | (0x04<<8) | (0x0<<11)));

7.设置SHE为输入时钟,同时HSE不分频

		//设置为输入时钟:bit16//设置为不分频:bit17//第一步:先置0rRCC_CFGR &=(~((1<<16) | (1<<17)));//第二步:置1rRCC_CFGR |= ((1<<18) | (0<<17));

8.设置PLL倍频系数

因为我们在开发板上接上的外部晶振就是8MHZ,如果我们想要在内部使用72MHZ,则需要在内部进行分频率(9倍)

		//9分频:0111:0x07rRCC_CFGR &=(~(0x0f<<18));//清零bit18-bit21rRCC_CFGR |= (0x07<<18);//设置为9倍频

9.打开使能

		//七、打开PLL开关rRCC_CR |= (1<<24);

10.等待开启PLL开启成功

		//八、等待开启PLL开启成功do{Rcc_CR_PLL_Ready=rRcc_CR & (1<<25);//检测第25位是否为1faultTime++;}while((faultTime<0x0fffffff) && (Rcc_CR_PLL_Ready==0))

11.将PLL作为SYSCLK的时钟来源

			//到这里说明PLL已经稳定,可以用了,下面可以切换成外部时钟了rRCC_CFGR &=(~(0x03)<<0);rRCC_CFGR |=(0x10<<0);

12. 判断切换成PLL是否成功

		do{RCC_CF_SWS_PLL=rRCC_CFGR & (0x03<<2);//读出bit2-bit3faultTime++;//0x02<<2:表示此时转换成PLL}while((faultTime<0x0fffffff) && (Rcc_CR_PLL_Ready!=(0x02<<2)))

13.此时PLL转换成功

14.完整代码

#include "clock.h"void Set_SysClockTo72M(void){//检测外部晶振是否准备好unsigned int Rcc_CR_HSE_Ready=0;//等待开启PLL开启成功unsigned int Rcc_CR_PLL_Ready=0;//判断切换成PLL是否成功unsigned int RCC_CF_SWS_PLL=0;unsigned int faultTime=0;//判断等待是否超时//一、复位RCC_CR寄存器rRCC_CR = 0x00000083;//二、开启外部时钟(外部晶振)//第一步:先置0【将bit16清零】rRCC_CR &= ~(1<<16);//关闭HSEON//第二步:在置1rRCC_CR |= (1<<16);//打开HSEON,让HSE开始工作//三、检测外部时钟开启是否成功do{//检测HSEREAY(bit17)是否为1,1表示准备好Rcc_CR_HSE_Ready=rRCC_CR&(1<<17);//取出bit17faultTime++;}while((faultTime<0x0fffffff) && (Rcc_CR_HSE_Ready==0));//跳出do-while 1)要么超时2)要么准好了//判断是超时还是准备好//注意点:不能直接使用“Rcc_CR_HSE_Ready”因为rRCC_CR是需要读一次寄存器//但是读出的结果可能还未改变,所以一定不能直接使用if((rRCC_CR&(1<<17))!=0)//rRCC_CR&(1<<17)==1{//这里HSE就ready,下面再去配置PLL并且等待他ready//四、对其进行预分频//HPRE【AHB】:对应bit4-bit7:不分频(000)//PPRE1【APB1】:对应bit8-bit10:进行二分频(100)//PPRE2【APB2】:对应bit11-bit13:不分频(000)//AHB和APB2未分频,APB1被2分频//所以最终:AHB和APB2都是72MHZ,APB1是36MHZ//第一步:先置0rRCC_CFGR=(~((0x0f<<4) | (0x07<<8) | (0x07<<11)));//等价于:rRCC_CFGR=(~(0x3ff<<4));//第二步:置1rRCC_CFGR=(((0x0<<4) | (0x04<<8) | (0x0<<11)));//五、设置SHE为输入时钟,同时HSE不分频//选择HSE作为PLL输入并且HSE不分频//设置为输入时钟:bit16//设置为不分频:bit17//第一步:先置0rRCC_CFGR &=(~((1<<16) | (1<<17)));//第二步:置1,bit16rRCC_CFGR |= ((1<<18) | (0<<17));//六、设置PLL倍频系数//9分频:0111:0x07rRCC_CFGR &=(~(0x0f<<18));//清零bit18-bit21rRCC_CFGR |= (0x07<<18);//设置为9倍频//七、打开PLL开关rRCC_CR |= (1<<24);//八、等待开启PLL开启成功do{Rcc_CR_PLL_Ready=rRCC_CR & (1<<25);//检测第25位是否为1faultTime++;}while((faultTime<0x0fffffff) && (Rcc_CR_PLL_Ready==0));if((rRCC_CR & (1<<25)) == (1<<25)){//到这里说明PLL已经稳定,可以用了,下面可以切换成外部时钟了//九、切换成PLLrRCC_CFGR &=(~(0x03)<<0);rRCC_CFGR |=(0x10<<0);//十、判断切换成PLL是否成功do{RCC_CF_SWS_PLL=rRCC_CFGR & (0x03<<2);//读出bit2-bit3faultTime++;//0x02<<2:表示此时转换成PLL}while((faultTime<0x0fffffff) && (Rcc_CR_PLL_Ready!=(0x02<<2)));//十一、此时PLL转换成功if((rRCC_CFGR & (0x03<<2))==(0x02<<2)){//到这里我们的时钟整个就设置好了,可以结束了}else{//到这里说明PLL输出作为PLL失败while(1);}}else{//到这里说明PLL启动时出错了,PLL不能稳定工作while(1);}}else{//超时,或者未准备好,此时HSE不可以使用while(1);}}

三、问题解决

1.我们想要让led快速闪3下,然后换成72MHZ的频率接着闪

void delay(){unsigned int i=0,j=0;for(i=0;i<1000;i++){for(j=0;j<2000;j++){}}
}void led_init(){rRCC_APB2ENR = 0x00000008;rGPIOB_CRH = 0x33333333;rGPIOB_ODR = 0x0000ff00;//全灭}
void led_flash(void){unsigned int i=0;for(i=0;i<3;i++){rGPIOB_ODR = 0x00000000;//全亮delay();rGPIOB_ODR = 0x0000ff00;//全灭delay();} 
}
void main(void){led_init();led_flash();Set_SysClockTo72M();led_flash();
}

但是实际上并无法实现,只能在闪烁完3次后就熄灭。

2.问题解决

led初始化时,默认是全亮的

1.degger方法

把点亮led灯的函数加到clock中去,看看代码运行到哪里不会亮

2.判断超时变量的初始化

因为我们多次使用到超时变量,则每一个进入do-while循环之前要重新置0

3.出错点

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

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

相关文章

【java爬虫】使用selenium获取某交易所公司半年报数据

引言 上市公司的财报数据一般都会进行公开&#xff0c;我们可以在某交易所的官方网站上查看这些数据&#xff0c;由于数据很多&#xff0c;如果只是手动收集的话可能会比较耗时耗力&#xff0c;我们可以采用爬虫的方法进行数据的获取。 本文就介绍采用selenium框架进行公司财…

2023年10月24日程序员节

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

基于Tucker分解的时序知识图谱补全10.23

基于Tucker分解的时序知识图谱补全 摘要引言相关工作静态知识图谱补全时序知识图谱补全 背景提出的模型学习时间复杂度和参数增长表达能力分析 实验 摘要 知识图谱已被证明是众多智能应用的有效工具。然而&#xff0c;大量有价值的知识仍然隐含在知识图谱中。为了丰富现有的知…

[python 刷题] 19 Remove Nth Node From End of List

[python 刷题] 19 Remove Nth Node From End of List 题目&#xff1a; Given the head of a linked list, remove the nth node from the end of the list and return its head. 题目说的是就是移除倒数第 n 个结点&#xff0c;如官方给的案例&#xff1a; 这里提供的 n 就是…

实时配送跟踪功能的实现:外卖跑腿小程序的技术挑战

在当今数字化时代&#xff0c;外卖和跑腿服务已经成为了生活中不可或缺的一部分。为了提供更好的用户体验&#xff0c;外卖跑腿小程序越来越注重实时配送跟踪功能的实现。这项技术挑战旨在确保顾客可以方便地跟踪他们的订单&#xff0c;以及配送员可以高效地完成送货任务。本文…

经典卷积神经网络 - VGG

使用块的网络 - VGG。 使用多个 3 3 3\times 3 33的要比使用少个 5 5 5\times 5 55的效果要好。 VGG全称是Visual Geometry Group&#xff0c;因为是由Oxford的Visual Geometry Group提出的。AlexNet问世之后&#xff0c;很多学者通过改进AlexNet的网络结构来提高自己的准确…

TDengine小知识-数据文件命名规则

TDengine 时序数据库对数据文件有自己的命名规则&#xff0c;文件名中包含了vnodeID、时间范围、版本、文件类型等多种信息。了解数据文件命名规则&#xff0c;可以让运维工作更简单。 废话不多说&#xff0c;直接上图&#xff1a; v4&#xff1a;文件所属 Vgroup 组&#xf…

leetcode:2347. 最好的扑克手牌(python3解法)

难度&#xff1a;简单 给你一个整数数组 ranks 和一个字符数组 suit 。你有 5 张扑克牌&#xff0c;第 i 张牌大小为 ranks[i] &#xff0c;花色为 suits[i] 。 下述是从好到坏你可能持有的 手牌类型 &#xff1a; "Flush"&#xff1a;同花&#xff0c;五张相同花色的…

安装visual studio报错“无法安装msodbcsql“

在安装visual studio2022时安装完成后提示无法安装msodbcsql, 查看日志文件详细信息提示&#xff1a;指定账户已存在。 未能安装包“msodbcsql,version17.2.30929.1,chipx64,languagezh-CN”。 搜索 URL https://aka.ms/VSSetupErrorReports?qPackageIdmsodbcsql;PackageActi…

用matlab求解线性规划

文章目录 1、用单纯形表求解线性规划绘制单纯形表求解&#xff1a; 2、用matlab求解线性规划——linprog()函数问题&#xff1a;补充代码&#xff1a;显示出完整的影子价格向量 1、用单纯形表求解线性规划 求解线性规划 m i n − 3 x 1 − 4 x 2 x 3 min -3x_1-4x_2x_3 min−…

【ArcGIS模型构建器】04:根据矢量范围批量裁剪影像栅格数据

本文以中国2000-2010-2020年3期GLC30土地覆盖数据为例,演示用模型构建器批量裁剪出四川省3年的数据。 文章目录 一、结果预览二、模型构建三、运行模型四、注意事项一、结果预览 用四川省行政区数据裁剪出的3年Globeland30(配套实验数据data04.rar中有三年中国区域成品数据)…

Java编写图片转base64

图片转成base64 url &#xff0c; 在我们的工作中也会经常用到&#xff0c;比如说导出 word,pdf 等功能&#xff0c;今天我们尝试写一下。 File file new File("");byte[] data null;InputStream in null;ByteArrayOutputStream out null;try{URL url new URL(&…

NAS搭建指南三——私人云盘

一、私人云盘选择 我选择的是可道云进行私人云盘的搭建可道云官网地址可道云下载地址&#xff0c;下载服务器端和 Windows 客户端可道云官方文档 二、环境配置 PHP 与 MySQL 环境安装&#xff1a;XAMPP 官网地址 下载最新的 windows 版本 安装时只勾选 MySQL 与 PHP相关即可…

信号继电器驱动芯片(led驱动芯片)

驱动继电器需要配合BAV99&#xff08;防止反向脉冲&#xff09;使用 具体应用参考开源项目 电阻箱 sbstnh/programmable_precision_resistor: A SCPI programmable precision resistor (github.com) 这个是芯片的输出电流设置 对应到上面的实际开源项目其设置电阻为1.5K&…

侯捷C++面向对象程序设计笔记(上)-Object Based(基于对象)部分

基于对象就是对于单一class的设计。 对于有指针的&#xff1a;complex.h complex-test.cpp 对于没有指针的&#xff1a; string.h string-test.cpp https://blog.csdn.net/ncepu_Chen/article/details/113843775?spm1001.2014.3001.5501#commentBox 没有指针成员——以复数co…

力扣第55题 跳跃游戏 c++ 贪心 + 覆盖 加暴力超时参考

题目 55. 跳跃游戏 中等 相关标签 贪心 数组 动态规划 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &…

【RocketMQ系列十二】RocketMQ集群核心概念之主从复制生产者负载均衡策略消费者负载均衡策略

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精…

自动驾驶之—车道线感知

零、前言 &#xff1a; 最近在学习自动驾驶方向的东西&#xff0c;简单整理一些学习笔记&#xff0c;学习过程中发现宝藏up 手写AI 一、视觉系统坐标系 视觉系统一共有四个坐标系&#xff1a;像素平面坐标系&#xff08;u,v&#xff09;、图像坐标系&#xff08;x,y&#xff09…

开源WAF--Safeline(雷池)测试手册

长亭科技—雷池(SafeLine)社区版 官方网站:长亭雷池 WAF 社区版 (chaitin.cn) WAF 工作在应用层&#xff0c;对基于 HTTP/HTTPS 协议的 Web 系统有着更好的防护效果&#xff0c;使其免于受到黑客的攻击 1.1 雷池的搭建 1.1.1 配置需求 操作系统&#xff1a;Linux 指令架构&am…

【数据结构与算法】二叉树的运用要点

目录 一&#xff0c;二叉树的结构深入认识 二&#xff0c;二叉树的遍历 三&#xff0c;二叉树的基本运算 3-1&#xff0c;计算二叉树的大小 3-2&#xff0c;统计二叉树叶子结点个数 3-3&#xff0c;计算第k层的节点个数 3-4&#xff0c;查找指定值的结点 一&#xff0c;二叉…