RP2040 C SDK 64位定时器功能使用

news2024/9/20 14:12:55

RP2040 C SDK 64位定时器功能使用


  • 🧨RP2040的64位定时器功能介绍参见:https://www.raspberrypi.com/documentation/pico-sdk/hardware.html#group_hardware_timer

🎉RP2040有一个单64位计数器,每微秒递增一次看起来很复杂,通过例程功能演示,可以发现,其实该定时器实现的功能l,类似Arduino中的Ticker库。通过一个定时器实现多任务运行。

这个64位计时器有4个警报,可以为每个警报输出一个单独的中断。警报在64位计数器的低32位上匹配,这意味着它们可以在未来最多触发2^32微秒。这相当于:
  • 2^32 ÷ 10^6: 大约4295秒钟
  • 4295 ÷ 60: 大约72分钟

📗 64位定时器库相关函数功能介绍

  • 🌿static inline alarm_id_t add_alarm_in_ms(uint32_t ms, alarm_callback_t callback, void *user_data, bool fire_if_past):创建一次性执行任务。
  • 参数1:任务运行时间
  • 参数2:回调函数
  • 参数3:可作为形参传递给回调函数。
  • 参数4:如果为true,并且在此调用期间警报时间下降,则可以设置警报,:那么回调函数应该在此函数期间调用。应该就是中断任务嵌套。
  • 返回值大于0,,the alarm id,应该是指前面有任务在执行
  • 返回值为0:如果告警时间在调用之前或调用期间过去,并且没有活动告警返回id。后者可能发生,因为fire_if_past是假的(即没有创建计时器),或者如果回调在此方法期间被调用,但回调通过返回0来取消自己
  • 返回值为-1,如果没有可用的告警,应该是指当前没有执行任务占用。
volatile bool timer_fired = false;

int64_t alarm_callback(alarm_id_t id, void *user_data)
{
    printf("Timer %d fired!\n", (int)id);
    timer_fired = true;
    // Can return a value here in us to fire in the future
    return 0;
}
 add_alarm_in_ms(6000, alarm_callback, NULL, false);//只调用一次
  • 🌿static inline bool add_repeating_timer_ms(int32_t delay_ms, repeating_timer_callback_t callback, void *user_data, repeating_timer_t *out):创建重复执行的任务。
    和上面的创建一次性任务功能差别就是,该任务创建后,会被一直间隔第一个形参设置的时间运行。直到调用cancel_repeating_timer函数进行任务取消为止。
/*!
 * \brief Add a repeating timer that is called repeatedly at the specified interval in milliseconds
 * \ingroup repeating_timer
 *
 * Generally the callback is called as soon as possible after the time specified from an IRQ handler
 * on the core of the default alarm pool (generally core 0). If the callback is in the past or happens before
 * the alarm setup could be completed, then this method will optionally call the callback itself
 * and then return a return code to indicate that the target time has passed.
 *
 * \note It is safe to call this method from an IRQ handler (including alarm callbacks), and from either core.
 *
 * @param delay_ms the repeat delay in milliseconds; if >0 then this is the delay between one callback ending and the next starting; if <0 then this is the negative of the time between the starts of the callbacks. The value of 0 is treated as 1 microsecond
 * @param callback the repeating timer callback function
 * @param user_data user data to pass to store in the repeating_timer structure for use by the callback.
 * @param out the pointer to the user owned structure to store the repeating timer info in. BEWARE this storage location must outlive the repeating timer, so be careful of using stack space
 * @return false if there were no alarm slots available to create the timer, true otherwise.
 */
// This is a repeating timer callback that will be called every 500ms
bool repeating_timer_callback(struct repeating_timer *t)
{
    printf("Repeat at %lld\n", time_us_64());
    return true;
}

......

struct repeating_timer timer;
    add_repeating_timer_ms(500, repeating_timer_callback, NULL, &timer);//创建任务
    sleep_ms(3000);
    bool cancelled = cancel_repeating_timer(&timer);//取消任务
     printf("cancelled... %d\n", cancelled);

在这里插入图片描述

📘测试例程

