STM32103ZET6 GPIO

  • GPIO(General-purpose input/output)通用-型输入/输出

【 1. 工作模式 】

1.1 GPIO基本结构

在这里插入图片描述

1.2 四种输入模式 - 读

1.2.1 输入浮空 GPIO_Mode_IN_FLOATING

  • I/O 电平由外部上下拉决定,并可被CPU读到。
  • 一般多用于外部按键输入。
  • 上电复位后,GPIO默认为输入浮空状态。

在这里插入图片描述

1.2.2 输入上拉 GPIO_Mode_IPU

  • 无外接上下拉时 IO 处于高电平,CPU读 IO 为高电平(这是因为内部上拉电阻处的开关闭合,电平拉高)
  • PS 输入上、下拉必要性:如果没有上拉,在没有外界输入的情况下输入端是悬空的,它的电平是未知的也就是说是无法保证的,上拉就是为了保证无信号输入时输入端的电平为高电平,同样 下拉是为了保证无信号输入时输入端的电平为低电平。

在这里插入图片描述

1.2.3 输入下拉 GPIO_Mode_IPD

  • 无外接上下拉时 IO 处于低电平,CPU读 IO 为低电平(这是因为内部下拉电阻处的开关闭合,即内部接上拉电阻,电平被拉低)

在这里插入图片描述

1.2.4 模拟输入 GPIO_Mode_AIN

  • 模拟量转化为数字量,被CPU读到。

在这里插入图片描述

1.3 四种输出模式 - 写

1.3.1 开漏输出 GPIO_Mode_Out_OD

在这里插入图片描述

  • 此时输出控制电路的作用:点击此处是有关场效应管的知识
    1. 令P-MOS管栅极G的电压为高电平,从而让P-MOS管截止、完全不工作。
    2. 选择器与N-MOS管之间的输出控制电路相当于一个反相器:写为 1/0 时,N-MOSA管栅极G处为 0/1
      在这里插入图片描述
  • 于是我们将上图简化,得到下图所示开漏输出的N-MOS门电路:
    • 写 为 1 时,经输出控制电路内部的反向器到达栅极Gate Input 处变为 0,NMOS管不工作,此时 I/O为高阻态,电平由外部上下拉决定,并可被CPU读到
    • 写 为 0 时,经输出控制电路内部的反向器到达到栅极Gate Input 处变为 1,NMOS管工作,I/O被下拉成低电平,并可被CPU读到低电平
    • 开漏输出输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行,适合做电流型的驱动,其吸收电流的能力相对较强(20mA以内)
      在这里插入图片描述
  • 一句话总结:开漏输出,写 0 输出0,写 1 输出高阻(外部加上拉电阻时,写 1 输出 1)。

1.3.2 开漏复用输出 GPIO_Mode_AF_OD

  • 电路的基本原理和开漏输出类似:
    • 外设模块输出为1,I/O电平由外部上下拉决定,并可被CPU读到;
    • 外设模块输出为0,I/O为低电平,并可被CPU读到低电平。

在这里插入图片描述

1.3.3 推挽输出 GPIO_Mode_Out_PP

在这里插入图片描述

  • 此时输出控制电路的作用:
    选择器与两个MOS管之间的输出控制电路相当于一个反相器:写为 1/0 时,两个MOS管栅极处都为 0/1。
    在这里插入图片描述

  • 于是,当写为 1/0 且无外部上下拉时,I/O为 高/低 电平,并可被CPU读到 1/0 ;

    • 写 为 1 时,反向后为0,NMOS管截止,PMOS管电流从S -> G -> D,输出为1 ,灌电流
    • 写 为 0 时,反向后为1,PMOS管截止,NMOS管电流从D -> G -> S,输出为0 ,拉电流
  • 两个管子轮流导通,使其负载能力和开关速度都比普通的方式有很大的提高。

  • 推挽输出的低电平为 0伏,高电平为 3.3伏。

  • 一句话总结:推挽输出,写 0 输出 0,写 1 输出1(其带负载能力很大)。

