STM32的LED点亮教程:使用HAL库与Proteus仿真
学习目标:掌握使用STM32 HAL库点亮LED灯,并通过Proteus进行仿真验证!
建立HAL库标准工程
1.新建工程文件夹
新建工程文件夹建议路径尽量为中文。建立文件夹的目的为了更好分类去管理项目工程中需要的各类工程文件。
首先需要在某个位置建立工程文件夹,例如我在桌面的protues文件夹的demo文件夹建立了一个LED工程文件夹C:\Users\Shinelon\Desktop\proteus\demo\LED
然后在该文件夹下建立下述的文件夹
名称 | 作用 |
Drivers | 存放硬件相关的驱动层文件 |
Middlewares | 存放中间层组件文件和第三方中间层文件 |
Output | 存放工程编译输出文件 |
Projects | 存放 MDK 工程文件 |
User | 存放 HAL 库用户配置文件、main.c、stm32f1xx_it.c、以及 我们自己编写的其它应用程序 |
另外可以在该文件夹下面建立一个readme的txt文件,用作该工程的说明。
建立之后效果如下:
建立后上述文件夹结构后,需要拷贝部分文件,用于后续的工程中使用,根据上诉的文件夹顺序依次说明。
Drivers 文件夹
用于存放驱动文件,建立BSP、CMSIS和STM32F1xx_HAL_Driver三个个文件夹,其中BSP存放个人编写驱动代码;CMSIS用于存放启动文件和stm32f1xx.h等底层代码;STM32F1xx_HAL_Driver用于存放 ST 提供的 F1xx HAL 库驱动代码。
CMSIS和STM32F1xx_HAL_Driver相关文件可以在STM32CubeF1 固件包中的Drivers拷贝。STM32CubeF1 固件包的获取可以在ST意法半导体官网直接搜索STM32CubeF1下载即可。
但官方提供的STM32CubeF1固件包里面包含的东西太多,我们在保留我们现在需要的,因此作如下处理。
在Drivers\CMSIS\Device\ST\STM32F1xx\Include路径下只保留下述文件
在Drivers\CMSIS\Device\ST\STM32F1xx\Source\Templates只保留下述文件
在Drivers\CMSIS\Device\ST\STM32F1xx\Source\Templates\arm中只保留启动文件startup_stm32f103xe.s
在Drivers\CMSIS\Include中保留下述文件
到此Drivers处理完成。
Middlewares 文件夹
Middlewares 文件夹用于存放中间层组件文件和第三方中间层文件。我们新建工程实验暂时用不到,留空就行,后面的实验将会陆续添加各种文件。
Output 文件夹
Output 文件夹用于存放编译器编译工程输出的中间文件,比如:.hex、.bin、.o 文件等。 这里不需要操作,后面只需要在 MDK 里面设置该文件夹为编译输出文件的存放文件夹就行。 Projects 文件夹
Projects 文件夹用于存放 MDK 工程,因为我们的工程是基于 ARM,所以我们在 Projects 文件夹里面新建一个命名为 MDK-ARM 的文件夹,用于存放 MDK 的工程文件
User 文件夹
User 文件夹用于存放 HAL 库用户配置文件、main.c、中断处理文件,以及配置文件 stm32f1xx_hal_conf.h。
从官方固件包里面直接拷贝官方的模板到我们的User。官方的模板工程路径:STM32Cube_FW_F1_V1.8.0\Projects\ STM3210E_EVAL \Templates,打开 Template_Project 文件夹,在 Inc 和 Src 文件夹里面,在这两个文件夹里面找到:stm32f1xx_it.c、 stm32f1xx_it.h、stm32f1xx_hal_conf.h 这三个文件,拷贝到我们的 User 文件夹下。同时在User建立一个main.c的文件如图:
到此新建工程文件夹完成。
2.新建工程
打开 Keil uVision5,点击菜单 Project ->New Uvision Project,如图所示。
然后弹出工程命名和保存的操作窗口,工程文件保存路径为:,工程名字我们取:LED,最后点击保存即可。
接下来会弹出一个选择 Device 的界面,就是选择我们的芯片设备型号,STM32F103C8T6,所以我们选择:STMicroelectronics→STM32F1 Series→STM32F103→STM32F103c8
点击OK出现下面弹窗点击Cancel
3.添加文件
在项目工程中设置工程名字和分组,目的是分类管理。分组如下表所示:
名称 | 作用 |
Startup | 存放启动文件 |
User | 存放man等用户文件 |
Drivers/CMSIS | 存放系统驱动代码 |
Drivers/STM32F1xx_HAL_Driver | 存放ST提供的HAL库驱动代码 |
Drivers/BSP | 存放个人系统驱动代码 |
可在工程管理中进行更改工程名字和分组,单击小魔方即可进入
进入小魔方之后,可双击空白区域新建
设置好之后,我们点击 OK,回到 MDK 主界面,可以看到我们设置的工程名和分组名
建立好文件管理之后需要依次添加文件
添加启动文件
该文件由 ST 官方提供,添加方式可以在小魔方中操作,点击小魔方按钮,进入工程管理界面,选中 Startup分组,然后点击:Add Files,进入文件添加对话框,
其路径在Drivers\CMSIS\Device\ST\STM32F1xx\Source\Templates\arm中。
注意文件类型需要更改为.s(默认是.c),点击Add即可。
添加 User 源码
同样在小魔方中操作,点击小魔方按钮,进入工程管理界面,选中 User 分组,然后点击:Add Files,进入文件添加对话框。路径为User,将依次添加main.c和stm32f1xx_it.c
添加 CIMC 源码
点击小魔方按钮,进入工程管理界面,选中 Drivers/CIMC分组,然后点击:Add Files,进入文件添加对话框,路径为:Drivers\CMSIS\Device\ST\STM32F1xx\Source\Templates
添加system_stm32f1xx.c文件
添加 STM32F1xx_HAL_Driver 源码
点击小魔方按钮,进入工程管理界面,选中 Drivers/STM32F1xx_HAL_Driver 分组,然后点击:Add Files,进入文件添加对话框,路径为:Drivers\STM32F1xx_HAL_Driver\Src
依次添加 stm32f1xx_hal.c、stm32f1xx_hal_cortex.c、stm32f1xx_hal_dma.c、stm32f1xx_hal_gpio.c、stm32f1xx_hal_gpio_ex.c、stm32f1xx_hal_rcc.c、 stm32f1xx_hal_rcc_ex.c、stm32f1xx_hal_uart.c 和 stm32f1xx_hal_usart.c 到该分组下
4.相关设置
建立好工程需要对一些内容进行设置,主要设置为
设置 Target 选项卡
选择 ARM Compiler 版本为:Use default compiler version 5(即 AC5 编译器),主要是AC5对中文的兼容性比较好,但这不是必须设置的,而是推荐设置。同时在Xtal(MHz)如果可以设置需要将其设置成8.
设置 Output 选项卡
将输出文件夹设置为我们的Output,同时勾选 Create HEX File和Browse Information
设置 Listing 选项卡
和上面一样将输出文件夹设置为我们的Output
设置 C/C++选项卡
在Define中设置全局宏定义:USE_HAL_DRIVER 和 STM32F103xE,他们之间是用英文逗号隔开的。
推荐设置优化等级(Optimization)为-O0,可以得到最好的调试效果,如果要提高优化效果提升性能并降低代码量,可以设置-O1~-O3,数字越大效果越明显,不过也越容易出问题。
勾选 C99 模式,即使用 C99 C 语言标准。
我们可以进行头文件包含路径设置,这一步很关键,关乎到程序能否正常找到.h头文件。我们需要将我们要用到的头文件的相关路径加载进来。点击include Paths后面的三个点,并将相关路径加载进来。具体如图所示
建立Protues仿真
protues工程建立
打开protues,点击新建工程
将工程名字改为LED,并选择合适的路径,推荐和LED工程文件同一个路径
然后正常下一步一直到完成。
元器件的查找和放置
完成后来到原理图绘制界面,我们需要先找到相关元器件,点击左侧元器件的图标,并点击P
点击P后来到元器件搜索界面,需要先了解一下元器件的名字,这个实验中需要用到的元器件及其在protues中的名字为
STM32单片机 | stm32f103c8 |
电阻 | RES |
电容 | CAP |
晶振 | CRYSTAL |
按钮 | BUTTON |
LED灯 | LED-BULE |
搜索出相关元器件,点击确定,
STM32最小系统
STM32的最小系统通常包括微控制器、时钟电路、电源电路、复位电路以及程序下载端口。它能够维持一个微控制器(MCU)的基本运作,是构建更复杂系统的基础。以下将详细解析这些组成部分,以便更好地理解每个部分的作用和设计要点:
- 微控制器(MCU):微控制器是整个系统的核心,负责处理数据和运行程序。在STM32家族中,例如STM32F103C8T6是一款常用的微控制器,集成了CPU、内存、I/O接口和多种外设功能。
- 时钟电路:时钟电路作为芯片的心脏提供MCU运行所需的时钟信号,通常包括晶体振荡器和相关的电容。晶振电路确保芯片获得稳定、准确的时钟信号,有助于系统时序的准确性和稳定性。
- 电源电路:电源电路为MCU和其他电路提供稳定的电源,可能包括电压调节器和滤波电容。
- 复位电路:复位电路确保MCU在上电或需要时能够正确地启动和复位。STM32支持多种复位方式,包括电源复位、系统复位和后备域复位。复位电路设计需考虑低电平复位逻辑,确保重启可靠性。
- 程序下载端口:程序下载端口允许程序员将代码烧录到MCU中,并在开发过程中进行调试。这通常包括JTAG、SWD等接口。BOOT电路设计决定芯片的启动方式,如从主闪存存储器启动、系统存储器启动还是内置SRAM启动。
综上所述,STM32的最小系统由若干关键部分组成,每个部分都起着至关重要的作用。了解和掌握这些基础知识,对于成功开发STM32应用具有重要意义。
在protues仿真中,由于可以直接将程序运行文件放入stm32仿真器件中,同时可以配置电源网络,因此不需要下载电路和电源电路。以下是protues的仿真系统的STM32的最小系统
protues的STM32最小系统仿真
微控制器stm32f103c8t6
时钟电路
双击晶振,将其频率修改为8MHZ
设置C1和C2容值为20pF
在终端模式中选择地GROUND并放置
复位电路
注意在终端模式放置电源POWER,并将其值改为3.3V
电源电路
protues仿真可以忽略
protues的LED电路仿真
LED选择使用高电平驱动,R1是为了限流,仿真中也可以不要。LED的额定电压和额定电流可以双击进行查看并修改
例如这个LED的额定电压是2.2V,额定电流是10mA,STM32的GPIO的驱动电压是3.3V,因此需要一个电阻去分担1.1V的电压,并使电路电流维持在10mA,根据欧姆定律可以计算出阻值应该为1.1/0.01=110.
整体电路
程序编写
STM32的GPIO
STM32的GPIO共有八种工作模式,包括模拟输入、浮空输入、下拉输入、上拉输入、开漏输出、推挽输出、复用开漏输出和复用推挽输出。下面是这八种工作模式的详细分析:
-
模拟输入模式(AIN):此模式主要用于ADC(模数转换)等需要读取模拟信号的场景。信号直接输入到ADC模块,适用于需要精确测量电压或其他模拟量的情况。
-
浮空输入模式(IN_FLOATING):此模式下,GPIO引脚既不接上拉电阻也不接下拉电阻,处于“浮空”状态。由于没有确定的电平,由外部条件决定,这种模式通常用于按键检测等场景,此时外部设备的状态可以直接反映在MCU的输入电平上。
-
下拉输入模式(IPD):在此模式下,GPIO引脚内部连接下拉电阻,使得在无外部信号输入时,引脚默认为低电平状态。这种模式常用于需要确保引脚在无信号时为低电平的场景,比如一些基于低电平触发的外部中断。
-
上拉输入模式(IPU):与下拉输入模式相对应,上拉输入模式在引脚内部连接了上拉电阻,使得引脚在无信号输入时默认为高电平状态。该模式适用于需要确保引脚在无信号时为高电平的场景,如某些基于高电平或下降沿触发的外部中断。
-
开漏输出模式(OUT_OD):在此模式下,GPIO的输出仅通过N-MOS管实现,当输出高电平时,N-MOS管关闭,引脚呈现高阻态,需要外部电阻拉高电平。开漏输出可用于需要“线与”功能的场合,比如I2C总线的通信。
-
推挽输出模式(OUT_PP):推挽输出模式通过P-MOS和N-MOS管实现引脚的高低电平输出,具有比开漏输出更强的驱动能力。适用于大多数需要大电流驱动的场合,如LED的驱动。
-
复用开漏输出模式(AF_OD):此模式类似于开漏输出,但是输出信号来源于片上外设而非GPIO本身。适用于需要使用片上外设(如I2C)且同时需要开漏特性的场合。
-
复用推挽输出模式(AF_PP):类似于推挽输出模式,但是输出信号源自片上外设,支持更强驱动能力同时具备片上外设功能,例如USART的TX引脚或者SPI通信。
总之,STM32 GPIO的八种工作模式各具特色,选择适当的工作模式对于嵌入式系统设计至关重要。合理配置GPIO不仅能够优化硬件资源利用,还能提高系统的可靠性和性能。开发者需根据具体应用场景仔细选择GPIO的工作模式,以满足不同外设和通信需求。
主函数的编写
引用HAL标准库头文件 #include "stm32f1xx_hal.h"
main函数结构
int main()
{
初始化区
while(1)
{
主要程序运行区
}
}
我们在初始化区要对芯片进行一些复位或者初始设定操作,主要包括GPIO初始化、外设初始化、系统配置等,在点LED的实验中,只需要最基本的系统初始化和相关GPIO的初始化。系统初始化直接在stm32f1xx_hal.c的142行找到并调用HAL_Init()即可。
LED相关GPIO初始化,主要做几件事,
1.使能打开控制该引脚的开关
2.确定控制LED的是哪个引脚
3.选择对应引脚的GPIO模式
4.选择引脚的上下拉状态
5.设置引脚的速度
6.设置引脚的初始状态
根据原理图,LED由PB5控制,因此要先对GPIOB进行使能,并且LED是由STM32引脚直接用高电平驱动的,因此要将GPIO模式设置为推挽输出模式,输出模式的上下拉状态不重要,因为在第六步的时候会进行设置,引脚速度选用高速,初始状态设置成低电平0
初始化区代码为:
HAL_Init();
GPIO_InitTypeDef gpio_init_struct;
do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0); /* LED时钟使能 */
gpio_init_struct.Pin = GPIO_PIN_5; /* LED引脚 */
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
HAL_GPIO_Init(GPIOB, &gpio_init_struct); /* 初始化LED引脚 */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
在主要程序运行区只需要将PB5设置成高电平即可实现点亮LED灯
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
完整程序:
#include "stm32f1xx_hal.h"
int main(void)
{
HAL_Init();
GPIO_InitTypeDef gpio_init_struct;
do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0); /* LED时钟使能 */
gpio_init_struct.Pin = GPIO_PIN_5; /* LED引脚 */
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
HAL_GPIO_Init(GPIOB, &gpio_init_struct); /* 初始化LED引脚 */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
while(1)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
}
}
仿真验证
MDK点击编译按钮出现以下提示即为生成hex文件
打开protues,打开原理图,双击芯片,选择生成的hex文件
选择路径为文件夹LED/output中选择led.hex文件,然后点击左下角的仿真开始按钮即可