/*
 CMSIS-DAP烧录命令:openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c  "adapter speed 5000"-c "program RP2040_Timer.elf verify reset exit"

 jlink命令: openocd -f interface/jlink.cfg -f target/rp2040.cfg  -c  "adapter speed 2000" -c  "program RP2040_Timer.elf verify reset exit"


*/

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/uart.h"
#include "hardware/gpio.h"
#include "hardware/divider.h"
#include "hardware/timer.h"
#include "hardware/clocks.h"

#define BUILTIN_LED PICO_DEFAULT_LED_PIN // LED is on the same pin as the default LED 25

volatile bool timer_fired = false;

int64_t alarm_callback(alarm_id_t id, void *user_data)
{
    printf("Timer %d fired!\n", (int)id);
    timer_fired = true;
    // Can return a value here in us to fire in the future
    return 0;
}

// This is a repeating timer callback that will be called every 500ms
bool repeating_timer_callback(struct repeating_timer *t)
{
    printf("Repeat at %lld\n", time_us_64());
    return true;
}

int main()
{
    stdio_init_all();
    printf("Hello Timer!\n");
    set_sys_clock_khz(133000, true); // 325us
                                     // GPIO initialisation.
    gpio_init(BUILTIN_LED);
    gpio_set_dir(BUILTIN_LED, 1);
    gpio_pull_up(BUILTIN_LED);

    // Timer example code - This example fires off the callback after 2000ms
    add_alarm_in_ms(6000, alarm_callback, NULL, false);//只调用一次
    while (!timer_fired)
    {
        gpio_xor_mask(1ul << BUILTIN_LED); // Toggle the LED
        // gpio_put(BUILTIN_LED, 1);
        // sleep_ms(500);
        // gpio_put(BUILTIN_LED, 0);
        sleep_ms(500);
    }
    // Create a repeating timer that calls repeating_timer_callback.
//如果延迟 > 0,那么这是上一次回调结束和下一次开始之间的延迟。
//如果延迟是负的(见下),那么下一个回调调用将恰好在500毫秒之后
//开始调用最后一个回调函数
    struct repeating_timer timer;
    add_repeating_timer_ms(500, repeating_timer_callback, NULL, &timer);
    sleep_ms(3000);
    bool cancelled = cancel_repeating_timer(&timer);
    printf("cancelled... %d\n", cancelled);
    sleep_ms(2000);

//负延迟将调用repeating_timer_callback,并再次调用它
//不管回调执行了多长时间,都将在500毫秒后执行
    add_repeating_timer_ms(-500, repeating_timer_callback, NULL, &timer);
  //  sleep_ms(3000);
  //  cancelled = cancel_repeating_timer(&timer);
  //  printf("cancelled... %d\n", cancelled);
   // sleep_ms(2000);
   // printf("Done\n");
    while (1)
    {
        // tight_loop_contents();
        uint f_pll_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY);
        uint f_clk_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS);
        uint f_clk_rtc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_RTC);
        printf("clk_sys  = %dkHz\n", f_clk_sys);
        printf("clk_usb  = %dkHz\n", f_pll_usb);
        printf("clk_rtc  = %dkHz\n", f_clk_rtc);
        sleep_ms(1000);
        gpio_xor_mask(1ul << BUILTIN_LED); // Toggle the LED
    }

    return 0;
}

📒利用64位定时器延后执行指定任务例程

📝利用24位定时器,创建一个任务,该任务会在,以创建任务为时间基准,开始计时,到指定时间后,指定的任务被执行。该任务创建到被执行中间的时间不是阻塞的。属于一次性执行的定时任务。

/*
 CMSIS-DAP烧录命令:openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c  "adapter speed 5000"-c "program RP2040_Timer.elf verify reset exit"

 jlink命令: openocd -f interface/jlink.cfg -f target/rp2040.cfg  -c  "adapter speed 2000" -c  "program RP2040_Timer.elf verify reset exit"


*/

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/uart.h"
#include "hardware/gpio.h"
#include "hardware/divider.h"
#include "hardware/timer.h"
#include "hardware/clocks.h"

#define BUILTIN_LED PICO_DEFAULT_LED_PIN // LED is on the same pin as the default LED 25

volatile bool timer_fired = false;

int64_t alarm_callback(alarm_id_t id, void *user_data)
{
    printf("Timer %d fired!\n", (int)id);
    timer_fired = true;
    // Can return a value here in us to fire in the future
    return 0;
}

