最近在寫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.