【WB32库开发】第15章 GPIO位带操作

在初级教程中,我们已经学会了使用GPIO标准库函数来控制GPIO;在中级教程开始,我们需要了解一种更贴近控制51单片机GPIO的方法来控制WB32的GPIO。

本节使用WB32固件库中GPIO例程的GPIO_BitBand工程来了解位带操作。

15.1 实验任务与代码分析

本次实验涉及GPIO的输入与输出,需要分别对PA0和PA1两个GPIO引脚进行判断,然后根据这两个引脚输入电平的状态来改变PB13和PB14引脚的电平状态。

15.1.1 main.c代码

打开工程后,可以看到只有一个main.c文件,打开可以看到:

#include "wb32f10x.h"
#include "gpio_bit_band.h"             //包含“位带”头文件

int main(void)
{
  /* 打开GPIOA、GPIOB时钟 */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_BMX1 |RCC_APB1Periph_GPIOA |RCC_APB1Periph_GPIOB, ENABLE);

  /* 配置 PA0 为下拉输入模式,即默认PA0引脚为低电平 */
  GPIO_Init(GPIOA, GPIO_Pin_0, GPIO_MODE_IN |GPIO_PUPD_DOWN);

  /* 配置 PA1 为上拉输入模式,即默认PA1引脚为高电平 */
  GPIO_Init(GPIOA, GPIO_Pin_1, GPIO_MODE_IN |GPIO_PUPD_UP);

  /* 配置 PB13、PB14 为推挽输出模式 */
  GPIO_Init(GPIOB, GPIO_Pin_13 |GPIO_Pin_14, GPIO_MODE_OUT |GPIO_OTYPE_PP |GPIO_PUPD_NOPULL |GPIO_SPEED_HIGH);

  while (1)
  {
    if (PAin(0) != 0)   //判断PA0引脚电平
    {
      PBout(14) = 0;    //若PA0不为低电平,则点亮LED1
    }
    else
    {
      PBout(14) = 1;    //若PA0为低电平,则关闭LED1
    }

    if (PAin(1) == 0)   //判断PA1引脚电平
    {
      PBout(13) = 0;    //若PA1为低电平,则点亮LED2
    }
    else
    {
      PBout(13) = 1;    //若PA1不为低电平,则关闭LED2
    }
  }
}

在代码开始部分,包含了“位带”头文件,顾名思义,此头文件中包含着本节课要使用到的最重要的内容,此处不过多分析,继续往下看;

进入main函数部分,开启时钟、初始化GPIO的部分都是一样的,根据需求配置输入引脚和输出引脚进行,这里要清楚输入模式时配置上拉和下拉的作用;

进入循环后,按照设计思路,当检测到PA0引脚为高电平时,将PB14置为低电平(注释中说点亮LED灯,意为PB14接在LED负极处,当PB14输出低电平时,LED导通,故点亮。具体可参考WB32核心板原理图),否则将PB14置为高电平;

当检测到PA1位低电平时,将PB13置为低电平,否则将PB13置为高电平。

可以注意到,与以往使用GPIO标准库中的函数不同,这部分代码采用了与编写C51代码风格相近的函数来操作GPIO,如:

PAin(0)          
PBout(14)
PAin(1)
PBout(13)

从这些函数的名称上,很容易推测出这些函数的意义,如“PAin(n)”:'PA’即表示为GPIOA端口,'in’即表示输入,'n’则表示为第n个引脚(范围为0-15);大胆猜测,“PAin(0)”表示GPIOA端口输入模式下第0个引脚此时的电平状态,电平状态由引脚输入电平决定。

再来看“PBout(n)”:'PB’即表示为GPIOB端口,'out’即表示输出,'n’则表示为第n个引脚(范围为0-15);猜测“PBout(14)”表示GPIOB端口输入出模式下第14个引脚此时的电平状态,电平状态由用户定义(0位低电平,1为高电平)。

15.1.2 gpio_bit_band.h代码

进入gpio_bit_band.h中,可以看到:

#ifndef __GPIO_BIT_BAND_H
#define __GPIO_BIT_BAND_H
#include "wb32f10x.h"

#define PAout(n)   (*(volatile uint32_t*)BIT_BAND_ADDR(&GPIOA->ODR, n))  // Output
#define PAin(n)    (*(volatile uint32_t*)BIT_BAND_ADDR(&GPIOA->IDR, n))  // Input

