C中三个值的有效平均

Efficient Average of Three Values in C

我们正在从引脚读取一些信号并根据此读数设置更多事件。

为了安全起见,我想对引脚进行3次采样,比较三个值并使用最常见的值(即采样A为1,B为3,C为1,我想使用1,如果A B 和 C 都是 2 然后使用 2 但如果 A 是 1 ,B 是 2 和 C 是 3,我想再次捕获三个样本)。

目前我正在使用:

int getCAPValues (void)
{
//  Get three samples to check CAP signals are stable:  

        uint32_t x = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;           // First set of CAP values
        for (uint32_t i = 0; i < 7; i++) dummy = i;                                                     // Pause
        uint32_t y = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;           // second set
        for (uint32_t i = 0; i < 7; i++) dummy = i;                                                     // Pause
        uint32_t z = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;           // third set

        if (x == y) || (x == z)
        {
            //use the x value
        }
        else if (y == z)
        {
            // use the y value
            x = y;
        }
        else
        {           
            x = -1;
        }

    return x;
}

但这对我来说似乎不是很有效,有没有更好的方法来做到这一点?

这是在 C 语言的 SAMD21 Xplained Pro 开发板上。

编辑:

我已经根据答案更改了代码,只读取 "z" 值(如果将要使用),并使用 delay_us() 而不是虚拟循环:

int getCAPValues (void)
{
//  Get three samples to check CAP signals are stable:  

        uint32_t x = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;           // First set of CAP values
        delay_us(1);
        //for (uint32_t i = 0; i < 7; i++) dummy = i;                                                   // Pause
        uint32_t y = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;           // second set
        // Using most common value, or error code of -1 if all different

        if (!(x == y))
        {
            delay_us(1);
            //for (uint32_t i = 0; i < 7; i++) dummy = i;                                               // Pause
            uint32_t z = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;       // third set
            if (x == z)
            {
                // use the x/z value
                return x;
            }
            else if (y == z)
            {
                // use the y/z value
                return y;
            }
            else
            {           
                return -1;
            }
        }
    return x;
}

如果 x==y 您将使用 x 的值。所以那样的话你就可以躲开三读了。

我不知道你的价值观有多不稳定,但如果有争议的价值观实际上很少见,它可以有效地将性能几乎翻倍以避免第二次延迟。

事实上,如果它们并不罕见,那么整个理由可能是无效的。

int getCAPValues (void)
{
//  Get three samples to check CAP signals are stable:  

        uint32_t x = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;           // First set of CAP values
        for (uint32_t i = 0; i < 7; i++) dummy = i;                                                     // Pause
        uint32_t y = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;           // second set
        if(x!=y){
            //x & y are different. Get a tie-breaker...
            for (uint32_t i = 0; i < 7; i++) dummy = i;                                                     // Pause
            uint32_t z = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;           // third set
            if (y == z) {
                // use the y value
                x = y;
            } else if(x!=z){
                //tie-breaking failed...
                x=-1;
            }
        }
        return x;
}

PS:我也认为你应该使用 `usleep()' 而不是虚拟循环。这取决于您的平台上可用的内容。

如果您可以假设 xyz01。然后你可以只使用 x+y+z>1 (如果它们中的大多数是 1 那么总和大于 1 并且比较评估为 1 否则它评估为 0).

否则你的(第二个)解决方案可能是最有效的。至少如果你不知道结果的概率。除了休眠一微秒这将是最耗时的操作。

你应该考虑的是,由于读取可能是非易失性的,所以如果你实际进行第三次读取,它可能会有所不同。另外,您也许应该考虑是否需要进行完整的重读。例如,如果您认为如果来自端口的前三个读取都不同并且第四个读取等于第二个或第三个,那么您可以这样做,您可以将其用作优化。例如:

 x = read_port();
 y = read_port();

 if( x == y )
    return x;

 for(;;) {
    z = read_port();
    if( z == x || z == y )
        return z;
    x = y;
    y = z;
 }