STM32 每一个片上外设资源都有自己的时钟,这些时钟被一个叫做RCC的外设统一管理, RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能或者失能APB2外设时钟 一. GPIO基础知识、寄存器及库函数 如果我们想读取某个推挽输出GPIO引脚现在的状态,怎么做呢? 由于我们不喜欢寄存器操作的方式, 现在我们想把它封装起来, 怎么封装呢? 这里我们用到一个位带别名区(可以理解为一大片寄存器), 位带区把每个GPIO寄存器的每个位(每个引脚)的状态映射到了自己的寄存器中. 我们根据GPIO的寄存器地址+位(引脚)偏移,可以算出去这个寄存器的哪个映射地址中可以读到这个位(引脚)的状态, 我们称之为地址转换计算。计算公式推导过程忽略, 直接记住结果: 地址转换计算公式 ((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5)+(bitnum<<2)) 在程序中, 我们定义这样一个宏: #define BITBAND(addr, bitnum) *(unsigned int*)((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5)+(bitnum<<2)) 当我们想获取GPIOB的ODR寄存器的某个位的状态时: #define GPIOB_ODR_Addr (GPIOB_BASE + 0X0C) //找到GPIOB的基地址 #define GPIOB_ODR_bitnum 0 //想读GPIOB的ODR寄存器的第0位 #define BITBAND(addr, bitnum) *(unsigned int*)((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5)+(bitnum<<2)) //位带操作地址转换公式 当函数调用时: BITBAND(GPIOB_ODR_Addr,GPIOB_ODR_bitnum)=0; //写位 a= BITBAND(GPIOB_ODR_Addr,GPIOB_ODR_bitnum); //读位 事实上,并非只有GPIO. 位带区分为外设位带区和SRAM位带区(两者的地址计算方法还不一样). 它们为STM32提供了按位读取的基础.就像51单片机里的sbit 这里举一个位带操作的完整例子: main.c #include 'stm32f10x.h' #include 'led.h' #include 'key.h' #ifndef BITBAND #define BITBAND(addr, bitnum) *(unsigned int*)((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5)+(bitnum<<2)) //位带操作地址转换公式 #endif /*BITBAND*/ int a; int main(void) { LED_GPIO_Config(); KEY1_GPIO_Config(); KEY2_GPIO_Config(); LED_G(OFF);//其实这里也可以改成LED_G_Out_Sbit=1 LED_R(OFF); LED_B(OFF); while(1) { if(KEY1_In_Sbit) { while(KEY1_In_Sbit); LED_G_Out_Sbit=!LED_G_Out_Sbit; } if(KEY2_In_Sbit) { while(KEY2_In_Sbit); LED_R_Out_Sbit=!LED_R_Out_Sbit; } } } led.h #ifndef __LED_H #define __LED_H #include 'stm32f10x.h' #define LED_G_GPIO GPIOB #define LED_G_Pin GPIO_Pin_0 #define LED_G_GPIO_ODR_Addr (GPIOB_BASE + 0X0C) //绿灯位带操作:找到GPIOB的基地址 #define LED_G_ODR_bitnum 0 //绿灯位带操作:想读GPIOB的ODR寄存器的第0位 #define LED_G_Out_Sbit BITBAND(LED_G_GPIO_ODR_Addr,LED_G_ODR_bitnum) //将绿灯的位定义出来了 #define LED_R_GPIO GPIOB #define LED_R_Pin GPIO_Pin_5 #define LED_R_GPIO_ODR_Addr (GPIOB_BASE + 0X0C) //红灯位带操作:找到GPIOB的基地址 #define LED_R_ODR_bitnum 5 //红灯位带操作:想读GPIOB的ODR寄存器的第5位 #define LED_R_Out_Sbit BITBAND(LED_R_GPIO_ODR_Addr,LED_R_ODR_bitnum) //将宏灯的位定义出来了 #define LED_B_GPIO GPIOB #define LED_B_Pin GPIO_Pin_1 #define LED_B_GPIO_ODR_Addr (GPIOB_BASE + 0X0C) //蓝灯位带操作:找到GPIOB的基地址 #define LED_B_ODR_bitnum 1 //蓝灯位带操作:想读GPIOB的ODR寄存器的第1位 #define LED_B_Out_Sbit BITBAND(LED_B_GPIO_ODR_Addr,LED_B_ODR_bitnum) //将蓝灯的位定义出来了 #define ON 1 #define OFF 0 #define LED_G(a) if(a) GPIO_ResetBits(LED_G_GPIO,LED_G_Pin); else GPIO_SetBits(LED_G_GPIO,LED_G_Pin);// 这里用了一个条件定义 #define LED_R(a) if(a) GPIO_ResetBits(LED_R_GPIO,LED_R_Pin); else GPIO_SetBits(LED_R_GPIO,LED_R_Pin);// 这里用了一个条件定义 #define LED_B(a) if(a) GPIO_ResetBits(LED_B_GPIO,LED_B_Pin); else GPIO_SetBits(LED_B_GPIO,LED_B_Pin);// 这里用了一个条件定义 void LED_GPIO_Config(void); #endif /*__LED_H*/ key.h #ifndef __KEY_H #define __KEY_H #include 'stm32f10x.h' #define KEY1_GPIO GPIOA #define KEY1_GPIO_Pin GPIO_Pin_0 #define KEY1_GPIO_IDR_Addr (GPIOA_BASE + 0X08) //key1位带操作:找到GPIOA的IDR基地址 #define KEY1_ODR_bitnum 0 //key1位带操作:想读GPIOA的IDR寄存器的第0位 #define KEY1_In_Sbit BITBAND(KEY1_GPIO_IDR_Addr,KEY1_ODR_bitnum) //将蓝灯的位定义出来了 #define KEY2_GPIO GPIOC #define KEY2_GPIO_Pin GPIO_Pin_13 #define KEY2_GPIO_IDR_Addr (GPIOC_BASE + 0X08) //key2位带操作:找到GPIOC的IDR基地址 #define KEY2_ODR_bitnum 13 //key2位带操作:想读GPIOC的IDR寄存器的第13位 #define KEY2_In_Sbit BITBAND(KEY2_GPIO_IDR_Addr,KEY2_ODR_bitnum) //按位操作KEY2 #define KEY_ON 1 #define KEY_OFF 0 void KEY1_GPIO_Config(void); void KEY2_GPIO_Config(void); #endif led.c和 key.c 都只有GPIO初始化函数, 这里省略了 三. GPIO库函数 1. GPIO初始化函数:GPIO_Init GPIO初始化用以下函数 参数1:可以看到,初始化时,需要一个GPIO_TypeDef类型的指针GPIOx 定义这个结构体,需要对以下参数进行初始化 参数2的参数1: GPIO_Pin: 可选值 参数2的参数2: GPIO_Speed 参数2的参数3: 例子: GPIO_InitTypeDef GPIO_InitStructure; //创建GPIO_InitTypeDef类型的结构体GPIO_InitStructure GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//最高输出速率50MHz GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出 GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化外设GPIOx寄存器 2. GPIO位输出1函数:GPIO_SetBits预置知识: 开时钟
所以,每一个片上外设想要应用第一件事就是: 开时钟!!!!!
根据系统结构图,GPIO都在APB2总线上
所以,我们要用void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)函数操作开启GPIO的时钟:
二. (重要)GPIO位带操作
我们可以读取它的ODR寄存器状态, 比如GPIOB的0脚可以这样读:GPIOB->ODR ^= GPIO_Pin_0;

