RT-Thread HWTIMER设备(学习)

这篇具有很好参考价值的文章主要介绍了RT-Thread HWTIMER设备(学习)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

定时器简介

硬件定时器一般有2种工作模式,定时器模式和计数器模式。不管是工作在哪一种模式,实质都是通过内部计数器模块对脉冲信号进行计数,下面是定时器的一些重要概念。

  • 计数器模式:对外部输入引脚的外部脉冲信号计数。
  • 定时器模式:对内部脉冲信号计数。定时器常用作定时时钟,以实现定时检测,定时响应,定时控制。

计数器:计数器可以递增计数或者递减计数,16位计数器的最大计数值为65535.

计数频率:定时器模式时,计数器单位时间内的计数次数,由于系统时钟频率是定值,所以根据计数器的计数值计算出定时时间,定时时间=计数值/计数频率。
例如计数频率为1MHz,计数器计数一次的时间为1/1000000,也就是没经过1微妙计数器加一,此时16位计数器的最大定时能力为65535微妙,即65.535毫秒。

本定时器设备框架内部会自动处理硬件定时器超时的问题,例如16位定时器在1MHz的频率下最大只能维持65.535ms。
但是本定时器框架下,用户可以将定时器的溢出时间设置为例如500ms,框架内部会自动处理硬件溢出问题。当时间达到500ms后,框架会调用用户预先设置好的回调函数。

访问硬件定时器设备

RT-Thread HWTIMER设备(学习),RT-Thread,学习,单片机,嵌入式硬件,RT-Thread

查找定时器设备

应用程序根据硬件定时器设备名称获取设备句柄,进而可以操作硬件定时器设备。

rt_device_t rt_device_find(const char* name);

一般情况下,注册到系统的硬件定时器设备名称为timer0,timer1等。

#define HWTIMER_DEV_NAME "timer0";
rt_device_t hw_dev;
hw_dev = rt_device_find(HWTIMER_DEV_NAME);

打开定时器设备

通过设备句柄,应用程序可以打开设备。
打开设备时,会检测设备是否已经初始化,没有初始化则会默认调用初始化接口初始化设备。

rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflags);
  • dev:硬件定时器设备句柄。
  • oflags:设备打开模式,一般以读写方式打开,即RT_DEVICE_OFLAG_RDWR

设置超时回调函数

在C语言和C++语言中,将一个函数声明为’static’具有以下含义:

  1. 作用域限制:函数声明为’static’会将其作用域限制在当前文件中,这意味着该函数只能在包含它的源文件中调用,而不能在其他文件中调用。这可以用于隐藏函数的实现细节,避免与其他文件中的同名函数发生冲突。
  2. 链接性:'static’函数具有内部链接性,这意味着它不会被放在全局符号表中,无法被其他文件访问。这有助于减小程序的全局命名空间污染。
rt_err_t rt_device_set_rx_indicate(rt_device_t dev, rt_err_t (*rx_ind)(rt_device_t dev, rt_size_t size))
  • dev:设备句柄。
  • rx_ind:超时回调函数,由调用者提供。
#define HWTIMER_DEV_NAME   "timer0"     /* 定时器名称 */
rt_device_t hw_dev;                     /* 定时器设备句柄 */

/* 定时器超时回调函数 */
static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size)
{
    rt_kprintf("this is hwtimer timeout callback fucntion!\n");
    rt_kprintf("tick is :%d !\n", rt_tick_get());

    return 0;
}

static int hwtimer_sample(int argc, char *argv[])
{
    /* 查找定时器设备 */
    hw_dev = rt_device_find(HWTIMER_DEV_NAME);
    /* 以读写方式打开设备 */
    rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);

    ...

    /* 设置超时回调函数 */
    rt_device_set_rx_indicate(hw_dev, timeout_cb);

    return 0;
}

控制定时器设备

通过命令控制字,应用程序可以对硬件定时器设备进行配置。

rt_err_t rt_device_control(rt_device_t dev, rt_uint8_t cmd, void *arg);
  • dev:设备句柄
  • cmd:命令控制字
  • arg:控制的参数
  • 返回:RT_EOK:函数执行成功。-RT_ENSYS:执行失败,dev为空。

硬件定时器设备支持的命令控制字如下:

  • HWTIMER_CTRL_FRQ_SET:设置计数频率(若未设置该项,默认为1MHz或支持的最小计数频率)
  • HWTIMER_CTRL_STOP:停止计时器
  • HWTIMER_CTRL_INFO_GET:获取定时器特征信息
  • HWTIMER_CTRL_MODE_SET:设置定时器模式(若未设置,默认是HWTIMER_MODE_ONESHOT)

获取定时器特征信息参数arg为指向结构体struct rt_hwtimer_info的指针,作为一个输出参数保存获取的信息。

设置定时器模式时,参数arg可取:

  • HWTIMER_MODE_ONESHOT:单次定时
  • HWTIMER_MODE_PERIOD:周期性定时
#define HWTIMER_DEV_NAME   "timer0"     /* 定时器名称 */
rt_device_t hw_dev;                     /* 定时器设备句柄 */
rt_hwtimer_mode_t mode;                 /* 定时器模式 */
rt_uint32_t freq = 10000;               /* 计数频率 */

