STM32裸机编程的基础知识(2)

发布时间:2024-03-05  

在前一篇文章中我们已经学习到可以通过直接访问存储地址来读写外设寄存器,下面复习下将 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,其它外设,比如串口,也可以用相似的方法来实现。这是一种很好的编程实践,可以让代码清晰可读。


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>