参数2:需要一个GPIO_InitTypeDef类型的指针GPIO_InitStruct
这个GPIO_InitTypeDef如何定义呢?




3. GPIO位输出0函数:GPIO_ResetBits

4. GPIO读取位输入 GPIO_ReadInputDataBit

5. GPIO读取位输出 GPIO_ReadOutputDataBit

6. GPIO整体写端口:

7. GPIO整体读端口:

上一篇:Arduino IDE下用STM32点亮OLED屏幕
下一篇:基于STM32的(GSM+DHT11)果园环境监测系统
- 热门资源推荐
- 热门放大器推荐
- LM2904DMR2G 函数发生器运算放大器的典型应用
- DEMO9RS08KA2: DEMO9RS08KA2 Demonstration Board
- MCP73871EV,MCP73871 锂离子电池充电器评估板
- STEVAL-IHM039V1,采用 STM32F415 微控制器的双电机控制演示板
- LTC1606CG 演示板、16 位、250ksps ADC
- RT8086B 3.5A、1.2MHz、同步降压转换器的典型应用
- TS4999EIJT 典型应用 免滤波器立体声 2.8 W D 类音频功率放大器,可选择 3D 音效
- LTM4615,采用 15mm-15mm 封装的完整双路和三路输出负载点模块稳压器
- LTC2415-1IGN 24 位 ADC 的典型应用电路使用电阻器阵列在励磁放大器中提供精确匹配
- 使用 Analog Devices 的 LTC1450LIN 的参考设计

现代雷达系统的信号设计
EL5624IRE-T13

BFR340T






京公网安备 11010802033920号