STM32-Project13-15:(IO输入)GPIO按键检测;位带操作实现控制IO输入输出;启动文件详解

一 按键检测实验

  1. 使能 GPIO 端口时钟;

  1. 初始化 GPIO 目标引脚为输入模式(浮空输入);

  1. 编写简单测试程序,检测按键的状态,实现按键控制 LED 灯

#ifndef __KEY_H
#define __KEY_H
​
#include "stm32f10x.h"
​
#define KEY0_GPIO_PIN GPIO_Pin_4
#define KEY0_GPIO_PORT GPIOE
#define KEY0_GPIO_CLK  RCC_APB2Periph_GPIOE
​
#define key0_down  0
#define key0_up    1
​
​
uint8_t Key_Scan( GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
void KEY0_GPIO_Config(void);
void delay(uint32_t count);
#endif
​
#include "key.h"
​
void KEY0_GPIO_Config(void){
    GPIO_InitTypeDef  GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Pin = KEY0_GPIO_PIN;
    GPIO_InitStruct.GPIO_Mode =  GPIO_Mode_IN_FLOATING;
​
    RCC_APB2PeriphClockCmd(KEY0_GPIO_CLK, ENABLE );
    GPIO_Init(KEY0_GPIO_PORT,&GPIO_InitStruct);
    
}
​
void delay(uint32_t count){
    for(;count!=0;count--);
}
​
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin){
    
    if (GPIO_ReadInputDataBit(GPIOx, GPIO_Pin)==key0_down){
        delay(0xfff);//等待低电平稳定
        while (GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == key0_down);//等待按键释放
        return key0_down;
    }
    else
        return key0_up;
    
}
​
#include "stm32f10x.h"  
#include "led.h" 
#include "key.h"
//按键检测:Key0按下一次 Led0的状态就反转一次
//存在问题:按键抖动导致cpu检测到短时间电平状态忽高忽低
//此时LED0来回反转,最终以低电平检测结束,一直等待按键释放
//这时候灯反转。
​
int main(void)
{
     LED0_GPIO_Config();
     KEY0_GPIO_Config();
    
    while (1){
    if (Key_Scan(KEY0_GPIO_PORT,KEY0_GPIO_PIN)== key0_down)
            LED0_TOGGLE;
    }
}
​
​
​

二.GPIO—位带操作

位操作就是可以单独的对一个比特位读和写,这个在 51 单片机中非常常见。51 单片机中通过关键字 sbit 来实现位定义,STM32 没有这样的关键字,而是通过访问位带别名区来实现.

在 STM32 中,有两个地方实现了位带,一个是 SRAM 区的最低 1MB 空间,另外一个是外设区最低 1MB 空间。

外设外带区的地址为:0X40000000~0X40100000,大小为 1MB,这 1MB 的大小在 103系列大/中/小容量型号的单片机中包含了片上外设的全部寄存器,这些寄存器的地址为:0X40000000~0X40029FFF 。 外 设 位 带 区 经 过 膨 胀 后 的 位 带 别 名 区 地 址 为 :0X42000000~0X43FFFFFF

这里仅仅演示下 GPIO 中 ODR 和 IDR 这两个寄存器的位操作

#include "stm32f10x.h"  
#include "led.h" 
#include "key.h"
//位带操作LED0闪烁;位带操作检测IO输入电平高低
​
​
​
#define GPIOB_ODR_ADDR  (GPIOB_BASE+0x0c)
#define PBout(n)     *(unsigned int*)((GPIOB_ODR_ADDR&0xF0000000)+0x02000000+((GPIOB_ODR_ADDR&0x00FFFFFF)<<5)+(n<<2)) 
​
​
#define GPIOE_IDR_ADDR  (GPIOE_BASE+0x08)
#define PEin(n)     *(unsigned int*)((GPIOE_IDR_ADDR&0xF0000000)+0x02000000+((GPIOE_IDR_ADDR&0x00FFFFFF)<<5)+(n<<2)) 
​
​
void delay(uint32_t count){
    for(;count!=0;count--);
}
​
​
int main(void)
{
     LED0_GPIO_Config();
     KEY0_GPIO_Config();
    
#if 0
    while (1){
    //GPIO_SetBits(LED0_GPIO_PORT, LED0_GPIO_PIN5);
    //LED0(ON);
     PBout(5) = 1; 
        
     delay(0xfffff);
        
    //GPIO_ResetBits(LED0_GPIO_PORT, LED0_GPIO_PIN5);
     //LED0(OFF);
        PBout(5) = 0;       
    }
    
#else   
    while (1){
    if (PEin(4)== key0_down){
        while(PEin(4)== key0_down);
        LED0_TOGGLE;
    }
            
    }
#endif
}
​
三.启动文件详解

启动文件由汇编编写,是系统上电复位后第一个执行的程序。主要做了以下工作:

1、初始化堆栈指针 SP=_initial_sp

2、初始化 PC 指针=Reset_Handler

3、初始化中断向量表

4、配置系统时钟

5、调用 C 库函数_main 初始化用户堆栈,从而最终调用 main 函数去到 C 的世界

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

dpq666dpq666

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

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

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

打赏作者

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

抵扣说明:

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

余额充值