NRF52840学习历程(六)RTC 实时计数器(滴答定时器)

发布者:RainbowMelody最新更新时间:2021-04-19 来源: eefocus关键字:NRF52840  RTC  滴答定时器 手机看文章 扫描二维码
随时随地手机看文章

开发板:初雪的100出头那块 NRF52840 EVAL KIT


下载工具:JINLK V11(最好是JLINK V9以上 也有人用JLINK OB也行,其他的下载器诸如STLINK,DAP不建议用)


版本号: KEIL5编程环境,CMSIS为5.3.0, NRF52840的CMSIS为8.35.0

参考资料: NRF52840-Eval-Kit-Schematic.pdf(原理图)


nRF5_SDK_17.0.2_d674dde(官方例程)


nRF5_SDK_17.0.0_offline_doc(官方文档)


nRF52840_PS_v1.1.pdf(官方数据手册)


RTC 实时计数器 32.768KHz外部低频晶振

 

nRF52 处理器内部的 RTC 是实时计数器,其是 Real-time counter 的缩写,是在低频时钟源LFCLK 上提供一个通用的低功耗定时器。区别于单片机中常使用的实时时钟,实时时钟的缩写也是RTC,其是 Real-time Clock 的缩写。实时时钟是为人们提供精确的实时时间或者为电子系统提供精确的时间基准。因此要注意本章内容讲述的 RTC 为实时计数器,它与实时时钟是有区别的

 

nRF52 处理器内部的 RTC 模块具有 RTC0、RTC1、RTC2 三个,每个模块其内部具有一个24 位计数器、12 位预分频器、捕获/比较寄存器和一个滴答事件生成器用于低功耗、无滴答 RTOS的实现。

 

添加驱动文件

大概在


......SDKcomponentsdrivers_nrfnrf_soc_nosdnrf_soc.c


............modulesnrfxdriverssrcnrfx_power.c


......SDKintegrationnrfxlegacynrf_drv_clock.c


添加SDK_CONFIG

分频                             跳动一次时间                     最大计时时间

实现功能: 滴答定时器点灯


添加头文件:


#include "nrf_drv_rtc.h"

#include "nrf_drv_clock.h"

配置低速时钟:


nrf_drv_clock_init(); // 开启时钟

nrf_drv_clock_lfclk_request(NULL); // 请求低频时钟请求,没有配置事件中断

配置RTC:


nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG;

config.prescaler = 0; // 不分频,就用32768为时钟,30.517us一次

然后定义一下 使用RTC0(RTC有0,1,2共3个)


const nrf_drv_rtc_t rtc = NRF_DRV_RTC_INSTANCE(0); /**< Declaring an instance of nrf_drv_rtc for RTC0. */

继续写代码:( 这个代码不行,后面有修改)


nrf_drv_rtc_init(&rtc, &config, My_RTCInterrupt); // 使用RTC0,写入结构体,

nrf_drv_rtc_tick_enable(&rtc,true); //开启滴答定时器事件中断

 

//使用RTC0 , CC为通道0, 比较值为,  比较成功后触发中断

// 33 * 30.517u = 1.007061ms

nrf_drv_rtc_cc_set(&rtc,0,33,true); //大概为1ms

nrf_drv_rtc_enable(&rtc); //启动RTC定时器

 

我用33 * 30.517u = 1.007061ms 约为1ms 就触发比较事件一次


 


测试后发现, 不能这么做


比较完1ms之后就无法重新计数1ms了, 无法恢复正常,只能使用1次,所以不要用比较了,那么就只用滴答定时器功能,不要输出比较定时


 


因为要定时1ms 于是修改为由32768分频出来的1ms


    1 / 32768 *33 = 1ms(约等于)


代码修改为:


nrf_drv_clock_init(); // 开启时钟

nrf_drv_clock_lfclk_request(NULL); // 请求低频时钟请求,没有配置事件中断

 

    nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG; //使用SDK_CONFIG那边的默认配置

config.prescaler = 33; // 1/ (32768/33) = 1ms

 

nrf_drv_rtc_init(&rtc, &config, My_RTCInterrupt); // 使用RTC0,写入结构体,中断函数

nrf_drv_rtc_tick_enable(&rtc,true); //开启滴答定时器事件中断