static int hwtimer_sample(int argc, char *argv[])
{
	hw_dev = rt_device_find(HWTIMER_DEV_NAME);
	rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);

	rt_device_control(hw_dev, HWTIMER_CTRL_FREQ_SET, &freq);
	mode = HWTIMER_MODE_PERIOD;
	rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
	return 0;
}

设置定时器超时值

通过如下函数可以设置定时器的超时值,在调用该函数后,定时器更新参数并开启。

rt_size_t rt_device_write(rt_device_t dev, rt_odd_t pos, const void* buffer, rt_size_t size);
  • dev:设备句柄。
  • pos:写入数据偏移量,未使用,可取0值。
  • buffer:指向定时器超时时间结构体的指针。
  • size:超时时间结构体的大小。
  • 返回:写入数据的实际大小,0:失败。

超时时间结构体原型:

typedef struct rt_hwtimerval
{
	rt_int32_t sec;
	rt_int32_t usec;
}

设置定时器超时值的使用示例如下:

#define HWTIMER_DEV_NAME "timer0"
rt_device_t hw_dev; //定时器设备句柄
rt_hwtimerval_t timeout_s; //定时器超时值

static int hwtimer_sample(int argc, char *argv[])
{
	//查找定时器设备
	hw_dev = rt_device_find(HWTIMER_DEV_NAME);
	rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);

	//设置定时器超时值为5s并启动定时器
	timeout_s.sec = 5;
	timeout_s.usec = 0;
	rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s));
	return 0;
	
}

获取定时器当前值

通过如下函数可以获取自定时器开始(rt_device_write)之后的运行时:

rt_size_t rt_device_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
  • dev:定时器设备句柄
  • pos:写入数据偏移量,未使用,可取0值
  • buffer:输出参数,指向定时器超时时间结构体的指针
  • size:超时时间结构体的大小
  • return:成功-超时时间结构体的大小,0:失败
rt_hwtimerval_t t;
rt_device_read(hw_dev, 0, &t, sizeof(t));
rt_kprintf("Read: Sec = %d, Usec = %d\n", t.sec, t.usec);

关闭定时器设备

通过如下函数关闭定时器设备:

rt_err_t rt_device_close(rt_device_t dev);
  • dev:定时器设备句柄
  • 返回:RT_EOK-关闭设备成功,-RT_ERROR-设备已经完全关闭,不能重复关闭设备,其它错误码-关闭设备失败。

关闭设备接口和打开设备接口需配对使用,打开一次设备对应要关闭一次设备,这样设备才会被完全关闭,否则设备仍处于未关闭状态。

注:可能出现定时误差。假设计数器最大值0xFFFF,计数频率1MHz,定时时间1s又1us。
由于定时一次最多只能计时到65535us,对于1000001us的定时要求,可以50000us定时20次完成,此时会出现计算误差1us。

硬件定时器设备完整使用示例

硬件定时器设备的具体使用方式可以参考如下示例代码,示例代码的主要步骤如下:文章来源地址https://www.toymoban.com/news/detail-726661.html

  1. 首先根据定时器设备名称“timer0”查找设备获取设备句柄。
  2. 以读写方式打开设备“timer0”。
  3. 设置定时器超时回调函数。
  4. 设置定时器模式为周期性定时器,并设置超时时间为5s,此时定时器启动。
  5. 延时3500ms后读取定时器时间,读取到的值会以秒和微妙的形式显示。
//例程导出了hwtimer_sample命令到控制终端
//程序功能:硬件定时器超时回调函数周期性的打印当前tick值,2次tick值之差换算为时间等同于定时时间

#include <rtthread.h>
#include <rtdevice.h>

#define HWTIMER_DEV_NAME "timer0" //定时器名称

//定时器超时回调函数
static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size)
{
	rt_kprintf("this is hwtimer timeout callback function\n");
	rt_kprintf("tick is : %d \n",rt_tick_get());

	return 0;
}

