【硬件开发自用手册】GPIO的寄存器介绍(STM32F103C8T6)

0、从GPIO_TypeDef结构体的定义中STM32F103C8T6的GPIO有7个寄存器:

typedef struct
{
  _IO uint32_t CRL; //低8位端口配置寄存器(配置工作模式,输出速度)
  _IO uint32_t CRH; //高8位端口配置寄存器(配置工作模式,输出速度)
  _IO uint32_t IDR; //端口输入数据寄存器(用于判断IO引脚的电平)
  _IO uint32_t ODR; //端口输出数据寄存器(用于设置IO引脚输出的电平)
  _IO uint32_t BSRR;//端口位设置,清除寄存器(设置ODR寄存器的值)
  _IO uint32_t BRR; //F4之后没有这个寄存器,考虑代码兼容性的话不建议使用
 _IO uint32_t LCKR;//配置锁定,用的不多
 }GPIO_TypeDef;

1、CRL(Configuration Register Low)

用于配置GPIO端口的低8位(即引脚0到7)的模式和特性,每个引脚占用4个位,配置8个引脚。
在这里插入图片描述 CRL寄存器的结构

  • 示例:用配置寄存器的方法配置PA0为输出模式(通用推挽输出)
#include"stm32f10x.h"

int main(void)
{
//开启GPIOA的时钟
RCC->APB2ENR|=RCC_APB2ENR_IOPAEN;

//直接修改CRL寄存器来配置PA0
//每个引脚占4位,所以PA0的配置位于CRL的低4位
//设置为输出模式(01:10MHz General Purpose Output Push-Pull
GPIOA->CRL&=~(0x0F<<(0*4));/*清除PA0原来的配置,~相当于把00001111倒写为11110000。
<<为左移操作符,0*4=0,表示左移0位,如果是配置的是PA1,则要改为1*4=4,左移4位*/
GPIOA->CRL|=(0x03<<(0*4));//设置PA0为输出模式(0x03表示10MHz General Purpose Output push-pull)
/*详细说明1
结合CRL寄存器结构表来看,每4位分2组2位,分别为CNF和MODE。
其中CNF取值:
    1、当MODE=00时:
      00 模拟输入模式
      01 浮空输入模式
      10 上拉/下拉输入模式
      11 保留
    2、当MODE>00时:
      00 通用推挽输出模式
      01 通用开漏输出模式
      10 复用功能推挽输出模式
      11 复用功能开漏输出模式
其中MODE取值:
      00 输入模式(复位后的状态)
      01 输出模式,最大速度10MHz
      10 输出模式,最大速度2MHz
      11 输出模式,最大速度50MHz
*/
/*详细说明2
   与操作&=:只有两个相应的二进制位都为1时,结果才为1

   11111111(reg)
 & 11110000(mask)
 ----------11110000(result)
   或操作|=:只有两个相应的二进制位中有一个为1,结果就为1
   11110000(reg)
 | 00001111(mask)
 ----------11111111(result)
 */
 //设置PA0为高电平
 GPIO->BSRR=(1<<0);//BSRR寄存器的低16位用于设置引脚为高电平
 while1{
 //主循环
 }

2、CRH(Configuration Register High)

用于配置GPIO端口的高8位(即引脚8到14)的模式和特性,每个引脚占用4个位,配置8个引脚,和CRL差不多。

CRH寄存器的结构

  • 示例:用配置寄存器的方法配置PA8为输出模式(通用开漏输出)
#include "stm32f10x.h"

int main(void)
{
//开启GPIOA的时钟
RCC->APB2ENR|=RCC_APB2ENR_IOPAEN;

GPIO->CRH&=~(0x0F<<((8-8)*4));/*清除PA8原来的配置,~相当于把00001111倒写为11110000。
<<为左移操作符,(8-8)*4=0,表示左移0位,如果配置的是PA9,则要改为(9-8)*4=4,左移4位*/
GPIOA->CRH|=(0x05<<((8-8)*4));//设置PA8为通用开漏输出模式,最大速度10MHz,即00000101
//设置PA8为高电平
GPIOA->BSRR=1<<0);//BSRR寄存器的低16位用于设置引脚为高电平

while1{
//主循环
}
}

3、IDR(Input Data Register)

