目录
STM32F10x的IO口分组,GPIOA,GPIOB,GPIOC等,每组IO最多16个 。STM32的库已经定义好了一个GPIO的寄存器组
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;
每组GPIO 直接将GPIO首地址转为这组结构指针。
#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)
下面介绍一个GPIO初始化和使用的过程
1. 使能GPIO的RCC
RCC->APB2ENR |= RCC_APB2Periph_GPIOn
其中n的范围为A-G,另外如果是复用的IO,则需要使能RCC_APB2Periph_AFIO。例如要使能GPIOA和AFIO,则代码如下:
RCC->APB2ENR |= RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA;
2. 定义使用的GPIO组和PIN
为了更快速的修改GPIO组和PIN,将使用到的GPIO组和PIN用宏定义定义好。例如I2C IO方式,将SDA和SCL的IO定义为:
#define IO_I2CIO_SDA GPIOA
#define PIN_I2CIO_SDA 7
#define IO_I2CIO_SCL GPIOA
#define PIN_I2CIO_SCL 5
即SDA用的是GPIOA7,SCL用的是GPIOA5.
3. 配置IO
GPIO用CRL和CRH配置IO的属性,CRL对应GPIO的低8位IO,CRH对应GPIO的高8位IO。每个IO用4bit数据来设置属性。
以I2C的SDA设置为例
#define SDA_SetOut(n) {\
*((uint32_t *)&(IO_I2CIO_SDA->CRL) + ((PIN_I2CIO_SDA / 8)))) &= ~(0x0000000F << ((PIN_I2CIO_SDA % 8) * 4)); \
*((uint32_t *)&(IO_I2CIO_SDA->CRL) + ((PIN_I2CIO_SDA / 8))) |= (0x00000007 << ((PIN_I2CIO_SDA % 8) * 4)); \
}
&(IO_I2CIO_SDA->CRL)是获取CRL的地址,如果PIN_I2CIO_SDA为8-15(即GPIOA的高8位IO),则(&(IO_I2CIO_SDA->CRL) + ((PIN_I2CIO_SDA > 7) * 4))对应&(IO_I2CIO_SDA->CRH)。
((PIN_I2CIO_SDA % 8) * 4)表示对应的4位配置,这4位配置含义如下:
配置表:
MODE[1:0]用于设置输入输出模式,0x00表示输入,0x01-0x11表示输出。输入时如果需要设置为上下拉输入,则需要设置ODR为0(下拉)或1(上拉),使用BSRR或BRR输出0或1即可以实现上下拉的设置。例如设置GPIOA10为IPU:
GPIOA->CRH &= ~(0x000000FF << ((9 % 8) * 4));
GPIOA->CRH |= (0x0000008B << ((9 % 8) * 4));
GPIOA->BSRR = ((uint32_t)1 << 10); //Input with pull high
CRL和CRH的复位值为0x4,即IO口默认是浮空输入。
4. 输出电平
输出电平通过寄存器BSRR(输出高电平和低电平)和BRR(输出低电平)实现,写入1表示对应操作,写入0无效。例如:
#define SDA_HIGH(n) IO_I2CIO_SDA->BSRR = ((uint32_t)1 << PIN_I2CIO_SDA)
#define SDA_LOW(n) IO_I2CIO_SDA->BRR = ((uint32_t)1 << PIN_I2CIO_SDA)
BSRR的低16位分别对应16个PIN的输出高电平操作,高16为对应输出低电平操作。
而BRR只有低16位有效,对应对应输出低电平操作。
8bit总线输出
#define I8080_D8_OUT(dat) IO_I8080_D8->BSRR = (dat & 0xff) | ((uint32)((~dat) & 0xff) << 16)
5. 读入IO
通过寄存器IDR读出对应I/O口的状态。低16位有效。
#define SDA_READ(n) (IO_I2CIO_SDA->IDR & ((uint32_t)1 << PIN_I2CIO_SDA))