一.GPIO入门知识
全称: general purpose intput outpot(通用输入输出端口)。
可以做输入也可以做输出。STM32芯片的GPIO引脚与外部设备连接起来,从而实现与外部通讯,控制以及数据采集的功能。
二 .GPIO的八种工作模式
1.4种输入模式(可以读取端口的高低电平或者电压,用于读取按键输入,外接模块,电平信号输入,ADC电压采集,模拟通信协议接收数据(SPI,I2C))
输入浮空:可读取引脚电平,若引脚悬空,则电平不稳定。
输入上拉:可读取引脚电平,内部连接上拉电阻,悬空时默认高电平
输入下拉:可读取引脚电平,内部连接下拉电阻,悬空时默认低电平
模拟输入:GPIO无效,引脚直接接入内部ADC。
2.4种输出模式(带上下拉)--(可以控制端口输出高低电平,可用于驱动LED,控制蜂鸣器,模拟通信协议输出时序)
开漏输出:可输出引脚电平,高电平为高阻态,低电平接VSS
开漏复用输出:由片上外设控制,高电平为高阻态,低电平接VSS
推挽输出:可输出引脚电平,高电平接VDD,低电平接VSS
推挽复用输出:由片上外设控制,高电平接VDD,低电平接VSS
3.4种最大输出速度
2MHZ(低速)
25MHZ(高速)
50MHZ(快速)
100MHZ(高速)
4.上电复位后IO口的状态
上电复位后,GPIO默认为浮空状态,部分特殊功能引脚为特定状态。
复位后,调试引脚处于复用功能上拉/下拉状态。
PA15:JTDI处于上拉状态
PA14:JTCK/SWCLK处于下拉状态
PA13:JTMS/SWDAT处于下拉状态
PB4:NJTRS处于下拉状态
PB 3:JTDO处于浮空状态。
三. GPIO寄存器
每一组IO口都包含10个寄存器,
其中有4个32为配置寄存器
模式寄存器 GPIOx_MODER
00:输入模式(复位状态) 01:通用输出模式
10:复用功能模式 11:模拟模式
输出类型寄存器GPIOx_OTYPER
0:推挽输出(复位状态) 1:开漏输出
输出速度寄存器GPIOx_OSPEEDR
00:低速 01:中速
10:快速 11:高速
上拉下拉寄存器 GPIOx_PUPDR
00:无上拉或者下拉 01:上拉
10:下拉 11:保留
2个32位的数据寄存器
输入数据寄存器GPIOx_IDR
1:高电平 0:低电平
输出数据寄存器GPIOx_ODR
1:高电平 0:低电平
1个32位置位/复位寄存器
置位/复位寄存器GPIOx_BSRR
控制输出的电平状态,
低16位端口置位 1:高电平 0:不影响
高16位端口复位 1:复位,输出0 0:不影响
1个32位的锁存寄存器
配置锁存寄存器 GPIOx_LCKR
2个32位复用功能共寄存器
复用功能寄存器(低位GPIOx_AFRL&高GPIO_AFRH)
四. 跑马灯实验
1.寄存器
led.h
#ifndef __LED_H_
#define __LED_H_
#include "sys.h"
//LED 端口定义
#define LED0 PBout(1) // DS0
#define LED1 PBout(0) // DS1
void LED_Init(void);
#endif
led.c
#include "LED.h"
void LED_Init(void)
{
RCC->AHB1ENR|=1<<1;//使能PORTB时钟
GPIO_Set(GPIOB,PIN0|PIN1,GPIO_MODE_OUT,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD_PU); //PB0,PB1设置
LED0=1;//LED0关闭
LED1=1;//LED1关闭
}
main
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "LED.h"
int main(void)
{
Stm32_Clock_Init(360,25,2,8);
delay_init(180);
LED_Init();
while(1)
{
LED0=0; //DS0亮
LED1=1; //DS1灭
delay_ms(500);
LED1=0; //DS0灭
LED0=1; //DS1亮
delay_ms(500);
}
}
2.HAL库版本
led.h
#ifndef _LED_H
#define _LED_H
#include "sys.h"
#define LED0 PBout(1) //LED0
#define LED1 PBout(0) //LED1
void LED_Init(void);
#endif
led.c
#include "led.h"
//初始化PB1为输出.并使能时钟
//LED IO初始化
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOB_CLK_ENABLE(); //开启GPIOB时钟
GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1; //PB1,0
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET); //PB0置1,默认初始化后灯灭
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET); //PB1置1,默认初始化后灯灭
}
main
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
int main(void)
{
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(360,25,2,8); //设置时钟,180Mhz
delay_init(180); //初始化延时函数
LED_Init(); //初始化LED
while(1)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET); //LED0对应引脚PB1拉低,亮,等同于LED0(0)
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET); //LED1对应引脚PB0拉高,灭,等同于LED1(1)
delay_ms(500); //延时500ms
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET); //LED0对应引脚PB1拉高,灭,等同于LED0(1)
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET); //LED1对应引脚PB0拉低,亮,等同于LED1(0)
delay_ms(500); //延时500ms
}
}
五.按键控制LED
KEY.h
#ifndef _KEY_H
#define _KEY_H
#include "sys.h"
#define KEY0 HAL_GPIO_ReadPin(GPIOH,GPIO_PIN_3) //KEY0按键PH3
#define KEY1 HAL_GPIO_ReadPin(GPIOH,GPIO_PIN_2) //KEY1按键PH2
#define KEY2 HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13) //KEY2按键PC13
#define WK_UP HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) //WKUP按键PA0
#define KEY0_PRES 1
#define KEY1_PRES 2
#define KEY2_PRES 3
#define WKUP_PRES 4
void KEY_Init(void);
u8 KEY_Scan(u8 mode);
#endif
KEY.c
#include "key.h"
#include "delay.h"
//
//按键初始化函数
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
__HAL_RCC_GPIOC_CLK_ENABLE(); //开启GPIOC时钟
__HAL_RCC_GPIOH_CLK_ENABLE(); //开启GPIOH时钟
GPIO_Initure.Pin=GPIO_PIN_0; //PA0
GPIO_Initure.Mode=GPIO_MODE_INPUT; //输入
GPIO_Initure.Pull=GPIO_PULLDOWN; //下拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
GPIO_Initure.Pin=GPIO_PIN_13; //PC13
GPIO_Initure.Mode=GPIO_MODE_INPUT; //输入
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOC,&GPIO_Initure);
GPIO_Initure.Pin=GPIO_PIN_2|GPIO_PIN_3; //PH2,3
HAL_GPIO_Init(GPIOH,&GPIO_Initure);
}
//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//0,没有任何按键按下
//1,WKUP按下 WK_UP
//注意此函数有响应优先级,KEY0>KEY1>KEY2>WK_UP!!
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1; //按键松开标志
if(mode==1)key_up=1; //支持连按
if(key_up&&(KEY0==0||KEY1==0||KEY2==0||WK_UP==1))
{
delay_ms(10);
key_up=0;
if(KEY0==0) return KEY0_PRES;
else if(KEY1==0) return KEY1_PRES;
else if(KEY2==0) return KEY2_PRES;
else if(WK_UP==1) return WKUP_PRES;
}else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0)key_up=1;
return 0; //无按键按下
}
main
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
{
u8 key;
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(360,25,2,8); //设置时钟,180Mhz
delay_init(180); //初始化延时函数
uart_init(115200); //初始化USART
LED_Init(); //初始化LED
KEY_Init(); //初始化按键
while(1)
{
key=KEY_Scan(0); //按键扫描
switch(key)
{
case WKUP_PRES: //控制LED0,LED1互斥点亮
LED1=!LED1;
LED0=!LED1;
break;
case KEY2_PRES: //控制LED0翻转
LED0=!LED0;
break;
case KEY1_PRES: //控制LED1翻转
LED1=!LED1;
break;
case KEY0_PRES: //同时控制LED0,LED1翻转
LED0=!LED0;
LED1=!LED1;
break;
}
delay_ms(10);
}
}