GPIO 的应用
在讲第一个外设实例之前,我要先对许多初学硬件芯片的朋友说明几个关键的学习问题:首先是学习资料的准备,在新的处理器出来后,我们要如何入门,如何进行开发,这时相关的技术手册就是必须的了,以后我们的讲解与分享中都会用到芯片的技术手册,来分析下如何采用手册查找相关说明,实际上这也是工程师的必经之路。
1. 原理分析:
对于一个处理器来说,最简单的控制莫过于通过 I/O 端口输出的电平控制设备,本节就讲述一个经典的 LED 灯控制来开启大小 nRF52832 系列处理器的开发之旅。
硬件方面nRF52832-Bluefruit52开发板上,通过管脚 P0.17 和管脚 P0.19 连接 2 个 LED 灯,我们下面的任务首先来点亮它。IO 管脚接分别接一个发光二级管,因此当把 IO 管脚定义为输出低电平的时候,在二级管两端产生电势差,就可以点亮发光二极管了。
ARM Cortex-M4 的 IO 口配置有多种状态需要设置,那么下面我们一一介绍:首先看看 IO 口的模式,查看 nRF52832 参考手册,端口可以配置为 4 种模式:输入模式,输出模式,复用模式,模拟通道模式。由于 nRF52832 的 IO 管脚复用了其它的外设功能,比如 I2C,SPI,UART 等。而通用 IO 口具有输入和输出模式:
中间的 Sense 寄存器可以捕捉 GPIO 端口状态,如果选择 LDETECT 模式,则可以把相关状态存储在 LATCH 寄存器内,结构如下图所示:
实际 nRF52832 上所包含的寄存器是非常的简单的,下面把数据手册的说明进行了标注:
如果大家使用 nRF52832 官方提供的库函数编程,可以在"nrf_gpio.h"库文件中找到设置 IO 模式的结构体 nrf_gpio_port_dir_t,这里完全是对照参考手册进行编写的,实际上 nRF52832 的库是比较简单的,大家完全可以直接用寄存器操作:
typedef enum
{
NRF_GPIO_PIN_DIR_INPUT = GPIO_PIN_CNF_DIR_Input, //< Input
NRF_GPIO_PIN_DIR_OUTPUT = GPIO_PIN_CNF_DIR_Output //< Output
} nrf_gpio_port_dir_t;
首 先 我 们 来 介 绍 下 输 入 和 输 出 模 式 也 就 是 NRF_GPIO_PORT_DIR_INPUT 和 NRF_GPIO_PORT_DIR_OUTPUT。其中输出模式寄存器为推挽输出。输入的模式可以分为上拉和下拉模式,这就比较简单了,同样大家使用库函数编程的时候,可以在"nrf_gpio.h"文件中找到设置输入模式的结构体 nrf_gpio_pin_pull_t ,如数据手册上描述:
"nrf_gpio.h"库文件也给出了定义:
typedef enum
{
NRF_GPIO_PIN_NOPULL=GPIO_PIN_CNF_PULL_Disabled,//无上拉下拉
NRF_GPIO_PIN_PULLDOWN=GPIO_PIN_CNF_PULL_Pulldown,// 下拉
NRF_GPIO_PIN_PULLUP= GPIO_PIN_CNF_PULL_Pullup,//上拉
并且对于输入管脚可以设置不同的 sense 级别,如手册上所描述:
"nrf_gpio.h"库文件也给出了定义:
typedef enum
{
NRF_GPIO_PIN_NOSENSE= GPIO_PIN_CNF_SENSE_Disabled, ///< Pin sense level disabled.
NRF_GPIO_PIN_SENSE_LOW= GPIO_PIN_CNF_SENSE_Low, ///< Pin sense low level.
NRF_GPIO_PIN_SENSE_HIGH = GPIO_PIN_CNF_SENSE_High, ///< Pin sense high level.
} nrf_gpio_pin_sense_t;
对应选择了 NRF_GPIO_PORT_DIR_OUTPUT 输出,也可以选择管脚的输出驱动模式,结构体如下所示:
typedef enum
{
NRF_GPIO_PIN_S0S1 = GPIO_PIN_CNF_DRIVE_S0S1, ///< !< Standard '0', standard '1'
NRF_GPIO_PIN_H0S1 = GPIO_PIN_CNF_DRIVE_H0S1, ///< !< High drive '0', standard '1'
NRF_GPIO_PIN_S0H1 = GPIO_PIN_CNF_DRIVE_S0H1, ///< !< Standard '0', high drive '1'
NRF_GPIO_PIN_H0H1 = GPIO_PIN_CNF_DRIVE_H0H1, ///< !< High drive '0', high 'drive '1''
NRF_GPIO_PIN_D0S1 = GPIO_PIN_CNF_DRIVE_D0S1, ///< !< Disconnect '0' standard '1'
NRF_GPIO_PIN_D0H1 = GPIO_PIN_CNF_DRIVE_D0H1, ///< !< Disconnect '0', high drive '1'
NRF_GPIO_PIN_S0D1 = GPIO_PIN_CNF_DRIVE_S0D1, ///< !< Standard '0'. disconnect '1'
NRF_GPIO_PIN_H0D1 = GPIO_PIN_CNF_DRIVE_H0D1, ///< !< High drive '0', disconnect '1'
} nrf_gpio_pin_drive_t;
2. 软件编写:
点亮第一个LED灯
MicroPython固件中已经对板载的LED灯编写好驱动了,在使用时只需要调用相关API函数即可。
MicroPython v1.10-230-ge0c6dfe-dirty on 2019-03-24; Bluefruit52 nRF52832 with NRF52832
Type "help()" for more information.
>>> import board
>>> led1 = board.LED(1)
>>> led1.on()
>>> led1.off()
>>> led1.on()
>>>
import board
import time
led1 = board.LED(1)
led2 = board.LED(2)
led1.on()
led2.on()
time.sleep_ms(200)
led1.off()
led2.off()
time.sleep_ms(200)
while True:
led1.toggle()
led2.toggle()
time.sleep_ms(300)