// This is a repeating timer callback that will be called every 500ms
bool repeating_timer_callback(struct repeating_timer *t)
{
    printf("Repeat at %lld\n", time_us_64());
    return true;
}
// Simplest form of getting 64 bit time from the timer.
// It isn't safe when called from 2 cores because of the latching
// so isn't implemented this way in the sdk
static uint64_t get_time(void) {
    // Reading low latches the high value
    uint32_t lo = timer_hw->timelr;
    uint32_t hi = timer_hw->timehr;
    return ((uint64_t) hi << 32u) | lo;
}
/// \end::get_time[]

/// \tag::alarm_standalone[]
// Use alarm 0
#define ALARM_NUM 0
#define ALARM_IRQ TIMER_IRQ_0

// Alarm interrupt handler
static volatile bool alarm_fired;

static void alarm_irq(void) {
    // Clear the alarm irq
    hw_clear_bits(&timer_hw->intr, 1u << ALARM_NUM);

    // Assume alarm 0 has fired
    printf("Alarm IRQ fired\n");
    alarm_fired = true;
}

static void alarm_in_us(uint32_t delay_us) {
    // Enable the interrupt for our alarm (the timer outputs 4 alarm irqs)
    hw_set_bits(&timer_hw->inte, 1u << ALARM_NUM);
    // Set irq handler for alarm irq
    irq_set_exclusive_handler(ALARM_IRQ, alarm_irq);
    // Enable the alarm irq
    irq_set_enabled(ALARM_IRQ, true);
    // Enable interrupt in block and at processor

    // Alarm is only 32 bits so if trying to delay more
    // than that need to be careful and keep track of the upper
    // bits
    uint64_t target = timer_hw->timerawl + delay_us;

    // Write the lower 32 bits of the target time to the alarm which
    // will arm it
    timer_hw->alarm[ALARM_NUM] = (uint32_t) target;
}

int main()
{
    stdio_init_all();
    printf("Hello Timer!\n");
    set_sys_clock_khz(133000, true); // 325us
                                     // GPIO initialisation.
    gpio_init(BUILTIN_LED);
    gpio_set_dir(BUILTIN_LED, 1);
    gpio_pull_up(BUILTIN_LED);

    // Timer example code - This example fires off the callback after 2000ms
    add_alarm_in_ms(6000, alarm_callback, NULL, false);//只调用一次
    while (!timer_fired)
    {
        gpio_xor_mask(1ul << BUILTIN_LED); // Toggle the LED
        // gpio_put(BUILTIN_LED, 1);
        // sleep_ms(500);
        // gpio_put(BUILTIN_LED, 0);
        sleep_ms(500);
    }
    // Create a repeating timer that calls repeating_timer_callback.
//如果延迟 > 0,那么这是上一次回调结束和下一次开始之间的延迟。
//如果延迟是负的(见下),那么下一个回调调用将恰好在500毫秒之后
//开始调用最后一个回调函数
    struct repeating_timer timer;
    add_repeating_timer_ms(500, repeating_timer_callback, NULL, &timer);
    sleep_ms(3000);
    bool cancelled = cancel_repeating_timer(&timer);
    printf("cancelled... %d\n", cancelled);
    sleep_ms(2000);

//负延迟so意味着我们将调用repeating_timer_callback,并再次调用它
//不管回调执行了多长时间,都将在500毫秒后执行
    add_repeating_timer_ms(-500, repeating_timer_callback, NULL, &timer);
   sleep_ms(3000);
   cancelled = cancel_repeating_timer(&timer);
   printf("cancelled... %d\n", cancelled);
   sleep_ms(2000);
   printf("Done\n");
   printf("Timer lowlevel!\n");
    alarm_fired = false;
        alarm_in_us(1000000 * 8);//创建任务

    while (1)
    {
        // tight_loop_contents();
        uint f_pll_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY);
        uint f_clk_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS);
        uint f_clk_rtc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_RTC);
        printf("clk_sys  = %dkHz\n", f_clk_sys);
        printf("clk_usb  = %dkHz\n", f_pll_usb);
        printf("clk_rtc  = %dkHz\n", f_clk_rtc);
        sleep_ms(1000);
        gpio_xor_mask(1ul << BUILTIN_LED); // Toggle the LED

        // Wait for alarm to fire
        if (!alarm_fired){

            printf("Alarm did not fire\n");
        }
    }

    return 0;
}

  • 从创建任务到执行指定任务,中间间隔8秒钟。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2119353.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[基于 Vue CLI 5 + Vue 3 + Ant Design Vue 3 搭建项目] 02 配置 nodejs 淘宝镜像仓库

