日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

STM32-GPIO学习-跑马灯实验和按键实验-寄存器版本和HAL库版本

發(fā)布時(shí)間:2025/3/12 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32-GPIO学习-跑马灯实验和按键实验-寄存器版本和HAL库版本 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、stm32跑馬燈實(shí)驗(yàn)

a.GPIO

  • general purpose input output

  • 通用輸入輸出端口,可以做輸入也可做輸出,GPIO端口可通過(guò)程序配置成輸入或輸出。

  • STM32FXXXIGT6一共9組IO:PA~ PI,其中PA~ PH每組16個(gè)IO,PI只有PI0~PI11。16*8+12=140,一共140個(gè)IO口。

  • STM32大部分引腳除了當(dāng)GPIO用,還可復(fù)用為外設(shè)功能引腳,比如串口。節(jié)省引腳資源。

b.GPIO的8種工作模式

  • 4種輸入模式:輸入浮空、輸入上拉、輸入下拉、模擬輸入
  • 4種輸出模式帶上下拉:開漏輸出(帶上拉或下拉)、開漏復(fù)用功能、推挽式輸出、推挽式復(fù)用
  • 推挽輸出可以輸出強(qiáng)高低電平,連接數(shù)字器件
  • 開漏輸出只可以輸出強(qiáng)低電平,高電平得靠外部電阻拉高。輸出端相當(dāng)于三級(jí)管的集電極

c.GPIO寄存器

4個(gè)32位配置寄存器

GPIOx_MODER 模式

GPIOx_OTYPER 輸出類型

GPIOx_OSPEEDR 輸出速度

GPIOx_PUPDR 上拉下拉

2個(gè)32位數(shù)據(jù)寄存器

GPIOx_IDR 輸入數(shù)據(jù)

GPIOx_ODR 輸出數(shù)據(jù)

1個(gè)32位置位/復(fù)位寄存器

GPIOx_BSRR 置位/復(fù)位

1個(gè)32位鎖存寄存器

GPIOx_LCKR 配置鎖存

2個(gè)32位復(fù)用功能寄存器

GPIOx_AFRL&GPIOx_AFRH 復(fù)用功能

  • 每組IO口由10個(gè)寄存器組成
  • 如果配置一個(gè)IO口需要2個(gè)位,32位寄存器配置一組IO口,16個(gè)IO口
  • 如果配置一個(gè)IO口只需要1個(gè)位,高16位保留

1.寄存器定義

F767:stm32f767xx.h

文件中查找GPIO得到:

typedef struct {__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */__IO uint32_t BSRR; /*!< GPIO port bit set/reset register, Address offset: 0x18 */__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */__IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */ } GPIO_TypeDef;

再查找GPIO_TypeDef找到:

#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) #define GPIOB ((GPIO_TypeDef *) GPIOB_BASE) #define GPIOC ((GPIO_TypeDef *) GPIOC_BASE) #define GPIOD ((GPIO_TypeDef *) GPIOD_BASE) #define GPIOE ((GPIO_TypeDef *) GPIOE_BASE) #define GPIOF ((GPIO_TypeDef *) GPIOF_BASE) #define GPIOG ((GPIO_TypeDef *) GPIOG_BASE) #define GPIOH ((GPIO_TypeDef *) GPIOH_BASE) #define GPIOI ((GPIO_TypeDef *) GPIOI_BASE) #define GPIOJ ((GPIO_TypeDef *) GPIOJ_BASE) #define GPIOK ((GPIO_TypeDef *) GPIOK_BASE)

可以看出GPIOA是一個(gè)結(jié)構(gòu)體指針,它指向基地址。

GPIOA->ODR即可訪問(wèn)GPIOA端口的ODR輸出寄存器。

2.跑馬燈硬件連接

可以看到,兩個(gè)LED燈,一端連到LED0、LED1,另一端通過(guò)上拉電阻連到VCC。如果PB0輸出0,那么LED1導(dǎo)通。

GPIO輸出方式:采用可以輸出高低電平的 推挽輸出(上拉)

