STM32开发基础知识入门
C语言基础
位操作
对基本类型变量可以在位级别进行操作。

1) 不改变其他位的值的状况下,对某几个位进行设值。
先对需要设置的位用&操作符进行清零操作,然后用|操作符设值。

2) 移位操作提高代码的可读性。

3) ~取反操作使用技巧
可用于对某一位取0,也是为了提高可读性。

define宏定义
常见格式:#define 标识符 字符串

ifdef条件编译
常见格式:
#ifdef 标识符
程序段1
#else
程序段2
#endif
它的作用是:当标识符已经被定义过一般是用 #define 命令定义 )),则对程序段 1 进行编译,否则编译程序段 2 。
extern变量申明
C语言中extern 可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义 。 这里面要注意,对于extern申明变量可以多次,但定义只有一次。
就是说变量只能定义一次,如果重复定义了需要用extern声明。

typedef类型别名
typedef用于为现有类型创建一个新的名字,或称为类型别名,用来简化变量的定义。

结构体
结构体就是将多个变量组合为一个有机的整体。
声明结构体类型:
Struct 结构体名{
成员列表;
}变量名列表;
在结构体申明的时候可以定义变量,也可以申明之后定义,方法是:
Struct 结构体名字 结构体变量列表 ;
结构体成员变量的引用方法是:(结构体指针成员变量引用方法是通过“->”符号实现)
结构体变量名字.成员名
STM32系统架构

STM32主系统主要由四个驱动单元和四个被动单元构成。
四个驱动单元是:内核DCode 总线;系统总线;通用 DMA1;通用DMA2。
四个被动单元是:AHB到 APB 的桥:连接所有的 APB 设备;内部FlASH 闪存;内部SRAM;FSMC。
总线:
① ICode 总线:该总线将 M3 内核指令总线和闪存指令接口相连,指令的预取在该总线上面完成。
② DCode 总线:该总线将 M3 内核的 DCode 总线与闪存存储器的数据接口相连接 ,常量加载和调试访问在该总线上面完成。
③ 系统总线:该总线连接 M3 内核的系统总线到总线矩阵,总线矩阵协调内核和 DMA 间访问。
④ DMA 总线:该总线将 DMA 的 AHB 主控接口与总线矩阵相连,总线矩阵协调 CPU 的DCode 和 DMA 到 SRAM, 闪存和外设的访问。
⑤ 总线矩阵:总线矩阵协调内核系统总线和 DMA 主控总线之间的访问仲裁,仲裁利用轮换算法。
⑥ AHB/APB 桥:这两个桥在 AHB 和 2 个 APB 总线间提供同步连接, APB1 操作速度限于36MHz ,APB2 操作速度全速。
STM32时钟系统
简单的说,时钟是单片机的脉搏,是单片机的驱动源,使用任何一个外设都必须打开相应的时钟。这样的好处是,如果不使用一个外设的时候,就把它的时钟关掉,从而可以降低系统的功耗,达到节能,实现低功耗的效果。
首先,任何外设都需要时钟,因为寄存器是由D触发器组成的,往触发器里面写东西,前提条件是有时钟输入。
51单片机不需要配置时钟,是因为一个时钟开了之后所有的功能都可以用了,而这个时钟是默认开启的。stm32之所以是低功耗,他将所有的门都默认设置为disable,在你需要用哪个门的时候,开哪个门就可以,也就是说用到什么外设,只要打开对应外设的时钟就可以,其他的没用到的可以还是disable,这样耗能就会减少。
在51单片机中一个时钟把所有的都包了,而stm32的时钟是有分工的,并且每类时钟的频率不一样,因为没必要所有的时钟都是最高频率,只要够用就行,所以不同的时钟也会有频率差别,或者在配置的时候可以配置时钟分频。

