linux 定時器編程實例(完善中).....

  最近在寫linux 下的定時器編程實驗,測試發現 usleep函數在 x86 架構下的定時仍是比較準確的,在arm9下 就不太準了.linux

今天用linux 下的setitimer()函數進行了定時 器的測試,代碼以下:編程

  1 #include <stdio.h>
  2 #include <time.h>
  3 #include <sys/time.h>
  4 #include <stdlib.h>
  5 #include <signal.h>
  6 #include <math.h>
  7 #define pi 3.1415926
  8 
  9 /*四元數的元素,表明估計方向  */
 10 float q0 = 1, q1 = 0, q2 = 0, q3 = 0;
 11 float q0_inc,q1_inc,q2_inc,q3_inc;     
 12 /*用於對四元進行更新,角增量,不是真實的歐拉角*/
 13 float Roll_inc,Pitch_inc,Yaw_inc;
 14 float Roll,Pitch,Yaw;                /*真實歐拉角*/
 15 
 16 void FromEulerAngle(float Roll_add,float Pitch_add,float Yaw_add) ;
 17 void ToEulerAngle();
 18 void Quaternion_nor();
 19 void Multiply(float q0_n,float q1_n,float q2_n,float q3_n);
 20 
 21 char flag=0;
 22 int count = 0;
 23 void set_timer()
 24 {
 25         struct itimerval itv, oldtv;
 26         itv.it_interval.tv_sec = 0;
 27         itv.it_interval.tv_usec =10000;
 28         itv.it_value.tv_sec = 0;
 29         itv.it_value.tv_usec = 10000;
 30 
 31         setitimer(ITIMER_REAL, &itv, &oldtv);
 32 }
 33 
 34 void sigalrm_handler(int sig)
 35 {
 36         flag=1;
 37 
 38         //printf("timer signal.. %d\n", count);
 39 }
 40 
 41 int main()
 42 {
 43 
 44         float time_use=0;
 45         struct timeval start;
 46         struct timeval end;
 47 
 48         signal(SIGALRM, sigalrm_handler);
 49         set_timer();
 50         while (count < 1000)
 51         {
 52                 if(flag)
 53                 {
 54                         Roll_inc=0.01;
 55                         Pitch_inc=0.01;
 56                         Yaw_inc=0.01;
 57 
 58                         gettimeofday(&start,NULL);
 59 
 60                         FromEulerAngle(Roll_inc,Pitch_inc,Yaw_inc) ;
 61                         /*更新四元  */
 62                         Multiply(q0_inc,q1_inc,q2_inc,q3_inc);
 63                         ToEulerAngle();
 64 
 65                         gettimeofday(&end,NULL);
 66                         time_use+=(end.tv_sec-start.tv_sec)*1000000+(end.tv_usec-start.tv_usec);//微秒
 67 
 68                         printf("The count is %i\n",count);
 69                         printf("yaw=%f\n",Yaw*57.3);
 70                         printf("pitch=%f\n",Pitch*57.3);
 71                         printf("roll=%f\n",Roll*57.3);
 72                         flag=0;
 73                         count++;
 74                 }
 75 
 76         }
 77         printf("time_use is %f\n",time_use);
 78 
 79         exit(0);
 80 
 81 }
 82 
 83 /*歐拉角轉四元,其它座標系 */
 84 /*這裏是否採用小角近似???*/
 85 
 86 void FromEulerAngle(float Roll_add,float Pitch_add,float Yaw_add)/*這裏只是機體轉角近似成歐拉*/
 87 {
 88 
 89     /*在其餘人的解算中,用的是小角近似  q=[1,Ω*t/2,Ω*t/2,Ω*t/2]T*/
 90 
 91     float fCosHRoll = (float)cos(Roll_add * .5f);
 92     float fSinHRoll = (float)sin(Roll_add * .5f);
 93     float fCosHPitch = (float)cos(Pitch_add * .5f);
 94     float fSinHPitch = (float)sin(Pitch_add * .5f);
 95     float fCosHYaw = (float)cos(Yaw_add * .5f);
 96     float fSinHYaw = (float)sin(Yaw_add * .5f);    /*回來看看這三角函數運算用了多長時間*/
 97                /*下面這個運算要根據座標第進行修改*/
 98     q0_inc = fCosHRoll * fCosHPitch * fCosHYaw + fSinHRoll * fSinHPitch * fSinHYaw;
 99     q1_inc = fSinHRoll * fCosHPitch * fCosHYaw - fCosHRoll * fSinHPitch * fSinHYaw;
100     q2_inc = fCosHRoll * fSinHPitch * fCosHYaw + fSinHRoll * fCosHPitch * fSinHYaw;
101     q3_inc = fCosHRoll * fCosHPitch * fSinHYaw - fSinHRoll * fSinHPitch * fCosHYaw;
102     
103 }
104 /*四元數轉歐拉角*/
105 void ToEulerAngle()
106 {
107     Roll=atan2(2 * (q0 * q1 + q2 * q3) , 1 - 2 * (q1 * q1 + q2 * q2)); 
108     Yaw = atan2(2 * (q0 * q3 + q1 * q2) , 1 - 2 * (q2 * q2 + q3 * q3));
109     Pitch = asin(2*(q0*q2-q3*q1)) ;
110 }
111     
112 /*更新四元數*/
113 /* q_n  這裏表明新來的四元數,這裏指的是增量   */
114 void Multiply(float q0_n,float q1_n,float q2_n,float q3_n)
115 {
116     float q0_temp=q0*q0_n      -q1*q1_n      -q2*q2_n      -q3*q3_n;
117     float q1_temp=q0*q1_n      +q1*q0_n      +q2*q3_n      -q3*q2_n;
118     float q2_temp=q0*q2_n      -q1*q3_n      +q2*q0_n      +q3*q1_n;
119     float q3_temp=q0*q3_n      +q1*q2_n      -q2*q1_n      +q3*q0_n;
120     q0=q0_temp;
121     q1=q1_temp;
122     q2=q2_temp;
123     q3=q3_temp;
124     float s=sqrt(q0*q0+q1*q1+q2*q2+q3*q3); //這裏從新進行規範化,避免的累積偏差
125     q0=q0/s;
126     q1=q1/s;
127     q2=q2/s;
128     q3=q3/s;
129 
130 }