1.3.4 推挽式复用输出 GPIO_Mode_AF_PP

  • 电路的基本原理和推挽输出类似:
    • 复用功能输出为 1/0 且无外部上下拉时,I/O为 高/低 电平,并可被CPU读到 1/0。

在这里插入图片描述

1.3.5 推挽输出和开漏输出在应用上的区别

在这里插入图片描述

1.4 三种最大翻转速度

  • 2MHZ
  • 10MHz
  • 50MHz

【 2. 相关寄存器 】

  • STM32103ZET6共有7组GPIO(从A到G),每组GPIO有16个端口(从0到15),每组GPIO端口有以下7个寄存器,每组寄存器可以控制16个I/O端口。

    GPIOx_CRL :端口配置低寄存器
    GPIOx_CRH:端口配置高寄存器
    GPIOx_IDR:端口输入寄存器
    GPIOx_ODR:端口输出寄存器
    GPIOx_BSRR:端口位设置/清除寄存器
    GPIOx_BRR :端口位清除寄存器
    GPIOx_LCKR:端口配置锁存寄存器   
    
  • 每个I/O端口位可以自由编程,然而I/O端口寄存器必须按32位字被访问(不允许半字或字节访问) 。所有IO口都可以作为中断输入。

2.1 端口 工作模式配置 寄存器(GPIOx_CRL , GPIOx_CRH)

  • 选择GPIO工作模式

GPIOx_CRH在这里插入图片描述GPIOx_CRL
在这里插入图片描述端口配置表
在这里插入图片描述

  1. 每组GPIO有16个IO口,每个IO口需要4位来控制,这4位分成两部分,每部分2位,低2位的部分用于选择输入或输出、速度,高2位的部分用于选择输入或输出的模式
  2. GPIOx_CRL用于控制低8个IO口,GPIOx_CRH用于控制高8个IO口。(例如:GPIOA_CRL控制PA0-PA7,GPIOA_CRH控制PA8-PA15)。

2.2 端口 输入数据 寄存器( GPIOx_IDR )

  • 读取 I/O 口电平
    在这里插入图片描述

2.3 端口 输出数据 寄存器 ( GPIOx_ODR )

  • 控制 I/O 口输出
    在这里插入图片描述

2.4 端口 位设置/清除 寄存器(GPIOx_BSRR)

  • 间接地设置ODR来控制端口输出
    在这里插入图片描述

2.5 端口 位清除 寄存器(GPIOx_BRR)

  • 间接地清除ODR来控制端口输出
    在这里插入图片描述

2.6 GPIO 使能 寄存器 (RCC_APB2ENR)

  • (APB2 外设时钟使能寄存器 (RCC_APB2ENR) 32位 )
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

【 3. 相关函数 】

  • 头文件:stm32f10x_gpio.h
  • 源文件:stm32f10x_gpio.c

3.1 使能函数

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx,ENABLE);

3.2 初始化函数

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
  1. 作用
    初始化一个或多个IO口(同一组)的工作方式。
    该函数主要是操作GPIO_CRL(CRH)寄存器,在上拉或者下拉的时候有设置BSRR或者BRR寄存器。
  2. 范例
 GPIO_InitTypeDef  GPIO_InitStructure;	 //定义GPIO参数结构体
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;    //选择要配置的IO口
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);	 //根据设定参数初始化GPIOB.5

3.3 读取输入电平

uint8_t  GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t  GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
  1. 作用
    读取GPIO的输入电平。实际操作的是GPIOx_IDR寄存器。
  2. 范例
GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5);//读取PA^5的输入电平
GPIO_ReadInputData(GPIOA);//读取GPIOA组中所有IO口输入电平

3.4 读取输出电平

uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//读取GPIOx组下某个引脚电平
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx); //读取GPIOx该组所有引脚输出电平
  1. 作用
    读取GPIO的输出电平。实际操作的是GPIO_ODR寄存器。
  2. 范例
GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_5);//读取GPIOA.5的输出电平
GPIO_ReadOutputData(GPIOA);//读取GPIOA组中所有io口输出电平

3.5 设置输出电平

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //输出置1
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//输出置0
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);//不常用
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal); //不常用

