脚本宝典收集整理的这篇文章主要介绍了逐行理解STM32点亮LED的过程,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
前言
记得刚开始学习stm32的时候,第一个程序就是点亮LED灯,但当时仅仅是照葫芦画瓢,只知道大概有哪些过程,并不清楚每一行代码所具有的意义,于是今天回过头来做个笔记,理解它每一行代码。我用的开发板是正点原子的STM32ZET6。
点亮LED的工作原理
点亮LED元件只需在其两端加上正向电势差。而在stm32开发版中,LED元件被焊在外围电路上与某个芯片引脚连接,这个引脚一定会在这个开发板的电路原理图中给出。而我们需要做的就是让芯片上的这个引脚输出特定电平从而产生电势差。
操作过程
STM32内部有逻辑电路,因此我们可以通过编程实现对引脚电平的控制。即编写代码->将程序编译并下载到芯片中->LED灯点亮。
代码实现
先贴出全部源代码(库函数实现)。
led.c
#include "led.h" #include "stm32f10x_rcc.h"//RCC寄存器库 #include "stm32f10x_gpio.h"//GPIO寄存器库 void Led_Init(void)//LED初始化函数 在STM32F103ZET6开发板中,LED0为PB5 LED1为PE5 { GPIO_InitTypeDef GPIO_InitStructure;//结构体另定义,包含配置GPIO的参数,详见stm32f10x_gpio.h RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);//使能GPIO_B GPIO_PE 详见stm32f10x_rcc.h GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//引脚5 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//引脚传输速率50MHz GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出模式 GPIO_Init(GPIOB, &GPIO_InitStructure);//根据结构体GPIO_InitStructure配置PB5 GPIO_ResetBits(GPIOB, GPIO_Pin_5);//PB5置0 GPIO_Init(GPIOE, &GPIO_InitStructure);//根据结构体GPIO_InitStructure配置PE5 GPIO_ResetBits(GPIOE, GPIO_Pin_5);//PE5置0 }
led.h
#ifndef __LED_H #define __LED_H void Led_Init(void); #endif
main.c
#include "stm32f10x.h" #include "led.h" int main(void) { Led_Init(); }
main.c和led.h的内容是最基本的C语言语法,这里不再阐述,我们主要看led.c。
时钟使能寄存器
STM32因为具有相当多的引脚,如果全部都默认工作的话,将会平白造成电能和热能的损失,以及减少芯片寿命。因此设计了一个时钟使能寄存器(简称RCC),这个寄存器可以细分为APB1 外设时钟使能寄存器和APB2 外设时钟使能寄存器,它们分开承包管理芯片的引脚,就好像地铁的两边站台,各自负责不同方向的客流,本质都是运输乘客。除此之外还有AHB外设时钟使能寄存器,这里不过多阐述。
使能:顾名思义就是给你使一个能量,在这里指激活该引脚从休眠进入工作状态。
时钟:由于stm32内部数字电路复杂,因此需要分清哪个寄存器在哪个时间点工作,从而让它们协调工作,就好比交响乐演奏的指挥家。因此单独拎出一个电路用于传递时钟信号,时钟信号在高电平和低电平之间会对芯片内部逻辑电路产生不同的反馈,具体涉及到数字电路的知识,想要快速理解可以尝试去看一下IIC通信协议。(跟我念,I方C)
综上所述,我们要编写STM32的程序,最首先做的就是使能需要用到的引脚。在官方给出的函数库当中,就有这么一个对寄存器操作的函数。
/** * @brief Enables or disables the High Speed APB (APB2) peripheral clock. * @param RCC_APB2Periph: specifies the APB2 peripheral to gates its clock. * This parameter can be any combination of the following values: * @arg RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB, * RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE, * RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1, * RCC_APB2Periph_ADC2, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1, * RCC_APB2Periph_TIM8, RCC_APB2Periph_USART1, RCC_APB2Periph_ADC3, * RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17, * RCC_APB2Periph_TIM9, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11 * @param NewState: new state of the specified peripheral clock. * This parameter can be: ENABLE or DISABLE. * @retval None */ void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState) { /* Check the parameters */ assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph)); assert_param(IS_FUNCTIONAL_STATE(NewState)); if (NewState != DISABLE) { RCC->APB2ENR |= RCC_APB2Periph; } else { RCC->APB2ENR &= ~RCC_APB2Periph; } }
这是一个APB2 外设时钟使能寄存器的使能函数,注释中给出了它能使能的GPIO口,在芯片手册上也有写。一个GPIO口包含16个芯片引脚,比如GPIOA就包含GPIOA0~GPIOA15,一般简称PA,相当于一个集合。在STM32中使能只能按照GPIO使能,比如你要调用PA5,则PA0~PA15都不得不一起跟着被使能。
看回到我们的代码。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);
在我这个开发板中,两个LED元件所对应的引脚分别为PB5、PE5,因此要使能PB和PE,而这两个GPIO口恰好都由APB2时钟使能寄存器管理,我们可以直接调用该函数使能,第一个参数为对应GPIO口,第二个参数为使能信号,ENABLE代表使能。
但是我们会有一个问题,为什么PB和PE之间加上一个"或"符号就能合二为一在一个函数中同时使能了呢,因为其本质是32位的二进制数,我们看下图。
可以看到每一位代表一个"操作",这样说可能有点抽象,直接上例子:假如我们要使能GPIOF,那么只需要把该二进制数的第0位置1,高位在左低位在右,此时该值应为000......0001,为了方便表达,可以转化为16进制的表达形式,0x00000001,剩下的工作就交给寄存器就行。因此我们通过C语言的或运算,可以合二为一,同时使能两个GPIO口。
GPIO口初始化
给引脚使能后,我们还需要配置它,配置内容有配置对象、传输速率和输入/输出模式。
在此之前,我们先认识认识CRL和CRH,即端口配置低寄存器和端口配置高寄存器,统称为配置寄存器。
CRL代表的就是GPIO口的低8位,即0~7引脚,CRH则代表8~15引脚。
由参考手册可知在该32位寄存器中每4位控制一个io口,正好对应8个。
接下来我们需要做的就是通过函数配置该寄存器,首先我们需要另定义一个结构体
GPIO_InitTypeDef GPIO_InitStructure;
该结构体有三个元素,从上到下分别为配置对象、传输速率和输入/输出模式。
typedef struct { uint16_t GPIO_Pin; /*!< Specifies the GPIO pins to be configured. This parameter can be any value of @ref GPIO_pins_define */ GPIOSpeed_TypeDef GPIO_Speed; /*!< Specifies the speed for the selected pins. This parameter can be a value of @ref GPIOSpeed_TypeDef */ GPIOMode_TypeDef GPIO_Mode; /*!< Specifies the operating mode for the selected pins. This parameter can be a value of @ref GPIOMode_TypeDef */ }GPIO_InitTypeDef;
由于要使能PB5、PE5,第一个参数我们选择5号引脚,第二个速率参数通常选择最快的50MHz,第三个选择推挽输出模式。
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//引脚5 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//引脚传输速率50MHz GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出模式
其中STM32有4种输出模式和4种输入模式,这8种模式具体工作原理请参考相关资料。对于LED点亮来说,推挽输出最简单方便,故采用推挽输出。
之后我们用初始化函数初始化相应引脚。
GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
点亮LED
最后再来认识个ODR——端口输出数据寄存器。顾名思义,就是负责输出高低电平信号的。
调用引脚控制函数,低电平时产生电势差,LED亮。
GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
这一系列的本质其实就是通过调节寄存器的每一比特位信号来驱动芯片完成相应功能,而库函数将其语言化,便于我们理解。
以上是脚本宝典为你收集整理的逐行理解STM32点亮LED的过程全部内容,希望文章能够帮你解决逐行理解STM32点亮LED的过程所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。