代碼簡介,我這裏用的以前寫的姿態解算的代碼.這裏進行100HZ的定時 ,在PC 上測試 10s ,運行結果以下圖架構

其中姿態解算部分佔用 3042us ,也就是說每次解算用時 3.042us  .函數

在am9平臺下測試,結果以下:測試

在freescale cortex-a9 雙核 測試結果spa

全志  cortex-a7   雙核 測試結果code

這裏測試結果差異仍是比較大的,姿態解算用了 188213us, 平均爲 0.188ms  ,相對與 10ms 的解算週期,佔用仍是比較小的.htm

補充一點,在arm9下linux 到200HZ仍是能夠的,可是就不太準了.這裏我也同時測試了usleep函數和利用select()這個系統調用,延時都不理想.blog

下面介紹一下是利用RTC進行定時,下面的程序來自這裏,http://www.linuxidc.com/Linux/2007-01/1821p2.htm接口

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <unistd.h>
 5 #include <errno.h>
 6 #include <fcntl.h>
 7 
 8 #include <linux/rtc.h>
 9 #include <sys/ioctl.h>
10 int main(int argc, char* argv[])
11 {
12     unsigned long i = 0;
13     unsigned long data = 0;
14     int retval = 0;
15     int fd = open ("/dev/rtc", O_RDONLY);
16     if(fd < 0)
17     {
18         perror("open");
19         exit(errno);
20     }
21       /*Set the freq as 4Hz*/
29     if(ioctl(fd, RTC_IRQP_SET, 4) < 0)
30     {
31         perror("ioctl(RTC_IRQP_SET)");
32         close(fd);
33         exit(errno);
34     }
35     /* Enable periodic interrupts */
36     if(ioctl(fd, RTC_PIE_ON, 0) < 0)
37     {
38         perror("ioctl(RTC_PIE_ON)");
39         close(fd);
40         exit(errno);
41     }
42     for(i = 0; i < 100; i++)
43     {    /*Blocking read*/
44         if(read(fd, &data, sizeof(unsigned long)) < 0)
45         {
46             perror("read");
47             close(fd);
48             exit(errno);
49         }
50         printf("timer\n");
51     }
52     /* Disable periodic interrupts */
53     ioctl(fd, RTC_PIE_OFF, 0);
54     close(fd);
55     return 0;
56 }

程序說明:代碼第 15行處的open()函數,非root下會被拒絕訪問。RTC定時有必定的侷限性,頻率只能爲2冪。

 2013.7.28,進行 posix timer 接口的編程測試,測試代碼以下:

 1 #include <stdio.h>  
 2 #include <time.h>  
 3 #include <signal.h>
 4 #include <pthread.h>  
 5 #include <string.h>
 6 #include <unistd.h>
 7 char flag;
 8 void  handle(union sigval v)  
 9 {  
10       flag=1;
11       return;  
12 }  
13    
14 int create (int ms,int id)  
15 {  
16       timer_t tid;  
17       struct sigevent se;  
18       struct itimerspec ts,ots;  
19       memset (&se,0,sizeof(se));  
20       se.sigev_notify = SIGEV_THREAD;  
21       se.sigev_notify_function = handle;  
22       se.sigev_value.sival_int = id;   //做爲handle()的參數
23       if(timer_create(CLOCK_REALTIME,&se,&tid)<0)  //create the timer
24       {  
25           perror("timer_creat");  
26           return   -1;  
27       }  
28       puts("timer_create successfully.");  
29       ts.it_value.tv_sec = 0;  
30       ts.it_value.tv_nsec =1000*1000*ms ;  
31       ts.it_interval.tv_sec = 0;  
32       ts.it_interval.tv_nsec = 1000*1000*ms;  
33       if(timer_settime (tid,TIMER_ABSTIME,&ts,&ots)   <   0)  //start/stop the timer
34       {  
35            perror("timer_settime");  
36            return   -1;  
37       }  
38       return   0;  
39 }  
40    
41 int main(void)  
42 {  
43       //create(3,1); 
44       int num=0; 
45       create(5,2);  
46       while(num<2000)  
47       {  
48           if(flag)
49           {
50                   flag=0;
51                   printf("the num is %i\n",num);
52                 num++;
53           }
54 
55       }
56       printf("2013.7.28.11\n");
57       return 0;
58 }

代碼參考百度空間,在PC 環境 下運行的時間爲 10s,在arm linux下定時 200hz ,實際運行的時間爲 20S,因此是極爲不許確的.這期間我現時進行了 gettimeofday()這個方法的測試,結果都不理想.總結這面這些代碼 ,要想進行 ms 級的精肯定時 ,只有到驅動層面進行編寫相關程序.

博文爲本人所寫,轉載請代表出處:博客園:夢工廠2012.

相關文章
相關標籤/搜索