nrf_drv_rtc_enable(&rtc); //启动RTC定时器

 

中断函数为:


void My_RTCInterrupt(nrfx_rtc_int_type_t int_type)

{

static uint16_t flag500ms = 0;

    if (int_type == NRF_DRV_RTC_INT_COMPARE0) 

    { //无法恢复正常,只能使用1次,所以不要用比较了

// nrf_gpio_pin_toggle(LED0);

    }

    //滴答中断 这边是 1/ 32768 * 33 = 1ms

    else if (int_type == NRF_DRV_RTC_INT_TICK)

    {

if( ++flag500ms == 500 )

{

nrf_gpio_pin_toggle(LED3);

flag500ms = 0;

}

    }

}

 

 


整体代码为:


 

#include

#include

#include "nrf_delay.h"

#include "nrf_gpio.h"

#include "nrf_drv_gpiote.h"

 

#include "nrf_uart.h"

#include "app_uart.h"

#include "nrf_drv_timer.h"

 

#include "nrf_drv_rtc.h"

#include "nrf_drv_clock.h"

 

uint32_t LED0,LED1,LED2,LED3;

uint32_t KEY0,KEY1,KEY2,KEY3;

 

void KEY_Interrupt(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action);

 

 

#define MAX_TEST_DATA_BYTES     (15U)                /**< max number of test bytes to be used for tx and rx. */

#define UART_TX_BUF_SIZE 256                         /**< UART TX buffer size. */

#define UART_RX_BUF_SIZE 256                         /**< UART RX buffer size. */

 

void uart_interrupt(app_uart_evt_t * p_event);

 

 

const nrf_drv_timer_t My_Timer0 = NRF_DRV_TIMER_INSTANCE(4);

// 0~4共5个定时计数器

void My_Timer0_Interrupt(nrf_timer_event_t event_type,

void  * p_context);

 

 

 

const nrf_drv_rtc_t rtc = NRF_DRV_RTC_INSTANCE(0); /**< Declaring an instance of nrf_drv_rtc for RTC0. */

void My_RTCInterrupt(nrfx_rtc_int_type_t int_type);

 

 

/**

 * @brief Function for application main entry.

 */

int main(void)