3.配置寄存器操作IO口步驟

  • 初始化HAL庫(kù):HAL_Init();

  • 初始化系統(tǒng)時(shí)鐘:

    stm32F767:Stm32_Clock_Init(431,25,2,9);

  • 使能IO口時(shí)鐘。配置IO口時(shí)鐘使能寄存器:RCC->AHB1ENR

    RCC AHB1 外設(shè)時(shí)鐘寄存器 (RCC_AHB1ENR)

  • 初始化IO口模式。配置四個(gè)配置寄存器

    GPIOx_MODER、GPIOx_OTYPER、GPIOx_OSPEEDR、GPIOx_PUPDR

  • 操作IO口,輸出高低電平

    配置寄存器GPIOX_ODR或者GPIOx_BSRR

  • 4.手寫跑馬燈

    在HALLIB里面的stm32f7xx_hal.c文件中可以找到HAL_Init函數(shù),復(fù)制過(guò)來(lái)粘到main()文件中,完成了初始化HAL庫(kù)。

    在SYSTEM里面的sys.c文件中找到Stm32_Clock_Init函數(shù),復(fù)制過(guò)來(lái)粘到main()文件中,完成了初始化系統(tǒng)時(shí)鐘。

    在HALLIB里面的stm32f7xx_hal.c文件中搜索RCC_TypeDef,可以看到:

    typedef struct {__IO uint32_t CR; /*!< RCC clock control register, Address offset: 0x00 */__IO uint32_t PLLCFGR; /*!< RCC PLL configuration register, Address offset: 0x04 */__IO uint32_t CFGR; /*!< RCC clock configuration register, Address offset: 0x08 */__IO uint32_t CIR; /*!< RCC clock interrupt register, Address offset: 0x0C */__IO uint32_t AHB1RSTR; /*!< RCC AHB1 peripheral reset register, Address offset: 0x10 */__IO uint32_t AHB2RSTR; /*!< RCC AHB2 peripheral reset register, Address offset: 0x14 */__IO uint32_t AHB3RSTR; /*!< RCC AHB3 peripheral reset register, Address offset: 0x18 */uint32_t RESERVED0; /*!< Reserved, 0x1C */__IO uint32_t APB1RSTR; /*!< RCC APB1 peripheral reset register, Address offset: 0x20 */__IO uint32_t APB2RSTR; /*!< RCC APB2 peripheral reset register, Address offset: 0x24 */uint32_t RESERVED1[2]; /*!< Reserved, 0x28-0x2C */__IO uint32_t AHB1ENR; /*!< RCC AHB1 peripheral clock register, Address offset: 0x30 */__IO uint32_t AHB2ENR; /*!< RCC AHB2 peripheral clock register, Address offset: 0x34 */__IO uint32_t AHB3ENR; /*!< RCC AHB3 peripheral clock register, Address offset: 0x38 */uint32_t RESERVED2; /*!< Reserved, 0x3C */__IO uint32_t APB1ENR; /*!< RCC APB1 peripheral clock enable register, Address offset: 0x40 */__IO uint32_t APB2ENR; /*!< RCC APB2 peripheral clock enable register, Address offset: 0x44 */uint32_t RESERVED3[2]; /*!< Reserved, 0x48-0x4C */__IO uint32_t AHB1LPENR; /*!< RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 */__IO uint32_t AHB2LPENR; /*!< RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 */__IO uint32_t AHB3LPENR; /*!< RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 */uint32_t RESERVED4; /*!< Reserved, 0x5C */__IO uint32_t APB1LPENR; /*!< RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 */__IO uint32_t APB2LPENR; /*!< RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 */uint32_t RESERVED5[2]; /*!< Reserved, 0x68-0x6C */__IO uint32_t BDCR; /*!< RCC Backup domain control register, Address offset: 0x70 */__IO uint32_t CSR; /*!< RCC clock control & status register, Address offset: 0x74 */uint32_t RESERVED6[2]; /*!< Reserved, 0x78-0x7C */__IO uint32_t SSCGR; /*!< RCC spread spectrum clock generation register, Address offset: 0x80 */__IO uint32_t PLLI2SCFGR; /*!< RCC PLLI2S configuration register, Address offset: 0x84 */__IO uint32_t PLLSAICFGR; /*!< RCC PLLSAI configuration register, Address offset: 0x88 */__IO uint32_t DCKCFGR1; /*!< RCC Dedicated Clocks configuration register1, Address offset: 0x8C */__IO uint32_t DCKCFGR2; /*!< RCC Dedicated Clocks configuration register 2, Address offset: 0x90 */} RCC_TypeDef;

    可以找到AHB1ENR。由寄存器可知只需要改變位1。在main中寫RCC->AHB1ENR |=1<<1(1左移一位,然后或上RCC->AHB1ENR可以把位1置為1),或者寫成RCC->AHB1ENR=0x02。

    • 配置GPIO端口模式寄存器GPIOx_MODER

    因?yàn)樾枰渲玫亩丝谖皇?和1,所以需要配置MODER1和MODER0.因?yàn)槭峭仆燧敵?#xff0c;所以設(shè)置最后四個(gè)位0101,那么也就是5,最終MODER寄存器設(shè)置成0x05。在main函數(shù)中寫上GPIOB->MODER=0x05。

    • 接著配置GPIO 端口輸出類型寄存器 (GPIOx_OTYPER)

    由于是推挽輸出,所以端口0和1都是0。在main函數(shù)中寫上GPIOB->OTYPER=0x00;

    • 接著配置GPIO 端口輸出速度寄存器 (GPIOx_OSPEEDR)

    設(shè)置為高速的話后面兩個(gè)端口的兩個(gè)位也都是11。這樣的話設(shè)置成GPIOB->OSPEEDR=0x0f;雖然只寫了8位,但是他其實(shí)一共有32位,前面都是零,可以省略不寫,但是要規(guī)范的話是需要把0全寫上補(bǔ)滿32位。

    • 配置GPIO 端口上拉/下拉寄存器 (GPIOx_PUPDR)

    這里要配置為上拉,所以后面兩個(gè)端口都是0101,也就是要設(shè)置成GPIOB->PUPDR=0x05;

    然后操作IO口,輸出高低電平,配置寄存器GPIOX_ODR或者GPIOx_BSRR。

    要配置端口1和0輸出高電平,也就是需要BS1和BS0為1,其它位保持不變?yōu)?,也就是說(shuō)要配置成0x03 。如果配置端口1和0輸出低電平,也就是需要BR1和BR0為1進(jìn)行復(fù)位,其它位保持不變?yōu)?,也就是說(shuō)要配置成0x00030000 。寫成代碼也就是GPIOB->BSRR=0x00000003;//1,GPIOB->BSRR=0x00030000;//0。

    然后由于開和關(guān)間隔時(shí)間過(guò)短,所以還需要一個(gè)delay函數(shù)。在SYSTEM-delay.c文件中可以找到delay.h,然后進(jìn)入delay.h頭文件,可看到void delay_init(u8 SYSCLK);void delay_ms(u16 nms);void delay_us(u32 nus);三個(gè)函數(shù)。使用delay首先進(jìn)行初始化delay_init(216);其中216是stm32f767的系統(tǒng)時(shí)鐘。然后就可以調(diào)用delay_ms(500);

    最終的代碼為:

    #include "sys.h" #include "delay.h" #include "usart.h"int main(void) {HAL_Init();Stm32_Clock_Init(431,25,2,9);delay_init(216);RCC->AHB1ENR |= 1<<1;GPIOB->MODER=0x05;GPIOB->OTYPER=0x00;GPIOB->OSPEEDR=0x0f;GPIOB->PUPDR=0x05;while(1){GPIOB->BSRR=0x00000003;//1delay_ms(500);GPIOB->BSRR=0x00030000;//0delay_ms(500);} }

    5.使用HAL庫(kù)

    優(yōu)點(diǎn):方便在各個(gè)stm32平臺(tái)移植。

    HAL庫(kù)很好的解決了程序移植的問(wèn)題,不同型號(hào)的stm32芯片它的標(biāo)準(zhǔn)庫(kù)是不一樣的,例如在F4上開發(fā)的程序移植到F3上是不能通用的,而使用HAL庫(kù),只要使用的是相通的外設(shè),程序基本可以完全復(fù)制粘貼,注意是相同外設(shè)。

    在HALLIB文件夾下可以找到stm32f7xx_hal_gpio.c文件,然后找到stm32f7xx_hal_gpio.h文件,可以看到里面有幾個(gè)函數(shù):

    /* Initialization and de-initialization functions *****************************/ void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);//初始化函數(shù) void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin); /** /* IO operation functions *****************************************************/ GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//讀取輸入電平函數(shù) void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);//設(shè)置輸出電平函數(shù) void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//電平翻轉(zhuǎn)函數(shù) HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//引腳電平鎖定函數(shù) void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);//外部中斷函數(shù) void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
    • void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);

      初始化一個(gè)或多個(gè)IO口(同一組)的工作模式,輸出類型,速度以及上下拉方式。也就是一組IO口的4個(gè)配置寄存器。MODER、OSPEEDR、OTYPER、PUPDR。在stm32f7xx_hal_gpio.h找到HAL_GPIO_Init函數(shù),然后go to definition,可以找到HAL_GPIO_Init的實(shí)現(xiàn),可以發(fā)現(xiàn)他主要操作的是MODER、OSPEEDR、OTYPER、PUPDR寄存器。

      GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1; //PB1,0GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽輸出GPIO_Initure.Pull=GPIO_PULLUP; //上拉GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速HAL_GPIO_Init(GPIOB,&GPIO_Initure); //一個(gè)參數(shù)是設(shè)置哪個(gè)組,另一個(gè)參數(shù)是初始化結(jié)構(gòu)體
    • GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

      讀取某個(gè)GPIO的輸入電平,實(shí)際操作是GPIOx_IDR寄存器

    • void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);

      設(shè)置引腳輸出電平

      HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET); //PB0置1 HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET); //PB1置1
    • void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

      輸出電平翻轉(zhuǎn)函數(shù)

    6.配置HAL庫(kù)操作IO口步驟

    • 初始化HAL庫(kù) HAL_Init()

    • 初始化系統(tǒng)時(shí)鐘 Stm32_Clock_Init()

    • 使能IO口時(shí)鐘 _HAL_RCC_GPIOB_CLK_ENABLE() ;配置IO口時(shí)鐘使能寄存器:RCC->AHB1ENR

      在HALLIB文件-stm32f7xx_hal_rcc.ex.h文件中可以找到:__HAL_RCC_GPIOA_CLK_ENABLE(),這個(gè)函數(shù)實(shí)際上操作的是RCC->AHB1ENR

      #define __HAL_RCC_GPIOA_CLK_ENABLE() do { \__IO uint32_t tmpreg; \SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOAEN);\/* Delay after an RCC peripheral clock enabling */ \tmpreg = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOAEN);\UNUSED(tmpreg); \} while(0)
    • 初始化IO口模式HAL_GPIO_Init() ;操作寄存器:GPIOx_MODER OTYPER OSPEEDR PUPDR

      在stm32f7xx_hal_gpio.c文件找到HAL_GPIO_Init(),然后觀察它的參數(shù)GPIO_TypeDef *GPIOx和GPIO_InitTypeDef *GPIO_Init,現(xiàn)在要弄明白GPIOx是什么,在下面的代碼中找到對(duì)GPIOx的操作。 assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));然后選擇IS_GPIO_ALL_INSTANCE點(diǎn)擊go to definition找到:

      #define IS_GPIO_ALL_INSTANCE(__INSTANCE__) (((__INSTANCE__) == GPIOA) || \((__INSTANCE__) == GPIOB) || \((__INSTANCE__) == GPIOC) || \((__INSTANCE__) == GPIOD) || \((__INSTANCE__) == GPIOE) || \((__INSTANCE__) == GPIOF) || \((__INSTANCE__) == GPIOG) || \((__INSTANCE__) == GPIOH) || \((__INSTANCE__) == GPIOI) || \((__INSTANCE__) == GPIOJ) || \((__INSTANCE__) == GPIOK))

      可以發(fā)現(xiàn)該函數(shù)是對(duì)GPIOA之類的進(jìn)行操作,要對(duì)GPIOB進(jìn)行操作,所以GPIO_TypeDef *GPIOx參數(shù)設(shè)置成GPIOB。

      下面要設(shè)置GPIO_InitTypeDef *GPIO_Init參數(shù),可以發(fā)現(xiàn)這個(gè)是結(jié)構(gòu)體類型。

      typedef struct {uint32_t Pin; /*!< Specifies the GPIO pins to be configured.This parameter can be any value of @ref GPIO_pins_define */uint32_t Mode; /*!< Specifies the operating mode for the selected pins.This parameter can be a value of @ref GPIO_mode_define */uint32_t Pull; /*!< Specifies the Pull-up or Pull-Down activation for the selected pins.This parameter can be a value of @ref GPIO_pull_define */uint32_t Speed; /*!< Specifies the speed for the selected pins.This parameter can be a value of @ref GPIO_speed_define */uint32_t Alternate; /*!< Peripheral to be connected to the selected pins. This parameter can be a value of @ref GPIO_Alternate_function_selection */ }GPIO_InitTypeDef;

      然后對(duì)這個(gè)結(jié)構(gòu)體成員進(jìn)行設(shè)置,首先要判斷MODE要怎么設(shè)置,找到

      assert_param(IS_GPIO_PIN(GPIO_Init->Pin));
      assert_param(IS_GPIO_MODE(GPIO_Init->Mode));
      assert_param(IS_GPIO_PULL(GPIO_Init->Pull));

      go to definition一下IS_GPIO_MODE,可以發(fā)現(xiàn)mode可以設(shè)置成很多個(gè)類型,我們這里設(shè)置成推挽輸出,所以設(shè)置成GPIO_MODE_OUTPUT_PP。

      #define IS_GPIO_PIN_ACTION(ACTION) (((ACTION) == GPIO_PIN_RESET) || ((ACTION) == GPIO_PIN_SET)) #define IS_GPIO_PIN(PIN) (((PIN) & GPIO_PIN_MASK ) != (uint32_t)0x00) #define IS_GPIO_MODE(MODE) (((MODE) == GPIO_MODE_INPUT) ||\((MODE) == GPIO_MODE_OUTPUT_PP) ||\((MODE) == GPIO_MODE_OUTPUT_OD) ||\((MODE) == GPIO_MODE_AF_PP) ||\((MODE) == GPIO_MODE_AF_OD) ||\((MODE) == GPIO_MODE_IT_RISING) ||\((MODE) == GPIO_MODE_IT_FALLING) ||\((MODE) == GPIO_MODE_IT_RISING_FALLING) ||\((MODE) == GPIO_MODE_EVT_RISING) ||\((MODE) == GPIO_MODE_EVT_FALLING) ||\((MODE) == GPIO_MODE_EVT_RISING_FALLING) ||\((MODE) == GPIO_MODE_ANALOG)) #define IS_GPIO_SPEED(SPEED) (((SPEED) == GPIO_SPEED_LOW) || ((SPEED) == GPIO_SPEED_MEDIUM) || \((SPEED) == GPIO_SPEED_FAST) || ((SPEED) == GPIO_SPEED_HIGH)) #define IS_GPIO_PULL(PULL) (((PULL) == GPIO_NOPULL) || ((PULL) == GPIO_PULLUP) || \((PULL) == GPIO_PULLDOWN))

      然后找到pin的設(shè)置,發(fā)現(xiàn)里面有個(gè)GPIO_PIN_MASK,選中GPIO_PIN_MASK點(diǎn)擊go to definition。可以發(fā)現(xiàn)下面這些代碼,所以這個(gè)可以設(shè)置成GPIO_PIN_0。

      #define GPIO_PIN_0 ((uint16_t)0x0001U) /* Pin 0 selected */ #define GPIO_PIN_1 ((uint16_t)0x0002U) /* Pin 1 selected */ #define GPIO_PIN_2 ((uint16_t)0x0004U) /* Pin 2 selected */ #define GPIO_PIN_3 ((uint16_t)0x0008U) /* Pin 3 selected */ #define GPIO_PIN_4 ((uint16_t)0x0010U) /* Pin 4 selected */ #define GPIO_PIN_5 ((uint16_t)0x0020U) /* Pin 5 selected */ #define GPIO_PIN_6 ((uint16_t)0x0040U) /* Pin 6 selected */ #define GPIO_PIN_7 ((uint16_t)0x0080U) /* Pin 7 selected */ #define GPIO_PIN_8 ((uint16_t)0x0100U) /* Pin 8 selected */ #define GPIO_PIN_9 ((uint16_t)0x0200U) /* Pin 9 selected */ #define GPIO_PIN_10 ((uint16_t)0x0400U) /* Pin 10 selected */ #define GPIO_PIN_11 ((uint16_t)0x0800U) /* Pin 11 selected */ #define GPIO_PIN_12 ((uint16_t)0x1000U) /* Pin 12 selected */ #define GPIO_PIN_13 ((uint16_t)0x2000U) /* Pin 13 selected */ #define GPIO_PIN_14 ((uint16_t)0x4000U) /* Pin 14 selected */ #define GPIO_PIN_15 ((uint16_t)0x8000U) /* Pin 15 selected */ #define GPIO_PIN_All ((uint16_t)0xFFFFU) /* All pins selected */#define GPIO_PIN_MASK ((uint32_t)0x0000FFFFU) /* PIN mask for assert test */

      同理設(shè)置pull和speed

    • 操作IO口,輸出高低電平 HAL_GPIO_WritePin(); 配置寄存器GPIOX_ODR或者GPIOx_BSRR

      最后在main中寫:

    int main() {GPIO_InitTypeDef GPIO_InitStructure;HAL_Init();delay_init(216);Stm32_Clock_Init(431,25,2,9);__HAL_RCC_GPIOB_CLK_ENABLE();//使能PB時(shí)鐘GPIO_InitStructure.Mode=GPIO_MODE_OUTPUT_PP;//推挽輸出GPIO_InitStructure.Pin=GPIO_PIN_0 | GPIO_PIN_1;GPIO_InitStructure.Pull=GPIO_PULLUP;//上拉GPIO_InitStructure.Speed=GPIO_SPEED_FREQ_VERY_HIGH;//高速HAL_GPIO_Init(GPIOB,&GPIO_InitStructure);while(1){HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);//PB0=0HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);//PB1=0delay_ms(500);HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);//PB0=1HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);//PB1=1delay_ms(500);}}

    二、stm32按鍵實(shí)驗(yàn)

    1.電路連接圖

    由圖可知,KEY0、KEY1、KEY2需要設(shè)置成上拉,這樣的話,如果按鍵KEY0、KEY1、KEY2按下,那么將得到低電平信號(hào),如果KEY0、KEY1、KEY2沒有按下,將是高電平信號(hào)。WK_UP設(shè)置為下拉,KEY_UP按下的話,將檢測(cè)到高電平信號(hào),沒有按下將是低電平信號(hào)。KEY0->PH3上拉輸入、KEY1->PH2上拉輸入、KEY2->PC13上拉輸入、WK_UP->PA0下拉輸入。

    2.步驟

    1.使能按鍵對(duì)應(yīng)IO口時(shí)鐘

    __HAL_RCC_GPIOx_CLK_ENABLE();

    由電路連接圖,可以發(fā)現(xiàn),涉及到的是A、C、H口:

    __HAL_RCC_GPIOA_CLK_ENABLE(); //開啟GPIOA時(shí)鐘__HAL_RCC_GPIOC_CLK_ENABLE(); //開啟GPIOC時(shí)鐘__HAL_RCC_GPIOH_CLK_ENABLE(); //開啟GPIOH時(shí)鐘

    2.初始化IO模式:上拉/下拉輸入

    HAL_GPIO_Init

    根據(jù)KEY0->PH3上拉輸入、KEY1->PH2上拉輸入、KEY2->PC13上拉輸入、WK_UP->PA0下拉輸入。

    GPIO_InitTypeDef GPIO_Initure; GPIO_Initure.Pin=GPIO_PIN_0; //PA0GPIO_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; //PC13GPIO_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,3HAL_GPIO_Init(GPIOH,&GPIO_Initure);

    3.掃描IO口電平(庫(kù)函數(shù)/寄存器)

    HAL庫(kù)函數(shù):GPIO_PinState HAL_GPIO_ReadPin();

    寄存器:GPIOx_IDR

    4.編寫按鍵掃描邏輯

    按鍵支持連按,舉個(gè)遙控器的例子,一直按,一直換臺(tái)。如果不支持連按,就說(shuō)明這個(gè)遙控器按下一次換臺(tái),如果后面也一直按,它不會(huì)換臺(tái)。如果不支持連按的話,需要一個(gè)變量記錄上一次的狀態(tài),如果是上一次是未按下,那么這一次檢測(cè)到按下,說(shuō)明這個(gè)按鍵算是按下了。如果檢測(cè)上一次按下了,那么這次按不算,也就是說(shuō),按鍵按下了,沒有松開,只能算一次。

    按鍵掃描支持連按的思路:

    u8 KEY_Scan(void){if(KEY按下){delay_ms(10);//延時(shí)防抖if(KEY確實(shí)按下){return KEY_Value;}return 無(wú)效值;} }

    每次調(diào)用getValue函數(shù)之后,返回值是多少

    int getValue() {static int flag = 0;flag++;return flag; }

    每一次調(diào)用,第一次返回1,第二次返回2…因?yàn)閟tatic變量存在,static修飾的變量只被初始化一次,并且保持最近的值,哪怕創(chuàng)建它的函數(shù)已經(jīng)結(jié)束,這個(gè)變量也不會(huì)被釋放,下次調(diào)用是同一個(gè)地址,所以里面的值是上次的。static定義的變量有記憶的作用。所以不支持連按的思路:注意key_up一定記錄的是上一次的狀態(tài)。

    u8 KEY_SCAN(void) {static u8 key_up = 1;//沒有按下if(key_up && KEY按下)//上一次松開,這次按下{delay_ms(10);key_up=0;if(KEY確實(shí)按下){return KEY_VALUE;}}else if(KEY沒有按下)key_up=1; }

    3.代碼

    //按鍵初始化函數(shù) void KEY_Init(void) {GPIO_InitTypeDef GPIO_Initure;__HAL_RCC_GPIOA_CLK_ENABLE(); //開啟GPIOA時(shí)鐘__HAL_RCC_GPIOC_CLK_ENABLE(); //開啟GPIOC時(shí)鐘__HAL_RCC_GPIOH_CLK_ENABLE(); //開啟GPIOH時(shí)鐘GPIO_Initure.Pin=GPIO_PIN_0; //PA0GPIO_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; //PC13GPIO_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,3HAL_GPIO_Init(GPIOH,&GPIO_Initure); }//按鍵處理函數(shù) //返回按鍵值 //mode:0,不支持連續(xù)按;1,支持連續(xù)按; //0,沒有任何按鍵按下 //1,WKUP按下 WK_UP //注意此函數(shù)有響應(yīng)優(yōu)先級(jí),KEY0>KEY1>KEY2>WK_UP!! u8 KEY_Scan(u8 mode) {static u8 key_up=1; //按鍵松開標(biāo)志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; //無(wú)按鍵按下 }int main(void) {u8 key;u8 led0sta=1,led1sta=1; //LED0,LED1的當(dāng)前狀態(tài)Cache_Enable(); //打開L1-CacheHAL_Init(); //初始化HAL庫(kù)Stm32_Clock_Init(432,25,2,9); //設(shè)置時(shí)鐘,216Mhz delay_init(216); //延時(shí)初始化uart_init(115200); //串口初始化LED_Init(); //初始化LEDKEY_Init(); //按鍵初始化while(1){key=KEY_Scan(0); //得到鍵值if(key){ switch(key){ case WKUP_PRES: //控制LED0,LED1互斥點(diǎn)亮led1sta=!led1sta;led0sta=!led1sta;break;case KEY2_PRES: //控制LED0翻轉(zhuǎn)led0sta=!led0sta;break;case KEY1_PRES: //控制LED1翻轉(zhuǎn) led1sta=!led1sta;break;case KEY0_PRES: //同時(shí)控制LED0,LED1翻轉(zhuǎn) led0sta=!led0sta;led1sta=!led1sta;break;}LED0(led0sta); //控制LED0狀態(tài)LED1(led1sta); //控制LED1狀態(tài)}else delay_ms(10);} }

    總結(jié)

    以上是生活随笔為你收集整理的STM32-GPIO学习-跑马灯实验和按键实验-寄存器版本和HAL库版本的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。