STM32外设GPIO(学习笔记) 您所在的位置:网站首页 批阅是什么意思 STM32外设GPIO(学习笔记)

STM32外设GPIO(学习笔记)

2024-07-15 10:31| 来源: 网络整理| 查看: 265

在编写stm32程序时,对寄存器进行操着需要知道每个外设的基地址,标准库的stm32f10x.h文件里也有各种外设的基地址。

比如GPIO:在定义输出数据寄存器地址GPIOA_ODR_Addr时,在GPIOA_BASE(GPIO端口A的基址地址)地址基础上偏移

#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C #define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C #define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C #define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C #define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C #define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C #define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C #define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808 #define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08 #define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008 #define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408 #define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808 #define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08 #define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08

在stm32f10x.h文件里面有定义GPIOA_BASE,是APB2PERIPH_BASE(APB2(Advanced Peripheral Bus 2)总线的基址地址,高速总线)偏移0x0800

APB2PERIPH_BASE是在PERIPH_BASE地址基础上偏移0x10000

PERIPH_BASE地址就是表示内存地址空间的起始地址

/**********************************************************/ #define GPIOA_BASE (APB2PERIPH_BASE + 0x0800) /**********************************************************/ #define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) /**********************************************************/ #define PERIPH_BASE ((uint32_t)0x40000000)

//通用IO口地址映射表

typedef struct {   __IO uint32_t CRL; // 端口配置低寄存器, 地址偏移 0X00   __IO uint32_t CRH; // 端口配置高寄存器, 地址偏移 0X04   __IO uint32_t IDR; // 端口数据输入寄存器, 地址偏移 0X08   __IO uint32_t ODR; // 端口数据输出寄存器, 地址偏移 0X0C   __IO uint32_t BSRR; // 端口位设置/清除寄存器,地址偏移 0X10   __IO uint32_t BRR; // 端口位清除寄存器, 地址偏移 0X14   __IO uint32_t LCKR; // 端口位锁定寄存器, 地址偏移 0X18 } GPIO_TypeDef;

这段代码定义了一个名为GPIO_TypeDef的结构体类型,这是一种通用输入输出端口(GPIO)的类型定义。

"__IO"前缀相当于代表了C 语言中的关键字“volatile”,在 C 语言中该关键字用于表示变量是易变的,要求编译器不要优化。因为GPIO_TypeDef这个结构体里面都对应着寄存器,经常由外设或者STM32芯片状态修改,即使CPU不去改变这些寄存器内的值,这些寄存器内的值也会发生变化,当使用这些变量时,就要求CPU重新去访问地址读取数据,若没有“__IO”前缀,就会从CPU某个缓存区读取没及时更新的旧的数据。

下面是结构体中每个成员的含义:

CRL(Configuration Low Register)- 低字节配置寄存器,用于配置端口低8位引脚的模式、速度和上拉/下拉选择。CRH(Configuration High Register)- 高字节配置寄存器,用于配置端口高8位引脚的模式、速度和上拉/下拉选择。IDR(Input Data Register)- 输入数据寄存器,用于存储输入引脚的状态。ODR(Output Data Register)- 输出数据寄存器,用于存储输出引脚的状态。BSRR(Bit Set/Reset Register)- 位设置/复位寄存器,用于单独设置或复位引脚的状态。BRR(Bit Reset Register)- 位复位寄存器,用于复位引脚的状态。LCKR(Lock Register)- 锁寄存器,用于锁定GPIO的配置寄存器,防止意外修改。

在使用库函数时,里面经常会看到下面这些:

#define I2C1 ((I2C_TypeDef *) I2C1_BASE) #define EXTI ((EXTI_TypeDef *) EXTI_BASE) #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) #define ADC1 ((ADC_TypeDef *) ADC1_BASE) #define TIM1 ((TIM_TypeDef *) TIM1_BASE) #define SPI1 ((SPI_TypeDef *) SPI1_BASE) #define USART1 ((USART_TypeDef *) USART1_BASE)

比如#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)为例,定义GPIO_TypeDef结构体指针,结构体里面成员的类型和分布顺序是和寄存器里面一一对应的(结构体里面成员是32位的(即四个字节),下表GPIO寄存器里面也是每一个偏移4个字节)

然后就可以通过该结构体指针就可以直接操作

用操作寄存器写一个配置GPIO的示例程序:(知道就行)

#include "stm32f10x.h" void GPIOA_PinConfig(uint32_t GPIO_Pin) { // 1. 使能GPIOA的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 2. 获取GPIOA对应的寄存器地址 GPIO_TypeDef *GPIOx = GPIOA; // 指向GPIOA寄存器的指针 // 3. 配置引脚为复用推挽模式(AF_PP) GPIOx->CRH &= ~(0x0F CRH |= (GPIO_Mode_Out_PP CRH &= ~(0x03 CRH |= (GPIO_Speed_50MHz CRH &= ~(0x0F CRH |= (GPIO_Mode_Out_PP CRH &= ~(0x03 CRH |= (GPIO_Speed_50MHz


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有