本次讲解以独立按键控制led灯为例
端口输入/输出
GPIO 端口的每个位可以由软件
配置成 8 种模式:
输入浮空(GPIO_Mode_IN_FLOATING),
输入上拉(GPIO_Mode_IPU),
输入下拉,模拟输入 (GPIO_Mode_AIN) ,
开 漏 输 出 (GPIO_Mode_Out_OD) ,
推挽输出(GPIO_Mode_Out_PP),
推挽复用功能(GPIO_Mode_AF_PP),
开漏复用功能(GPIO_Mode_AF_OD)。
本次实验只用到led的推挽输出(增加驱动电流)和独立按键的上拉输入
GPIO常用函数
GPIO配置方法
在对 GPIO 配置时,常用到函数 GPIO_Init()函数的说明如下表所示。
GPIO_InitTypeDef 的定义于文件“stm32f10x_gpio.h”,主要配置引脚、引脚速度、引脚输入输出模式等。引脚可以整个 IO 口一起配置,也可以一位或几个位一起配置,每个位以”|”隔开。引脚速度可以为 2MHz、10MHz、50MHz。引脚模式可以在模拟输入、浮空输入、下拉输入、上拉输入、开漏输出、推挽输出、复用开漏输出、复用推挽输出。
对 GPIO 的配置步骤如下:
1、打开指定 I/O 的时钟;
2、设定用到的 I/O 位;
3、设定 I/O 引脚传输速率;
4、设定 I/O 的工作模式;
5、调用 GPIO 初始化函数 GPIO_Init()把上面的配置写入寄存器;
6、I/O 的初始状态
独立按键和led的原理图
独立按键和led的代码配置
#include <stm32f10x.h>
void GPIO_LEDandKEY_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;//结构体定义
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); // 使能IO口时钟
//独立按键配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; //独立按键
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;// 上拉
GPIO_Init(GPIOE, &GPIO_InitStructure); //初始化PE的独立按键
// LED灯PE4,PE5配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽
GPIO_Init(GPIOE, &GPIO_InitStructure); //初始化PE的led
//预设LED状态
LED1_OFF;
LED2_OFF;
注意:我们在一个PE口上要同时配置两个不同状态的IO口,所以我们必须要有两次对IO口的初始化。如果我们需要在配置中加一些模块的状态我们需要将其写在初始化的下面,例如上示的预设LED。I/0口的输出模式下,有3种输出速度可选(2MHz、10MHz和50MHz), 这个速度是指/0口驱动电路的响应速度而不是输出信号的速度,输出信号的速度与程序有关。
#ifndef _LED_H
#define _LED_H
#define LED1_ON GPIO_ResetBits(GPIOE, GPIO_Pin_4)//
#define LED1_OFF GPIO_SetBits(GPIOE, GPIO_Pin_4)
#define LED1_State GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_4)
#define LED1_Toggle GPIO_WriteBit(GPIOE, GPIO_Pin_4, (BitAction)(1 - LED1_State))
#define LED2_ON GPIO_ResetBits(GPIOE, GPIO_Pin_5)
#define LED2_OFF GPIO_SetBits(GPIOE, GPIO_Pin_5)
#define LED2_State GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_5)
#define LED2_Toggle GPIO_WriteBit(GPIOE, GPIO_Pin_5, (BitAction)(1 - LED2_State))
#endif
这是led的.h文件,通过宏定义,可将其GPIO函数简单化,GPIO函数见第一张图。LED1_Toggle 是对 LED 灯取反操作,实现 LED 交替闪烁效果。LED1_Toggle 是通过 BitAction 枚举实现 IO 状态取反的,BitAction 库里定义的,其枚举值为 0 和 1。通过“#define LED1_State GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_4)”读取 LED1 的状态
后,再通过“(BitAction)(1-LED1_State)”就可以获得 LED1 相反的状态,在库文件stm32f10x_gpio.h中。
#ifndef x //先测试x是否被宏定义过
#define x //如果没有宏定义下面就宏定义x并编译下面的句 … #endif //如果已经定义了则编译#endif后面的语句
条件指示符#ifndef检查预编译常量在前面是否已经被宏定义。如果在前面没有被宏定义,则条件指示符的值为真,于是从#ifndef到#endif之间的所有语句都被包含进来进行编译处理。
void Key_Scan(void)
{
if ((KEY1 == 0) || (KEY2 == 0) || (KEY3 == 0) || (KEY4 == 0))
{
Delay_1ms(10); // 延时10ms去抖动
if (KEY1 == 0) // KEY1按下
{
LED1_Toggle;//通过BitAction枚举实现IO状态取反
while (KEY1 == 0)
; // 松手检测
}
if (KEY2 == 0)
{
LED2_Toggle;
while (KEY2 == 0)
;
}
}
以上是key.c代码
#ifndef _KEY_H
#define _KEY_H
#define KEY1 GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_0)
#define KEY2 GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_1)
#define KEY3 GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_2)
#define KEY4 GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3)
extern void Key_Scan(void);
#endif
在key.h中我们尤其要注意,这是上拉输入所以要选取GPIO_ReadInputDataBit和led.h唯一的区别就是Input换成Output,要搞清楚每个模块的输入输出状态,否则很容易搞混。由于我们在key.c中写了Key_Scan(void)函数,所以要在key.h中通过extern去外部函数声明,