文章目录 为什么要配置淘宝镜像仓库呢如何查看镜像仓库如何配置镜像仓库 为什么要配置淘宝镜像仓库呢 主要是因为默认的镜像仓库是国外的&#xff0c;当我们使用 npm 安装依赖的时候会很慢或者失败&#xff0c;我们配置国内的镜像仓库这样就可以加速我们安装镜像的过程&#x…

这些加密软件功能你都知道吗?

1.透明加密与无感操作&#xff1a; 透明加密是许多现代加密软件的核心功能之一&#xff0c;它允许用户在无感知的情况下对文件进行加密和解密。这意味着用户无需改变日常操作习惯&#xff0c;加密和解密过程在后台自动完成&#xff0c;确保了数据的安全性同时不影响工作效率。…

【阿雄不会写代码】全国职业院校技能大赛GZ036第十套

也不说那么多了&#xff0c;要用到这篇博客&#xff0c;肯定也知道他是干嘛的&#xff0c;给博主点点关注点点赞&#xff01;&#xff01;&#xff01;这样博主才能更新更多免费的教程&#xff0c;不然就直接丢付费专栏里了&#xff0c;需要相关文件请私聊

关于OceanBase MySQL 模式中全局索引 global index 的常见问题

在OceanBase的问答区和开源社区钉钉群聊中&#xff0c;时常会有关于全局索引 global index的诸多提问&#xff0c;因此&#xff0c;借这篇博客&#xff0c;针对其中一些普遍出现的问题进行简要的解答。 什么是 global index &#xff1f; 由于 MySQL 不具备 global index 的概…

利用TCP编程实现FTP功能

模拟FTP核心原理&#xff1a;客户端连接服务器后&#xff0c;向服务器发送一个文件。文件名可以通过参数指定&#xff0c;服务器端接收客户端传来的文件&#xff08;文件名随意&#xff09;&#xff0c;如果文件不存在自动创建文件&#xff0c;如果文件存在&#xff0c;那么清空…

uboot源码分析uboot启动流程,uboot-CMD命令调用关系

uboot的最终目的是引导启动内核加载系统&#xff0c;根据这个线索我们可以首先找到uboot引导内核的main函数&#xff0c;查看系统引导的执行跳转的函数 main_loop。 下面对uboot函数的调用关系和主要调用函数进行分析。 一、uboot函数调用关系梳理 函数调用如下&#xff1a; …

Ollama 本地运行大模型(LLM)完全指南

文章介绍了 Ollama 本地运行大模型&#xff08;LLM&#xff09;的方方面面&#xff0c; 包括安装运行、对话、自定义模型、系统提示配置、调试、开发、存储、如何作为服务、OpenAI 的兼容等。 这一年来&#xff0c;我已经习惯了使用线上大模型 API 来工作&#xff0c;只要网络…

2025毕业设计免费指导!!

本人专注于Android/java/PHP/Python/人工智能/数据库/微信小程序技术等领域的开发&#xff0c;以及有好几年的计算机毕业设计方面的实战开发经验和技术积累&#xff1b;尤其是在图像识别、网站开发和微信小程序的开发&#xff0c;很是熟悉和了解&#xff1b;本人也是多年的全栈…

DevOps实现CI/CD实战(六)- Jenkins集成k8s

十、 Jenkins集成k8s Jenkins在集成K8s之前&#xff0c;需要搭建k8s集群&#xff0c;具体搭建步骤&#xff0c;完整笔记 https://github.com/ITenderL/ITenderL.github.io/tree/main/docs/DevOps&#xff0c; 包括完整的DevOps的笔记。 1. 准备部署的yml文件 pipeline.yml …

祝福在茶礼丨酒茶香充满东方古韵特色的中秋礼盒,太惊艳了

