• 野火霸天虎 STM32F407 学习笔记_5 按键输入;位带操作介绍


    输入——按键点灯

    开发板按键电路如下:

    image-20231109191525189

    按键未按下接地,按下后为高电平。电容起到消抖作用,软件处理就不需要手动延时消抖了。

    编程没啥难度,就是改了一下输入模式。使用 ReadInputDataBits 读取。

    //bsp_button.c
    #include "bsp_button.h"
    
    void Button_GPIO_Config(void){
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
        {
            GPIO_InitTypeDef GPIOInitStruct;
            GPIOInitStruct.GPIO_Mode=GPIO_Mode_IN;
            GPIOInitStruct.GPIO_Pin=GPIO_Pin_0;
            GPIOInitStruct.GPIO_OType=GPIO_OType_PP;
            GPIOInitStruct.GPIO_Speed=GPIO_Speed_50MHz;
            GPIOInitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;
            
            GPIO_Init(GPIOA,&GPIOInitStruct);
        }
    }
    
    //main.c
    #include "stm32f4xx.h"
    
    #include "bsp_led.h"
    #include "bsp_button.h"
    
    int main()
    {
        //RCC
        LED_GPIO_Config();
        Button_GPIO_Config();
        while (1)
        {
            if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0))GPIO_SetBits(GPIOF, GPIO_Pin_6);
            else GPIO_ResetBits(GPIOF, GPIO_Pin_6);
        }
    }
    
    • 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

    实现按键按下后翻转:

    int main()
    {
        //RCC
        LED_GPIO_Config();
        Button_GPIO_Config();
        while (1)
        {
            if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==Bit_SET){
                while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==Bit_SET);
                GPIO_ToggleBits(GPIOF, GPIO_Pin_6);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    要等到按键松开的时候再翻转,轮询直到松开。

    位带操作

    之前51单片机常见位定义。比如 PA 引脚有8个 IO 口,我们可以定义 sbit LED1=PA^0 这样单独操作某一位。

    stm32 里没有直接的位定义方式。一种解决办法是我们利用与或操作不影响其他位的同时操作特定位;另一种就是位带操作。

    stm32 里有一部分别名区域,用于映射外设、SRAM 中特定的位带区,我们操作这一部分别名区域时就可以实现对外设、SRAM 位带区与的位操作。

    片上外设位带区:0X4000 0000~0X400F 0000,别名区:0X4200 0000~0X43FF FFFF,包含 APB12,AHB1 外设。

    SRAM 位带区:0X2000 0000~0X200F 0000,别名区:0X2200 0000~0X23FF FFFF

    image-20231109220918350

    外设地址 A 别名地址为:AliasAddr= =0x42000000+ (A-0x40000000)84 +n*4 (n是位序号)

    SRAM 地址 A 别名地址为:AliasAddr= =0x22000000+ (A-0x20000000)84 +n*4

    扩大了32倍,可以对32位寄存器中的每一位进行操作。

    统一公式:\#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x02000000+((addr & 0x000FFFFF)<<5)+(bitnum<<2))

    使用:比如我们操作一个 GPIO 的位操作。

    #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x02000000+((addr & 0x000FFFFF)<<5)+(bitnum<<2))
    // 把一个地址转换成一个指针
    #define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
    // 把位带别名区地址转换成指针
    #define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
    
    // GPIO ODR 和 IDR 寄存器地址映射
    #define GPIOF_ODR_Addr (GPIOF_BASE+20)
    #define GPIOF_IDR_Addr (GPIOF_BASE+16)
    
    // 单独操作 GPIO 的某一个 IO 口,n(0,1,2...15),
    // n 表示具体是哪一个 IO 口
    #define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出
    #define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入
    
    //使用示例
    PFout(6)= 0;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    这个概念学学就好,好像实际应用没啥意义。我们微处理器考试也考过hh。

  • 相关阅读:
    shell命令合集(loading)
    21.4 Python 使用GeoIP2地图定位
    Standard Template Libary or C++ Standard Library
    DDoS防护方式以及产品
    vBox+K8s坑记录
    记一次断电引起的CentOS引导失败
    C++提高篇——STL(上)
    动作捕捉用于仿生机器人的运动规划
    uvm白皮书练习_ch2_ch231_加入transaction
    Linux操作文件的底层系统调用
  • 原文地址:https://blog.csdn.net/jtwqwq/article/details/134322171