用于读取对应I/O口的状态,前16位的各1位对应1个I/O口;后16位保留,始终为0。注意,一般用来读取输入模式下的状态,如果是输出模式,也可以读取,但建议直接读取或检查ODR的值。
!(https://i-blog.csdnimg.cn/direct/c8566db586a34c16a89f6d2c527d0673.png)
IDR寄存器的结构

  • 示例:在PA0为浮空输入模式的高电平状态下,读取PA0的值,然后执行对应的操作。
#include "stm32f10x.h"//根据你的STM32系列选择合适的头文件

int main(void){

RCC->APB2ENR|=RCC_APB2ENR_IOPAEN;//开启GPIOA的时钟

GPIOA->CRL&=~(0x0F<<(0*4));//对PA0清零
GPIOA->CRL|=(0x04<<(0*4));//配置PA0为浮空输入模式

GPIOA->BSRR=(1<<0);//设置PA0为高电平

while(1){
    //读取PA0的值
    if(GPIOA->IDR&GPIO_PIN_0){
      /*如果PA0为高电平,在"stm32f1xx_hal_gpio.h"里,GPIO_PIN_0定义为    (uint16_t)0x0001,也就是被读取的值与1进行与运算,全为1才是真,不全为假*/
      //执行相关操作
  }else{
     //如果PA0为低电平
     //执行相关操作
     }
  }
}

4、ODR(Output Data Register)

用于设置或读取某个IO口输出低电平还是高电平,只有在输出模式下有效,前16位的各1位对应1个I/O口;后16位保留,始终为0。
在这里插入图片描述
ODR寄存器的结构

  • 示例:在PA0为通用推挽输出模式、最大速度10MHz下,设置PA0为高电平,然后检查PA0的状态,执行对应的操作
#include "stm32f10x.h"

int main(void){

RCC->APB2ENR|=RCC_APB2ENR_IOPAEN;//开启GPIOA的时钟

GPIOA->CRL&=~(0x0F<<(0*4));//对PA0清零
GPIOA->CRL|=(0x01<<(0*4));//配置PA0为通用推挽输出模式、最大速度10MHz

GPIOA->ODR|=0x01;//设置PA0为高电平,也可以写成GPIOA->ODR|=GPIO_ODR_ODR0,因为在"stm32f10xb.h"里对GPIO_ODR_ODR0的宏定义为0x1UL

uint32_t odrValue=GPIOA->ODR;//读取GPIOA的ODR寄存器的值

//检查PA0的电平状态
if (ordValue&GPIO_ODR_ODR0){
//PA0是高电平
}else{
//PA0是低电平
}

while(1){

    }
  }
}

5、BSRR(Bit Set/Reset Register)

用于同时设置或复位多个引脚的电平状态,前16位为BS,后16位为BR,都是对应0~15的I/O口,都是在设置为1时起作用,BS的优先级比BR高,在对应BS和BR都设置为1时,只起BS的作用。注意,一般情况下,BSRR对输出模式才起作用。
在这里插入图片描述
BSRR寄存器的结构

  • 示例:将PA0~PA15设置为推挽输出模式,然后设置为高电平,再把PA8-PA15改为低电平
#include "stm32f10x.h"//根据你的STM32系列选择合适的头文件

int main(void){

RCC->APB2ENR|=RCC_APB2ENR_IOPAEN;//开启GPIOA的时钟

for(uint32_t k=0;k<8;k++)
{
GPIOA->CRL&=~(0x0F<<(k*4));//对PA0~PA7清零
GPIOA->CRL|=(0x01<<(k*4));//配置PA0~PA7为通用推挽输出模式、最大速度10MHz
GPIOA->ODR|=(0x01<<k);//用ODR对PA0~PA7设置为高电平
}

for(uint32_t i=0;i<8;i++)
{
GPIOA->CRH&=~(0x0F<<(i*4));//对PA8~PA15清零
GPIOA->CRL|=(0x01<<(i*4));//配置PA8~PA15为通用推挽输出模式、最大速度10MHz
GPIOA->ODR|=(0x01<<(i+8));//用ODR对PA8~PA15设置为高电平
}


GPIOA->BSRR|=(0x0F<<(3*8));//对PA8~PA15清零
GPIOA->BSRR|=(0x00<<(1*8));//确保没有影响

uint32_t odrValue=GPIOA->ODR;//读取GPIOA的ODR寄存器的值

//检查PA0的电平状态
if(odrValue&0xFF){
//PA0~PA7是高电平,PA8~PA15是低电平
}else{
//不符合"PA0~PA7是高电平,PA8~PA15是低电平"的条件
}

while(1){

   }
}

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值