【STM32F407学习笔记】GPIO(二)

1. 输入模式

1.1 四种输入模式:

GPIO共有四种输入模式:

  • 输入浮空
  • 输入上拉
  • 输入下拉
  • 模拟输入

1.2 相关寄存器

  • GPIOx_MODER:端口模式寄存器
  • GPIOx_

2. 按键输入检测

对于按键输入检测,首先需要确定按键的状态。
不同状态的按键

  • 对于按下后为高电平的按键,则平时为低电平,设置端口为下拉输入,检测高电平
  • 对于按下后为低电平的按键,则平时为高电平,设置端口为上拉输入,检测低电平

在STM32F407 Discovery板载资源中,按键的形式为第一种,因此需要设置为输入下拉(PuPd_DOWN)

3. 相关操作

  • 库函数读取IO输入电平

    uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
    
  • 寄存器读取IO输入电平
    GPIOx_IDR:端口输入寄存器

    GPIOx->IDR&GPIO_Pin_x
    
  • 位带操作
    Bit-Banding简称位带。支持位带操作后,可以使用普通的加载存储指令来对单一的bit进行读写操作。
    在STM32中不能直接操作寄存器的某一个Bit位。例如单独控制PA端口输出数据寄存器中的ODR的位15:0只能以字(16位)的形式进行操作。
    为了能直接操作ODR这类的Bit位,在Cortex内核中开辟了一块地址区域:位带别名 ,可以将ODR这类Bit位(位带区)映射到(位带别名区),只需要操作映射后的位带别名区的地址就可以实现操作ODR的Bit位了。

    • 位带区:支持位带操作的地址区域
    • 位带别名:对别名地址的访问会最终作用到位带区上
    • 位带区->位带别名区计算公式:
      位带操作的主要目的:通过Bit位地址(A)计算得到位带别名区地址(AliasAddr)。
      • SRAM计算方式:
        AliasAddr = 0 x 22000000 + ( ( A‐ 0 x 20000000 ) × 8 + n ) × 4 = 0 x 42000000 + ( A − 0 x 20000000 ) × 32 + n × 4 \text{AliasAddr}= 0\text{x}22000000 + ((\text{A}‐0\text{x}20000000)\times8+n)\times4=0\text{x}42000000+( \text{A}- 0\text{x}20000000)\times32 + n\times4 AliasAddr=0x22000000+((A‐0x20000000)×8+n)×4=0x42000000+(A0x20000000)×32+n×4
      • 外设:
        AliasAddr = 0 x 42000000 + ( ( A‐ 0 x 40000000 ) × 8 + n ) × 4 = 0 x 42000000 + ( A − 0 x 40000000 ) × 32 + n × 4 \text{AliasAddr}= 0\text{x}42000000 + ((\text{A}‐0\text{x}40000000)\times8+n)\times4= 0\text{x}42000000+( \text{A}- 0\text{x}40000000)\times32 + n\times4 AliasAddr=0x42000000+((A‐0x40000000)×8+n)×4=0x42000000+(A0x40000000)×32+n×4

    由此可以对IO进行

    • 读取:PXin(n) ⇒ \Rightarrow 读取端口X的第n位输入,返回端口输入的值
    • 写入:PXout(n)=M ⇒ \Rightarrow 对端口X的第n位进行写入值M
    //计算映射地址
    #define BITBAND(addr,bitnum) ((addr&0xF00000000)+0x20000000+((addr&0xFFFFF)<<5)+(bitnum<<2))  
    //访问映射后的地址
    #define MEM_ADDR(addr) *((volatile unsigned long*)(addr)) '
    //由addr和bitnum计算出映射后的地址,然后访问
    #define BIT_ADDR(addr,bitnum) MEM_ADDR(BITBAND(addr,bitnum)) 
    // IO口地址映射
    #define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014
    #define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414 
    #define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814 
    #define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14 
    #define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 
    #define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414    
    #define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814   
    #define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14    
    #define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014     
     
    #define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010 
    #define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410 
    #define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810 
    #define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10 
    #define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 
    #define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 
    #define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810 
    #define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 
    #define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010 
    //IO口操作,只对单一的IO口!
    //确保n的值小于16!
    #define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
    #define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 
     
    #define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
    #define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 
     
    #define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
    #define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 
     
    #define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
    #define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 
     
    #define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
    #define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入
     
    #define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
    #define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入
     
    #define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
    #define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入
     
    #define PHout(n)   BIT_ADDR(GPIOH_ODR_Addr,n)  //输出 
    #define PHin(n)    BIT_ADDR(GPIOH_IDR_Addr,n)  //输入
     
    #define PIout(n)   BIT_ADDR(GPIOI_ODR_Addr,n)  //输出 
    #define PIin(n)    BIT_ADDR(GPIOI_IDR_Addr,n)  //输入
    

4. 实验验证

使用STM32F407Discovery套件,对端口输入和输出进行实验验证。首先需要初始化外设,分别是LED和Key。其中LED为PD13

// 挂载GPIOD的时钟
RCC->AHB1ENR|=1<<3;
// 配置GPIOD
// 普通输出模式
GPIOD->MODER&=~(3<<(13*2));
GPIOD->MODER|=(1<<(13*2)); //PD13
// 高速输出
GPIOD->OSPEEDR|=(3<<(13*2));
// 推挽输出
GPIOD->OTYPER|=(0<<13); 
// 输出上拉
GPIOD->PUPDR|=(1<<(13*2));

Key为PA0

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIOInitStructure;
GPIOInitStructure.GPIO_Mode=GPIO_Mode_IN;
GPIOInitStructure.GPIO_Pin=GPIO_Pin_0;//Pin0
GPIOInitStructure.GPIO_PuPd=GPIO_PuPd_DOWN;
GPIOInitStructure.GPIO_Speed=GPIO_Speed_100MHz;
GPIO_Init(GPIOA,&GPIOInitStructure);

编写按键扫描函数,使用库函数进行端口读入操作

uint8_t KeyScan(void)
{
	if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)!=0)// 有按键按下
	{
		delay_ms(20); // 延时消抖
		if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)!=0)
		{
			return 1;
		}
		return 0;
	}
	return 0;
}

主函数

int main(void)
{
	
	LED_Init();
	Key_Init();
	
	while(1)
	{
		if(KeyScan())// 有按键按下
		{
			GPIOD->BSRRL|=(1<<13);
		}
		else
		{
			GPIOD->BSRRH|=(1<<13);	
		}
		delay_ms(200);// 为了让按键按下后LED点亮的效果更明显
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值