#define PBout(n)   (*(volatile uint32_t*)BIT_BAND_ADDR(&GPIOB->ODR, n))  // Output
#define PBin(n)    (*(volatile uint32_t*)BIT_BAND_ADDR(&GPIOB->IDR, n))  // Input

#define PCout(n)   (*(volatile uint32_t*)BIT_BAND_ADDR(&GPIOC->ODR, n))  // Output
#define PCin(n)    (*(volatile uint32_t*)BIT_BAND_ADDR(&GPIOC->IDR, n))  // Input

#define PDout(n)   (*(volatile uint32_t*)BIT_BAND_ADDR(&GPIOD->ODR, n))  // Output
#define PDin(n)    (*(volatile uint32_t*)BIT_BAND_ADDR(&GPIOD->IDR, n))  // Input


#endif /* __GPIO_BIT_BAND_H */

大家一直跟着例程学习,第一次接触由用户自定义的头文件可能有些头痛:“这是什么?有什么用?怎么用?”

其实无论是自定义头文件还是固件库中给出的头文件,本质是为了将繁复的函数操作给封装在一个可以预处理的文件中(即.h文件);在要使用到这些函数的场合下,不必再重复定义,只需使用include进行包含即可在代码中使用头文件内定义好的函数,在节约处理器资源的同时还简化了代码。

此处代码分为两部分:

1)

#ifndef x						//先测试x是否被宏定义过
#define x						//如果x没有被宏定义过,定义x,并编译程序段 1
   程序段 1
#endif /* x */                  //如果x已经定义过了则编译程序段2的语句,“忽视”程序段 1
   程序段 2

ifndef是if not define 的简写,是宏定义的一种,实际上确切的说,这应该是预处理功能三种(宏定义、文件包含、条件编译)中的一种----条件编译;条件指示符#ifndef 的最主要目的是防止头文件的重复包含和编译;#ifndef 和 #endif 要一起使用,如果丢失#endif,可能会报错。

“define”为宏定义命令;在C或C++语言源程序中允许用一个标识符来表示一个字符串,称为“宏”;被定义为“宏”的标识符称为“宏名”,在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”;宏定义是由源程序中的宏定义命令完成的;宏代换是由预处理程序自动完成的。

其中"x"部分可根据我们使用的功能自定义名称,一般要求为大写。

这几行代码是用户自定义头文件时需要添加,此为默认的规范。

2)

#include "wb32f10x.h"

#define PAout(n)   (*(volatile uint32_t*)BIT_BAND_ADDR(&GPIOA->ODR, n))  // Output
#define PAin(n)    (*(volatile uint32_t*)BIT_BAND_ADDR(&GPIOA->IDR, n))  // Input

#define PBout(n)   (*(volatile uint32_t*)BIT_BAND_ADDR(&GPIOB->ODR, n))  // Output
#define PBin(n)    (*(volatile uint32_t*)BIT_BAND_ADDR(&GPIOB->IDR, n))  // Input

#define PCout(n)   (*(volatile uint32_t*)BIT_BAND_ADDR(&GPIOC->ODR, n))  // Output
#define PCin(n)    (*(volatile uint32_t*)BIT_BAND_ADDR(&GPIOC->IDR, n))  // Input

#define PDout(n)   (*(volatile uint32_t*)BIT_BAND_ADDR(&GPIOD->ODR, n))  // Output
#define PDin(n)    (*(volatile uint32_t*)BIT_BAND_ADDR(&GPIOD->IDR, n))  // Input

根据 1)中的解释,此部分代码即为程序段 1 ,也就是该头文件中我们实际使用到的部分,其中为保证代码正常运行,还需要在代码内包含wb32f10x的头文件#include "wb32f10x.h"

如果只追求会使用,那么代码分析到此为止,实际在项目中新建一个同名头文件,然后将全部代码复制过去,再在"魔术棒"的路径中包含新建的文件即可。

15.2 实验现象

代码编译完成烧录到开发板内,将PB14引脚连接到外部共阳极LED1电路上,将PB13引脚连接到外部共阳极LED2电路上;此时,若将PA0接到板载3.3V上,则LED1点亮,若将PA1接到板载GND上,则LED2点亮。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值