nrf51822裸机教程-GPIO

本文详细介绍了nRF51系列微控制器中GPIO的相关寄存器及其使用方法,包括OUT、OUTSET、OUTCLR等输出控制寄存器,DIR、DIRSET、DIRCLR等方向控制寄存器,以及PIN_CNF配置寄存器的功能和应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先看看一下相关的寄存器说明
 

Out寄存器 输出设置寄存器

每个比特按顺序对应每个引脚,bit0对应的就是 引脚0

该寄存器用来设置 引脚作为输出的时候的 输出电平为高还是低。


与输出设置相关的 还有另外两个寄存器

OUTSET和OUTCLR

OUTSET用来设置某个引脚的输出为高电平

OUTCLR用来设置某个引脚的输出为低电平

这两个寄存器同OUT寄存器一样 每个位按顺序对应每个引脚。但有个特别的地方在于OUTSET和OUTCLR两个寄存器的每个bit都是写1有效,写0无效。



比如在引脚都被设置为输出的情况下:

将OUTSET赋值为0x03那么引脚0和引脚1将输出高电平,其他引脚不收影响(输出电平不变)

将OUTCLR赋值为0x80那么引脚7将输出低电平,其他引脚电平不收影响。


这样的特性也是为什么有设设置输出的寄存器 OUT后还要引入OUTSET和OUTCLR寄存器的原因。

比如你需要将引脚3的输出电平设置为高,那么如果只有OUT寄存器的情况下,你需要先读出OUT寄存器然后修改值再写会。原因在于你只需要修改引脚2而不需要改变其他引脚的状态

 A = OUT;

A |= 0x04;

OUT = A;

但是有OUTSET寄存器的话就和方便,只需要OUTSET = 0x04就可以设置引脚2输出高电平同时不改变其他引脚的状态。

同样要单独设置某个引脚输出低电平时用OUTCLR寄存器就可以了


DIR寄存器用来设置引脚是作为输入引脚还是输出引脚

如上的输出控制寄存器,DIR 同样也有两个单独设置输入还是输入的寄存器DIRSET和DIRCLR

作用和上面说的也是一样,这里不赘述


最后剩下 PIN_CNF寄存器。 每个引脚都有其对应的 PIN_CNF寄存器。

主要是设置一些 更具体的设置。像是最为输入时的是否有上拉/下拉电阻。驱动的强度(我都是直接用S0S1,没有单独测试每个强度的区别),以及引脚作为输入时设置的 input buffer。

有一个比较特殊的设置是SENSE,这个是一个深度睡眠唤醒机制。

深度睡眠时普通的中断是无法将处理器从睡眠状态唤醒的。51822从深度睡眠状态唤醒可以通过 PIN_CNF 中的这个SENSE来设置某个引脚可以产生DETECT signal来作为深度睡眠唤醒引脚。(另外的唤醒方式还有LPCOMP模块产生的ANADETECT signal 以及复位)


比如,将PIN_CNF[4]寄存器设置为输入脚,并且其中的SENSE位的值设置3,那么引脚4就作为深度睡眠的唤醒脚,并且在引脚4的电平变为低的时候就会将处理器从深度睡眠状态中唤醒。


如果只是简单的设置一个引脚作为输入可以直接使用DIR相关的函数设置某个引脚作为输出就可以了

比如如下实现


//Pin_num从0开始

Void config_pin_output(uint8_t pin_num){

    If ( pin_num >= 0 && pin_num <= PIN_MAX){

        DIRSET = 1 << pin_num;

}

}



如果是设置引脚作为输入引脚需要设置PIN_CNF寄存器。

比如只是设置某个引脚作为简单的输入功能。

Void config_pin_input(uint8_t pin_num){

    If ( pin_num >= 0 && pin_num <= PIN_MAX){

        PIN_CNF[pin_num] = (1 << 0)         //做输入

                            |(0 << 1)     //座输入时需设置Connect input buffer

                                                                 |(0 <<2)                //使能上拉

                                                                 |(0 << 8)               //标准的电平”0”和电平’”1”

                                                                 |(0 <<16)             //普通输入引脚,不产生DETECT signa

}

}




