C语言中的精确定时
下面我有一个小代码。我使用此代码从嵌入式板的GPIO输出一些1和0(C语言中的精确定时,c,linux,time,C,Linux,Time,下面我有一个小代码。我使用此代码从嵌入式板的GPIO输出一些1和0(无符号输出[38]) 我的问题:两个输出值(1,0或0,1)之间的时间应该416微秒正如我在代码下面的clock\u nanosleep中定义的那样,我还使用了sched\u priority()以获得更好的时间分辨率。然而,示波器(下图)测量表明两个输出值之间的时间770 usec。我想知道为什么信号之间有那么多不准确的地方 另外,该板(beagleboard)有Linux 3.2.0-23-omap 36 Ubuntu Ub
无符号输出[38]
)
我的问题:两个输出值(1,0或0,1)之间的时间应该416微秒正如我在代码下面的clock\u nanosleep
中定义的那样,我还使用了sched\u priority()
以获得更好的时间分辨率。然而,示波器(下图)测量表明两个输出值之间的时间770 usec。我想知道为什么信号之间有那么多不准确的地方
另外,该板(beagleboard)有Linux 3.2.0-23-omap 36 Ubuntu Ubuntu周二4月10日20:24:21 UTC 2012 armv7l armv7l armv7l GNU/Linux内核,它有750 MHz的CPU,top
显示几乎没有CPU(~1%),在我运行代码之前,内存(~0.5%)被消耗掉。我使用的电子示波器没有校准问题
#include <stdio.h>
#include <stdlib.h> //exit();
#include <sched.h>
#include <time.h>
void msg_send();
struct sched_param sp;
int main(void){
sp.sched_priority = sched_get_priority_max(SCHED_FIFO);
sched_setscheduler(0, SCHED_FIFO, &sp);
msg_send();
return 0;
}
void msg_send(){
unsigned output[38] = {0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,1};
FILE *fp8;
if ((fp8 = fopen("/sys/class/gpio/export", "w")) == NULL){ //echo 139 > export
fprintf(stderr,"Cannot open export file: line844.\n"); fclose(fp8);exit(1);
}
fprintf(fp8, "%d", 139); //pin 3
fclose(fp8);
if ((fp8 = fopen("/sys/class/gpio/gpio139/direction", "rb+")) == NULL){
fprintf(stderr,"Cannot open direction file - GPIO139 - line851.\n");fclose(fp8); exit(1);
}
fprintf(fp8, "out");
fclose(fp8);
if((fp8 = fopen("/sys/class/gpio/gpio139/value", "w")) == NULL) {
fprintf(stderr,"error in openning value\n"); fclose(fp8); exit(1);
}
struct timespec req = { .tv_sec=0, .tv_nsec = 416000 }; //416 usec
/* here is the part that my question focus*/
while(1){
for(i=0;i<38;i++){
rewind(fp8);
fprintf(fp8, "%d", output[i]);
clock_nanosleep(CLOCK_MONOTONIC ,0, &req, NULL);
}
}
}
#包括
#包括//退出();
#包括
#包括
void msg_send();
结构sched_参数sp;
内部主(空){
sp.sched_priority=sched_get_priority_max(sched_FIFO);
调度设置调度器(0、调度FIFO和sp);
msg_send();
返回0;
}
void msg_send(){
无符号输出[38]={0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,1,0,0,1,0,1,0,1,0,0,0,1,1,0,0,1,1};
文件*fp8;
如果((fp8=fopen(“/sys/class/gpio/export”,“w”))==NULL){//echo 139>export
fprintf(stderr,“无法打开导出文件:line844。\n”);fclose(fp8);退出(1);
}
fprintf(fp8,“%d”,139);//引脚3
fclose(fp8);
如果((fp8=fopen(“/sys/class/gpio/gpio139/方向”,“rb+”)==NULL){
fprintf(stderr,“无法打开方向文件-GPIO139-line851。\n”);fclose(fp8);退出(1);
}
fprintf(fp8,“输出”);
fclose(fp8);
if((fp8=fopen(“/sys/class/gpio/gpio139/value”,“w”))==NULL){
fprintf(stderr,“打开值出错”);fclose(fp8);退出(1);
}
struct timespec req={.tv_sec=0,.tv_nsec=416000};//416 usec
/*这是我问题的重点*/
而(1){
对于(i=0;i我猜问题在于时钟的睡眠时间为416微秒
循环中的其他命令以及循环和clock_nanosleep
体系结构本身都需要354微秒。操作系统也可能提出要求
如果你将睡眠设置为0,你会得到什么间隔
你是在计算机上运行还是在PLC上运行
评论回复
似乎你的硬件/软件中有一些东西正在做一些意想不到的事情——这可能是一个错误
根据这段时间的关键程度,我有两个建议:
低临界-在程序中输入一个数字,使循环按您想要的时间进行。但是,如果这是瞬态或时间/温度相关影响,您需要定期检查漂移
高临界性-在硬件中建立一个温度稳定的振荡器。这些可以从现货中购买
如果您正在执行对时间敏感的I/O,您可能不应该使用stdio.h
中的内容,而应该使用I/O系统调用,因为stdio完成了缓冲。看起来您可能也会受到缓冲的最坏影响,因为您的程序执行以下步骤:
填满缓冲区
睡眠
倒带,我相信这会刷新缓冲区
您希望内核在您睡眠时为写操作提供服务,而不是在您睡眠后刷新缓冲区,您必须等待内核处理它
我认为最好的办法是使用open(“/sys/class/gpio/gpio139/value”,O|WRONLY | O|u DIRECT)
,以最大限度地减少缓存造成的延迟
如果仍然需要刷新缓冲区以强制写入,则可能需要使用clock\u gettime
计算刷新数据所花费的时间,并从睡眠时间中减去该时间。或者,将所需的间隔添加到clock\u gettime
的结果中,并将其传递到clock\u nanosleep
并使用TIMER_ABSTIME
标记等待绝对时间。我不知道调用clock_getres()如何解决您的问题。在手册页中,据说只读取时钟的分辨率
正如Geoff所说,使用绝对休眠时钟应该是一个更好的解决方案。这可以避免来自其他代码的未经检查的时间延迟
struct timespec Time;
clock_gettime(CLOCK_REALTIME, &(Time));
while(1){
Time.tv_nsec += 416000;
if(Time.tv_nsec > 999999999){
(Time.tv_sec)++;
Time.tv_nsec -= 1000000000;
}
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &(Time), NULL);
//Do something
}
我在fews程序上使用它在以太网网络上生成一些常规消息。它工作得很好。我在运行linux的嵌入式板上运行它。我删除了“while(1)”循环中的“clock_nanosleep”行,以查看执行“rewind()”、“fprintf()”和“for()”需要多少时间在这个循环中。它需要11.1纳秒。奇怪的是,如果将20分配给“tv_nsec”,那么两个值之间的时间是102纳秒。你应该将你的解决方案放入正确的答案中(你可以回答自己的问题),并接受它为正确答案。