作用

  1. void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
    设置某个IO口输出为高电平1。实际操作BSRR寄存器
  2. void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
    设置某个IO口输出为低电平0。实际操作的BRR寄存器。
  3. void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
    void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
    这两个函数不常用,也是用来设置IO口输出电平。

【 4. 范例:开关灯 】

  • 硬件设计1:
    根据下图分析,三个按键可以设置成上拉输入模式,即未按下按键时,由于内部上拉电阻的作用,I/O口为高电平;当按键按下后,I/O口被下拉到低电平。
    在这里插入图片描述
  • 硬件设计2:
    根据下图分析,两个LED可设置为推挽输出模式(即写0输出0,写1输出1),正常的让LED输出高/低即可灭/亮。
    在这里插入图片描述
  • 软件设计:
//按键控制灯的闪烁
#include "stm32f10x.h"
#include "sys.h"

#define LED0 PBout(5)// PB5
#define LED1 PEout(5)// PE5	

#define KEY0  GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)//读取按键0
#define KEY1  GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)//读取按键1
#define KEY2  GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)//读取按键2 
#define WK_UP GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//读取按键3(WK_UP) 

#define KEY0_PRES 	1	//KEY0按下
#define KEY1_PRES	2	//KEY1按下
#define KEY2_PRES	3	//KEY2按下
#define WKUP_PRES   4	//KEY_UP按下(即WK_UP/KEY_UP)

/**********************************
延时函数
**********************************/
 void Delay(u32 count)
 {
   u32 i=0;
   for(;i<count;i++);
 }
 
/**********************************
按键判断
返回按键值
mode:0,不支持连续按;1,支持连续按;
0,没有任何按键按下
1,KEY0按下
2,KEY1按下
3,KEY2按下 
4,KEY3按下 WK_UP
注意此函数有响应优先级,KEY0>KEY1>KEY2>KEY3!! 
**********************************/
u8 KEY_Scan(u8 mode)
{	 
	static u8 key_up=1;//按键按松开标志
	if(mode)key_up=1;  //支持连按		  
	if(key_up&&(KEY0==0||KEY1==0||KEY2==0||WK_UP==1))
	{
		Delay(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;// 无按键按下
}

/**********************************
初始化LED
**********************************/
void led_init(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure; //定义GPIO参数结构体
	 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);//使能PB,PE端口时钟
  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;			    //选择IO: 5 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 	 //推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	 //IO口速度为50MHz
  GPIO_Init(GPIOB, &GPIO_InitStructure);			     //将结构体参数配置到GPIOB
  GPIO_SetBits(GPIOB,GPIO_Pin_5);					//PB^5 输出高

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;	 //选择IO: 5
  GPIO_Init(GPIOE, &GPIO_InitStructure);	 //将结构体参数配置到GPIOE
  GPIO_SetBits(GPIOE,GPIO_Pin_5); 			 //PE^5 输出高 	
}
/**********************************
初始化key
**********************************/
void key_init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO参数结构体
 
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);//使能GPIOA,GPIOE时钟

	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;//选择IO: 2,3,4
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
 	GPIO_Init(GPIOE, &GPIO_InitStructure);//将结构体参数配置到GPIOE

	//初始化 WK_UP-->GPIOA.0	  下拉输入
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0; //选择IO:0
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //设置成输入,默认下拉	  
	GPIO_Init(GPIOA, &GPIO_InitStructure);//将结构体参数配置到GPIOA

}

int main(void)
 {	 	  
	vu8 key=0;	
 	led_init();			     //LED端口初始化
	key_init();          //初始化与按键连接的硬件接口
	LED0=0;					//先点亮红灯
	while(1)
	{
 		key=KEY_Scan(0);	//得到键值
	   	if(key)
		{						   
			switch(key)
			{				 
				case KEY2_PRES:	//控制LED0翻转
					LED0=!LED0;
					break;
				case KEY1_PRES:	//控制LED1翻转	 
					LED1=!LED1;
					break;
				case KEY0_PRES:	//同时控制LED0,LED1翻转 
					LED0=!LED0;
					LED1=!LED1;
					break;
			}
		}
		else Delay(10); 
	}	 
	
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MR_Promethus

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值