{

nrf_drv_gpiote_in_config_t key_ex_config; //按键中断配置用

LED0 =  NRF_GPIO_PIN_MAP(0,13);

LED1 =  NRF_GPIO_PIN_MAP(0,14);

LED2 =  NRF_GPIO_PIN_MAP(1,9);

LED3 =  NRF_GPIO_PIN_MAP(0,16);

 

KEY0 =  NRF_GPIO_PIN_MAP(0,11);

KEY1 =  NRF_GPIO_PIN_MAP(0,24);

KEY2 =  NRF_GPIO_PIN_MAP(0,20);

KEY3 =  NRF_GPIO_PIN_MAP(0,17);

 

nrf_gpio_cfg_output(LED0);

nrf_gpio_cfg_output(LED1);

nrf_gpio_cfg_output(LED2);

nrf_gpio_cfg_output(LED3);

 

nrf_gpio_pin_set(LED0);

nrf_gpio_pin_set(LED1);

nrf_gpio_pin_set(LED2);

nrf_gpio_pin_set(LED3);

nrf_gpio_cfg_input(KEY0,NRF_GPIO_PIN_PULLUP );

nrf_gpio_cfg_input(KEY1,NRF_GPIO_PIN_PULLUP );

nrf_gpio_cfg_input(KEY2,NRF_GPIO_PIN_PULLUP );

nrf_gpio_cfg_input(KEY3,NRF_GPIO_PIN_PULLUP );

nrf_drv_gpiote_init();//启动GPIOTE时钟,可以这么说

key_ex_config.hi_accuracy=false; // 启用低精确度PORT事件

key_ex_config.pull = NRF_GPIO_PIN_PULLUP ; //上啦

key_ex_config.sense = NRF_GPIOTE_POLARITY_HITOLO ;//下降沿

nrf_drv_gpiote_in_init(KEY0, &key_ex_config, KEY_Interrupt);

nrf_drv_gpiote_in_init(KEY1, &key_ex_config, KEY_Interrupt);

nrf_drv_gpiote_in_init(KEY2, &key_ex_config, KEY_Interrupt);

nrf_drv_gpiote_in_init(KEY3, &key_ex_config, KEY_Interrupt);

 

nrf_drv_gpiote_in_event_enable(KEY0, true);//启动KEY0中断

nrf_drv_gpiote_in_event_enable(KEY1, true);//启动KEY1中断

nrf_drv_gpiote_in_event_enable(KEY2, true);//启动KEY2中断

nrf_drv_gpiote_in_event_enable(KEY3, true);//启动KEY3中断

    const app_uart_comm_params_t comm_params =

      {

          8,

          6,

          0,

          0,

          APP_UART_FLOW_CONTROL_DISABLED,

          false,

          NRF_UART_BAUDRATE_115200

      };

uint32_t err_code;

    APP_UART_FIFO_INIT(&comm_params,

                         UART_RX_BUF_SIZE,

                         UART_TX_BUF_SIZE,

                         uart_interrupt,

                         APP_IRQ_PRIORITY_LOWEST,

                         err_code);

nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG; //定义定时器结构体  

timer_cfg.bit_width= NRF_TIMER_BIT_WIDTH_16 ;

timer_cfg.frequency= NRF_TIMER_FREQ_1MHz;

timer_cfg.interrupt_priority= 7;

timer_cfg.mode=NRF_TIMER_MODE_TIMER ;

  

nrf_drv_timer_init(&My_Timer0, &timer_cfg,My_Timer0_Interrupt); 

  

uint32_t time_ticks ;

time_ticks = nrfx_timer_ms_to_ticks(&My_Timer0, 1); //算出1ms需要计数多少次

  

nrf_drv_timer_extended_compare( //       time_ticks可以直接写1000

         &My_Timer0, NRF_TIMER_CC_CHANNEL5 , time_ticks, NRF_TIMER_SHORT_COMPARE5_CLEAR_MASK, true);  

/* 使用定时器实例0, CC通道0(定时器0可以用0~3), 比较时间为time_ticks次(1000次), 

清除比较器CC0的任务, 开启定时器0CC通道 */

 

nrf_drv_timer_enable(&My_Timer0);

 

 

 

nrf_drv_clock_init(); // 开启时钟

nrf_drv_clock_lfclk_request(NULL); // 请求低频时钟请求,没有配置事件中断

 

    nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG; //使用SDK_CONFIG那边的默认配置

config.prescaler = 33; // 1/ (32768/33) = 1ms

 

nrf_drv_rtc_init(&rtc, &config, My_RTCInterrupt); // 使用RTC0,写入结构体,中断函数

nrf_drv_rtc_tick_enable(&rtc,true); //开启滴答定时器事件中断

nrf_drv_rtc_enable(&rtc); //启动RTC定时器

 

while(1)

{

// printf("hello world! rn");

}

}

 

void KEY_Interrupt(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action)

{

if(KEY0 == pin)

nrf_gpio_pin_toggle(LED0);

if(KEY1 == pin)

nrf_gpio_pin_toggle(LED1);

if(KEY2 == pin)

nrf_gpio_pin_toggle(LED2);

if(KEY3 == pin)

nrf_gpio_pin_toggle(LED3);

}

 

void uart_interrupt(app_uart_evt_t * p_event)

{

uint8_t dat;

    if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR)

    {

        APP_ERROR_HANDLER(p_event->data.error_communication);

    }

    else if (p_event->evt_type == APP_UART_FIFO_ERROR)

    {

        APP_ERROR_HANDLER(p_event->data.error_code);

    }

    else if (p_event->evt_type == APP_UART_DATA_READY)

{//数据已到达串口 , 可以读数据了

app_uart_get(&dat); //读取数据

app_uart_put(dat); // 原路发回

}

    else if (p_event->evt_type == APP_UART_TX_EMPTY) 

{//发送完成

//发送完成不知道要做什么的,可以点个灯提醒

nrf_gpio_pin_toggle(LED0);

}

}

 

void My_Timer0_Interrupt(nrf_timer_event_t event_type,

void  * p_context) //1ms

{

static uint16_t flag_500ms;

    switch (event_type)

    {

        case NRF_TIMER_EVENT_COMPARE5: // 匹配到了1ms的次数了

if( ++flag_500ms == 500 ) //500ms

{

nrf_gpio_pin_toggle(LED1);

flag_500ms = 0;

}

            break;

 

        default:

            //Do nothing.

            break;

    }

}

 

 

