前言
从这节课开始呢我们就正式进入了固件库编程,我们学习了GPIO口的相关知识,那么我们的第一个程序就写GPIO输出——使用固件库点亮LED吧。下面就让我们一起来学习,创作不易,点个三连支持一下吧!
STM32第六节:GPIO输出——使用固件库点亮LED
LED原理
首先,我们还是先熟悉一下LED的原理图,我们所需要操作的io口为PB(0,1,5),即GPIOB寄存器上的操作。通过控制这三个端口的高低电平,来控制灯的亮灭。
对于F103的固件库编程
拷贝模板
首先我们先拷贝一份上节课的工程模板,然后命名为本节课的内容(最好是英文,要不然可能会报错)。这里需要模板的可以去看上节课讲的模板创建过程创建一个普遍性的工程模板。拷贝过来后,我们打开USER文件夹,创建两个文件,一个是bsp_led.c源文件,另一个是bsp_led.h头文件。创建好这两个文件后,我们熟练的打开keil5,打开工程,从本地目录的USER中导入文件到keil5的USER中,并编译。到这里,就是我们在以后的工程中新建文件的过程。
功能框图——GPIO
如图所示,上半部分是输入,下半部分是输出。那么我们要用到的就是下半部分输出控制。我们可以看到,在下半部分中,我们可以控制ODR寄存器直接控制,也可以使用BRR,BSRR寄存器间接控制输出。
如果我我们写入的数据为0,那么到达输出控制的时候,在上面的反向控制器(这里画反了),数据信号就会转化为1,那么就会导通下面的VSS(推挽,开漏或关闭),反之则导通上面的VDD。大致了解了内容后我们就开始编写代码吧。
编写bsp_led.c,bsp_led.h代码
接下来我们开始正式编写代码,打开bsp_led.c,为什么我们这里要用bsp作为前缀?
bsp : board support package 板级支持包,和开发板有相关性(只和板子有关,只要带bsp开头的文件,都只是针对该板子)
在文件下先引入bsp_led.h头文件备用,
//bsp : board support package 板级支持包 和开发板有相关性
//(只和板子有关,只要带bsp开头的文件,都只是针对该板子)
#include "bsp_led.h"
接下来打开bsp_led.h,输入通用的模板(防止重复定义):
#ifndef __BSP_LED_H_
#define __BSP_LED_H_
#include "stm32f10x.h"
#endif /* __BSP_LED_H_(条件编译) */
在stm32f10x_gpio.h文件中,我们可以发现,上上节课我们所写的代码也在其中(77行),他们设置了GPIO口的输出方式和输出速度,用结构体变量封装起来,具体的几个模式就用枚举法都列出来,像下述代码一样:
/**
* @brief Output Maximum frequency selection
*/
typedef enum
{
GPIO_Speed_10MHz = 1,
GPIO_Speed_2MHz,
GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;
#define IS_GPIO_SPEED(SPEED) (((SPEED) == GPIO_Speed_10MHz) || ((SPEED) == GPIO_Speed_2MHz) || \
((SPEED) == GPIO_Speed_50MHz))
/**
* @brief Configuration Mode enumeration
*/
typedef enum
{ GPIO_Mode_AIN = 0x0,
GPIO_Mode_IN_FLOATING = 0x04,
GPIO_Mode_IPD = 0x28,
GPIO_Mode_IPU = 0x48,
GPIO_Mode_Out_OD = 0x14,
GPIO_Mode_Out_PP = 0x10,
GPIO_Mode_AF_OD = 0x1C,
GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeDef;
#define IS_GPIO_MODE(MODE) (((MODE) == GPIO_Mode_AIN) || ((MODE) == GPIO_Mode_IN_FLOATING) || \
((MODE) == GPIO_Mode_IPD) || ((MODE) == GPIO_Mode_IPU) || \
((MODE) == GPIO_Mode_Out_OD) || ((MODE) == GPIO_Mode_Out_PP) || \
((MODE) == GPIO_Mode_AF_OD) || ((MODE) == GPIO_Mode_AF_PP))
在bsp_led.c文件中,我们编写第一个函数:
配置初始化结构体
那么我们第一步就是新建一个初始化结构体,往结构体中输入我们所要改变的代码:
#include "bsp_led.h"
void LED_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin =
}
然而写到这里我们发现,如果这样的话,我们代码的可移植性就不会很高了,想要提高我们代码的可移植性,我们可以把Pin定义为宏,这样在修改的时候就可以很快找到我们要修改的代码,并且快速把所有需要修改的地方一次性修改完。那么接下来我们定义宏:
#define LED_G_GPIO_PIN GPIO_Pin_0
#define LED_G_GPIO_PORT GPIOB
在定义完宏定义后,我们就改.c文件中的代码为下,配置结构体成员的成员内容:
GPIO_InitStruct.GPIO_Pin = LED_G_GPIO_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
配置好后,我们要调用一个初始化函数,要把我们的这些成员内容写入到RCL寄存器,我们观察该寄存器,要的是PB0,即前四位,CNF0,MODE0,我们设置的为0011,那么输入的就该是0011。
对于初始化函数,我们之前是配置好的,从stm32f10x_gpio.h文件中找到void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);函数声明,复制到bsp_led.c文件中,再带入宏定义,完成函数的运行。在这里,第二个参量我们已经定为地址,所以现在就使用&取地址符,获取其地址就可以了。
GPIO_Init(LED_G_GPIO_PORT, &GPIO_InitStruct); //&地址即可
打开时钟
从上图可以看出,要打开AHB上的时钟,是由RCC控制的,那么我们的GPIO端口在APB2上。我们找到对此的函数声明,APB2时钟开关函数。把他拷贝到bsp_led.c中,修改宏定义,使第一个形参为RCC_APB2Periph_GPIOB,第二个形参就改为ENABLE使能。如下三行代码所示:
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
#define LED_G_GPIO_CLK RCC_APB2Periph_GPIOB
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
这时候时钟就打开了,然后我们就可以配置ODR寄存器了。如果我们现在在main.c文件中输入函数,我们发现LED灯亮起,这是因为如果调为输入模式的话,ODR寄存器复位值为0x0。那么反逻辑就输出1,那么很巧合的就点亮了LED为Green。
关掉打开的LED(GPIO_SetBits 函数)
int main(void)
{
// 来到这里的时候,系统的时钟已经被配置成72M。
LED_GPIO_Config();
}
我们要想关掉的话,也使用固件库编程,打开头文件,找到GPIO_SetBits函数,写入到main函数中,使用宏定义输入我们要的参数。
GPIO_SetBits(LED_G_GPIO_PORT,LED_G_GPIO_PIN);
打开关掉的LED(GPIO_ResetBits 函数)
那么我们需要在上一个函数声明的下面找到GPIO_ResetBits函数,调用到主函数中来。
代码如下,改变参量:
GPIO_ResetBits(LED_G_GPIO_PORT,LED_G_GPIO_PIN);
设置延时函数使灯闪烁
那么如何让LED灯闪烁呢?这里就需要用到延时函数。还是使用软件延时,编写一个简单的Delay代码:
#include "stm32f10x.h" // 相当于51单片机中的 #include <reg51.h>
#include "bsp_led.h"
void Delay(uint32_t count)
{
for(;count!=0;count--);
}
int main(void)
{
// 来到这里的时候,系统的时钟已经被配置成72M。
LED_GPIO_Config();
GPIO_SetBits(LED_G_GPIO_PORT,LED_G_GPIO_PIN);
Delay(0xFFFFF);
GPIO_ResetBits(LED_G_GPIO_PORT,LED_G_GPIO_PIN);
Delay(0xFFFFF);
}
小结
好啦,到这里我们的函数以及固件库就编写完成了,本节课我们学习了GPIO输出——使用固件库点亮LED,包含LED以及GPIO的讲解,以及具体代码的编写。那么我们下节课讲带参宏以及GPIO输入——按键检测。
创作不易,点个三连霸!