RT-Thread 是一个集实时操作系统(RTOS)内核、中间件组件和开发者社区于一体的技术平台,由熊谱翔先生带领并集合开源社区力量开发而成,RT-Thread 也是一个组件完整丰富、高度可伸缩、简易开发、超低功耗、高安全性的物联网操作系统。RT-Thread 具备一个 IoT OS 平台所需的所有关键组件,例如GUI、网络协议栈、安全传输、低功耗组件等等。经过11年的累积发展,RT-Thread 已经拥有一个国内最大的嵌入式开源社区,同时被广泛应用于能源、车载、医疗、消费电子等多个行业,累积装机量超过 8亿 台,成为国人自主开发、国内最成熟稳定和装机量最大的开源 RTOS。
任何系统都有一个时钟节拍,负责处理和时间相关的事件,在RT-Thread中时钟节拍可以根据RT_TICK_PER_SECOND宏来定义,下面设定为频率时1000HZ节拍是1ms
和裸机的STM32一样,有一个系统滴答定时器,每1ms触发一次中断
在滴答中断函数里面会有一个全局变量,中断一次就加一
我们可以通过下面一个函数获取滴答定时器里面的全局变量。
rt_tick_t rt_tick_get(void)
定时器可以分为硬件定时器和软件定时器
struct rt_list_node
{
struct rt_list_node *next; /**< point to next node. */
struct rt_list_node *prev; /**< point to prev node. */
};
typedef struct rt_list_node rt_list_t;
t_inline void rt_list_init(rt_list_t *l)
{
l->next = l->prev = l;
}
void rt_system_timer_thread_init(void)
{
#ifdef RT_USING_TIMER_SOFT
int i;
for (i = 0;
i < sizeof(rt_soft_timer_list) / sizeof(rt_soft_timer_list[0]);
i++)
{
rt_list_init(rt_soft_timer_list + i);
}
/* start software timer thread */
rt_thread_init(&timer_thread,
"timer",
rt_thread_timer_entry,
RT_NULL,
&timer_thread_stack[0],
sizeof(timer_thread_stack),
RT_TIMER_THREAD_PRIO,
10);
/* startup */
rt_thread_startup(&timer_thread);
#endif
}
添加定时器
/**
* This function will create a timer
*
* @param name the name of timer
* @param timeout the timeout function
* @param parameter the parameter of timeout function
* @param time the tick of timer
* @param flag the flag of timer
* #define RT_TIMER_FLAG_ONE_SHOT 0x0 /**< one shot timer */
* #define RT_TIMER_FLAG_PERIODIC 0x2 /**< p eriodic timer **/
* #define RT_TIMER_FLAG_HARD_TIMER 0x0 /**< hard timer,the timer's callback function will be called in tick isr. */
* #define RT_TIMER_FLAG_SOFT_TIMER 0x4 /**< soft timer,the timer's callback function will be called in timer thread. */
* @return the created timer object
**/
rt_timer_t rt_timer_create(const char *name,
void (*timeout)(void *parameter),
void *parameter,
rt_tick_t time,
rt_uint8_t flag)
定时器删除
/**
* This function will delete a timer and release timer memory
*
* @param timer the timer to be deleted
*
* @return the operation status, RT_EOK on OK; RT_ERROR on error
*/
rt_err_t rt_timer_delete(rt_timer_t timer)
静态初始化
/**
* This function will initialize a timer, normally this function is used to
* initialize a static timer object.
*
* @param timer the static timer object (typedef struct rt_timer *rt_timer_t;)
* @param name the name of timer
* @param timeout the timeout function
* @param parameter the parameter of timeout function
* @param time the tick of timer
* @param flag the flag of timer
*/
void rt_timer_init(rt_timer_t timer,
const char *name,
void (*timeout)(void *parameter),
void *parameter,
rt_tick_t time,
rt_uint8_t flag)
定时器脱离
/**
* This function will detach a timer from timer management.
*
* @param timer the static timer object
*
* @return the operation status, RT_EOK on OK; RT_ERROR on error
*/
rt_err_t rt_timer_detach(rt_timer_t timer)
启动定时
**
* This function will start the timer
*
* @param timer the timer to be started
*
* @return the operation status, RT_EOK on OK, -RT_ERROR on error
*/
rt_err_t rt_timer_start(rt_timer_t timer)
停止定时器
/**
* This function will stop the timer
*
* @param timer the timer to be stopped
*
* @return the operation status, RT_EOK on OK, -RT_ERROR on error
*/
rt_err_t rt_timer_stop(rt_timer_t timer)
``
## 定时器控制
当定时器启动后我们想更改定时器的某些状态,可以调用下面的函数
```c
/**
* This function will get or set some options of the timer
*
* @param timer the timer to be get or set
* @param cmd the control command
* @param arg the argument
* #define RT_TIMER_CTRL_SET_TIME 0x0 /**< set timer control command */
* #define RT_TIMER_CTRL_GET_TIME 0x1 /**< get timer control command */
* #define RT_TIMER_CTRL_SET_ONESHOT 0x2 /**< change timer to one shot */
* #define RT_TIMER_CTRL_SET_PERIODIC 0x3 /**< change timer to periodic */
* @return RT_EOK
*/
rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
注意:这个函数只支持低于1个OS Tick的延时, 否则SysTick会出现溢出而不能够获得指定的延时时间
/**
效果:定时打印结果,当打印十次后调用rt_timer_control(&tm2, RT_TIMER_CTRL_SET_ONESHOT,NULL);变为一次性的定时器。
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-11-13 15118 the first version
*/
#include
rt_timer_t tm1 ;
struct rt_timer tm2;
int flags = 0;
void tm1_callback(void *parameter)
{
rt_kprintf("tm1_callback running...\n");
}
void tm2_callback(void *parameter)
{
flags++;
if(flags == 10){
rt_timer_control(&tm2, RT_TIMER_CTRL_SET_ONESHOT,NULL);
flags = 0;
}
rt_tick_t timeout = 1000;
rt_timer_control(&tm2, RT_TIMER_CTRL_SET_TIME , (void *)&timeout);
rt_kprintf("[%u]tm2_callback running...\n",rt_tick_get());//获取系统节拍数
}
int main()
{
//动态创建定时器
tm1 = rt_timer_create("tm1_demo",tm1_callback, NULL, 3000, \
RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER);
if(tm1 == RT_NULL){
LOG_E("rt_timer_create faile...\n");
return -ENOMEM;
}
LOG_D("rt_timer_create successed...\n");
rt_timer_start(tm1);
//静态定时器创建
//静态创建定时器
rt_timer_init(&tm2, "tm2_demo", tm2_callback, NULL, 3000, \
RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER);
rt_timer_start(&tm2);
return 1;
}
Linux 内核最初只是由芬兰人林纳斯·托瓦兹(Linus Torvalds)在赫尔辛基大学上学时出于个人爱好而编写的。
Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 UNIX 的多用户、多任务、支持多线程和多 CPU 的操作系统。
Linux 能运行主要的 UNIX 工具软件、应用程序和网络协议。它支持 32 位和 64 位硬件。Linux 继承了 Unix 以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。
Linux分有内核定时器和应用层定时器,在这里我们只讨论应用层的定时器
说起Linux的定时器,又不得不说起信号,应用程序会给系统订一个时间,如果这个时间到达之后,就会发送SIGALRM信号,这个默认的动作是终止调用某个进程
这个是最简单的定时器,我们只要使用它的时候调用它就行了,不过他会和sleep函数冲突,因为sleep()函数会中断信号,使得定时器失效,定时之后我们可以去写他的信号函数,在里面执行回调函数,在里面做自己想做的事
#include
unsigned int alarm(unsigned int seconds);
功能:
在 seconds 秒后,向调用进程发送一个 SIGALRM 信号,SIGALRM 信号的默认动作是终止调用 alarm 函数的进程。
返回值:
若以前没有设置过定时器, 或设置的定时器已超时, 返回 0; 否则返回定时器剩余的秒数, 并重新设定定时器。
现在我们知道alarm函数是用来接收SIGALRM信号的,当我们这个信号接收到之后会执行它默认的处理方式,现在我们需要重写它默认的处理方式。程序中可用函数 signal()改变信号的处理方式。
#include
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum,sighandler_t handler);
功能:
注册信号处理函数( 不可用于 SIGKILL、 SIGSTOP 信号), 即确定收到信号后处理函数的入口地址。
参数:
signum: 信号编号
handler 的取值:
忽略该信号: SIG_IGN
执行系统默认动作: SIG_DFL
自定义信号处理函数: 信号处理函数名
返回值:
成功: 返回函数地址, 该地址为此信号上一次注册的信号处理函数的地址。
失败: 返回 SIG_ERR
效果:五秒后打印魔动山霸你好呀
/* ************************************************************************
* Filename: test.c
* Description:
* Version: 1.0
* Created: 2021年11月14日 14时37分25秒
* Revision: none
* Compiler: gcc
* Author: YOUR NAME (),
* Company:
* ************************************************************************/
#include
#include
#include
void signal_handeler(int signo)
{
int a=31;
printf("%c\n",a);
printf("%d魔动山霸你好呀\n",signo);
}
int main()
{
int serconds = 0;
serconds = alarm(5);
printf("%d\n",serconds);
printf("seconds %d\n",serconds);
signal(SIGALRM,signal_handeler);
while(1);
}
函数alarm设置的定时器只能精确到秒,而以下函数理论上可以精确到微妙
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);
函数setitimer可以提供三种定时器,它们相互独立,任意一个定时完成都将发送定时信号到进程,并且自动重新计时。参数which确定了定时器的类型,如表10-6所示:表10-6 参数which与定时器类型取值 含义 信号发送 ITIMER_REAL 定时真实时间,与alarm类型相同。 SIGALRM ITIMER_VIRT 定时进程在用户态下的实际执行时间。
SIGVTALRM ITIMER_PROF 定时进程在用户态和核心态下的实际执行时间。 SIGPROF 这三种定时器定时完成时给进程发送的信号各不相同,其中
在一个Unix进程中,不能同时使用alarm和ITIMER_REAL类定时器。结构itimerval描述了定时器的组成: struct itimerval {
struct tim. it_interval; /* 下次定时取值 */
struct tim. it_value; /* 本次定时设置值 */
}
结构tim.描述了一个精确到微妙的时间:
struct tim. {
long tv_sec; /* 秒(1000000微秒) */
long tv_usec; /* 微妙 */
}
本处设计了一个精确定时器的例子,进程每隔1.5秒数发送定时信号SIGPROF,在接收到信号时将打印定时的次数,用户可以键入CTRL_C或DELETE结束程序
#include
#include
#include
#include
#include
int n = 0;
void timefunc(int sig) /* 定时事件代码 */
{
fprintf(stderr, "ITIMER_PROF[%d]\n", n++);
}
void main()
{
struct itimerval value;
value.it_value.tv_sec=1; /* 定时1.5秒 */
value.it_value.tv_usec=500000;
value.it_interval.tv_sec=1; /* 定时1.5秒 */
value.it_interval.tv_usec=500000;
signal(SIGALRM, timefunc); /* 捕获定时信号 */
setitimer(ITIMER_REAL, &value, NULL); /* 定时开始 */
while (1);
}
信号简要说明:
SIGHUP 终止进程 终端线路挂断
SIGINT 终止进程 中断进程
SIGQUIT 建立CORE文件终止进程,并且生成core文件
SIGILL 建立CORE文件 非法指令
SIGTRAP 建立CORE文件 跟踪自陷
SIGBUS 建立CORE文件 总线错误
SIGSEGV 建立CORE文件 段非法错误
SIGFPE 建立CORE文件 浮点异常
SIGIOT 建立CORE文件 执行I/O自陷
SIGKILL 终止进程 杀死进程
SIGPIPE 终止进程 向一个没有读进程的管道写数据
SIGALARM 终止进程 计时器到时
SIGTERM 终止进程 软件终止信号
SIGSTOP 停止进程 非终端来的停止信号
SIGTSTP 停止进程 终端来的停止信号
SIGCONT 忽略信号 继续执行一个停止的进程
SIGURG 忽略信号 I/O紧急信号
SIGIO 忽略信号 描述符上可以进行I/O
SIGCHLD 忽略信号 当子进程停止或退出时通知父进程
SIGTTOU 停止进程 后台进程写终端
SIGTTIN 停止进程 后台进程读终端
SIGXGPU 终止进程 CPU时限超时
SIGXFSZ 终止进程 文件长度过长
SIGWINCH 忽略信号 窗口大小发生变化
SIGPROF 终止进程 统计分布图用计时器到时
SIGUSR1 终止进程 用户定义信号1
SIGUSR2 终止进程 用户定义信号2
SIGVTALRM 终止进程 虚拟计时器到时