52832 SDK开发学习循序渐进NEW(三)systick2/定时器0

一、systick的使用技巧

 

按键可以响应了,那么怎么处理去抖呢? 包括处理长按,短按?我们上次用systick做了简单的去抖,可以在上次基础上增加长按,短按的识别。

 

这个操作之前,我们先把程序的文件组织方式调整下,增强程序的可读性和可维护性。 

1)建立新的目录mydrivers, 新建led.c, button.c, 将led和button操作的函数都移入驱动文件

2)新建led.h, button.h头文件,将需要include的库和函数定义放入头文件

3)调整变量定义位置等

4)编译,纠错

驱动文件分离后,方便我们复用驱动和修改调试。 

上次的systick程序有个bug发现么? 就是systick打印值的时候用的%d, 所以就会发现打印出来一会正数,一会负数,固定延时1000ms,应该都打印出正数啊。 

这里有个printf的小知识点: 

在变量值的值大于0x7FFFFFFF时,%d 格式符输出的结果会变成负数。

正确的程序应该为:

printf(“%u”, Value);

修改后的打印结果:

00> 52832 systick get value:12970321 
00> 52832 systick get value:16075986 
00> 52832 systick get value:2404433 
00> 52832 systick get value:5510319 
00> 52832 systick get value:8616077 
00> 52832 systick get value:11721954 
00> 52832 systick get value:14827618 
00> 52832 systick get value:1156065 
00> 52832 systick get value:4261953 
00> 52832 systick get value:7367710 

这里可以看到,固定的间隔基本在31xxxxx

也就是说1s的systick间隔在3105xxx,以这个为依据我们来设计长按,短按的时间。

但是这里发现一个前面程序的bug,就是溢出值, 开始设置的是32位整数的满值,8个F,其实查看systick相关头文件的定义,是6个F

 

去抖,短按,长按,就需要计数器对按键状态改变来进行计时,,我们来看看使用Timer来处理长按,短按。 

定义不同的阈值

#define KEY_TRIGGER 310000  // about 0.1s
#define Long_Press 6200000  // about 2s

在程序中做分支判断:

while (true)
    {
            // Do Nothing - GPIO can be toggled without software intervention.

            nrf_drv_systick_delay_ms(10);
             
             if(reKeyTick>KEY_TRIGGER){
        if (reKeyTick>Long_Press){
                SEGGER_RTT_printf(0," pressed  for long time, LED_2 toggle, %u. \r\n",reKeyTick);
                    nrf_drv_gpiote_out_task_trigger(LED_2);
                    reKeyTick=0;
                }
                else{
        nrf_drv_gpiote_out_task_trigger(LED_1);
        SEGGER_RTT_printf(0,"pressed normal , LED_2 toggle, %u. \r\n",reKeyTick);
                    reKeyTick=0;
                }
     
    }
  
    
    }

编译下载后,三个按键短按LED1状态变化,长按LED2状态变化

 

 

二、nrf52832 定时器部分学习使用


定时器可被配置为两种模式:定时模式和计数模式。nrf52832有5个定时器,分别为timer0~time4,使用蓝牙协议栈时timer0会被占用。

其信号来源及工作模式如下图所示。

在这里插入图片描述

定时器分成了软件定时器和硬件定时器,其初始化、定义、创建、启动及关闭分别如下表所示。

å¨è¿éæå¥å¾çæè¿°

软件定时器使用在其他例子里说明,这个试验先学习硬件定时器使用。 

1.根据时钟频率自动选择时钟源,无需手动指定选择哪个时钟源。ftimer<1M时选择1M时钟,否则选择16M时钟
2.时钟频率计算,ftimer=16M/(2^分频),无论时钟源是1M还是16M都是按照16M计算。设置分频,位宽等参数时,必须先停止timer工作
3.定时模式下要设置比较/捕获的值,也就是定时时间。

说明:

nRF52840有5个定时器0,1,2有4个CC寄存器, 3,4有6个CC寄存器

 

定时/计数器有任务类型:

1)定时

2)计数

3)输入捕获Capture(有多少个CC就能捕获多少路信号)

4)输出比较(也是依赖CC)  

5)任务定时触发

6)抢断清除任务,计数任务和停止任务

 

定时器有8 16 24 32位定时计数模式

 

我们先来看硬件定时器使用要做什么:

要在sdk_config.h中打开响应的开关

#ifndef NRFX_TIMER_ENABLED
#define NRFX_TIMER_ENABLED 1
#endif

#ifndef NRFX_TIMER0_ENABLED
#define NRFX_TIMER0_ENABLED 1
#endif

// <q> NRFX_TIMER1_ENABLED  - Enable TIMER1 instance
 

#ifndef NRFX_TIMER1_ENABLED
#define NRFX_TIMER1_ENABLED 1
#endif
 

#ifndef TIMER0_ENABLED
#define TIMER0_ENABLED 1
#endif

/
然后指定handler,处理定时中断事件

void timer0_event_handler(nrf_timer_event_t event_type, void* p_context)
{
        extern int32_t key_count;
    switch (event_type)
    {
        case NRF_TIMER_EVENT_COMPARE0:
          
                        key_count+=1;
                    if (key_count>KEY_COUNT_LIMIT) {
                        key_count=0;
                        }
            break;

        default:
            //Do nothing.
            break;
    }
}

定义初始化函数: 

void timer0_init(){
        uint32_t time_ms = 10; //Time(in miliseconds) between consecutive compare events.
    uint32_t time_ticks;
        nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    
    nrf_drv_timer_init(&KEY_TIMER, &timer_cfg, timer0_event_handler);
   
    time_ticks = nrf_drv_timer_ms_to_ticks(&KEY_TIMER, time_ms);

    nrf_drv_timer_extended_compare(
         &KEY_TIMER, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);

    nrf_drv_timer_enable(&KEY_TIMER);


}

重新修改按键按下的处理:button.c


void BUTTON_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
    extern int32_t temp_count,press_count,key_count;
    
    if (!nrf_drv_gpiote_in_is_set(pin)){
      press_count=0;
        temp_count=key_count;
    
}
else if(nrf_drv_gpiote_in_is_set(pin)){
                    if(key_count<temp_count){
                    press_count=key_count+KEY_COUNT_LIMIT-temp_count;
                    }
                    else{
           press_count=key_count-temp_count;}
}
}

 

主函数检查计数器,区分长按短按

int main(void)
{
    
    /* Configure board. */
   led_blinking_setup();
     button_setup();
   timer0_init();
    
    SEGGER_RTT_Init();
    SEGGER_RTT_printf(0,"52832 SAMPLE: 1.8 check the button pressed via timer0. \r\n");
    /* Toggle LEDs. */
    while (true)
    {

            nrf_delay_ms(10);
            if(press_count>10){
            if(press_count>100){  // long pressed
                nrf_drv_gpiote_out_task_trigger(LED_2);
                SEGGER_RTT_printf(0,"long pressed. trigger LED2. \r\n");
                
            
            }
            else{
            nrf_drv_gpiote_out_task_trigger(LED_1);
                SEGGER_RTT_printf(0,"normal pressed. trigger LED1. \r\n");
            }
            press_count=0;
            }

    }
  
}

下载运行,RTT打印效果: 

 

经测试,效果理想

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海里的鱼2022

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值