STM32F4教程从零开始2——更合理的工程与GPIO操作

来源:互联网 发布:淘宝详情页 拍摄 价格 编辑:程序博客网 时间:2024/06/05 05:59


这次主要来介绍一下STM32的GPIO,GPIO是通用IO口的意思,一般用来管理单片机的单个管脚的操作,也可以拿来模拟通信协议(比较麻烦,而且稳定性不如硬件),最常见的用处就用来操作LED灯和捕获按键状态。我们今天主要是操作LED灯。。。。

先上一张STM32关于GPIO的原理图:

看起来是比较复杂的,大概可以这样看左边是芯片的内部,右边是最外面暴露出来的真正的管脚。在管脚处有两个上下拉电阻,而再后面的部分,可以看成上面是输入,下面是输出。

单片机的IO口是有输入功能和输出功能的,并不是说输出功能就是输出电流,输入功能就是输入电流。我认为正确的说法应该是,输出状态下,单片机是主动的,它决定了管脚是高电平还是低电平,当输出高电平的时候往往会输出电流,而输出低电平的时候会输入电流;而输入状态下,单片机是被动的,由外界决定管脚的电平高低,这个时候一般是输入电流的,是不是有点像男生比较主动而女生比较被动的感觉。显然,单片机不可能同时处于输出又输入的状态!

其实,stm32的输出功能还更麻烦一些,有推挽和开漏两种模式,这里我就不从电路电路分析了,直接说结果,大概可以理解成,推挽(PP)可以输出高电平(拉电流),也可以输出低电平(灌电流);而开漏(OD)只能输出低电平(灌电流),它输出高电平是处于高阻态的。开漏其实可以看成一个与地相连接的开关,当开关闭合(输出低)时,把管脚与地相连,当开关断开(输出高)时,管脚悬空,这时外界可以很容易地改变这个管脚的电平,也可以说这个管脚的电平处于不稳定状态。

stm32的输入功能,也分成模拟输入和数字输入两种情况,当使用ADC功能的时候,要配置成模拟输入。

至于当使用管脚复用功能时,管脚基本是由硬件功能自己配置的,基本不用我们管。

接下来,我们来看看如何具体操作。

如果使用的是上一个教程建好的工程的话,需要做一些处理,如果只是单纯的想学GPIO的话可以跳过这部分,这样做只是更为了更优雅的编程而已。

1、首先,按照上一个教程把晶振设置好。

2、新建一个Global.h在User目录下,并添加到工程里。添加文件到工程里可以使用工具栏上的文件管理的图标,也可以在工程目录(左边那个)的响应目录上双击,然后选择文件。

在Global.h里写入以下代码

#ifndef _GLOBAL_H#define _GLOBAL_H#include "main.h"#include "stm32f4xx.h"#include "Bsp.h"#endif
这是典型的H文件的写法,前两行和最后一行是为了防止重复包含,以后当工程里面添加其他的H文件时,就在那个H文件里面包含Global.h,然后在Global.h里面包含那个文件,这样就可以全面包含,使全局函数在随处可调了。

3、把main.c换成以下内容,就是把大部分东西都删了就可以了

#include "main.h"int main(void){ while(1) { }}
把main.h换成以下内容,只需要包含Global.h就可以了

#ifndef __MAIN_H#define __MAIN_H#include "Global.h"#endif /* __MAIN_H */
4、然后需要修改Driver目录下的stm32f4xx_it.c里的SysTick_Handle()r函数,官方默认的这个函数里面调用了TimingDelay_Decrement(),这个函数在main.c里面定义,已经背我们删掉了,所以这里也需要删掉TimingDelay_Decrement()。

然后编译,应该是没有error,没有waring的。

5、在Driver目录下新建Bsp.c和Bsp.h两个文件,添加到工程里,并写入以下内容

Bsp.h

#ifndef _BSP_H#define _BSP_H#include "Global.h"void Bsp_init(void);static Bsp_gpioInit(void);#endif

Bsp.c

#include "Bsp.h"void Bsp_init(void){Bsp_gpioInit();}static Bsp_gpioInit(void){}

这样对工程的修整就差不多了。

接下来,我们就具体来编写GPIO部分的代码,只看GPIO的小伙伴们可以从这里开始。

首先,从我的原理图中可知我的板子的LED连接到了PD12-PD15

所以我就初始化这几个引脚

在Bsp_gpioInit函数里编写关于GPIO的初始化的部分。

static Bsp_gpioInit(void){GPIO_InitTypeDef gpioInitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);gpioInitStructure.GPIO_Mode = GPIO_Mode_OUT;gpioInitStructure.GPIO_OType = GPIO_OType_PP;gpioInitStructure.GPIO_Speed = GPIO_Speed_2MHz;gpioInitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;GPIO_Init(GPIOD, &gpioInitStructure);}

简单地说一下,第一句是定义一个GPIO的初始化类型变量,STM32基本为每种外设都设计了初始化类型。

然后是初始化时钟,使用大部分的模块前都需要初始化它的时钟。

然后就是配置那个初始化类型,首先是设置为输出(我们要驱动LED灯,显然单片机要主动),然后输出模式是推挽,由于我的板子的LED灯接法,开漏是亮不了滴,即需要输出高电平LED才会亮。再接着是配置管脚速度,2M基本够用,跑协议的话要快一些。再接着设置要初始化的管脚,就是LED对应的那个几个管脚。最后,调用初始化函数,初始化变量前面的&符合别漏了哦。

然后去main函数调用初始化函数,再调用一下写管脚高的指令,LED就可以亮起来了。

int main(void){Bsp_init();GPIO_WriteBit(GPIOD, GPIO_Pin_12, Bit_SET);GPIO_WriteBit(GPIOD, GPIO_Pin_13, Bit_SET);GPIO_WriteBit(GPIOD, GPIO_Pin_14, Bit_RESET);GPIO_WriteBit(GPIOD, GPIO_Pin_15, Bit_RESET); while(1) { }}

由于我的LED是共阴接法,所以,当管脚设置成Bit_SET时亮,设置成Bit_RESET时灭。

GPIO还是很简单的,其它常用的函数大家可以参考技术手册,都是一句话的事。




效果图


1 1