中国是礼仪之邦&#xff0c;礼尚往来更是普通不过。象征东方古韵的茶礼成为现代送礼热门&#xff0c;尤其是逢年过节茶礼氛围更是浓郁&#xff0c;跃居礼单榜首。 中秋节作为团圆之节&#xff0c;送礼肯定少不了&#xff01;送茶礼的这几个理由你一定要知道&#xff01; 送茶即…

【动手学深度学习】06 矩阵计算(个人向笔记)

标量导数 这个比较简单&#xff0c;就是直接求导 亚导数 举了两个例子 梯度 下面是当 y 和 x 分别为向量和标量时求导的结果。一个为向量&#xff0c;一个为标量则结果为向量。两个都为向量结果为矩阵&#xff0c;两个都为标量结果为标量 当 y 为标量&#xff0c;x 为列…

关于腾讯IM消息ID不统一的问题?服务端的MsgKey和前端的msgID不一样

角色>前端&#xff1a;web、小程序、客户端&#xff08;ios、安卓&#xff09;&#xff1b;服务端&#xff1b;腾讯IM&#xff1b; 1、背景 IM消息ID不一致&#xff0c;本地没有缓存历史数据&#xff0c;导致在调用腾讯sdk方法时&#xff0c;id不一致报错问题 2、调研目的…

MySQL进阶篇4 - 锁

五、锁 5.1 概述 介绍 分类 5.2 全局锁 介绍 红色代表不可执行的操作&#xff0c;绿色代表可执行的操作 # mysqldump 是 MySQL 提供的数据备份的命令演示 # 如果想进行全库的逻辑备份&#xff0c;那么就需要在逻辑备份之前 # 手动的加上全局锁 flush tables with read …

flask下https教程

一、定义 linux 下flask https 协议 二、实现 linux 下flask https 协议 生成SSL证书和密钥文件。您可以使用工具如openssl来生成自签名SSL证书和密钥文件。运行以下命令生成证书和密钥文件&#xff1a; openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout…

HCIE和CCIE,哪个含金量更高点?

在现在内卷的大环境下&#xff0c;技术岗可谓人人自危&#xff0c;也因此各种认证的重视程度直线升高。 特别是华为认证的HCIE和思科认证的CCIE&#xff0c;它们都代表着网络技术领域的顶尖水平。 但面对这两个高含金量的认证&#xff0c;不得不让人问出这个问题&#xff1a;同…

找到办法了!一个站点,搞定所有访问权限需求

在知识库的构建与管理过程中&#xff0c;如何平衡信息的公开与私密性始终是一大挑战。传统方法往往需要建立多个具有不同访问权限的站点&#xff0c;操作繁琐且难以维护。尤其当企业需同时向公众和内部成员提供知识文章时&#xff0c;这一问题尤为突出。用户频繁反馈&#xff0…

振弦式渗压计安装流程全面指南

在大坝安全监测体系中&#xff0c;振弦式渗压计作为关键设备之一&#xff0c;承担着监测大坝内部渗流压力变化的重任。其安装质量直接关系到监测数据的准确性和大坝安全的评估。因此&#xff0c;制定一套科学、精细的安装流程&#xff0c;对于确保渗压计的正常运行和延长使用寿…

什么是生成式 AI?

人工智能 (AI) 通过使用机器学习与环境交互并执行任务来模仿人类行为&#xff0c;而无需明确指示要输出的内容。 生成式 AI 描述 AI 中用于创建原创内容的一类功能。 人员通常与聊天应用程序中内置的生成式 AI 交互。 此类应用程序的一个常见示例是 Microsoft Copilot&#xf…

Telephony STK 域选

在场测过程中,经常遇到STK功能不生效,点击STK会出现无响应的问题. 一般需要对比DUT和REF来确认问题所在。一般情况下,出现类似问题需要check是否域选是一致的。 测试机 对比机 对比机为展锐平台会出现弹框情况,从Log看,相关业务进行了报错回落,从IMS业务回落到了…

基于spring的博客系统(一)

通过前⾯课程的学习, 我们掌握了Spring框架和MyBatis的基本使⽤, 并完成了图书管理系统的常规功能 开发, 接下来我们系统的从0到1完成⼀个项⽬的开发&#xff1b; 1. 项⽬介绍 使⽤SSM框架实现⼀个简单的博客系统 共5个⻚⾯ 1. 用户登录 2. 博客发表⻚ 3. 博客编辑⻚ 4. 博客…