nordic 的SDK中提供了很多GPIO相关的设置函数,均在nrf_gpio.h头文件中以内联函数形式定义了。


我是用的开发工具是keil5,用的sdk是9.0.下面演示创建一个nrf51的工程的步骤

选择keil中的project->new project

选择你的设备对应的芯片。我的板子是 51422_xxac的

之后会弹出如下界面。

这里我们只是写一个很简单的按键点灯程序,没有用到SDK中提供的其他相关工程。所以下面勾选一个CMSIS下的CORE,device下的startup,以及nRF_Drivers下的nrf_gpio就行了。这样工程就会自动添加设备的 .s启动文件以及相关配置


如果需要的话,可以设置工程产生  .hex

之后工程结构如下:

然后新建文件 main.c 编写如下代码

 

#include "nrf_gpio.h"

 

//定义自己板子上的 按键 和 led灯 的引脚

#define BUTTON_PIN      17

#define LED_PIN               21

 

int main(void){

 

         nrf_gpio_pin_pull_t config = NRF_GPIO_PIN_PULLUP;

        

         nrf_gpio_cfg_output(LED_PIN);

         nrf_gpio_cfg_input(BUTTON_PIN, config);

        

         while(1){

                   if ( nrf_gpio_pin_read(BUTTON_PIN) == 0 ){

                            nrf_gpio_pin_clear(LED_PIN);                            //按下按键就点灯

                   }else{

                            nrf_gpio_pin_set(LED_PIN);                                //没按键就灭灯

                   }

         }

         return 0;

}

 

编译后下载就可以了


