阅读前提示: 我们使用的板子是正点原子的ALIENTEK精英STM32F103。本文使用固件库进行编程,因为使用固件库编程较为方便,且阅读程序也较易理解。
零、GPIO简介及其库函数
1. GPIO简介
7组IO口(具体地址可见头文件stm32f10x.h): GPIOA ~ GPIOG。每组IO口可控制7个寄存器,这7个寄存器可控制一组GPIO的16个IO口:
- GPIOx_CRL:端口配置低寄存器
- GPIOx_CRH:端口配置高寄存器
- GPIOx_IDR:端口输入寄存器
- GPIOx_ODR:端口输出寄存器
- GPIOx_BSRR:端口位设置/清除寄存器
- GPIOx_BRR:端口位清除寄存器
- GPIOx_LCKR:端口配置锁存寄存器
16个管脚(GPIO_Pin)(位于头文件stm32f10x_gpio.h): GPIO_Pin_0 ~ GPIO_Pin_15,若想全部选中则GPIO_Pin_All。
4种输入模式(GPIO_Mode)(位于头文件stm32f10x_gpio.h):
- 浮空输入(GPIO_Mode_IN_FLOATING)
- 上拉输入(GPIO_Mode_IPU)
- 下拉输入(GPIO_Mode_IPD)
- 模拟输入(GPIO_Mode_AIN)
4种输出模式(GPIO_Mode)(位于头文件stm32f10x_gpio.h):
- 开漏输出( GPIO_Mode_Out_OD)
- 复用开漏输出(GPIO_Mode_AF_OD)
- 推挽输出(GPIO_Mode_Out_PP)
- 复用推挽输出(GPIO_Mode_AF_PP)
3种最大输出速度(GPIO_Speed)(位于头文件stm32f10x_gpio.h):
- GPIO_Speed_2MHz
- GPIO_Speed_10MHz
- GPIO_Speed_50MHz
简要介绍常用的输出模式:
推挽输出:
可以输出强高低电平,连接数字器件。
开漏输出:
只可以输出强低电平,高电平得靠外部电阻拉高。输出端相当于三极管的集电极. 要得到高电平状态需要上拉电阻才行. 适合于做电流型的驱动,其吸收电流的能力相对强(一般20mA以内)
GPIO结构体定义(位于头文件stm32f10x_gpio.h):
1 2 3 4 5 6 7 8
| typedef struct { uint16_t GPIO_Pin;
GPIOSpeed_TypeDef GPIO_Speed;
GPIOMode_TypeDef GPIO_Mode; }GPIO_InitTypeDef;
|
2. 与GPIO有关的几个常用库函数
(1)初始化函数:
1
| void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
|
作用:初始化一个或者多个IO口(同一组)的工作方式和速度。该函数主要是操作GPIO_CRL(CRH)寄存器,在上拉或者下拉的时候有设置BSRR或者BRR寄存器。
(2)读取输入电平函数
读取某个GPIO的输入电平(实际操作的是GPIOx_IDR寄存器):
1
| uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
|
读取某组GPIO的输入电平(实际操作的是GPIOx_IDR寄存器):
1
| uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
|
(3)读取输出电平函数
读取某个GPIO的输出电平(实际操作的是GPIOx_ODR寄存器):
1
| uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
|
读取某组GPIO的输出电平(实际操作的是GPIOx_ODR寄存器):
1
| uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
|
(4)设置输出电平函数
设置某个IO口输出为高电平(实际操作BSRR寄存器):
1
| void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
|
设置某个IO口输出为低电平(实际操作的BRR寄存器):
1
| void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
|
不常用的两个函数:
1 2 3
| void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal); void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
|
(5)初始化GPIO口的一般步骤
我们以一段程序为例来说明初始化GPIO口的几个步骤。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
一、LED跑马灯的实现
本程序实现了两个LED轮流点亮及熄灭的效果。
有关LED的电路图如下所示:
从电路图中可知,当输出IO口电平为低电平时,LED灯亮;当输出IO口电平为高电平时,LED灯灭。
从LED电路图可知,LED0接在PB5,LED1接在PE5。选择的输出模式:推挽输出。
程序如下(本程序包含3个源文件,其中delay.h为正点原子资料盘内自带的头文件,亦可使用51单片机常用的简易延时函数,即循环延时法):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| #include "stm32f10x.h" #include "led.h" #include "delay.h"
int main(void) { delay_init(); LED_Init(); while(1) { GPIO_ResetBits(GPIOB, GPIO_Pin_5); GPIO_SetBits(GPIOE, GPIO_Pin_5); delay_ms(500); GPIO_SetBits(GPIOB, GPIO_Pin_5); GPIO_ResetBits(GPIOE, GPIO_Pin_5); delay_ms(500); } }
#ifndef __LED_H #define __LED_H
void LED_Init(void);
#endif
#include "led.h" #include "stm32f10x.h"
void LED_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_SetBits(GPIOB, GPIO_Pin_5); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_Init(GPIOE, &GPIO_InitStructure); GPIO_SetBits(GPIOE, GPIO_Pin_5); }
|
二、蜂鸣器循环响灭
有关蜂鸣器的电路图如下所示:
从电路图中可知,当输出IO口电平为低电平时,三极管处于截止状态,蜂鸣器不响;当输出IO口电平为高电平时,三极管处于放大状态,蜂鸣器响。BEEP接在PB8。
程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| #include "stm32f10x.h" #include "delay.h" #include "beep.h"
int main(void) { Beep_Init(); delay_init(); while(1) { GPIO_SetBits(GPIOB, GPIO_Pin_8); delay_ms(500); GPIO_ResetBits(GPIOB, GPIO_Pin_8); delay_ms(500); } }
#ifndef __BEEP_H #define __BEEP_H
void Beep_Init(void);
#endif
#include "stm32f10x.h" #include "beep.h"
void Beep_Init() { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_ResetBits(GPIOB, GPIO_Pin_8); }
|
三、蜂鸣器和LED灯循环
本程序实现了蜂鸣器与两个LED轮流工作的效果。前500ms,LED1和BEEP工作,后500ms,仅LED0工作。
为方便程序阅读,我们将设置高低电平的函数封装成宏。程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| #include "stm32f10x.h" #include "delay.h" #include "beep.h" #include "led.h"
int main(void) { LED_Init(); Beep_Init(); delay_init(); while(1) { BEEP_ON; LED0_OFF; LED1_ON; delay_ms(500); BEEP_OFF; LED0_ON; LED1_OFF; delay_ms(500); } }
#ifndef __LED_H #define __LED_H
#define LED0_OFF GPIO_SetBits(GPIOB, GPIO_Pin_5) #define LED0_ON GPIO_ResetBits(GPIOB, GPIO_Pin_5) #define LED1_OFF GPIO_SetBits(GPIOE, GPIO_Pin_5) #define LED1_ON GPIO_ResetBits(GPIOE, GPIO_Pin_5)
void LED_Init(void);
#endif
#include "stm32f10x.h" #include "led.h"
void LED_Init() { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_Init(GPIOE, &GPIO_InitStructure); LED0_OFF; LED1_OFF; }
#ifndef __BEEP_H #define __BEEP_H
#define BEEP_ON GPIO_SetBits(GPIOB, GPIO_Pin_8) #define BEEP_OFF GPIO_ResetBits(GPIOB, GPIO_Pin_8)
void Beep_Init(void);
#endif
#include "stm32f10x.h" #include "beep.h"
void Beep_Init() { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); BEEP_OFF; }
|