STM32裸机编程指南-2

本文目录

系列目录

配置GPIO

在前一篇文章中我们已经学习到可以通过直接访问存储地址来读写外设寄存器,下面复习下将GPIO A3设为输出模式的代码:

  * (volatile uint32_t *) (0x40020000 + 0) &= ~(3 << 6);  // CLear bit range 6-7
  * (volatile uint32_t *) (0x40020000 + 0) |= 1 << 6;     // Set bit range 6-7 to 1

这段代码有些诡秘,如果不加以注释,很难理解。我们可以把这段代码重写成更易读的形式,方法就是用一个包含32位域的结构体来表示整个外设。我们来看一下数据手册8.4节中描述的GPIO外设的寄存器,它们是MODER、OTYPER、OSPEEDR、PUPDR、IDR、ODR、BSRR、LCKR、AFR,它们的偏移量分别是0、4、8,等等,以此类推,这意味着我们可以用一个32位域的结构体来表示,然后这样定义GPIOA:

struct gpio {
  volatile uint32_t MODER, OTYPER, OSPEEDR, PUPDR, IDR, ODR, BSRR, LCKR, AFR[2];
};

#define GPIOA ((struct gpio *) 0x40020000)

这样我们就可以定义一个设置GPIO引脚模式的函数:

// Enum values are per datasheet: 0, 1, 2, 3
enum {GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, GPIO_MODE_AF, GPIO_MODE_ANALOG};

static inline void gpio_set_mode(struct gpio *gpio, uint8_t pin, uint8_t mode) {
  gpio->MODER &= ~(3U << (pin * 2));        // Clear existing setting
  gpio->MODER |= (mode & 3) << (pin * 2);   // Set new mode
}

现在重写上面将GPIO A3设为输出模式的代码:

gpio_set_mode(GPIOA, 3 /* pin */, GPIO_MODE_OUTPUT);  // Set A3 to output

MCU有好多个GPIO外设(也常被叫作’banks’):A、B、C…K,在数据手册2.3节可以看到,它们映射的存储空间相隔1KB,GPIOA起始地址为0x40020000,GPIOB起始地址为0x40020400,以此类推:

#define GPIO(bank) ((struct gpio *) (0x40020000 + 0x400 * (bank)))

我们可以给引脚进行编号,既包含组号,也包含序号。为了做到这一点,我们用一个2字节的uint16_t类型的数,高字节表示组号,低字节表示序号:

#define PIN(bank, num) ((((bank) - 'A') << 8) | (num))
#define PINNO(pin) (pin & 255)
#define PINBANK(pin) (pin >> 8)

通过这种方法,我们可以指定任意GPIO引脚:

  uint16_t pin1 = PIN('A', 3);    // A3   - GPIOA pin 3
  uint16_t pin2 = PIN('G', 11);   // G11  - GPIOG pin 11

现在,我们用这个方法再次改写gpio_set_mode()函数:

static inline void gpio_set_mode(uint16_t pin, uint8_t mode) {
  struct gpio *gpio = GPIO(PINBANK(pin)); // GPIO bank
  uint8_t n = PINNO(pin);                 // Pin number
  gpio->MODER &= ~(3U << (n * 2));        // Clear existing setting
  gpio->MODER |= (mode & 3) << (n * 2);   // Set new mode
}

这样再设置GPIO A3为输出模式就很明了了:

  uint16_t pin = PIN('A', 3);            // Pin A3
  gpio_set_mode(pin, GPIO_MODE_OUTPUT);  // Set to output

至此我们已经为GPIO外设创建了一个有用的初始化API,其它外设,比如串口,也可以用相似的方法来实现。这是一种很好的编程实践,可以让代码清晰可读。

公众号 | FunIO
微信搜一搜 “funio”,发现更多精彩内容。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值