<think>我们正在配置nRF54L15芯片的TIMER外设来捕获GPIO信号。根据nRF5 SDK的常见配置模式,通常步骤如下: 1. 配置GPIO引脚作为输入,并连接到TIMER的捕获通道。 2. 配置TIMER的工作模式(如定时器模式、计数器模式等)。 3. 配置捕获任务(CAPTURE TASK)和相应的事件(EVENT)。 4. 使能中断(如果需要)并设置中断处理函数。 5. 启动TIMER。 注意:nRF54系列是较新的系列,其配置可能与nRF52系列有所不同,但基本概念相似。具体寄存器名称和位域可能会有所变化,需要参考nRF54L15的芯片手册和头文件。 由于没有直接关于nRF54L15的详细文档在手,我们基于nRF5 SDK的通用方法进行推导,并参考了nRF54H20的一些时钟信息(因为同属54系列)[^1]。但请注意,具体到nRF54L15,我们需要查看其技术手册。 步骤详细说明: 1. **配置GPIO**: 将需要捕获信号的GPIO引脚配置为输入,并设置上拉/下拉(根据信号特性)。然后,将该引脚连接到TIMER的特定捕获通道(通过PSEL.CAPTURE[n]寄存器)。 2. **配置TIMER**: 初始化TIMER外设,设置预分频器(PRESCALER)以确定计数频率,设置位宽(BITMODE,如16位或32位)。选择工作模式(MODE),通常为定时器模式(Timer mode)。 3. **配置捕获通道**: 每个TIMER可以有多个捕获通道(通常为4个或6个,具体看芯片)。为需要捕获的通道配置捕获任务(TASKS_CAPTURE[n])。当捕获事件发生时,当前计数器的值会被存入捕获寄存器(CC[n])。 4. **配置事件和中断**: 如果需要,可以配置捕获事件(EVENTS_COMPARE[n])来触发中断。在中断服务程序(ISR)中读取捕获值,并处理(例如计算脉冲宽度)。使能中断(INTENSET寄存器)。 5. **启动TIMER**: 通过触发START任务来启动TIMER。 6. **触发捕获**: 可以通过程序触发TASKS_CAPTURE[n]任务,或者在GPIO信号边沿自动捕获(这需要配置GPIO和TIMER之间的连接,通常通过PPI和GPIOTE实现自动触发)。 但是,在nRF系列中,TIMER本身并不直接支持通过GPIO边沿自动触发捕获任务。通常,我们需要结合GPIOTE和PPI来实现: - 配置GPIOTE:设置GPIO引脚的事件模式(Event mode),当检测到指定边沿(上升沿、下降沿或双边沿)时产生事件。 - 配置PPI:将GPIOTE产生的事件连接到TIMER的捕获任务(TASKS_CAPTURE[n])。这样,当GPIO信号边沿到来时,自动触发TIMER捕获当前计数值。 因此,完整的配置步骤还应包括GPIOTE和PPI的配置。 具体步骤(结合GPIOTE和PPI): 1. 配置GPIO引脚为输入。 2. 配置GPIOTE:选择一个GPIOTE通道,配置为事件模式,指定引脚和边沿(例如上升沿)。 3. 配置TIMER:初始化TIMER,设置预分频器和位宽,启动TIMER(START任务)。 4. 配置PPI:将GPIOTE事件连接到TIMER的捕获任务(例如CAPTURE[0]任务)。 5. 使能PPI通道。 这样,当指定边沿到来时,GPIOTE产生事件,通过PPI触发TIMER的捕获任务,将当前计数器值存入CC[0]寄存器。 示例代码框架(基于nRF5 SDK风格,但注意nRF54系列可能使用nRF Connect SDK,这里以寄存器级操作为例): 由于nRF54系列可能使用新的外设结构,以下代码仅供参考,具体请查阅nRF54L15的文档。 ```c #include <stdint.h> #include "nrf.h" // 假设使用TIMER0,GPIOTE通道0,PPI通道0,捕获通道0 #define CAPTURE_PIN 3 // GPIO引脚号 #define TIMER NRF_TIMER0 #define GPIOTE_CH 0 #define PPI_CH 0 #define CAPTURE_CH 0 // TIMER的捕获通道 void timer_capture_init(void) { // 1. 配置GPIO NRF_P0->PIN_CNF[CAPTURE_PIN] = (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos); // 根据信号选择上拉 // 2. 配置GPIOTE NRF_GPIOTE->CONFIG[GPIOTE_CH] = (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos) | (CAPTURE_PIN << GPIOTE_CONFIG_PSEL_Pos) | (GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos); // 上升沿 // 3. 配置TIMER TIMER->PRESCALER = 4; // 16MHz / (2^4) = 1MHz,即1us计数 TIMER->BITMODE = TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos; // 32位模式 TIMER->TASKS_START = 1; // 启动定时器 // 4. 配置PPI NRF_PPI->CH[PPI_CH].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[GPIOTE_CH]; // GPIOTE事件地址 NRF_PPI->CH[PPI_CH].TEP = (uint32_t)&TIMER->TASKS_CAPTURE[CAPTURE_CH]; // TIMER捕获任务地址 NRF_PPI->CHENSET = (1 << PPI_CH); // 使能PPI通道 } // 在需要读取捕获值的地方,可以读取: // uint32_t capture_value = TIMER->CC[CAPTURE_CH]; ``` 注意:以上代码是概念性的,实际开发中应使用nRF54L15的特定外设寄存器名称,并注意新系列中可能存在的差异。例如,nRF54系列可能将外设寄存器组织方式做了调整,或者使用新的同步机制(如使用DPPI代替PPI)。 根据引用[^1]中提到的nRF54H20的时钟信息,nRF54L15可能也有类似的时钟结构,因此设置预分频器时需注意时钟源频率。 由于没有nRF54L15的具体手册,建议查阅Nordic官方提供的nRF54L15技术规格书和头文件。 另外,在nRF Connect SDK(基于Zephyr)中,可以使用其提供的驱动,步骤会有所不同,但原理相同。 如果使用Zephyr RTOS,配置步骤可能如下: 1. 在设备树中配置引脚和TIMER节点。 2. 在代码中使用Zephyr的API进行配置。 但用户问题中没有说明使用何种开发环境(裸机还是Zephyr),因此我们提供了寄存器级的参考。 如果用户需要更具体的代码,请提供开发环境(如是否使用nRF Connect SDK)以及具体需求(如捕获的边沿类型、需要几个通道等)。 注意:以上代码仅为示例,实际使用中需要根据具体情况进行调整。 相关问题: 1. 如何配置nRF54L15的GPIOTE来捕获GPIO边沿? 2. nRF54L15的TIMER外设与nRF52系列有什么主要区别? 3. 在nRF Connect SDK中如何使用TIMER捕获GPIO信号?</think>以下是配置 nRF54L15 芯片使用 TIMER 捕获 GPIO 信号的详细步骤: ### 配置步骤 1. **GPIO 引脚配置** - 将目标 GPIO 引脚设为输入模式 - 配置上拉/下拉电阻(根据信号特性选择) ```c nrf_gpio_cfg_input(PIN_TO_CAPTURE, NRF_GPIO_PIN_PULLDOWN); ``` 2. **GPIOTE 设置** - 配置 GPIOTE 通道为事件模式(Event Mode) - 指定触发边沿(上升沿/下降沿/双边沿) ```c nrf_gpiote_event_configure(GPIOTE_CHANNEL, PIN_TO_CAPTURE, NRF_GPIOTE_POLARITY_TOGGLE); nrf_gpiote_event_enable(GPIOTE_CHANNEL); ``` 3. **TIMER 初始化** - 选择 TIMER 实例(如 TIMER0) - 设置预分频器(Prescaler)控制计数频率 - 配置为定时器模式(非计数器模式) ```c nrf_timer_mode_set(TIMER0, NRF_TIMER_MODE_TIMER); nrf_timer_frequency_set(TIMER0, NRF_TIMER_FREQ_16MHz); // 基准频率 nrf_timer_bit_width_set(TIMER0, NRF_TIMER_BIT_WIDTH_32); // 32位模式 ``` 4. **PPI 通道连接** - 通过 PPI 将 GPIOTE 事件与 TIMER 捕获任务绑定 - 实现信号边沿自动触发捕获 ```c nrf_ppi_channel_endpoint_setup( PPI_CHANNEL, (uint32_t)&nrf_gpiote_event_addr_get(NRF_GPIOTE_EVENT_IN_0), (uint32_t)&nrf_timer_task_address_get(TIMER0, NRF_TIMER_TASK_CAPTURE0) ); nrf_ppi_channel_enable(PPI_CHANNEL); ``` 5. **启动 TIMER** ```c nrf_timer_task_trigger(TIMER0, NRF_TIMER_TASK_START); ``` 6. **读取捕获值** - 当信号边沿触发时,TIMER 当前值自动存入捕获寄存器 ```c uint32_t capture_value = nrf_timer_cc_read(TIMER0, NRF_TIMER_CC_CHANNEL0); ``` ### 关键配置说明 1. **时钟配置** nRF54L15 的 TIMER 时钟源为高速外设时钟(通常 128 MHz[^1]),通过预分频器调整实际计数频率: $$f_{实际} = \frac{128\text{MHz}}{2^{PRESCALER}}$$ 2. **信号捕获原理** -GPIO 边沿触发时,GPIOTE 生成事件 - PPI 无延迟触发 TIMER 的 `CAPTURE` 任务 - TIMER 当前计数值锁存到 CC 寄存器 - 两次捕获值之差即为脉冲宽度: $$\Delta t = \frac{|CC_1 - CC_0|}{f_{实际}}$$ 3. **精度优化** - 使用 32 位 TIMER 模式避免溢出 - 最小预分频值(PRESCALER=0)可获得最高时间分辨率: $$\text{分辨率} = \frac{1}{128\text{MHz}} \approx 7.8\text{ns}$$ ### 注意事项 1. 确保 GPIOTE、PPI、TIMER 使用的通道无冲突 2. 高频信号捕获时需考虑中断延迟影响,建议使用 PPI 直接传输 3. 长脉冲测量时需处理 TIMER 溢出(启用溢出中断或使用 SAMPLE 任务) [^1]: nRF54 系列时钟架构参考文档
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值