使用寄存器控制STM32的GPIO操作
一、输出配置
前言:为什么要介绍寄存器来控制I/O口呢,我们在平常时序操作时会用到GPIO,调用库函数去控制不仅显得代码冗长且可能造成响应时间变长,所以了解一下寄存器操作IO口是有必要的。
1.端口输出数据寄存器(GPIOx_ODR) (x=A..E)
此寄存器也可以实现对GPIO的控制,例如想控制GPIOC的13口置0(为第一行)
当然,也能实现对GPIO的读操作,第二行;
GPIOC->ODR = 0xef;
temp = GPIOC->ODR;
可以发现对于ODR寄存器操作必须以16位的形式进行。
对于ODR的读可以发现库函数对于读取输出IO口状态用到了此寄存器:
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
uint8_t bitstatus = 0x00;
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GET_GPIO_PIN(GPIO_Pin));
if ((GPIOx->ODR & GPIO_Pin) != (uint32_t)Bit_RESET)
{
bitstatus = (uint8_t)Bit_SET;
}
else
{
bitstatus = (uint8_t)Bit_RESET;
}
return bitstatus;
}
2.端口位设置/清除寄存器(GPIOx_BSRR) (x=A..E)
BSRR是一个32位的寄存器,为端口的置1或清0寄存器,低16位的作用是让指定的IO口置1;而高16位的作用是让指定的IO口置0。(置1有效)
(每个GPIO有16个口,对应寄存器的低16位和高16位)
#define LED_GPIO_PORT GPIOC
#define LED_GPIO_PIN GPIO_PIN_13
#define LED(x) LED_GPIO_PORT->BSRR = LED_GPIO_PIN << (16 * (!x))
如果为LED(1),即将GPIOC的13口置1,等号后边运算结果就等于16位的GPIO,即向BSRR寄存器的13位写1,为低位,相应的GPIO口被拉高;反之,如果为LED(0),即将GPIOC的13口置0,等号后边运算结果就等于16位的GPIO向高位移16位,即向BSRR寄存器的29位写1,为高位,相应的GPIO口被拉低;
BSRR是使用最多的一个寄存器了,其中ODR寄存器负责直接控制端口输出电平,但是某些情况下我们需要更高效、更精准的控制电平状态,便要用到BSRR寄存器了。
3.端口位清除寄存器(GPIOx_BRR) (x=A..E)
此寄存器实现功能就是将I/O口置低电平了,例如将PC13置0:
GPIOC->BRR = GPIO_Pin_13;
为32位寄存器,高16位为保留地址,低16位相应位置1则输出低电平,与BSRR区别是只能控制I/O口为低电平;
二、输入配置
1.端口输入数据寄存器(GPIOx_IDR) (x=A..E)
这个寄存器可以读取I/O状态,可以宏定义一下读取也可以直接读取。例如读取GPIOC电平:
#define DATA_GPIO_PORT GPIOC
#define DATA_IN DATA_GPIO_PORT->IDR
/* 等价于 */
uint6_t temp = GPIOC -> IDR;
可以发现读出的为16位数据,如何读一位数据呢?
uint8_t temp;
temp = (uint8_t)(GPIOC->IDR&GPIO_Pin_13);
由于IDR为32位,所以最后要强制转换为16位数据;
三、端口配置寄存器
为什么要介绍这个寄存器,就是为了在某些时序可能会用到修改I/O模式的时候,比如IIC通信,所以了解一下还是很有必要的。
1.端口配置低寄存器(GPIOx_CRL) (x=A..E)
如这个寄存器名字一样,这个寄存器主要操作低八位I/O口,也就是0…7;
这是数据手册截的图,可能第一眼还看不明白,其实这是一个32位寄存器,其中每四个位控制一个I/O口,比如要控制0口: 0和1位就是写引脚速度,00就是输入模式,01为输出10MHz…. 2和3位就是控制MODE,图中写的比较明白了,如果还不明白也没关系,我再举几个例子:
eg:PA1配置为推挽输出,速度50MHz
GPIOA->CRL&= 0XFFFFFF0F;
GPIOA->CRL |= (u32)3<<4;
第一条语句是将第4、5、6、7位清0(&是有0则0),此时模式为模拟输入(看上图)。第二条是将第4、5位置1(或运算有1则1);此时模式就为推挽输出,50MHz。3也就是0011,右移4位:0011 0000(当然为32位数据,高位未写出)
2.端口配置高寄存器(GPIOx_CRH) (x=A..E)
如这个寄存器名字一样,这个寄存器主要操作高八位I/O口,也就是8…15;
这个和上面的寄存器一样的配置方法,举个例子:
将PA12配置为输入模式:代码第一行
将PA12配置为推挽输出模式:代码第二行
//IO方向设置
#define SDA_IN() {GPIOA->CRH &= 0XFFF0FFFF;GPIOA->CRH |= (u32)8<<16;}
#define SDA_OUT() {GPIOA->CRH &= 0XFFF0FFFF;GPIOA->CRH |= (u32)3<<16;}
当然,在某些型号的单片机你会发现没有CRH和CRL了,当然这些在F1系列是肯定用不到的,F1系列的就不用看下面介绍的了,下面细分为了下面几种寄存器
MODER寄存器的功能就是设置输入与输出模式:
00-输入模式
01-通用输出模式
02-备用功能模式
03-模拟模式
OTYPER其16到31位必须保持复位值,也就是不能写入数据。低15位直接控制16个IO口输出类型:
0-推挽输出
1-开漏输出
这个OSPEEDR寄存器主要控制输出速度了,00-低速、01-中速、02-高速、03-超高速
PUPDR寄存器主要控制输出模式:
00-无上下拉,即浮空输入;01-上拉输入;02-下拉输入;03-保留
作者:辞丶176