西安微信网站开发北京网页制作案例

当前位置: 首页 > news >正文

西安微信网站开发,北京网页制作案例,wordpress 导航下拉,淄博网站建设 很乱这里写目录标题 GPIOTE 原理分析GPIOTE 输入事件应用GPIOTE 事件寄存器应用GPIOTE 事件组件的应用#xff08;库函数#xff09;GPIOTE PORT 事件应用 GPIOTE 任务应用GPIOTE 任务触发 LED 寄存器操作组件方式进行任务配置 GPIOTE 原理分析 GPIO 任务和时间#xff08;GPIO… 这里写目录标题 GPIOTE 原理分析GPIOTE 输入事件应用GPIOTE 事件寄存器应用GPIOTE 事件组件的应用库函数GPIOTE PORT 事件应用 GPIOTE 任务应用GPIOTE 任务触发 LED 寄存器操作组件方式进行任务配置 GPIOTE 原理分析 GPIO 任务和时间GPIOTE模块提供了使用任务和事件访问 GPIO 引脚的功能。每个 GPIOTE 通道被分配到一个引脚GPIOTE 其实就是对 GPIO 口进行操作同时引入了外部中断的概念。 比如按键控制分为两种情况 按键扫描CPU 需要不停工作来判断 GPIO 引脚是否有拉低或者置高效率很低外部中断控制中断控制的效率很高一旦系统 IO 口出现上升或下降沿电平就会触发中断内的程序。 在 nRF52832 内部普通的 IO 管脚设置成 GPIO中断和任务管脚设置成 GPIOTE。 nRF5x 系列处理器将 GPIO 的中断的快速触发做成了一个单独的模块 GPIOTE这个模块不仅提供了 GPIO 的中断功能同时提供了通过 task 和 event 方式来访问 GPIO 的功能。GPIOTE 的后缀 T 即为 taskE 为 event。 Event 称为事件来源与 GPIO 的输入、定时器的匹配中断等可以产生中断的外设来触发。Task 称为任务就是执行某一特定功能比如翻转 IO 端口等。那么事件 event 触发任务 task。task 和 event 的组合是为了和 52832 中的 PPI可编程外围设备互联系统模块的配合使用。这种机制不需要 CPU 参与极大的减少了内核消耗降低功率特别适合于 BLE 低功耗蓝牙进行应用。 GPIOTE 实际上分为两种模式 任务模式作为输出使用事件模式作为中断触发使用 GPIOTE task 任务模式每个 GPIOTE 通道最多可以使用三个任务来执行引脚的写操作。 固定的输出高电平SET固定的输出低电平CLR输出任务OUT可以配置为执行 置位、清零、切换。 GPIOTE event 事件模式可以从以下输入条件之一在每个 GPIOTE 通道中生成事件 上升边缘下降边缘任何改变 任务模式有三种状态置位、清零、翻转事件模式有三种触发状态上升沿触发、下降沿触发、任意变化触发。TASJK 任务通过通道 OUT[0]-OUT[7] 设置输出触发状态Event 则可以通过检测信号产生 PORT event 事件产生 IN[n] event 事件。 整个 GPIOTE 寄存器的个数非常少。GPIOTE 模块提供了 8 个通道这 8 个通道都是通过 CONFIG[0]~CONFIG[7] 寄存器来配置。八个通道可以通过单独设置来分别和普通的 GPIO 绑定。当需要使用 GPIOTE 的中断功能时可以设置相应寄存器的相关位让某个通道作为 event 事件模式同时配置触发 event 动作。比如绑定的引脚有上升沿跳变或者下降沿跳变触发 event然后配置中断使能寄存器配置让其 event 产生时触发输入中断。这样实现了 GPIO 的中断方式。
GPIO 绑定 GPIOTE 通道 那么如何实现和普通 GPIO 端口的绑定了关键是设置 GPIOTE 的 CONFIG[n]n 0~7 寄存器如下。 如上描述每个 GPIOTE 通道通过 CONFIG.PSEL 字段与一个物理 GPIO 引脚相绑定。 在 CONFIG.MODE 中选择时间模式时CONFIG.PSEL 绑定的引脚将被配置为输入从而覆盖 GPIO 中的 DIR 设置。当在 CONFIG.MODE 中选择任务模式时CONFIG.PSEL 绑定的引脚将被配置为输出也会覆盖 GPIO 中的 DIR 寄存器设置和 OUT 值的输出。当在 CONFIG.MODE 中选择 disabled 时CONFIG.PSEL 绑定的引脚将使用普通 GPIO 中 PIN[n].CNF 寄存器的配置也就是不绑定。因此只能将一个 GPIOTE 通道分配给一个 GPIO 物理引脚。 设置为事件模式 当设置为事件模式时因为事件模式就是输入通过输入信号可以出发事件中断。基本步骤如下 首先在寄存器 CONFIG.PSEL 绑定引脚设置一个 GPIO 管脚绑定 GPIOTE 通道在 CONFIG.MODE 设置为事件模式在 CONFIG.POLARITY 中设置触发事件模式的输入电平当对应电平输入 GPIOTE 通道后就会产生中断EVENTS_IN 寄存器就来判断对应端口中断事件是否发生。 设置为任务模式 因为任务模式为输出模式。配置过程 首先需要设置 CONFIG.PSEL 绑定 GPIO 管脚然后设置 CONFIG.MODE 为 GPIOTE 任务模式设置 CONFIG.POLARITY OUT[n[ 任务输出置位、清零、切换设置完成后触发任务。TASKS_OUT[n] 触发 OUT[n] 值、TASKS_SET[n] 触发高电平、TASKS_CLR[n] 触发低电平 三种状态触发同时申请则优先级如下执行 任务状态优先级TASKS_OUT1TASKS_CLR2TASKS_SET3 中断配置 中断是在事件模式下触发的如果在配置寄存器 CONFIG[n] 中绑定了对应的 GPIO 端口同时配置为事件输入模式那么可以通过 INTENSET 寄存器是能对应的中断通道。通过 INTENCLR 寄存器关闭对应的中断通道。INTENSET 寄存器和 INTENCLR 寄存器如下表所示 INTENSET 寄存器
INTENCLR 寄存器
GPIOTE 输入事件应用 GPIOTE 事件寄存器应用 修改前面 GPIO 应用按键应用改为中断控制方式。中断控制的效率很高一旦系统 IO 口出现上升沿或者下降沿电平就会触发执行中断内的处理程序。这样可以大大节省 CPU 的占用。中断在计算机多任务处理尤其是实时系统重尤为有用这样的系统包括运行在骑上的操作系统也成为“中断驱动”。 硬件方面和前面讲述 GPIO 输入扫描哪里的按键输入应用一样。四个按键分别连接 P0.13、 P0.14、 P0.15、 P0.16。 在使用 nRF52832 完成中断时当 IO 管脚为低的时候可以判断管脚已经按下。通过 key 的中断来控制 led 的亮灭。硬件上设计是比较简单的这和普通的 MCU 的中断用法一致。如下创建工程。 这样我们需要编写 exit.c 文件主要有两部分初始化开发板上的按键中断编写中断执行代码。 按键中断这里实际上使用了事件模式。在 CONFIG 寄存器里进行了事件模式的配置。代码如下 NRF_GPIOTE-CONFIG0_POLARITY_HiToLo GPIOTE_CONFIG_POLARITY_Pos) //输入事件极性| (13 GPIOTE_CONFIG_PSEL_Pos)//绑定的引脚| (GPIOTE_COFNIG_MODE_Event GPIOTE_CONFIG_MODE_Pos);//模式配置上面的代码严格按照寄存器要求进行首先是 MODE 模式设置配置 GPIOTE 通道作为 event 还是 task 使用这里设置成 event 事件。PSEL 设置对应绑定的 IO 管脚选择 P0.13 作为触发管脚POLARIY 极性设置为下降沿触发。 设置好了工作方式后我们就需要进行中断的使能了因为前面绑定的是 GPIOTE 的 0 通道因此中断使能代码如下 NVIC_EnableIRQ(GPIOTE_IRQn);//中断嵌套是能 NRF_GPIOTE-INTENSET GPIOTE_INTENSET_IN0_Set GPIOTE_INTENSET_IN0_Pos;//是能中断通道 IN0上面任务基本上就可以把 GPIOTE 管脚中断配置好了如果搞清楚这些寄存器配置很简单。中断函数的设计这里主要讲 LED 灯状态翻转当然也可以加入对应的其他处理操作。 void GPIOTE_IRQHander() {if((NRF_GPIOTE-EVENTS_IN[0] 1) (NRF_GPIOTE-INTENSET GPIOTE_INTENSET_IN0_Msk)){Delay(10000);//延迟消抖NRF_GPIOTE-EVENTS_IN[0] 0;//中断事件清零}LED_Toggle();//led 灯状态翻转 }完成 exit.c 的编写后main 主函数的操作就很简单直接调用写好的驱动函数然后尝试按键是否有对应的响应即可。 #include nrf52.h #include nrf_gpio.h #include exit.h #include led.hint mian() {LED_Init();LED_Open();EXIT_KEY_Init();while(1){//这里暂时控制主操作死循环}return 0; }GPIOTE 事件组件的应用库函数 通过使用 nrf 官方库函数可以更加方便完成整个过程的操作对于寄存器操作我们仅仅只需要了解原理即可如果非要使用寄存器去完成开发对日后维护和使用有很大弊端所以官方已经将这部分进行了完美的封装。我们根据官方 SDK 的封装接口进行调用完成对应操作即可。 添加了 SDK 库函数的工程和之前也有所不同这里添加了 nRF_Libraries 库函数路径。 官方也提供了一个驱动 nrfx_gpiote 的 GPIOTE 驱动库但是这个驱动库带有错误跟踪函数所以工程中必须添加错误跟踪库。同时区别于寄存器编程组件库还需要配置 sdk_config.h 配置文件。 打开 sdk_config.h 配置文件打开配置向导 Configuration Wizard勾选以下两个使能项目 GPIOTE_ENABLE 使能 GPIOTE 驱动库NRFX_GPIOTE__ENABLE 使能 GPIOTE 兼容库 同时需要再 C/C 中添加硬件 GPIOTE 的库文件和头文件路径如下 库函数介绍 函数 nrf_drv_gpiote_init 等同于函数 nrfx_gpiote_init 函数 nrf_drv_gpiote_in_init 等同于函数 nrfx_gpiote_in_init nrf_drv_gpiote_in_event_enable 等同于函数 nrfx_gpiote_in_event_enable
介绍完了前面的库函数接口。由于驱动组件库 SDK 已经编写好了我们只需要编写 main.c 的主函数调用即可。 #include stdbool.h #include nrf.h #include nrf_drv_gpiote.h #include app_error.h #include boards.h#ifdef BSP_BUTTON_0#define PIN_IN BSP_BUTTON_0 #endif #ifndef PIN_IN#error Please indicate input pin #endif#ifdef BSP_LED_0#define PIN_OUT BSP_LED_0 #endif #ifndef PIN_OUT#error Please indicate output pin #endif/GPIOTE中断处理*/ void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {if(nrf_gpio_pin_read(PIN_IN) 0)//按键防抖{nrf_gpio_pin_toggle(PIN_OUT);} } / 配置GPIOTE初始化/ static void gpio_init(void) {nrf_gpio_cfg_output(PIN_OUT);//led灯的输出ret_code_t err_code;err_code nrf_drv_gpiote_init();//初始化GPIOTEAPP_ERROR_CHECK(err_code);nrf_drv_gpiote_in_config_t in_config GPIOTE_CONFIG_IN_SENSE_TOGGLE(true);in_config.pull NRF_GPIO_PIN_PULLUP;//设置GPIOTE输入极性模式err_code nrf_drv_gpiote_in_init(PIN_IN, in_config, in_pin_handler);APP_ERROR_CHECK(err_code);//使能GPIOTEnrf_drv_gpiote_in_event_enable(PIN_IN, true); }/** 主函数循环等待中断/ int main(void) {gpio_init();while (true){// Do nothing.} } GPIOTE PORT 事件应用 把普通的 GPIO 端口配置为 GPIOTE 中断输入事件能够绑定的只有 8 个通道如果我们中断的数据量超过了 8 个多的中断无法处理如何出现这种情况怎么处理显然芯片设计厂家为了针对这种情况特别在 GPIOTE 模块中提出了 GPIOTE PORT 功能。 GPIOTE PORT 是从使用 GPIO DETECT 信号的多个 IO 输入引脚来生成的事件。该事件将在 DETECT 信号的上升沿而产生。也就是说这个功能可以通过 32 个 IO 端口来产生相当于一个总通道32 个 IO 端口共用这个通道来申请中断。 同时 GPIO DETECT 信号就是通过 GPIO 的 SENSE 寄存器打开此功能始终处于启用状态。即便外围设备本身是休眠状态也不需要请求时钟或其他功率密集型基础架构来启用此功能。因此此功能可用于在系统启动时从 WFI 或 WFE 类型的睡眠时来唤醒 CPU、所有外设和 CPU 空闲。达到唤醒系统启动模式下的最低功耗模式。 为了在配置源时防止来自 PORT 事件的虚假中断用户应首先禁用 PORT 事件中的中断通过 INTENCLR.PORT然后配置源PIN_CNF[n].SENSE清除配置期间可能发生的任何潜在事件向EVENTS_PORT写入“1”最后启用中断通过INTENSET.PORT。 采用组件库编写 GPIOTE 输入事件与 GPIOTE PORT 事件的主要区别 配置事件的时候选择 IN 事件还是 PORT 事件这个通过配置函数实现GPIOTE_CONFIG_IN_SENSE_HITOLO(false当函数参数是 false 的时候选择 PORT 事件当函数参数是 true 的时候选择 IN 事件所有 32 个 IO 端口触发的中断都是 INTENSET.PORT因此配置都指向一个中断配置就可以了。 #include stdbool.h #include nrf.h #include nrf_drv_gpiote.h #include app_error.h #include boards.h/GPIOTE中断处理*/ void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {//事件由按键S1产生即按键S1按下if(pin BUTTON_1){//翻转指示灯D1的状态nrf_gpio_pin_toggle(LED_1);}//事件由按键S2产生即按键S2按下else if(pin BUTTON_2){//翻转指示灯D2的状态nrf_gpio_pin_toggle(LED_2);}//事件由按键S3产生即按键S3按下else if(pin BUTTON_3){//翻转指示灯D3的状态nrf_gpio_pin_toggle(LED_3);}//事件由按键S4产生即按键S4按下else if(pin BUTTON_4){//翻转指示灯D4的状态nrf_gpio_pin_toggle(LED_4);}} / 配置GPIOTE初始化/ static void gpio_init(void) { //配置LED灯输出nrf_gpio_cfg_output(LED_1);nrf_gpio_cfg_output(LED_2);nrf_gpio_cfg_output(LED_3);nrf_gpio_cfg_output(LED_4);ret_code_t err_code;//初始化GPIOTEerr_code nrf_drv_gpiote_init();APP_ERROR_CHECK(err_code);//配置SENSE模式选择fales为sense配置nrf_drv_gpiote_in_config_t in_config GPIOTE_CONFIG_IN_SENSE_HITOLO(false);in_config.pull NRF_GPIO_PIN_PULLUP;//配置按键0绑定POTRerr_code nrf_drv_gpiote_in_init(BSP_BUTTON_0, in_config, in_pin_handler);APP_ERROR_CHECK(err_code);nrf_drv_gpiote_in_event_enable(BSP_BUTTON_0, true);//配置按键1绑定POTRerr_code nrf_drv_gpiote_in_init(BSP_BUTTON_1, in_config, in_pin_handler);APP_ERROR_CHECK(err_code);nrf_drv_gpiote_in_event_enable(BSP_BUTTON_1, true);//配置按键2绑定POTRerr_code nrf_drv_gpiote_in_init(BSP_BUTTON_2, in_config, in_pin_handler);APP_ERROR_CHECK(err_code);nrf_drv_gpiote_in_event_enable(BSP_BUTTON_2, true);//配置按键3绑定POTRerr_code nrf_drv_gpiote_in_init(BSP_BUTTON_3, in_config, in_pin_handler);APP_ERROR_CHECK(err_code);nrf_drv_gpiote_in_event_enable(BSP_BUTTON_3, true);}/** 主函数循环等待中断/ int main(void) {gpio_init();while (true){// Do nothing.} } 修改 sdk_config.h 配置文件将其中中断配置的事件数目修改为 4。
GPIOTE 任务应用 GPIOTE 任务触发 LED 寄存器操作 GPIOTE 具有任务模式任务模式就是输出模式。如果把 GPIO 管脚绑定了 GPIOTE 通道后把它配置为任务模式则可以实现输出功能。任务模式的使用不是孤立的一般都是由事件来触发任务如果在事件和任务中间假设一个通道也就是后面的 PPI那么整个过程不需要 CPU 参与了大大节省了 MCU 资源。 构建工程 新建 GPIOTE.c首先是 GPIOTE 任务初始化初始化两个 GPIOTE 通道。初始化首先设置通道 CONFIG[0].PSEL 域设置绑定 GPIO 的 19 管脚CONFIG[1].PSEL 绑定 20 管脚再设置两个通道的 CONFIG.MODE 为 TASK 任务模式最后设置 CONFIG.POLARITY 为 OUT[0] 任务输出位翻转电平OUT[1] 输出低电平。具体如下 #include nrf52.h #include nrf_gpio.h #include GPIOTE.hvoid Delay(uint32_t temp) {for(; temp! 0; temp–); } void GPIOTE_TASK_Init(void) {NVIC_EnableIRQ(GPIOTE_IRQn);//中断嵌套设置//绑定两个GPIOTENRF_GPIOTE-CONFIG0//设置极性翻转| (GPIOTE0 GPIOTE_CONFIG_PSEL_Pos) //绑定管脚| (GPIOTE_CONFIG_MODE_Task GPIOTE_CONFIG_MODE_Pos);//设置模式//配置任务输出状态、绑定通道、任务模式详细说明请参看青风教程NRF_GPIOTE-CONFIG1//输出低电平| (GPIOTE1 GPIOTE_CONFIG_PSEL_Pos) | (GPIOTE_CONFIG_MODE_Task GPIOTE_CONFIG_MODE_Pos);配置任务输出状态、绑定通道、任务模式详细说明请参看青风教程}主函数 main 中只需要初始化即可。 #include nrf52.h #include nrf_gpio.h #include GPIOTE.h #include led.h #include nrf_delay.hint main(void) {/初始化输出任务/GPIOTE_TASK_Init();while(1){//触发输出任务模式NRF_GPIOTE-TASKS_OUT[0]1;//由config寄存器里的极性配置觉得输出的信号NRF_GPIOTE-TASKS_OUT[1]1;nrf_delay_ms(500);} }组件方式进行任务配置 和前面操作类似这里使用 SDK 库函数的 API 进行组件方式的任务配置。 nrf_drv_gpiote_out_init类似 nrfx_gpiote_out_init。 nrf_drv_gpiote_out_task_enabel , 类似 nrfx_gpiote_out_task_enabel 具体操作代码如下 #include stdbool.h #include nrf.h #include nrf_drv_gpiote.h #include app_error.h #include nrf_delay.h#define GPIOTE0 19 #define GPIOTE1 20void GPIOTE_TASK_Init(void){ret_code_t err_code; //初始化GPIOTE程序模块err_code nrf_drv_gpiote_init();APP_ERROR_CHECK(err_code);//定义GPIOTE输出初始化结构体主要是配置为翻转模式nrf_drv_gpiote_out_config_t config1 GPIOTE_CONFIG_OUT_TASK_TOGGLE(true);////绑定GPIOTE输出引脚err_code nrf_drv_gpiote_out_init(GPIOTE0, config1);APP_ERROR_CHECK(err_code);//配置为引脚LED_3所在GPIOTE通道的任务模式nrf_drv_gpiote_out_task_enable(GPIOTE0); //定义GPIOTE输出初始化结构体主要是配置为低电平模式nrf_drv_gpiote_out_config_t config2 GPIOTE_CONFIG_OUT_TASK_LOW;//绑定GPIOTE输出引脚err_code nrf_drv_gpiote_out_init(GPIOTE1, config2);APP_ERROR_CHECK(err_code);//配置为引脚LED_4所在GPIOTE通道的任务模式nrf_drv_gpiote_out_task_enable(GPIOTE1); }int main(void) {GPIOTE_TASK_Init(); while(true){ //触发输出即指示灯D3D4翻转状态nrf_drv_gpiote_out_task_trigger(GPIOTE0); nrf_drv_gpiote_out_task_trigger(GPIOTE1);nrf_delay_ms(500);} }