31 3029 2827 2625 2423 2221 2019 1817 16保留15 1413 1211 10 9 8IDR9IDR8 7 6IDR7IDR65 4IDR5IDR4 3 2IDR3IDR21 0IDR1IDR0IDR15IDR14IDR13IDR12IDR11IDR10r rr r位31:16位15:0r rr rr rr rr rr r保留,始终读为0IDRy[15:0]:端口输入数据(y=0...15)(Port Input Data)这些位为只读并能以字(16位)的形式读出,读出的值为对应I/O口的状态
17 16图3.2 GPIO_IDR寄存器
31 3029 2827 2625 2423 2221 2019 18保留15 14ODR15ODR1413 12ODR13ODR1211 10ODR11ODR10 9 8 7 65 4 3 21 0ODR9ODR8ODR7ODR6ODR5ODR4ODR3ODR2ODR1ODR0r rr rr rr rr rr rr r位31:16位15:0r r保留,始终读为0ODRy[15:0]:端口输入数据(y=0...15)(Port Input Data)这些位为可读并只能以字(16位)的形式操作。
图3.3 GPIO_ODR寄存器
GPIOx_IDR是端口的输入数据寄存器,GPIOx_ODR是端口的输出寄存器。当配置引脚的输入输出模式是通过GPIOx_CRL和GPIOx_CRH两个寄存器来配置的,但是每个端口的16个引脚它们有的可能是输出模式,有的是输入模式,甚至一会输出一会输入,而GPIOx_IDR和GPIOx_ODR两个寄存器是以word模式访问而不能以bit模式访问,GPIOx_IDR只能读,而GPIOx_ODR可以读写。因此,如果输入输出公用一个寄存器,将不知道读出的数据到底应该是输入还是输出。
如果是模拟输入或者浮空输入模式,那么与GPIOx_ODR无关,如果配置成下拉输入模式,则应将GPIOx_ODR各位都设置0,如果是上拉输入模式,则GPIOx_ODR各位设置成1。在开漏输出模式下,通过读GPIOx_IDR来获取IO状态。
3)置位/复位寄存器
31 30BR15BR1429 28BR13BR1227 26BR11BR1025 24BR9BR823 22BR7BR621 20BR5BR419 18BR3BR217 16BR1BR0w w15 14BS15BS14w w13 12BS13BS12w w11 10BS11BS10w w 9 8BS9BS8w w 7 6BS7BS6w w5 4BS5BS4w w 3 2BS3BS2w w1 0BS1BS0w ww ww ww ww ww ww ww w位31:16Bry:清除端口x的 位y(y=0...15)(Port x Reset bit y) 这些位只能写入并只能以字(16位)的形式操作0:对对应的ODRy位不产生影响1:清除对应的ODRy为为0Bry:清除端口x的 位y(y=0...15)(Port x Set bit y) 这些位只能写入并只能以字(16位)的形式操作0:对对应的ODRy位不产生影响1:清除对应的ODRy为为1位15:0
图3.4 GPIO_ODR寄存器
GPIOx_BSRR和GPIOx_BRR寄存器,通过这两个寄存器可以直接对对应的GPIOx端口置'1'或置'0'。GPIOx_BSRR的高16位中每一位对应端口x的每个位,对高16位中的某位置'1'则端口x的对应位被清'0';寄存器中的位置'0',则对它对应的位不起作用。GPIOx_BSRR的低16位中每一位也对应端口x的每个位,对低16位中的某位置'1'则它对应的端口位被置'1';寄存器中的位置'0',则对它对应的端口不起作用。
简单地说GPIOx_BSRR的高16位称作清除寄存器,而GPIOx_BSRR的低16位称作设置寄存器。另一个寄存器GPIOx_BRR只有低16位有效,与GPIOx_BSRR的高16位具有相同功能。
使用BRR和BSRR寄存器可以方便地快速地实现对端口某些特定位的操作,而不影响其它位的状态。
比如希望快速地对GPIOE的位7进行翻转,则可以: GPIOE->BSRR = 0x80; GPIOE->BRR = 0x80;
// 置'1' // 置'0'
如果使用常规'读-改-写'的方法: GPIOE->ODR = GPIOE->ODR | 0x80;
// 置'1' // 置'0'
GPIOE->ODR = GPIOE->ODR & 0xFF7F;
BSRR的高16位并不是多余,假如在一个操作中对GPIOE的位7置'1',位6置'0',则使用BSRR非常方便:
GPIOE->BSRR = 0x400080;
如果没有BSRR的高16位,则要分2次操作,结果造成位7和位6的变化不同步! GPIOE->BSRR = 0x80; GPIOE->BRR = 0x40;
三、固件库函数
1)初始化函数
在固件库开发中,操作寄存器CRH和CRL来配置I/O口的模式和速度是通过GPIO初始化函数完成:
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
这个函数有两个参数,第一个参数用来指定GPIO,取值范围GPIOA~GPIOG。第二个参数为初始化参数结构体指针,结构体类型为GPIO_InitTypeDef,在此可以详细了解该结构体定义,该定义在stm32f10x_gpio.h中。
typedef struct {
uint16_t GPIO_Pin;
GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; } GPIO_InitTypeDef; 配置GPIO的代码如下:
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
// 配置端口中引脚5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 速度50MHz GPIO_Init(GPIOB, &GPIO_InitStrucure);
上述代码设置GPIOB的第5个端口为推挽输出模式,同时速度为50Mbit/s。 首
先
GPIOB是端口GPIOB的配置寄存器编址,该编址可以在 中查到。结构体GPIO_InitStructure的第一个成员变量GPIO_Pin实际指出了需要配置的引脚在GPIOB配置寄存器中的偏移量。成员变量GPIO_Mode用来设置引脚的输入输出模式,这是通过一个枚举类型定义:
typedef enum {
GPIO_Mode_AIN = 0x0,
GPIO_Mode_IN_FLOATING = 0x04, GPIO_Mode_IPD = 0x28, GPIO_Mode_IPU = 0x48, GPIO_Mode_Out_OD = 0x14, GPIO_Mode_Out_PP = 0x10, GPIO_Mode_AF_OD = 0x1C, GPIO_Mode_AF_PP = 0x18
} GPIOMode_TypeDef;
2)数据输入/输出函数
A.. uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); 返回输入端口某个引脚的状态.GPIOx: x (A~G). GPIO_Pin: 端口的哪个bit位需要读取 (0~15).
如GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0); 读A0的状态,返回值可能0 或 1 B.
uint16_t
GPIO_ReadInputData(GPIO_TypeDef*
GPIOx);
如GPIO_ReadInputData(GPIOA); 返回A0~A15的状态 其中 typedef struct {
__IO uint32_t CRL; __IO uint32_t CRH; __IO uint32_t IDR; __IO uint32_t ODR; __IO uint32_t BSRR; __IO uint32_t BRR; __IO uint32_t LCKR; } GPIO_TypeDef;
C. uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); 读GPIO某一位的输出
D. uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx); //读GPIO的输出
3)位设置函数
将GPIO的某个位置位
A. void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); 将GPIO的某个位复位
B. void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
四、实验设计
本实验是STM32开发最基础的实验,如图3.4所示,3个LED灯分别接GPIOD的引脚PD5、PD6、PD7,实现LED灯的闪烁功能。
图3.4 LED灯硬件连接图
完成上述功能的步骤为:
(1)使能I/O口时钟,调用函数为RCC_APB2PeriphClockCmd( ); (2)初始化I/O参数,调用函数GPIO_Init( );
(3)操作I/O,调用函数GPIO_SetBits( )和GPIO_ResetBits。
五、例程
/*
********************************************************************** * 文件:main.c
* 编辑:武汉理工大学计算机学院 * 日期:2013/12/04 * 修改: * 版本:V1.0
* 描述:UE-STM32F103开发板板载了3个LED,分别为LED1、LED和LED3 本实验将通过教你如何控制STM32的IO口配置实现这三个灯的交替闪烁 ********************************************************************** */
#include \
/*宏定义*/
#define LED_PORT GPIOD #define LED1 GPIO_Pin_5 #define LED2 GPIO_Pin_6 #define LED3 GPIO_Pin_7 /*函数声明*/
void LED_Init(void);
void delayms(int loop_times); /*
****************************************************************** * 函 数:main * 入口参数:无