参考
STM32+PCB设计+物联网,手牵手带你从零开始画板子+写代码
https://www.bilibili.com/video/BV18arkYjEuL
STM32入门教程-2023版 细致讲解 中文字幕
https://www.bilibili.com/video/BV1th411z7sn
【已完结STM32】–自学江协科技笔记汇总
https://blog.csdn.net/2301_81011494/article/details/147069164
1.1课程简介
https://www.bilibili.com/video/BV1th411z7sn/
2-1软件开发
安装过程见
00-Keil与STLINK与CH340安装
2-2新建工程
1.新建文件夹
新建工程的文件夹,
d:\stm32pro\打开Keil5软件–>选择Project—>New uVision Project -->选择d:\stm32pro\
然后选择刚刚我们新建的文件夹,在 新建文件夹 里面再建一个文件夹
d:\stm32pro\2-1STM32工程模板进入
d:\stm32pro\2-1STM32工程模板输入工程文件名Project,然后点击保存工程,
接下来就是选择芯片型号,我们的芯片型号是STM32F103C8T6。
用来存放本次工程。
点击OK,弹出来的是新建工程小助手,这个可以帮助我们快速新建工程,我们暂时用不到这个,直接选择叉掉。
这样就新建好一个工程,但是还不完整,还需要添加文件
此时的工程目录如下
2.start启动文件
添加文件到本地的Start目录下
工程建好之后 还需要添加一些库文件,首先在工程文件夹下新建一个Start启动文件
然后打开固件库文件夹
D:\BaiduNetdiskDownload\STM32入门教程资料\固件库\固件库\STM32F10x_StdPeriph_Lib_V3.5.0\STM32F10x_StdPeriph_Lib_V3.5.0\找到启动文件,
D:\BaiduNetdiskDownload\STM32入门教程资料\固件库\固件库\STM32F10x_StdPeriph_Lib_V3.5.0\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm(固件库文件来自b站江科大,可自行下载,见固件库的下载方式)
将arm里面的启动文件全部复制到工程模板文件夹Start文件夹下
接着回到STM32F10x文件夹,找到STM32头文件和配置时钟文件,也复制到Star文件夹下
接着还需要添加内核寄存器的描述文件,打开文件路径:
D:\BaiduNetdiskDownload\STM32入门教程资料\固件库\固件库\STM32F10x_StdPeriph_Lib_V3.5.0\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\CoreSupport\,同样复制到Start文件夹下
把本地Start目录下的文件添加到Keil5工程中
接着回到Kile5,把刚才复制到的文件添加到工程里,单击Source Group 1可将其改为Start
然后右键单击Start,选择AddExisting Files to Group ‘Start’
弹出的页面默认只添加.c文件
选择文件类型中的所有类型,可以看到所有文件
这里只需要添加后缀为md.s的启动文件就可以了 ,选择add,然后单击close
然后把 本地Start目录中剩下的的.c和.h文件都要添加进来
3、添加头文件路径
最后还需要在工程选项添加头文件路径
首先确定ARM 的Compiler ,选择version5
右键Keil5中左侧,选择Options for Target ‘Target1’
弹出的选项界面中,选择C/C++选项,然后选择Include Paths,选择新建new,选择三个点的图标,选择头文件的目录
按照要求选择目录即可
4、 测试工程
测试工程是否可行,在工程本地文件夹下新建一个User文件用来存放main函数
进来Kile5右击Target1添加组
并将其改名为User
,然后右击User添加新项目到组里
选择文件类型,设置文件名,文件的路径
单击确定即可
这样工程文件夹里面就可以看到有一个main文件了
插入头文件
并编写一个main函数,注意代码最后一行必须空行,否则会报警告
#include "stm32f10x.h" // Device header int main(void) { while(1) { } }以上配置就可以用寄存器开发32单片机了。当然用寄存器开发STM32不太适合初学者,后面还要添加库函数。
现在进行build, 编译通过0错误0警告就证明工程建立成功
5、连接下载器ST-LINK(注意事项)
ST-LINK通过杜邦线链接最小系统版,注意接线
插上后,会出现一个灯亮表示电源,链接在PC13的灯默认是闪烁状态,这是芯片里的一个测试程序
插上下载器ST-LINK,点击魔术棒找到Debug,选择ST-Link ,然后选择Flash Download为自动复位
然后选择工程的build,编译成功后,单击load,如果load成功,Keil会提示,同时最小系统版的灯不再闪烁
因为load进去的代码没有操作
6、测试点灯
基于寄存器配置,测试点灯程序 ,最小系统板上的的灯是低电平点亮的,0x00002000是灯灭,0x00000000是灯亮
打开
D:\BaiduNetdiskDownload\STM32入门教程资料\参考文档\参考文档\STM32F10xxx参考手册(中文).pdf7.3.7 APB2外设时钟使能寄存器(RCC_APB2ENR)
GPIO都是APB2的外设,在7.3.7 APB2外设时钟使能寄存器(RCC_APB2ENR)
00000000 00000000 00000000 00010000 00 00 00 10 0X00000010#include "stm32f10x.h" // Device header int main(void) { // 使能GPIOC RCC->APB2ENR = 0X00000010; while(1) { } }在8.2.2端口配置寄存器(GPIOx_CRH)(x=A…E)
这样如果给GPIOC的13设置为通用推挽 输出模式设置为50MHz,
21:20位为 11输出模式设置为50MHz 23:22位为00通用推挽模式 00000000 00110000 00000000 00000000 00 30 00 00 00300000代码如下
#include "stm32f10x.h" // Device header int main(void) { // 使能GPIOC RCC->APB2ENR = 0X00000010; // 设置GPIOC 推挽与50MHz GPIOC->CRH=0X00300000; while(1) { } }在8.2.4端口输出寄存器(GPIOx_ODR)(x=A…E)
可以看到,如果想给PC13上的灯点亮(低电平点亮),给ODR设置为0,可以都设置为0,即
GPIOC->ODR=0X00000000 表示灯亮
给GPIOC->ODR=0X00002000表示灯灭
二进制和十六进制为
00000000 00000000 00100000 00000000 00 00 20 00 00002000 00000000 00000000 00100000 00000000 00 00 20 00 00002000#include "stm32f10x.h" // Device header int main(void) { // 使能GPIOC RCC->APB2ENR = 0X00000010; // 设置GPIOC 推挽与50MHz GPIOC->CRH=0X00300000; // 设置灯亮 GPIOC->ODR=0X00000000; // 设置灯灭 //GPIOC->ODR=0X00002000; while(1) { } }实现闪烁
#include "stm32f10x.h" // Device header int main(void){ RCC->APB2ENR = 0x00000010; // 设置GPIOC 推挽与50MHz GPIOC->CRH=0X00300000; while(1){ uint32_t i, j; // 在循环外声明变量(兼容C90标准) for(i = 0; i < 3000; i++) for(j = 0; j < 3600; j++); // 大约1ms的延时 GPIOC->ODR=0X00000000 ;//表示灯亮 for(i = 0; i < 3000; i++) for( j = 0; j < 3600; j++); // 大约1ms的延时 GPIOC->ODR=0X00002000 ;//表示灯灭 } }循环版本
#include "stm32f10x.h" // Device header // 延时函数,大约延时ms毫秒 void Delay_ms(uint32_t ms) { uint32_t i, j; // 简单的软件延时,具体值需要根据实际系统时钟校准 for(i = 0; i < ms; i++) for(j = 0; j < 7200; j++); // 大约1ms的延时 } int main(void){ //RCC->APB2ENR=0X00000010; // 使能GPIOC RCC->APB2ENR = 0X00000010; // 设置GPIOC 推挽与50MHz GPIOC->CRH=0X00300000; while(1){ // 设置灯亮 GPIOC->ODR=0X00000000; Delay_ms(3000); // 延时3秒 // 设置灯灭 GPIOC->ODR=0X00002000; Delay_ms(3000); // 延时3秒 } }7.添加库函数
上面的方式需要经常查看手册的寄存器,采用库函数可以解决这个问题
打开工程文件夹,新建一个文件夹Library,用来存放库函数
打开固件库文件找内核库函数源文件,路径:
D:\BaiduNetdiskDownload\STM32入门教程资料\固件库\固件库\STM32F10x_StdPeriph_Lib_V3.5.0\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver\src打开固件库文件找内核库函数头文件,路径:
D:\BaiduNetdiskDownload\STM32入门教程资料\固件库\固件库\STM32F10x_StdPeriph_Lib_V3.5.0\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver\inc然后Ctrl+a全选复制刚刚新建的到工程文件夹下Library文件夹下
回到Kile5右击Target1添加组并命名为Library,右击Library添加存在的文件,将库函数源文件和头文件全部添加进来
至此库函数还不能直接使用,还需要再添加一个文件。接着打开固件库文件
D:\BaiduNetdiskDownload\STM32入门教程资料\固件库\固件库\STM32F10x_StdPeriph_Lib_V3.5.0\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Template\把
stm32f10x_it.h stm32f10x_it.c stm32f10x_conf.h复制到User目录下
接着回到Kile5把刚刚的三个文件添加到User组里
最后我们还需要一个宏定义,跳转到头文件stm32f10x.h下滑到最后,找到 USE_STDPERIPH_DRIVER
然后选择魔法棒–选择C++,将USE_STDPERIPH_DRIVER复制到Define ,同时在include中添加User和Library目录
最后编译一下,0错误0警告说明工程建立成功
8.用库函数点灯
RCC_APB2PeriphClockCmd函数
通过右键RCC_APB2PeriphClockCmd()跳转到定义的位置
第一个参数选择 RCC_APB2Periph_GPIOC,第二个参数ENABLE
// #define RCC_APB2Periph_GPIOC ((uint32_t)0x00000010)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);GPIO_Init函数
通过右键RCC_APB2PeriphClockCmd()跳转到定义的位置
第一个参数为GPIO_TypeDef* GPIOx, 第二个参数为GPIO_InitTypeDef* GPIO_InitStruct
参数需要一个结构体,就需要先定义一个结构体
// 定义GPIO的结构体,通过.设置结构体的属性 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_InitStructure.GPIO_Pin = GPIO_InitStructure.GPIO_Speed =右键GPIO_Mode可以看到定义的位置,注释中的无法跳转,选择GPIOMode_TypeDef然后复制查找
可以看到GPIOMode_TypeDef是一个枚举,可以把GPIO_Mode_Out_PP设置给结构体
// 定义GPIO的结构体,通过.设置结构体的属性 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_InitStructure.GPIO_Speed =右键GPIO_Pin查看定义,出现左下角的多个定义,选择member,
跳转到
选择注释中的GPIO_pins_define,ctrl+f可以快速查找,选择Find Next
复制 GPIO_Pin_13 到GPIO_Pin
// 定义GPIO的结构体,通过.设置结构体的属性 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Speed =右键跳转,在注释中ctrl+f查找,可以看到是一个枚举类型,选择GPIO_Speed_50MHz
复制GPIO_Speed_50MHz到 GPIO_InitStructure.GPIO_Speed如下:
// 定义GPIO的结构体,通过.设置结构体的属性 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;把结构体地址赋值给GPIO_Init函数
// 定义GPIO的结构体,通过.设置结构体的属性 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 初始化GPIOC // 第一个参数为GPIO_TypeDef* GPIOx, 第二个参数为GPIO_InitTypeDef* GPIO_InitStruct // 先在上面初始化一个GPIO_InitTypeDef结构体 变量名为 GPIO_InitStructure GPIO_Init(GPIOC,&GPIO_InitStructure);编译下,出现如下问题
问题13:编译时,出现错误declaration may not appear after executable statement in block
可以把GPIO_InitTypeDef GPIO_InitStructure;放在句首,也可以在c/c++选项卡在,勾选C99 Mode,就可以在 在函数的可执行语句之后定义变量了。
GPIO_SetBits和GPIO_ResetBits函数
// 给GPIOC的13端口设置高电平 //GPIO_SetBits(GPIOC,GPIO_Pin_13); // 给GPIOC的13端口设置低电平 GPIO_ResetBits(GPIOC,GPIO_Pin_13);编译下,然后load 就出现灯亮了
9.新建工程步骤
建立工程文件夹,Keil中新建工程,选择型号
工程文件夹里建立Start、Library、User等文件夹,复制固件库里面的文件到工程文件夹
工程里对应建立Start、Library、User等同名称的分组,然后将文件夹内的文件添加到工程分组里
工程选项,C/C++,Include Paths内声明所有包含头文件的文件夹
工程选项,C/C++,Define内定义USE_STDPERIPH_DRIVER
工程选项,Debug,下拉列表选择对应调试器,Settings,Flash Download里勾选Reset and Run
10.工程结构
所以复位键后,程序后重新启动
单片机的程序最后为一个死循环,永远不会结束
SystemInit的函数定义在system开头.c的里了
拓展:固件库的下载方式
进入官网
意法半导体官网 | ST官网 - STMicroelectronics
选择产品–微处理器
选择主流MCU,选择F1系列,选择STM32F103
选择工具与软件
选择嵌入式软件中的MCU and MPU embedded software,
选择
STM32 Standard Peripheral Libraries,选择STSW-STM32054
选择打开Open software page,选择对应的版本,这里选择的是3.5
选择版本后,谈成是否接受界面
单击接受后,进入登录或访客下载页面
登录或访客都可以,
进入版本选择并选择版本边上的下载按钮,即完成下载的功能
下载后的压缩包与提供的压缩包内容一致。
拓展:固件库的目录说明
STM32 标准外设库(StdPeriph Library)是 ST 官方为简化开发提供的工具包,其目录结构分工明确。以下结合典型目录(以 STM32F1 系列为例),解析核心目录的作用:
一、核心目录:Libraries(驱动库核心)
是外设库的底层支撑,包含CMSIS 内核抽象层和STM32 外设驱动层,让开发者无需直接操作寄存器即可控制硬件。
1.CMSIS 文件夹(Cortex-M 软件接口标准)
- 作用:实现 Cortex-M 内核与芯片外设的解耦,让代码兼容不同厂商的 Cortex-M 芯片,同时简化内核相关操作(如中断、调试)。
- 子目录分解:
Core_Support:
core_cm3.c/h(对应 Cortex-M3 内核,M4/M7 内核则为core_cm4.c/h等):
定义内核寄存器的操作函数(如配置 NVIC 中断优先级、系统滴答定时器),实现内核外设(如 SysTick、NVIC)的驱动。- 这些文件是 ARM 官方提供的通用代码,与 STM32 芯片无关,只负责内核层面的抽象。
Device/ST/STM32F1xx:
- 启动文件(如
startup_stm32f10x_h/m/ld.s,汇编编写):
芯片上电后第一步执行的代码,负责初始化栈指针、复制全局变量到 RAM、跳转到main函数。不同容量的芯片(小/中/大容量)对应不同启动文件(如hd代表大容量)。 system_stm32f10x.c/h:
定义SystemInit()函数,初始化系统时钟(配置 HSE、HSI、PLL 等,设置 AHB/APB 总线分频),是启动流程的关键步骤。 STM32主频是72MHz,就是这个文件中配置的stm32f10x.h:
外设寄存器的映射文件,通过宏和结构体(如GPIO_TypeDef)定义所有外设的寄存器地址(如GPIOA->CRL对应 GPIOA 的配置寄存器),是库函数操作硬件的基础。类似Reg51.h ,描述有哪些寄存器和地址,有些类似域名与ip地址的关系
- 启动文件(如
2.STM32F10x_StdPeriph_Driver 文件夹(外设驱动层)
- 作用:为 STM32 的每个外设(GPIO、UART、SPI 等)提供封装好的库函数,开发者通过调用函数即可配置外设,无需深入寄存器细节。
- 子目录分解:
inc 文件夹:
存放外设的头文件(如stm32f10x_gpio.h、stm32f10x_usart.h):- 定义初始化结构体(如
GPIO_InitTypeDef,包含引脚模式、速度、上下拉等参数)。 - 声明库函数(如
GPIO_Init()、USART_SendData())。 - 定义寄存器的位掩码(如
GPIO_Mode_Out_PP代表推挽输出模式)。
- 定义初始化结构体(如
src 文件夹:
存放外设的源文件(如stm32f10x_gpio.c、stm32f10x_usart.c):- 实现
inc中声明的函数,内部通过操作stm32f10x.h的寄存器完成功能(如GPIO_Init()会修改GPIOx->CRL/CRH寄存器)。 - 每个外设的功能(如 GPIO 翻转、UART 发送数据)都通过这里的函数封装。
- 实现
特殊文件:misc.c/h:
提供对**内核 NVIC(中断控制器)**的操作函数(如NVIC_Init()配置中断优先级、NVIC_EnableIRQ()使能中断),因为 NVIC 属于内核外设,需与芯片外设的中断配合使用。
二、辅助目录(项目开发相关)
1.Project 文件夹
- 作用:提供官方示例工程和编译器模板,快速上手开发。
- 内容:
STM32F10x_StdPeriph_Examples:按外设分类的示例(如 GPIO 翻转、UART 通信、SPI 传输),可直接导入 Keil/IAR 编译,学习外设的典型用法。Templates:针对不同编译器(Keil、IAR)的工程模板,包含最小化的文件结构(已关联库路径、包含必要头文件),开发者可在此基础上扩展功能。
2.Utilities 文件夹
- 作用:存放 ST 官方评估板(如 STM32 Discovery、Eval 板)的专用驱动和示例。
- 内容:
- 评估板上的扩展硬件(如显示屏、传感器、按键)的驱动代码(如
stm32_eval_led.c)。 - 若使用通用开发板,这部分可忽略,但其中的驱动设计思路(如分层封装、状态机)可借鉴。
- 评估板上的扩展硬件(如显示屏、传感器、按键)的驱动代码(如
3.根目录文件
stm32f10x_stdperiph_lib_um.chm:
库函数帮助文档(CHM 格式),详细说明每个库函数的参数、功能、使用示例(如USART_Config()如何配置波特率、校验位),是开发时的核心参考。Release_Notes.html:
版本说明,记录库的更新内容、支持的芯片型号、已知问题,用于确认库的兼容性。
三、目录协作关系与开发流程
- 底层支撑:
Libraries/CMSIS负责内核和芯片的基础初始化(启动、时钟、寄存器映射)。 - 外设控制:
Libraries/STM32F10x_StdPeriph_Driver提供外设的库函数,开发者通过调用这些函数配置硬件(如GPIO_Init()设置引脚模式)。 - 快速验证:
Project中的示例和模板可直接复用,减少搭建工程的时间。 - 参考学习:
Utilities中的评估板代码和chm文档辅助理解外设用法。
通过合理利用这些目录,开发者可跳过寄存器级的繁琐操作,专注于应用层逻辑,大幅提升开发效率。若需深入底层,也可通过stm32f10x.h和core_cm3.h查看寄存器定义,实现库函数的扩展或自定义。
拓展:GPIO 与 APB2
在STM32微控制器中,这句话描述的是GPIO(通用输入/输出端口)与系统总线架构中APB2总线的连接关系,以下从微控制器的总线架构、APB2总线特点、GPIO作为外设的属性这几个方面来深入理解:
微控制器的总线架构
STM32微控制器采用了先进的总线架构,以实现不同功能模块之间高效的数据传输和控制。其中,常见的总线有AHB(Advanced High-performance Bus,高级高性能总线)和APB(Advanced Peripheral Bus,高级外设总线) 。
- AHB总线:主要用于连接高性能、高数据传输速率的模块,如CPU内核、存储器、DMA控制器等。它能够支持高速的数据传输,满足对带宽要求较高的设备之间的数据交互。
- APB总线:则是用于连接低带宽的外设模块,为这些外设提供了一种相对简单且低功耗的通信方式。APB又分为APB1和APB2,它们的主要区别在于工作频率和所连接的外设类型。
APB2总线特点
APB2总线相较于APB1总线,通常具有更高的工作频率。这意味着连接到APB2总线上的外设可以在更快的时钟信号驱动下工作,从而具备更高的数据传输速率和响应速度。在STM32系列中,APB2总线通常用于连接那些对速度要求相对较高的外设。
GPIO作为APB2的外设
- GPIO功能简介:GPIO是STM32中非常重要且常用的外设,它允许用户通过软件灵活地配置引脚的功能,如设置为输入模式来读取外部信号(像按键状态),或者设置为输出模式来控制外部设备(如点亮LED灯)。
- 连接关系原因:GPIO在工作时,有时需要快速地响应外部信号的变化或者及时输出控制信号,比如在驱动高速通信接口的使能引脚,或者快速切换LED灯的亮灭状态来实现高频闪烁效果等场景下,就对数据传输和处理速度有一定要求。将GPIO连接到APB2总线上,利用APB2相对较高的工作频率,能够满足GPIO在这些快速操作场景下的性能需求。
不过需要注意,并不是所有STM32系列微控制器的GPIO都是APB2的外设 。不同型号的STM32,其外设与总线的连接情况会根据芯片的设计和定位有所差异。比如,一些低功耗或低成本的STM32型号,其GPIO可能会连接到APB1总线上,以平衡性能和功耗等方面的需求。
拓展:RCC_APB2ENR
在STM32微控制器中,RCC_APB2ENR是一个寄存器,它是复位和时钟控制(Reset and Clock Control,RCC)模块的一部分,全称为APB2外设时钟使能寄存器(Advanced Peripheral Bus 2 Peripheral Clock Enable Register),主要用于控制连接在APB2总线上的外设时钟的开启和关闭。以下从寄存器基本概念、作用原理以及使用方式这几个方面来理解它:
寄存器基本概念
寄存器是微控制器内部的一组存储单元,每个寄存器都被分配了特定的地址。通过对这些地址进行读写操作,就可以访问和修改寄存器中的值,进而实现对微控制器不同功能模块的配置和控制。RCC_APB2ENR寄存器也是如此,它在内存中占据特定的地址空间,用户可以通过编程来读写这个寄存器。
作用原理
- 时钟控制机制:在STM32中,为了降低功耗以及对不同外设进行灵活管理,并不是所有外设的时钟在系统上电后都处于开启状态。每个外设都有对应的时钟使能位,当该位被设置为1时,相应外设的时钟才会被打开,外设才能正常工作;如果设置为0 ,外设时钟被关闭,此时外设处于低功耗状态,无法执行数据处理等操作。
- 与APB2总线外设关联:APB2总线上连接着一些对速度要求相对较高的外设,比如GPIO端口(部分STM32型号)、ADC(模拟数字转换器)、SPI1(串行外设接口1)等。
RCC_APB2ENR寄存器中的每一位都对应着一个连接在APB2总线上的外设。例如,在STM32F103系列中,RCC_APB2ENR寄存器的第2位对应着IOPAEN(GPIOA时钟使能位),第3位对应着IOPBEN(GPIOB时钟使能位)等。当要使用某个APB2外设时,就需要将该外设对应的时钟使能位置1 ,为其提供时钟信号,外设才能按照设定的功能运行。
具体使用方式(以STM32F103为例,基于标准外设库)
- 头文件包含:在使用与
RCC_APB2ENR相关的功能之前,需要在代码中包含对应的头文件,如stm32f10x.h,该头文件中定义了RCC_APB2ENR寄存器以及相关的宏定义。
#include"stm32f10x.h"- 使能外设时钟:比如要使用GPIOA端口,就需要使能GPIOA的时钟,示例代码如下:
// 使能GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);在上述代码中,RCC_APB2PeriphClockCmd是标准外设库中提供的函数,它的第一个参数指定要使能时钟的外设(这里是RCC_APB2Periph_GPIOA,对应RCC_APB2ENR寄存器中的IOPAEN位),第二个参数ENABLE表示使能该外设时钟,其本质就是对RCC_APB2ENR寄存器中对应的位进行置1操作。
- 关闭外设时钟:当某个外设不再使用时,为了降低功耗,可以关闭其时钟,示例代码如下:
// 关闭GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,DISABLE);这里的DISABLE参数会将RCC_APB2ENR寄存器中IOPAEN位清0,从而关闭GPIOA的时钟。
总之,RCC_APB2ENR寄存器是STM32中管理APB2总线上外设时钟的关键部件,合理地配置它能够有效地控制外设的工作状态,实现对系统功耗和性能的优化。
拓展:GPIOx_CRH寄存器
在STM32微控制器中,配置完RCC_APB2ENR使能GPIO时钟后,还需要配置端口配置寄存器GPIOx_CRH(x = A..E),这是因为两者承担着不同且互补的功能,具体如下:
时钟使能是基础前提
RCC_APB2ENR寄存器用于使能连接在APB2总线上的外设时钟,对于GPIO端口而言,使能其时钟是必不可少的准备工作。只有当GPIO对应的时钟使能位(例如RCC_APB2ENR中与GPIOA对应的IOPAEN位)被置1 ,GPIO端口才能正常工作。
这就好比给一个工厂供电,只有先接通电源,工厂里的机器(GPIO外设)才有可能运转起来, 但仅接通电源,机器并不会自动按照我们期望的方式工作,还需要对其进行功能设定。
GPIOx_CRH决定端口具体功能
GPIOx_CRH寄存器是GPIO端口的配置寄存器(高8位配置寄存器,对应引脚GPIOx_8 - GPIOx_15,低8位配置寄存器是GPIOx_CRL,对应引脚GPIOx_0 - GPIOx_7),它的作用是详细设定GPIO引脚的工作模式和输出速度等关键参数,具体如下:
1. 配置引脚工作模式
GPIO引脚可以配置为多种工作模式,以满足不同的应用需求,GPIOx_CRH中的相关位用于选择这些模式:
- 输入模式:
- 浮空输入(IN_FLOATING):引脚的电平状态完全由外部输入决定,内部没有上拉或下拉电阻,常用于读取外部信号,如按键输入。
- 上拉输入(IPU):引脚内部连接了上拉电阻,默认情况下引脚被拉高为高电平,当外部连接低电平信号时,引脚电平被拉低,适用于按键等外部信号常态为高电平的场景。
- 下拉输入(IPD):与上拉输入相反,引脚内部连接下拉电阻,默认被拉低为低电平,用于外部信号常态为低电平的情况。
- 模拟输入(AIN):引脚用于连接模拟信号源,关闭施密特触发器(一种用于波形整形的电路),直接将外部模拟信号接入内部ADC(模拟数字转换器),用于模拟量采集。
- 输出模式:
- 通用推挽输出(GPIO_Mode_Out_PP):引脚可以输出高电平或低电平,驱动能力较强,常用于驱动LED灯、继电器等需要较大电流的负载。
- 通用开漏输出(GPIO_Mode_Out_OD):引脚只能输出低电平,输出高电平时需要外部上拉电阻将引脚拉高,适用于需要“线与”逻辑(多个开漏输出引脚连接在一起,只要有一个输出低电平,整体就为低电平)的场景,或者用于电平转换。
- 复用推挽输出(GPIO_Mode_AF_PP):引脚用于复用功能,如SPI、USART等外设的引脚,由外设模块控制引脚的输出信号,同样具有较强的驱动能力。
- 复用开漏输出(GPIO_Mode_AF_OD):与复用推挽输出类似,但输出高电平时需要外部上拉电阻,常用于I2C等需要“线与”逻辑的复用功能场景。
2. 配置输出速度
在输出模式下,还可以通过GPIOx_CRH设置引脚的输出速度,常见的有2MHz、10MHz、50MHz等选项。 输出速度决定了引脚电平翻转的速率,合理选择输出速度可以避免信号干扰和电磁兼容性(EMC)问题。例如,驱动LED灯时,较低的输出速度(如2MHz)即可满足要求;而在高速通信接口(如SPI)中,可能就需要选择较高的输出速度(如50MHz)以满足数据传输速率的要求。
两者配合实现完整功能
配置RCC_APB2ENR打开GPIO时钟,是让GPIO模块能够正常工作;而配置GPIOx_CRH(和GPIOx_CRL)则是告诉GPIO模块具体要做什么,比如某个引脚是用于输入按键信号,还是用于输出驱动LED的信号,以及以什么样的速度和方式进行输入输出操作。
只有这两步配置都正确完成,GPIO引脚才能按照开发者的预期在电路中发挥作用,实现与外部设备的有效交互。
拓展:stm32f10x_it.h和stm32f10x_it.c和stm32f10x_conf.h作用
在STM32F10x系列的标准外设库项目中,stm32f10x_it.h、stm32f10x_it.c和stm32f10x_conf.h是三个具有特定功能的核心文件,分别承担中断服务程序管理和库配置的作用,具体解析如下:
1.stm32f10x_it.h和stm32f10x_it.c:中断服务程序(ISR)的集中管理
这两个文件是中断服务程序的专用存放地,用于定义和实现STM32的所有中断处理函数,是系统响应外部事件(如GPIO触发、定时器溢出、串口接收等)的核心逻辑载体。
核心作用:
中断函数声明与实现分离:
stm32f10x_it.h:声明所有中断服务函数的原型(如EXTI0_IRQHandler()、TIM2_IRQHandler()),供其他模块调用或引用。stm32f10x_it.c:实现这些中断服务函数的具体逻辑,例如在外部中断触发时读取GPIO状态、在定时器中断中更新变量等。
统一管理中断向量表映射:
STM32的中断向量表(启动文件中定义)会将硬件中断信号映射到stm32f10x_it.c中对应的函数。例如,当外部中断线0(EXTI0)触发时,系统会自动跳转到EXTI0_IRQHandler()函数执行。避免中断函数命名冲突:
中断服务函数的名称是固定的(由芯片硬件决定,如USART1_IRQHandler对应串口1中断),将其集中放在这两个文件中,可避免与其他模块的函数命名冲突,规范代码结构。
示例场景:
当需要处理按键触发的外部中断(如PA0引脚连接按键,触发EXTI0中断)时,会在stm32f10x_it.c中实现:
voidEXTI0_IRQHandler(void){if(EXTI_GetITStatus(EXTI_Line0)!=RESET){// 处理中断逻辑(如点亮LED、更新标志位)GPIO_SetBits(GPIOC,GPIO_Pin_13);// 清除中断标志位(必须操作,否则会持续触发中断)EXTI_ClearITPendingBit(EXTI_Line0);}}而stm32f10x_it.h中会声明该函数:
voidEXTI0_IRQHandler(void);2.stm32f10x_conf.h:外设库的配置开关
该文件是标准外设库的“配置中心”,通过宏定义控制是否启用特定外设的驱动文件、中断向量和调试信息,用于裁剪项目代码、减少编译体积。
核心作用:
选择性包含外设驱动头文件:
文件中通过#define宏控制是否包含某个外设的头文件。例如:#defineUSE_STDPERIPH_DRIVER// 启用标准外设库#include"stm32f10x_gpio.h"// 包含GPIO驱动#include"stm32f10x_usart.h"// 包含USART驱动// #include "stm32f10x_adc.h" // 注释掉则不启用ADC驱动未被包含的外设驱动不会被编译,从而减少固件体积。
控制中断向量的使能:
部分外设的中断向量需要通过该文件间接控制(结合stm32f10x_it.c)。例如,若不启用ADC,则可注释掉#include "stm32f10x_adc.h",避免ADC相关的中断函数被编译。定义库函数的调试输出开关:
部分库函数(如assert_param()参数检查)的调试信息输出,可通过该文件中的宏(如USE_FULL_ASSERT)控制是否启用,便于开发阶段调试和量产阶段关闭冗余输出。
典型配置示例:
// 启用参数检查(开发阶段用,量产可关闭)#defineUSE_FULL_ASSERT// 包含需要使用的外设驱动#include"stm32f10x_rcc.h"// 时钟控制#include"stm32f10x_gpio.h"// GPIO控制#include"stm32f10x_tim.h"// 定时器控制// 不包含SPI和I2C驱动(项目中用不到)// #include "stm32f10x_spi.h"// #include "stm32f10x_i2c.h"三者的协作关系
stm32f10x_conf.h决定项目中启用哪些外设驱动,为中断处理和其他功能提供基础支持。- 当外设触发中断时,中断向量表会引导系统执行
stm32f10x_it.c中对应的中断服务函数,而这些函数的声明在stm32f10x_it.h中。 - 三者共同构成了STM32中断系统和外设管理的核心框架,确保中断响应的规范性和代码的可维护性。
void);
#### 2. `stm32f10x_conf.h`:外设库的配置开关 该文件是**标准外设库的“配置中心”**,通过宏定义控制是否启用特定外设的驱动文件、中断向量和调试信息,用于裁剪项目代码、减少编译体积。 ##### 核心作用: - **选择性包含外设驱动头文件**: 文件中通过`#define`宏控制是否包含某个外设的头文件。例如: ```c #define USE_STDPERIPH_DRIVER // 启用标准外设库 #include "stm32f10x_gpio.h" // 包含GPIO驱动 #include "stm32f10x_usart.h" // 包含USART驱动 // #include "stm32f10x_adc.h" // 注释掉则不启用ADC驱动未被包含的外设驱动不会被编译,从而减少固件体积。
控制中断向量的使能:
部分外设的中断向量需要通过该文件间接控制(结合stm32f10x_it.c)。例如,若不启用ADC,则可注释掉#include "stm32f10x_adc.h",避免ADC相关的中断函数被编译。定义库函数的调试输出开关:
部分库函数(如assert_param()参数检查)的调试信息输出,可通过该文件中的宏(如USE_FULL_ASSERT)控制是否启用,便于开发阶段调试和量产阶段关闭冗余输出。
典型配置示例:
// 启用参数检查(开发阶段用,量产可关闭)#defineUSE_FULL_ASSERT// 包含需要使用的外设驱动#include"stm32f10x_rcc.h"// 时钟控制#include"stm32f10x_gpio.h"// GPIO控制#include"stm32f10x_tim.h"// 定时器控制// 不包含SPI和I2C驱动(项目中用不到)// #include "stm32f10x_spi.h"// #include "stm32f10x_i2c.h"三者的协作关系
stm32f10x_conf.h决定项目中启用哪些外设驱动,为中断处理和其他功能提供基础支持。- 当外设触发中断时,中断向量表会引导系统执行
stm32f10x_it.c中对应的中断服务函数,而这些函数的声明在stm32f10x_it.h中。 - 三者共同构成了STM32中断系统和外设管理的核心框架,确保中断响应的规范性和代码的可维护性。
通过合理配置这三个文件,开发者可以高效管理中断逻辑、裁剪项目代码,适配不同场景的需求(如资源受限的嵌入式设备需最小化固件体积)。