void My_RTCInterrupt(nrfx_rtc_int_type_t int_type)

{

static uint16_t flag500ms = 0;

    if (int_type == NRF_DRV_RTC_INT_COMPARE0) 

    { //无法恢复正常,只能使用1次,所以不要用比较了

// nrf_gpio_pin_toggle(LED0);

    }

    //滴答中断 这边是 1/ 32768 * 33 = 1ms

    else if (int_type == NRF_DRV_RTC_INT_TICK)

    {

if( ++flag500ms == 500 )

{

nrf_gpio_pin_toggle(LED3);

flag500ms = 0;

}

    }

[1] [2]
关键字:NRF52840  RTC  滴答定时器 引用地址:NRF52840学习历程(六)RTC 实时计数器(滴答定时器)

上一篇:mc9s08dz60添加BootLoader实现CANboot下载更新功能
下一篇:MC9S08DZ60移植ucos小记

推荐阅读最新更新时间:2024-11-05 10:12

第8课:WatchDog定时器RTC
首先来讲看门狗定时器:它有2个功能 1:当系统发生紊乱时,自动重启系统 2:普通定时 对于定时狗而言,它使用的是PCLK,和PWM一样有2个分屏器,但是它多了一样复位信号发生器,当看门狗中的CNT递减到0时,复位信号将被发出。作为写一般的程序而言,我们要做的就是不能让看门狗中的计数器CNT到0,要进行 喂狗 。 喂狗:在CNT递减到0之前,重设CNT里的值 原本我们的程序是0.5秒小灯亮,0.5秒小灯暗,现在加入了看门狗,如果发送5秒中内不喂狗的话,就将重启开发板 程序:main.c 功能:初始化计时器,小灯,uart,中断等 #include s3c2440.h #define UART_CLK 50000000
[单片机]
武林教你学PIC32(十)实时时钟RTC
PIC32MX 器件上提供的实时时钟和日历(Real-Time Clock and Calendar,RTCC) 硬件模块及其操作。下面列出了该模块的部分主要特性: • 时间:时、分和秒 • 24 小时格式 (军用时间) • 可分辨半秒的时长 • 提供日历:星期、日、月和年 • 闹钟间隔可配置为 0.5 秒、1 秒、10 秒、1 分钟、10 分钟、1 小时、1 天、1 周、1 月或 1 年 • 闹钟使用递减计数器进行重复 • 可无限重复的闹钟:响铃 (chime) • 年份范围:2000 至 2099 • 闰年修正 • BCD 格式以减少固件开销 • 为长时间电池工作进行了优化 • 小数秒同步 • 用户可使用自动调节功能校准时钟晶
[单片机]
武林教你学PIC32(十)<font color='red'>实时</font>时钟<font color='red'>RTC</font>
ARM学习笔记--RTC编程(二)
上一篇我们从用户手册对RTC有了一个大致的了解,现在就开始通过程序编写来学习RTC的应用和操作了。这里先总结一下:实时时钟是一组用于测量时间的计数器,如果使用电池供电,在系统掉电以后它也可以正常运行以记录系统的时间。LPC1788时钟采用内部的32K振荡器输出1HZ的时钟信号做为RTC的时钟源。 RTC的寄存器比较简单,主要有时钟计数器寄存器包括秒SEC 分MIN 小时HOUR 日期(月)DOM 星期DOW 日期(年)DOY 月MONTH 年YEAR, 这些寄存器为R/W 可以从中读出具体的时间信息。其中的秒计数由1HZ时钟驱动。报警寄存器组中的值将和时间计数器寄存器中的值比较,如果所有为屏蔽的报警寄存器都与他们对应的时间计数器
[单片机]
ARM学习笔记--<font color='red'>RTC</font>编程(二)
Nordic 半导体宣布可利用nRF Connect SDK和nRF52840多协议SoC构建Amazon Sidewalk设备
Nordic 半导体宣布可利用现有nRF Connect SDK和nRF52840多协议SoC构建Amazon Sidewalk设备 Amazon Sidewalk是零连接成本的“社区”无线物联网网络,它借助普遍的Amazon Echo和Ring智能家居设备作为网关(称为Sidewalk Bridge),提供短距离蓝牙和长距离“邻里范围” 的1GHz以下无线连接。 挪威奥斯陆 – 2023年3月29日 –– Nordic 半导体的蓝牙无线技术再次一马当先,参与了无线物联网领域巨大行业发展商机:Amazon Sidewalk。 即日起,开发人员可以立即使用Nordic屡获奖项的nRF52840低功耗蓝牙系统级芯片(
[网络通信]
Nordic 半导体宣布可利用nRF Connect SDK和<font color='red'>nRF52840</font>多协议SoC构建Amazon Sidewalk设备
使用MSP430连接RTC模块(DS2321)制作数字时钟
在本篇文章中,我们将使用MSP430连接RTC模块DS3231来制作一款数字时钟,然后在1602液晶显示屏上显示时间和日期。 MSP-EXP430G2是德州仪器提供的开发工具,也称为LaunchPad,用于学习和练习如何使用其微控制器。该电路板属于MSP430产品线,我们可以对所有MSP430系列微控制器进行编程。 所需的材料 ● MSP430开发板 ● DS3231 RTC模块 ● 电位器10k ● LCD模块1602 ● 连接导线 ● 面包板 什么是RTC? RTC是一个实时时钟模块。它用于维护大多数电子项目的日期和时间。该模块具有自己的纽扣电池电源,即使主电源被移除或MCU被硬件复位,也可使用该纽扣电池电
[单片机]
使用MSP430连接<font color='red'>RTC</font>模块(DS2321)制作数字时钟
STM32独立看门狗和低功耗模式_RTC定时唤醒来喂狗
在STM32开发中经常会用到独立看门狗(IWDG)和低功耗模式,看门狗是为了检测和解决由软件错误引起的故障,低功耗模式是为了在CPU不需要继续运行时进入到休眠模式用以节省电能。其中独立看门狗的时钟由独立的RC振荡器(STM32F10x一般为40kHz)提供,即使在主时钟出现故障时,也仍然有效,因此可以在停止和待机模式下工作。而且独立看门狗一旦启动,除了系统复位,它不能再被停止。但这样引发的一个问题是当MCU进入到低功耗模式后由于CPU停止运行无法喂狗,会导致系统频繁复位。那如何解决这个问题呢,难道独立看门狗和低功耗模式没法同时使用? 一个很好的方式是在休眠模式下通过RTC定时唤醒来喂狗,喂完够在进入继续进入到休眠模式。比如看门
[单片机]
STM32的RTC晶振不起振的可能原因?
最近做的几块板子也用到了STM32的RTC,前后两版一共做了大概6片,幸运的是并未遇到晶振不起振的现象。而我采用的是3毛钱一个的普通晶振,并未选用传说中低负载高精度晶振。。。后来在另外一片实验性质的板子上首次遇到了晶振不起振的问题,而且做了2片都不起振,这才让我意识到这个问题的严重性。 从上述现象来看,我认为对RTC晶振起振影响最大的因素应该是PCB的布线。但是遇到问题时通常是PCB已做好,甚至已经做了几百块,没有回头路了。于是大家更关注的问题似乎就是“如何补救”了。在网上搜索一下,你就会发现世界是如此美好!每个人的经验和建议都不一样,甚至是完全相反的!这种现象告诉我们,除了PCB布线,对晶振起振影响最大的似乎不是电气参数,而
[单片机]
STM32基于固件库学习笔记(11)RTC实时时钟
实时时钟(RTC) 小容量产品是指闪存存储器容量在16K至32K字节之间的STM32F101xx、STM32F102xx和STM32F103xx微控制器。 中容量产品是指闪存存储器容量在64K至128K字节之间的STM32F101xx、STM32F102xx和STM32F103xx微控制器。 大容量产品是指闪存存储器容量在256K至512K字节之间的STM32F101xx和STM32F103xx微控制器。 互联型产品是指STM32F105xx和STM32F107xx微控制器。 主要特性 ● 可编程的预分频系数:分频系数最高为20 。 ● 32位的可编程计数器,可用于较长时间段的测量。 ● 2个分离的时钟:用于APB1接口的PC
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
更多往期活动

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved