C语言 等同于Arduino米利斯()

yqlxgs2m  于 2022-12-17  发布在  其他
关注(0)|答案(3)|浏览(130)

我目前正致力于在电子板上集成“分流”型传感器。我的选择是线性传感器(LTC 2947),但遗憾的是它只有Arduino驱动程序。我必须在Linux下将所有内容翻译成C,以便与我的微处理器(APQ 8009 ARM Cortex-A7)兼容。我对其中一个函数有一个小问题:

int16_t LTC2947_wake_up() //Wake up LTC2947 from shutdown mode and measure the wakeup time
{
   byte data[1];
   unsigned long wakeupStart = millis(), wakeupTime;
   LTC2947_WR_BYTE(LTC2947_REG_OPCTL, 0);
   do
   {
      delay(1);
      LTC2947_RD_BYTE(LTC2947_REG_OPCTL, data); 
      wakeupTime = millis() - wakeupStart;
      if (data[0] == 0) //! check if we are in idle mode
      {
         return wakeupTime;
      }
     if (wakeupTime > 200)
     {
  //! failed to wake up due to timeout, return -1
        return -1;
     }
   }
   while (true);
}

在找到usleep()作为delay()的等价函数后,我在C语言中找不到米利斯()的等价函数。你能帮我翻译这个函数吗?

e4yzc0pl

e4yzc0pl1#

Arduino millis()基于一个定时器,该定时器在非常接近1 KHz(或1毫秒)时触发溢出中断。为了实现同样的目的,我建议您在ARM平台上设置一个定时器,并使用计数器更新volatile unsigned long变量。这将相当于millis()。
下面是米利斯()的幕后工作:

SIGNAL(TIMER0_OVF_vect)
{
    // copy these to local variables so they can be stored in registers
    // (volatile variables must be read from memory on every access)
    unsigned long m = timer0_millis;
    unsigned char f = timer0_fract;

    m += MILLIS_INC;
    f += FRACT_INC;
    if (f >= FRACT_MAX) {
        f -= FRACT_MAX;
        m += 1;
    }

    timer0_fract = f;
    timer0_millis = m;
    timer0_overflow_count++;
}

unsigned long millis()
{
    unsigned long m;
    uint8_t oldSREG = SREG;

    // disable interrupts while we read timer0_millis or we might get an
    // inconsistent value (e.g. in the middle of a write to timer0_millis)
    cli();
    m = timer0_millis;
    SREG = oldSREG;

    return m;
}

来自嵌入式世界的你,在一个新的平台上开始一个项目时,可以说第一件应该做的事是建立时钟并使定时器中断以规定的速率进行,这就是嵌入式系统的“Hello World”。)如果选择以1 KHz频率执行此操作,则已完成大部分工作。

ippsafx7

ippsafx72#

#include <time.h>
unsigned int millis () {
  struct timespec t ;
  clock_gettime ( CLOCK_MONOTONIC_RAW , & t ) ; // change CLOCK_MONOTONIC_RAW to CLOCK_MONOTONIC on non linux computers
  return t.tv_sec * 1000 + ( t.tv_nsec + 500000 ) / 1000000 ;
}

#include <sys/time.h>
unsigned int millis () {
  struct timeval t ;
  gettimeofday ( & t , NULL ) ;
  return t.tv_sec * 1000 + ( t.tv_usec + 500 ) / 1000 ;
}

gettimeofday()版本可能无法在非linux计算机上工作。
clock_gettime()版本可能不适用于旧的C编译器。
小袋鼠()返回unsigned long,32位unsigned integer,大多数计算机都是32位或64位的,所以除了像arduino这样的16位计算机外,没有必要使用long,所以这些版本返回unsigned int,如果你想以毫秒为单位度量一个超过50天的时间段,或者如果你想要从1970年unix开始以来的毫秒数,您需要一个long long(64位)整数。
如果计算机时钟的时间不正确,操作系统或系统管理员或使计算机时钟与互联网时钟同步的程序可能会将计算机时钟更改为正确的时间。这将影响这些功能,尤其是gettimeofday()版本。通常在计算机启动、连接到网络、并使计算机时钟与网络时间服务器同步。但大多数程序在 Boot 过程中不会运行这么早,因此不会受到影响。通常计算机时钟的其他变化非常小,而且对其他程序的影响很小。所以通常改变计算机时钟不是问题。
clock_gettime()需要时钟ID。
CLOCK_MONOTONIC不受系统时间不连续跳转的影响,但受增量调整的影响,并且不计算计算机挂起的时间。
CLOCK_MONOTONIC_RAW仅适用于Linux,不受系统时间不连续跳转的影响,不受增量调整的影响,不计算计算机暂停的时间。
CLOCK_BOOTTIME仅适用于Linux,不受系统时间不连续跳转的影响,但受增量调整的影响,不计算计算机挂起的时间。它计算计算机启动后的时间。
CLOCK_REALTIME受系统时间不连续跳转和增量调整的影响。它计算计算机挂起的时间。它计算标准unix时间(自1970年unix开始以来的时间)。
我认为CLOCK_MONOTONIC_RAW是linux的最佳选择,而CLOCK_MONOTONIC是非linux的最佳选择。通常毫秒时间是用来衡量短时间的,比如一个计算机程序的一部分运行需要多长时间。在短时间内,计算机时钟大概不会有任何变化,计算机大概也不会挂起,所以任何时钟id都可以工作,因此时钟ID的选择并不重要。
精确的时间测量在多任务计算机上是不可靠的,因为时间测量可能被中断。误差通常很小。有时这是个问题,有时不是。如果你需要更精确的时间测量,你需要专用的硬件,不能被中断。一些计算机有这样的硬件内置。例如,如果一个程序使用软件pwm,如果在计算机需要改变输出的时候中断计算机,则对输出的改变将被延迟。但是如果程序使用硬件pwm,则硬件pwm控制器不能被中断,并且将在正确的时间改变输出。
在乌藨子派上测试过。

vxbzzdmp

vxbzzdmp3#

我希望这对我有用。在Lubuntu 20. 04 LTS下对我有效。

#include <sys/time.h>
#include <stdio.h>
#include <unistd.h>

struct timeval __millis_start;

void init_millis() {
    gettimeofday(&__millis_start, NULL);
};

unsigned long int millis() {
    long mtime, seconds, useconds; 
    struct timeval end;
    gettimeofday(&end, NULL);
    seconds  = end.tv_sec  - __millis_start.tv_sec;
    useconds = end.tv_usec - __millis_start.tv_usec;

    mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;
    return mtime;
};

int main()
{
    init_millis();
    printf("Elapsed time: %ld milliseconds\n", millis());

    return 0;
}

注:

基于评论中的讨论(与dear @MarcCompere),我必须提到,在millis函数中,secondsusecondsmtime的转换是通过添加0.5来舍入的(阅读评论以了解如何舍入!);但是0.5可以被移除。这取决于您的应用。如果您使用米利斯进行精确的时间测量,那么添加它以降低转换的“均方误差(MSE)”。但是如果您需要基于一般逻辑的决策的计时(或者更接近Arduino的行为),那么floor(在这种情况下,当铸造时的自然行为)可以被认为是更好的选择。所以不要添加0.5

相关问题