在STM32 中,有五个时钟源,为 HSI 、 HSE 、 LSI 、 LSE 、 PLL 。 从时钟频率来分可以分为高速时钟源和低速时钟源,在这 5 个中 HIS,HSE 以及 PLL 是高速时钟, LSI 和 LSE 是低速时钟。从来源可分为外部时钟源和内部时钟源,外部时钟源就是从外部通过接晶振的方式获取时钟源,其中 HSE 和 LSE 是外部时钟源,其他的是内部时钟源。
① 、 HSI 是高速内部时钟, RC 振荡器, 频率 为 8MHz 。
② 、 HSE 是高速外部时钟, 可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz 。 我们的开发板接的是 8M 的晶振。
③ 、 LSI 是低速内部时钟, RC 振荡器,频率为 40kHz 。 独立看门狗的时钟源只能是 LSI ,同时LSI 还可以作为 RTC 的时钟源。
④ 、 LSE 是低速外部时钟,接频率为 32.768kHz 的 石英晶体。 这个主要是 RTC 的时钟源。
⑤ 、 PLL 为锁相环倍频输出 ,其时钟输入源可选择为 HSI/2 、 HSE 或者 HSE/2 。倍频可选择为2~16倍,但是其输出频率最大不得超过 72MHz 。
时钟源给外设以及系统提供时钟:
A. MCO 是 STM32 的一个时钟输出 IO(PA8),它可以选择一个时钟信号输出可以选择为 PLL 输出的 2 分频、 HSI 、 HSE 、或者系统时钟 。这个时钟可以用来给外部其他系统提供时钟源。
B. 这里是 RTC 时钟源,从图上可以看出, RTC 的时钟源可以选择 LSI,LSE ,以及HSE 的 128 分频。
C. 从图中可以看出 C 处 USB 的时钟是来自 PLL 时钟源。 STM32 中有一个全速功能的 USB 模块 ,其串行接口引擎需要一个频率为 48MHz 的时钟源。该时钟源只能从 PLL 输出端获取,可以选择为 1.5 分频或者 1 分频,也就是,当需要使用 USB模块时, PLL 必须使能,并且时钟频率配置为 48MHz 或 72MHz 。
D. D 处就是 STM32 的系统时钟 SYSCLK ,它是供 STM32 中绝大部分部件工作 的时钟源 。 系统时钟可选择为 PLL 输出、 HSI 或者 HSE 。系统时钟最大频率 为 72MHz当然你也可以超频,不过一般情况为了系统稳定性是没有必要 冒风险去超频的。
E. 这里的E 处是指其他所有外设了。从时钟图上可以 看出,其他所有外设的时钟最终来源都是 SYSCLK 。 SYSCLK 通过 AHB 分频器分频后送给各模块使用 。这些模块包括:
①、 AHB 总线、内核、内存和DMA 使用的 HCLK 时钟。
② 、通过 8 分频后送给 Cortex 的系统 定时器时钟 ,也就是 systick 了 。
③ 、直接送给 Cortex 的空闲运行时钟 FCLK 。
④ 、送给 APB1 分频器。 APB1 分频器输出一路供 APB1 外设使用 (PCLK1 ,最大频率 36MHz),另一路送给定时器 (Timer)2 、 3 、4 倍频器使用。
⑤、送给 APB2 分频器。 APB2 分频器 分频输出一路供 APB2 外设使用 (PCLK2最大频率 72MHz),另一路送给定时器 (Timer)1 倍频器使用。
其中需要理解的是APB1 和 APB2 的 区别, APB1 上面连接的是低速外设,包括电源接口、备份接口、 CAN 、 USB 、 I2C1 、 I2C2 、 UART2 、 UART3 等等, APB2 上面连接的是高速外设包括 UART1 、 SPI1 、 Timer1 、 ADC1 、 ADC2 、所有普通 IO 口 (PA~ PE)、第二功能 IO 口等。
端口复用和重映射
端口复用功能
一个 GPIO如果可以复用为内置外设的功能引脚,那么当这个 GPIO 作为内置外设使用的时候,就叫做复用。(既是引脚也是内置外设的引脚)
复用端口初始化:
GPIO 端口时钟使能;
复用的外设时钟使能;
端口模式配置,在 IO 复用位内置外设功能引脚的时候,必须设置 GPIO 端口的模式。
端口重映射
一个外设的引脚除了具有默认的端口外,还可以通过设置重映射寄存器的方式,把这个外设的引脚映射到其它的端口 。
重映射步骤:
使能重映射的GPIO时钟;
使能外设时钟;
使能AFIO时钟;
开启重映射;
STM32 NVIC中断优先级管理
CM3内核支持 256 个中断,其中包含了 16 个内核中断和 240 个外部中断,并且具有 256级的可编程中断设置。但 STM32 并没有使用 CM3 内核的全部东西,而是只用了它的一部分。STM32 有 84 个中断,包括 16 个内核中断和 6 8 个可屏蔽中断,具有 16 级可编程的中断优先级。而我们常用的就是这 6 8 个可屏蔽中断, 但是 STM32 的 68 个可屏蔽中断,在STM32F103 系列上面,又只有 60 个(在 107 系列才有 68 个)。
typedef struct
__IO uint32_t ISER[8]; /*!< Interrupt Set Enable Register
uint32_t RESERVED0[24];
__IO uint32_t ICER[8]; /*!< Interrupt Clear Enabl e Regi ster */
uint32_t RSERVED1[24];
__IO uint32_t ISPR[8]; /*!< Interrupt Set Pending Register
uint32_t RESERVED2[24];
__IO uint32_t ICPR[8]; /*!< Interrupt Clear Pending Register
uint3 2_t RESERVED3[24];
__IO uint32_t IABR[8]; /*!< Interrupt Active bit Register
uint32_t RESERVED4[56];
__IO uint8_t IP[240]; /*!< Interrupt Priority Register, 8Bit wide
uint32_t RESERVED5[644];
__O uint32_t STIR; /*!< Software Trigger Interrupt Register
} NVIC_
ISER:全称是: Interrupt Set Enable Registers ,这是一个中断使能寄存器组。有用的就是两个 ISER [0]和 ISER [1]总共可以表示 64 个中断。而 STM32F103 只用了其中的前 60 位。 ISER[0] 的 bit0~ bit31 分别对应中断 0~ 31 。 ISER[1] 的 bit0~ 27 对应中断 32~59 ;这样总共 60 个中断就分别对应上了。 你要使能某个中断,必须设置相应的 ISER 位为 1 ,使该中断被使能 这里仅仅是使能,还要配合中断分组、屏蔽、 IO 口映射等设置才算是一个完整的中断设置 。
ICER:全称是 Interrupt Clear Enable Registers ,是一个中断除能寄存器组。该寄存器组与 ISER 的作用恰好相反,是用来清除某个中断的使能的。其对应位的功能,也和 ICER 一样。这里要专门设置一个 ICER 来清除中断位,而不是向 ISER 写 0 来清除,是因为 NVIC 的这些寄存器都是写 1 有效的,写 0 是无效的。
ISPR:全称是 Interr upt Set Pending Register s ,是一个中断挂起控制寄存器组。每个位对应的中断和 ISER 是一样的。通过置 1 ,可以将正在进行的中断挂起,而执行同级或更高级别的中断。写 0 是无效的。
ICPR:全称是 Interrupt Clear Pending Register s ,是一个中断解挂控制寄存器组。其作用与 ISPR 相反,对应位也和 ISER 是一样的。通过设置 1 ,可以将挂起的中断接挂。写 0 无效。
IABR:全称是 Interrupt Active Bit Registers ,是 一个中断激活 标志位寄存器 组。对应位所代表的中断和 ISER 一样,如果为 1 ,则表示该位所对应的中断正在被执行。这是一个只读寄存器,通过它可以知道当前在执行的中断是哪一个。在中断执行完了由硬件自动清零。
IP:全称是 Interrupt Priority Registers ,是一个中断优先级控制的寄存器组。 IP 寄存器组由 240 个 8 bit 的寄存器组成,每个可屏蔽中断占用 8bit ,这样总共可以表示 240 个可屏蔽中断。 而 STM32 只用到了其中的 前 60 个 。 I P[ 59 ]~IP[0] 分别对应中断 59 ~0 。 而每个可屏蔽中断占用的 8bit 并没有全部使用,而是 只用了高 4 位。这 4 位,又分为抢占优先级和子优先级。抢占优先级在前,子优先级在后。而这两个优先级各占几个位又要根据 SCB -->AIRCR 中的 中断分组设置来决定。

第一,如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;
第二,高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。而抢占优先级相同的中断,高优先级的响应优先级不可以打断低响应优先级的中断。
中断分组设置和中断优先级管理:
中断优先级分组函数NVIC_PriorityGroupConfig,这个函数的作用是对中断的优先级进行分组,这个函数在系统中只能被调用一次,一旦分组确定就最好不要更改。
void NVIC_ Priori tyGroupConfig(uint32_t NVIC_PriorityGroup);
中断初始化函数NVIC_Init
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
typedef struct
uint8_t NVIC_IRQChannel;//:定义初始化的是哪个中断,这个我们可以在 stm32f10x.h 中找到每个中断对应的名字。例如 USART1_IRQn 。
uint8 _t NVI C_IRQChannelPreemptionPriority;//定义这个中断的抢占优先级别。
uint8_t NVIC_IRQChannelSubPriority;//定义这个中断的子优先级别。
FunctionalState NVIC_IRQChannelCmd;//该中断是否使能。
} NVIC_InitTypeDef;
中断优先级设置的步骤:
- 系统运行开始的时候设置中断分组 。 确定组号,也就是确定抢占优先级和子优先级的分配位数。 调用函数为 NVIC_PriorityGroupConfig
- 设置 所用到的中断的中断优先级别。 对每个中断调用函数为 NVIC_Init();
MDK 中寄存器地址名称映射分析
MDK 采用的方式是通过结构体来将寄存器组织在一起。
相关文章:
STM32开发基础知识入门
C语言基础 位操作 对基本类型变量可以在位级别进行操作。 1) 不改变其他位的值的状况下,对某几个位进行设值。 先对需要设置的位用&操作符进行清零操作,然后用|操作符设值。 2) 移位操作提高代码的可读性。 3) ~取反操作使用技巧 可用于对某…...
学习操作系统的必备教科书《操作系统:原理与实现》| 文末赠书4本
使用了6年的实时操作系统,是时候梳理一下它的知识点了 摘要: 本文简单介绍了博主学习操作系统的心路历程,同时还给大家总结了一下当下流行的几种实时操作系统,以及在工程中OSAL应该如何设计。希望对大家有所启发和帮助。 文章目录…...
大数据的常用算法(分类、回归分析、聚类、关联规则、神经网络方法、web数据挖掘)
在大数据时代,数据挖掘是最关键的工作。大数据的挖掘是从海量、不完全的、有噪声的、模糊的、随机的大型数据库中发现隐含在其中有价值的、潜在有用的信息和知识的过程,也是一种决策支持过程。其主要基于人工智能,机器学习,模式学…...
【数据结构】详解二叉树与堆与堆排序的关系
🌇个人主页:平凡的小苏 📚学习格言:别人可以拷贝我的模式,但不能拷贝我不断往前的激情 🛸C语言专栏:https://blog.csdn.net/vhhhbb/category_12174730.html 🚀数据结构专栏ÿ…...
【Pandas】数据分析入门
文章目录前言一、Pandas简介1.1 什么是Pandas1.2 Pandas应用二、Series结构2.1 Series简介2.2 基本使用三、DataFrame结构3.1 DataFrame简介3.2 基本使用四、Pandas-CSV4.1 CSV简介4.2 读取CSV文件4.3 数据处理五、数据清洗5.1 数据清洗的方法5.2 清洗案例总结前言 大家好&…...
【c++】:list模拟实现“任意位置插入删除我最强ƪ(˘⌣˘)ʃ“
文章目录 前言一.list的基本功能的使用二.list的模拟实现总结前言 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中࿰…...
QT表格控件实例(Table Widget 、Table View)
欢迎小伙伴的点评✨✨,相互学习🚀🚀🚀 博主🧑🧑 本着开源的精神交流Qt开发的经验、将持续更新续章,为社区贡献博主自身的开源精神👩🚀 文章目录前言一、图示实例二、列…...
第二章Vue组件化编程
文章目录模块与组件、模块化与组件化模块组件模块化组件化Vue中的组件含义非单文件组件基本使用组件注意事项使用 kebab-case使用 PascalCase组件的嵌套模板templateVueComponent一个重要的内置功能单文件组件Vue脚手架使用Vue CLI脚手架先配置环境初始化脚手架分析脚手架结构实…...
面试官:vue2和vue3的区别有哪些
目录 多根节点,fragment(碎片) Composition API reactive 函数是用来创建响应式对象 Ref toRef toRefs 去除了管道 v-model的prop 和 event 默认名称会更改 vue2写法 Vue 3写法 vue3组件需要使用v-model时的写法 其他语法 1. 创…...
【TopK问题】——用堆实现
文章目录一、TopK问题是什么二、解决方法三、时间复杂度一、TopK问题是什么 TopK问题就是从1000个数中找出前K个最大的数或者最小的数这样的类似问题。 不过并不要求这k个数字必须是有序的,如果题目有要求,则进行堆排序即可。 还有比如求出全国玩韩信…...
【Spring从成神到升仙系列 四】从源码分析 Spring 事务的来龙去脉
👏作者简介:大家好,我是爱敲代码的小黄,独角兽企业的Java开发工程师,CSDN博客专家,阿里云专家博主📕系列专栏:Java设计模式、数据结构和算法、Kafka从入门到成神、Kafka从成神到升仙…...
使用Nginx反向代理OpenAI API
由于OpenAI的API在国内无法访问,所以可以通过海外服务器利用Nginx实现反向代理。 安装Nginx 这一步就不赘述了,不同的Linux系统安装方式略有不同,根据自己的服务器的系统自行百度即可。 OpenSSL创建证书 因为OpenAI的接口是https协议的&a…...
USB键盘实现——字符串描述符(四)
字符串描述符 字符串描述符内容解析和 HID鼠标 一致。 获取字符串描述符请求 标准设备请求 typedef struct __attribute__ ((packed)){union {struct __attribute__ ((packed)) {uint8_t recipient : 5; ///< Recipient type usb_request_recipient_t.uint8_t type …...
STM32的中断
目录 一、STM32中断概述 二、外部中断控制器EXTI 三、按键中断 四、串口中断 一、STM32中断概述 处理器中的中断在处理器中,中断是一个过程,即CPU在正常执行程序的过程中,遇到外部/内部的紧急事件需要处理,暂时中止当前程序的…...
Flink进阶篇-CDC 原理、实践和优化采集到Doris中
简介 基于doris官方用doris构建实时仓库的思路,从flinkcdc到doris实时数仓的实践。 原文 Apache Flink X Apache Doris 构建极速易用的实时数仓架构 (qq.com) 前提-Flink CDC 原理、实践和优化 CDC 是什么 CDC 是变更数据捕获(Change Data Captur…...
看完这篇 教你玩转渗透测试靶机vulnhub——My File Server: 1
Vulnhub靶机My File Server: 1渗透测试详解Vulnhub靶机介绍:Vulnhub靶机下载:Vulnhub靶机安装:Vulnhub靶机漏洞详解:①:信息收集:②:FTP匿名登入:③:SMB共享服务…...
OpenHarmony实战STM32MP157开发板 “控制” Hi3861开发板 -- 中篇
一、前言 我们在 OpenHarmony实战STM32MP157开发板 “控制” Hi3861开发板 – 上篇 中介绍到了,App面板的开发,以及JS API接口的开发和调用。 那么本篇文章,会详解:BearPi-HM Nano开发板,如何实现数据上报和指令接收响应的。 看到这里,可能有同学可能已经知道思路了,因…...
【数据结构初阶】单链表
目录一、思路>>>>>>>>>>>>过程<<<<<<<<<<<<<<<1.打印2.尾插3.尾删4.头插5.头删6.查找7.指定位置后插入8.指定位置后删除9.链表的销毁二、整个程序1.SLTlist.c2.SLTlist.c一、思路 #define …...
多线程代码案例-阻塞队列
hi,大家好,今天为大家带来多线程案例--阻塞队列 这块知识点也很重要,要好好掌握呀~~~ 🌸🌸🌸🌸🌸🌸🌸🌸🌸🌸🌸🌸🌸&#x…...
mysql的limit查询竟然有坑?
背景 最近项目联调的时候发现了分页查询的一个bug,分页查询总有数据查不出来或者重复查出。 数据库一共14条记录。 如果按照一页10条。那么第一页和第二页的查询SQL和和结果如下。 .png) 那么问题来了,查询第一页和第二页的时候都出现了11,12,13的记录…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