static int hwtimer_sample(int argc, char *argv[])
{
	rt_err_t ret = RT_EOK;
	rt_hwtimerval_t timeout_s; //定时器超时值
	rt_device_t hw_dev = RT_NULL;
	rt_hwtimer_mode_t mode; //定时器模式
	rt_uint32_t freq = 10000; //计数频率

	hw_dev = rt_device_find(HWTIMER_DEV_NAME);
	if(hw_dev == RT_NULL)
	{
		 rt_kprintf("hwtimer sample run failed! can't find %s device!\n", HWTIMER_DEV_NAME);
		 return RT_ERROR;
	}
	ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
	if(ret != RT_EOK)
	{
		rt_kprintf("open %s device failed\n",HWTIMER_DEV_NAME);
		return ret;
	}
	rt_device_set_rx_indicate(hw_dev, timeout_cb);

	rt_device_control(hw_dev, HWTIMER_CTRL_FREQ_SET, &freq);
	mode = HWTIMER_MODE_PERIOD;
	ret = rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
	
	if (ret != RT_EOK)
    {
        rt_kprintf("set mode failed! ret is :%d\n", ret);
        return ret;
    }
	
	timeout_s.sec = 5;
	timeout_s.usec = 0;
	if(rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
	{
		rt_kprintf("set timeout value failed\n");
        return RT_ERROR;
	}
	rt_thread_mdelay(3500);
	
	rt_device_read(hw_dev, 0, &timeout_s, sizeof(timeout_s));
	rt_kprintf("Read: Sec = %d, Usec = %d\n", timeout_s.sec, timeout_s.usec);

    return ret;
}
MSH_CMD_EXPORT(hwtimer_sample, hwtimer sample);

到了这里,关于RT-Thread HWTIMER设备(学习)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • RT-Thread GD32F4xx PWM设备驱动

      PWM(Pulse Width Modulation,脉冲宽度调制) 是一种对模拟信号电平进行数字编码的方法,通过不同频率的脉冲使用方波的占空比用来对一个具体模拟信号的电平进行编码,使输出端得到一系列幅值相等的脉冲。在具体的芯片中,PWM功能的实现一般定时器绑定,借助定时器的计数

    2024年02月10日
    浏览(44)
  • RT-Thread(学习)

    RT-Thread是一款完全由国内团队开发维护的嵌入式实时操作系统(RTOS),具有完全的自主知识产权。经过16个年头的沉淀,伴随着物联网的兴起,它正演变成一个功能强大、组件丰富的物联网操作系统。 RT-Thread,全称是Real Time-Thread,顾名思义,它是一个嵌入式实时多线程操作

    2024年02月07日
    浏览(43)
  • RT-Thread 中断管理学习(二)

    RTT不对中断服务程序所需要的处理时间做任何假设、限制,但如图其它实时操作系统或非实时操作系统一样,用户需要保证所有的中断服务程序在尽可能短的时间内完成(中断服务程序在系统中相当于拥有最高的优先级,会抢占所有线程优先执行)。这样在发生中断嵌套,或

    2024年02月10日
    浏览(50)
  • RT-Thread 中断管理学习(一)

    什么是中断?简单的解释就是系统正在处理某一个正常事件,忽然被另一个需要马上处理的紧急事件打断,系统转而处理这个紧急事件,待处理完毕,再恢复运行刚才被打断的事件。生活中,我们经常会遇到这样的场景: 当你正在专心看书的时候,忽然来了一个电话,于是记

    2024年02月10日
    浏览(49)
  • [攻城狮计划]RT-Thread—详解UART设备(基于RA2E1)

    🚀🚀开启攻城狮的成长之旅!这是我参与的由 CSDN博客专家 架构师李肯和 瑞萨MCU 联合发起的「 致敬未来的攻城狮计划 」的第4天,点击查看活动计划详情 🚀🚀首先非常感谢李老师能给我参加这个计划的机会,让我有机会接触到许多的开发板,同时也感谢瑞萨官方 为我们

    2024年02月13日
    浏览(82)
  • RT-Thread Studio学习(十四)ADC

    本文将基于STM32F407VET芯片介绍如何在RT-Thread Studio开发环境下使用ADC设备。硬件及开发环境如下: OS WIN10 STM32F407VET6 STM32CubeMX v6.10.0 STM32Cube MCU Package for STM32F4 Series v1.28.0 RT-Thread Studio v2.2.7 RT-Thread Source Code v5.0.2 STM32F4 chip support packages v0.2.3 打开RT-Thread Studio软件新建基于芯片的项

    2024年01月19日
    浏览(44)
  • RT-Thread学习(一)简介及基础环境配置

    之前学习了FreeRTOS,但是一直想深入学习,但是没有人指导,又不知道该如何学习,于是再学习一个操作系统看看情况。 RT-Thread是一个物联网操作系统,几乎支持所有主流的MCU和Wi-Fi芯片,实时多线程操作系统,主要用在32位的MCU上面。物联网(Internet Of Things,IoT),RT-Threa

    2024年01月17日
    浏览(38)
  • 嵌入式MCU学习利器-03-在线做RT-Thread实验

    很多学生想要学习RT-Thread,但是苦于没有好的学习工具或者物理开发板而选择放弃。现在福利来了,同学们可以基于我们的仿真平台做嵌入式demo,通过调试功能深入学习RT-Thread的原理。本仿真平台基于STM32F103ZE芯片上线了一套RT-Thread课程,逐步深入讲解FreeRTOS。 本文章以第一节

    2024年02月08日
    浏览(38)
  • RT-Thread 1. GD32移植RT-Thread Nano

    1. RT-Thread Nano 下载 RT-Thread Nano 是一个极简版的硬实时内核,它是由 C 语言开发,采用面向对象的编程思维,具有良好的代码风格,是一款可裁剪的、抢占式实时多任务的 RTOS。其内存资源占用极小,功能包括任务处理、软件定时器、信号量、邮箱和实时调度等相对完整的实

    2024年02月05日
    浏览(48)
  • RT-Thread 9. VS2012下仿真RT-Thread 和LVGL

    1. 在ENV中添加组件 2. 下载组件 3. 生成代码 4. 打开代码 双击project.vcxproj 编译 5. 运行

    2024年02月06日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包