linux 定时器编程实例(完善中).....
最近在写linux 下的定时器编程实验,测试发现 usleep函数在 x86 架构下的定时还是比较准确的,在arm9下 就不太准了.
今天用linux 下的setitimer()函数进行了定时 器的测试,代码如下:
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>
#include <signal.h>
#include <math.h>
#define pi 3.1415926 /*四元数的元素,代表估计方向 */
float q0 = , q1 = , q2 = , q3 = ;
float q0_inc,q1_inc,q2_inc,q3_inc;
/*用于对四元进行更新,角增量,不是真实的欧拉角*/
float Roll_inc,Pitch_inc,Yaw_inc;
float Roll,Pitch,Yaw; /*真实欧拉角*/ void FromEulerAngle(float Roll_add,float Pitch_add,float Yaw_add) ;
void ToEulerAngle();
void Quaternion_nor();
void Multiply(float q0_n,float q1_n,float q2_n,float q3_n); char flag=;
int count = ;
void set_timer()
{
struct itimerval itv, oldtv;
itv.it_interval.tv_sec = ;
itv.it_interval.tv_usec =;
itv.it_value.tv_sec = ;
itv.it_value.tv_usec = ; setitimer(ITIMER_REAL, &itv, &oldtv);
} void sigalrm_handler(int sig)
{
flag=; //printf("timer signal.. %d\n", count);
} int main()
{ float time_use=;
struct timeval start;
struct timeval end; signal(SIGALRM, sigalrm_handler);
set_timer();
while (count < )
{
if(flag)
{
Roll_inc=0.01;
Pitch_inc=0.01;
Yaw_inc=0.01; gettimeofday(&start,NULL); FromEulerAngle(Roll_inc,Pitch_inc,Yaw_inc) ;
/*更新四元 */
Multiply(q0_inc,q1_inc,q2_inc,q3_inc);
ToEulerAngle(); gettimeofday(&end,NULL);
time_use+=(end.tv_sec-start.tv_sec)*+(end.tv_usec-start.tv_usec);//微秒 printf("The count is %i\n",count);
printf("yaw=%f\n",Yaw*57.3);
printf("pitch=%f\n",Pitch*57.3);
printf("roll=%f\n",Roll*57.3);
flag=;
count++;
} }
printf("time_use is %f\n",time_use); exit(); } /*欧拉角转四元,其它坐标系 */
/*这里是否采用小角近似???*/ void FromEulerAngle(float Roll_add,float Pitch_add,float Yaw_add)/*这里只是机体转角近似成欧拉*/
{ /*在其他人的解算中,用的是小角近似 q=[1,Ω*t/2,Ω*t/2,Ω*t/2]T*/ float fCosHRoll = (float)cos(Roll_add * .5f);
float fSinHRoll = (float)sin(Roll_add * .5f);
float fCosHPitch = (float)cos(Pitch_add * .5f);
float fSinHPitch = (float)sin(Pitch_add * .5f);
float fCosHYaw = (float)cos(Yaw_add * .5f);
float fSinHYaw = (float)sin(Yaw_add * .5f); /*回来看看这三角函数运算用了多长时间*/
/*下面这个运算要根据坐标第进行修改*/
q0_inc = fCosHRoll * fCosHPitch * fCosHYaw + fSinHRoll * fSinHPitch * fSinHYaw;
q1_inc = fSinHRoll * fCosHPitch * fCosHYaw - fCosHRoll * fSinHPitch * fSinHYaw;
q2_inc = fCosHRoll * fSinHPitch * fCosHYaw + fSinHRoll * fCosHPitch * fSinHYaw;
q3_inc = fCosHRoll * fCosHPitch * fSinHYaw - fSinHRoll * fSinHPitch * fCosHYaw; }
/*四元数转欧拉角*/
void ToEulerAngle()
{
Roll=atan2( * (q0 * q1 + q2 * q3) , - * (q1 * q1 + q2 * q2));
Yaw = atan2( * (q0 * q3 + q1 * q2) , - * (q2 * q2 + q3 * q3));
Pitch = asin(*(q0*q2-q3*q1)) ;
} /*更新四元数*/
/* q_n 这里代表新来的四元数,这里指的是增量 */
void Multiply(float q0_n,float q1_n,float q2_n,float q3_n)
{
float q0_temp=q0*q0_n -q1*q1_n -q2*q2_n -q3*q3_n;
float q1_temp=q0*q1_n +q1*q0_n +q2*q3_n -q3*q2_n;
float q2_temp=q0*q2_n -q1*q3_n +q2*q0_n +q3*q1_n;
float q3_temp=q0*q3_n +q1*q2_n -q2*q1_n +q3*q0_n;
q0=q0_temp;
q1=q1_temp;
q2=q2_temp;
q3=q3_temp;
float s=sqrt(q0*q0+q1*q1+q2*q2+q3*q3); //这里重新进行规范化,避免的累积误差
q0=q0/s;
q1=q1/s;
q2=q2/s;
q3=q3/s; }
代码简介,我这里用的之前写的姿态解算的代码.这里进行100HZ的定时 ,在PC 上测试 10s ,运行结果如下图
其中姿态解算部分占用 3042us ,也就是说每次解算用时 3.042us .
我在am9平台下测试,结果如下:
在freescale cortex-a9 双核 测试结果
全志 cortex-a7 双核 测试结果
这里测试结果差别还是比较大的,姿态解算用了 188213us, 平均为 0.188ms ,相对与 10ms 的解算周期,占用还是比较小的.
补充一点,在arm9下linux 到200HZ还是可以的,但是就不太准了.这里我也同时测试了usleep函数和利用select()这个系统调用,延时都不理想.
下面介紹一下是利用RTC进行定时,下面的程序来自这里,http://www.linuxidc.com/Linux/2007-01/1821p2.htm
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h> #include <linux/rtc.h>
#include <sys/ioctl.h>
int main(int argc, char* argv[])
{
unsigned long i = ;
unsigned long data = ;
int retval = ;
int fd = open ("/dev/rtc", O_RDONLY);
if(fd < )
{
perror("open");
exit(errno);
}
/*Set the freq as 4Hz*/
if(ioctl(fd, RTC_IRQP_SET, ) < )
{
perror("ioctl(RTC_IRQP_SET)");
close(fd);
exit(errno);
}
/* Enable periodic interrupts */
if(ioctl(fd, RTC_PIE_ON, ) < )
{
perror("ioctl(RTC_PIE_ON)");
close(fd);
exit(errno);
}
for(i = ; i < ; i++)
{ /*Blocking read*/
if(read(fd, &data, sizeof(unsigned long)) < )
{
perror("read");
close(fd);
exit(errno);
}
printf("timer\n");
}
/* Disable periodic interrupts */
ioctl(fd, RTC_PIE_OFF, );
close(fd);
return ;
}
程序说明:代码第 15行处的open()函数,非root下会被拒绝访问。RTC定时有一定的局限性,频率只能为2幂。
2013.7.28,进行 posix timer 接口的编程测试,测试代码如下:
#include <stdio.h>
#include <time.h>
#include <signal.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
char flag;
void handle(union sigval v)
{
flag=;
return;
} int create (int ms,int id)
{
timer_t tid;
struct sigevent se;
struct itimerspec ts,ots;
memset (&se,,sizeof(se));
se.sigev_notify = SIGEV_THREAD;
se.sigev_notify_function = handle;
se.sigev_value.sival_int = id; //作为handle()的参数
if(timer_create(CLOCK_REALTIME,&se,&tid)<) //create the timer
{
perror("timer_creat");
return -;
}
puts("timer_create successfully.");
ts.it_value.tv_sec = ;
ts.it_value.tv_nsec =**ms ;
ts.it_interval.tv_sec = ;
ts.it_interval.tv_nsec = **ms;
if(timer_settime (tid,TIMER_ABSTIME,&ts,&ots) < ) //start/stop the timer
{
perror("timer_settime");
return -;
}
return ;
} int main(void)
{
//create(3,1);
int num=;
create(,);
while(num<)
{
if(flag)
{
flag=;
printf("the num is %i\n",num);
num++;
} }
printf("2013.7.28.11\n");
return ;
}
代码参考百度空间,在PC 环境 下运行的时间为 10s,在arm linux下定时 200hz ,实际运行的时间为 20S,所以是极为不准确的.这期间我现时进行了 gettimeofday()这个方法的测试,结果都不理想.总结这面这些代码 ,要想进行 ms 级的精确定时 ,只有到驱动层面进行编写相关程序.
博文为本人所写,转载请表明出处:博客园:梦工厂2012.
linux 定时器编程实例(完善中).....的更多相关文章
- linux内核模块编程实例
linux内核模块编程实例 学号:201400814125 班级:计科141 姓名:刘建伟 1.确定本机虚拟机中的Ubuntu下Linux的版本 通过使用命令uname -a/uname -r/una ...
- Linux c编程实例_例子
例一:字符与整型变量的实现 #include <stdio.h> int main() { int c1,c2; char c3; c1='a'-'A'; c2='b'-'B'; c3=; ...
- Linux多线程编程实例解析
Linux系统下的多线程遵循POSIX线程接口,称为 pthread.编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a.顺便说一下,Linux ...
- Linux网络编程实例解析
**************************************************************************************************** ...
- Linux文件编程实例
//捕获fopen调用中的错误 #include <stdio.h> #include <errno.h> #include <string.h> #define ...
- Linux多进程编程实例
前言:编写多进程程序时,我们应该了解一下,创建一个子进程时,操作系统内核是怎样做的.当通过fork函数创建新的子进程时,内核将父进程的用户地址空间的内容复制给子进程,这样父子进程拥有各自独立的用户空间 ...
- Linux管道编程实例
/*管道 可以把管道想象为两个实体之间的单向连接器.注意,管道是半双工的, 如果需要全双工通讯,应该转而考虑套接字. 匿名管道又称管道,提供了一个进程与它的兄弟进程通讯的方法,只存在于父进程中: 命名 ...
- Linux 多线程编程实例
一.多线程 VS 多进程 和进程相比,线程有很多优势.在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护代码段和数据.而运行于一个进程中的多个线程,他们之间使用相同 ...
- Linux shell编程 4 ---- shell中的循环
1 for循环 1 for语句的结构 for variable in values; do statement done 2 for循环通常是用来处理一组值,这组值可以是任意的字符串的集合 3 for ...
随机推荐
- Fresco好案例
http://www.open-open.com/lib/view/open1436094840774.html
- iOS应用日志:开始编写日志组件与异常日志
应用日志(一):开始编写日志组件 对于那些做后端开发的工程师来说,看 LOG解Bug应该是理所当然的事,但我接触到的移动应用开发的工程师里面,很多人并没有这个意识,查Bug时总是一遍一遍的试图重现,试 ...
- C++@命名空间(转)
转自http://hi.baidu.com/rainysky_2006/blog/item/a490e01fc3de7964f724e4d1.html 本讲基本要求 * 掌握:命名空间的作用及定义:如 ...
- Android度量单位说明(DIP,DP,PX,SP)
本文转载于:http://blog.sina.com.cn/s/blog_6b26569e0100xw6d.html (一)概念 dip: device independent pixels(设备独立 ...
- FreeSWITCH安装报错“You must install libyuv-dev to build mod_fsv”的解决方案
昨天下午安装FreeSWITCH时遇到该问题时,整了一个下午都没解决,也走了许多弯路.如果直接通过yum安装libyuv-devel时,会报错说找不到该安装包.后来又通过FreeSWITCH官网的网上 ...
- python--flask使用
Flask是一个使用 Python 编写的轻量级 Web 应用框架.下面我将使用Flask框架,创建一个简单的html页面示例. 1.项目的目录结构如下所示:exweb\ uniqueenv\ a ...
- 联表更新 Update Left Join
Update a set a.Manage_FunctID=b.Manage_FunctID From Manage_PageUrl a Left join Manage_ButtonBar b on ...
- fastBinaryJSON
fastBinaryJSON 是基于 fastJSON 的二进制 JSON 序列化器.详细介绍请看这里. 数据编码格式: 序列化速度比较:
- 转 关于ruby gem无法连接到rubygems.org的解决方案
为什么有这个? 由于国内网络原因(你懂的),导致 rubygems.org 存放在 Amazon S3 上面的资源文件间歇性连接失败.所以你会与遇到 gem install rack 或 bundle ...
- Saiku OLAP
简介 Saiku成立于2008年,由Tom Barber和Paul Stoellberger研发.最初叫做Pentaho分析工具,起初是基于OLAP4J库用GWT包装的一个前端分析工具.经过多年的演化 ...