繁体   English   中英

划分由16位和32位变量组成的48位数字

[英]Divide a 48-bit number which is composed of a 16bit and a 32bit variable

我正在开发用于嵌入式微控制器(STN1110)的软件。 它没有FPU或SFP仿真。

有一个SDK方法可返回控制器的正常运行时间(以微秒为单位),分为两个变量:uint16(msw)和uint32(lsw)。

我想将此“对”转换为具有秒精度( / 1000 / 1000 1000/1000)的单个uint32。

SDK API文档规定以下内容:

uint32 TimeGet48 (uint16 * time_msw)
-----------------------------------------   
Read the current full 48-bit system time.

Returns all 48 bits of the current value of the system's 1MHz clock. The resolution of the returned 32 bit value is one microsecond, with the most significant word returned through the pointer passed as a parameter. The clock therefore wraps after approximately 8.9 years. That should be enough for most purposes.

Parameters:
- time_msw: A pointer to store the most significant word of the current system time
Returns:
- Lower 32 bits to the current system time.

这里的主要问题是,控制器最多仅支持uint32 ,因此不支持uint64

我“粘合”了一些我认为可能是解决方案的代码。 并非如此,因为uint16值> 0时就会出现错误,而我找不到它。

uint32 divide(uint32 time_in_us_lsb, uint16 time_in_us_msb, uint32 divisor)
{
    uint32 value1 = (uint32)time_in_us_msb & 0xFFFF;
    uint32 value2 = (uint32)(time_in_us_lsb >> 16) & 0xFFFF;
    uint32 value3 = (uint32)time_in_us_lsb & 0xFFFF;

    value2 += (value1 % divisor) << 16;
    value3 += (value2 % divisor) << 16;

    return (((value2 / divisor) << 16) & 0xFFFF0000) | ( value3 / divisor);
}

uint32 getUptimeSeconds() {
    uint32 time_in_us_lsb;
    uint16 time_in_us_msb;

    time_in_us_lsb = TimeGet48(&time_in_us_msb);   
    uint32 result = divide(time_in_us_lsb, time_in_us_msb, 100000);

    time_in_us_lsb = (uint32)result & 0xFFFFFFFF;
    time_in_us_msb = 0;

    return divide(time_in_us_lsb, time_in_us_msb, 10); 
}

注意:这里速度不是问题,因为在应用程序生存期内不会经常调用该函数。

编辑:添加了uint32功能限制。

..一旦uint16值> 0,就会出现错误,而我找不到它。

在“控制器正常运行时间(以微秒为单位)”中给出至少一个错误

// uint32 result = divide(time_in_ms_lsb, time_in_ms_msb, 100000);
uint32 result    = divide(time_in_ms_lsb, time_in_ms_msb, 1000000);

仅仅使用uint64_t更有意义。

uint32 divide(uint32 time_in_ms_lsb, uint16 time_in_ms_msb, uint32 divisor) {
  uint64_t sum = ((uint64_t)time_in_ms_msb << 32) | divisor;
  return (uint32)(sum / divisor);
}

推荐:在代码中使用ms毫秒数看起来像毫秒 建议us使用“μSeconds”。

给定您定位的CPU,您可能需要针对固定除数对其进行优化。 您的情况除以1000000。

为此,您可以使用a / 1000000 = a *(2 ^ 64/1000000)/ 2 ^ 64。 (2 ^ 64/1000000)不是整数,但是一个近似值就足够了。 乘法可以通过一系列移位和加法来完成。 您可以对(2 ^ 64/1000000)添加一些错误,以减少移位和增加。 结果将略有下降,但不会太大。

正确完成后,正确答案的结果将不超过1。 如果那很重要,则可以再次将结果乘以1000000,进行比较,然后根据需要将结果调整为1。

注意:在上面的近似中,您不必使用2 ^ 64。 尝试2 ^ 32或2 ^ 48或其他数字,看看是否能减少移位和增加次数。

PS:检查编译器的作用是(a * uint64_t(1<<48 / 1000000)) >> 48

应该:

uint32 getUptimeSeconds() {
    uint32 time_in_us_lsb;
    uint16 time_in_us_msb;

    time_in_us_lsb = TimeGet48(&time_in_us_msb);   
    uint32 result = divide(time_in_us_lsb, time_in_us_msb, 10000);

    time_in_us_lsb = (uint32)result & 0xFFFFFFFF;
    time_in_us_msb = 0;

    return divide(time_in_us_lsb, time_in_us_msb, 100); 
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM