【问题标题】:Efficient mapping from bits of one variable to another从一个变量的位到另一个变量的有效映射
【发布时间】:2015-06-23 07:25:43
【问题描述】:

我有 4 个 Uint32 变量,分别命名为 lowLevelErrors1、lowLevelErrors2... 最多 4 个。这些变量上的每一位都代表一个低级错误。我需要将它们映射到一个名为 userErrors 的 Uint64 变量。 userError 的每一位都表示向用户显示的错误,该错误可以由于 1 个或多个低级错误而设置。换句话说,每个低级错误都映射到 1 个用户错误。 2 个或更多低级错误可以映射到同一个用户错误。

让我们将其缩小到 2x Uint8 低级错误和 1x Uint8 用户错误,以便我们看一个示例。

示例:如果设置了以下任何低级错误 {ERR_VOLT_LOW || ERR_NO_BATTERY || ERR_NOT_CHARGING}(对应lowLevelErrors1的bit 0、bit 2和bit 3)然后设置用户错误US_ERR_POWER_FAIL(即userErrors的bit 5)。

所以我能想到的唯一方法是为每个 lowLevelErrors 变量设置一个映射数组,用于映射到 userErrors 的相应位。

/* Let's say the lowLevelErrors have to be mapped like this:
lowLevelErrors1 bit maps to userError bit
        0                         5 
        1                         1
        2                         5
        3                         5
        4                         0
        5                         2
        6                         7
        7                         0

lowLevelErrors2 bits maps to userError bit
        0                         1
        1                         1
        2                         0
        3                         3
        4                         6
        5                         6
        6                         4
        7                         7
*/

Uint8 lowLevelErrors1 = 0;
Uint8 lowLevelErrors2 = 0;
Uint8 userErrors = 0;

Uint8 mapLLE1[8] = {5, 1, 5, 5, 0, 2, 7, 0};
Uint8 mapLLE2[8] = {1, 1, 0, 3, 6, 6, 4, 7};

void mapErrors(void)
{
    for (Uint8 bitIndex = 0; bitIndex < 8; i++)
    {
        if (lowLevelErrors1 && (1 << i))  //If error bit is set
        {
            userErrors |= 1 << mapLLE1[bitIndex];  //Set the corresponding user error
        }
    }

    for (Uint8 bitIndex = 0; bitIndex < 8; i++)
    {
        if (lowLevelErrors2 && (1 << i))  //If error bit is set
        {
            userErrors |= 1 << mapLLE2[bitIndex];  //Set the corresponding user error
        }
    }

}

这个实现的问题是需要地图数组。我需要 4x uint8 array[32] = 128 uint8 变量,而我们的微控制器内存不足。

还有其他方法可以使用更少的 RAM 实现相同的功能吗?

【问题讨论】:

  • 我不认为你可以做得更好,除非你重新排列位以便userErrors 中的每个位对应于lowLevelErrors 中的连续位范围。即使这样,映射表也是 64 字节。
  • 另一个想法是将 mapLLE 数组声明为 const 以便编译器将它们放入 ROM 而不是 RAM。如果编译器不配合,您通常可以选择使用链接器控制文件移动内容。
  • 为什么需要重新映射?只要每个用户错误仅源自四个低级错误变量之一,您就不能使用 #define US_ERR_POWER_FAIL (ERR_VOLT_LOW | ERR_NO_BATTERY | ERR_NOT_CHARGING) 之类的掩码吗?
  • @WeatherVane 每个用户错误都可以源自 4 个低级错误中的任何一个(如上面的示例代码所示)。当然你不知道其余的代码和整个项目,但我可以肯定地告诉你#define 在这种情况下不是一个选项:)
  • @user3386109 const 是个好主意。我认为我们的 ROM 也很低,但我会检查一下。也许确实更好:)

标签: c++ c bit-manipulation


【解决方案1】:

您有 128 个输入位,每个输入位都映射到一个从 0 到 63 的位号。所以这是 128 * 6 = 768 位信息,除非有一些常规模式来存储,否则至少需要 96 个字节的存储空间它。

所以你至少需要 96 个字节;即便如此,它也会被存储为压缩的 6 位整数。解压这些整数的代码可能比打包它们节省的 32 个字节还要多。

所以你基本上有三个选择:一个 128 字节的数组,正如你所建议的那样;打包的 6 字节整数;或者一些更容易解包的错误代码的常规分配(如果特定的错误代码映射是固定的,这是不可能的)。

【讨论】:

    【解决方案2】:

    由于您没有给出一个包含所有错误的完整示例,因此很难说什么是“最佳”方法,但我会构建一个“掩码”和“值”表:

    类似这样的:

    struct Translate
    {
        uint32_t mask;
        // Maybe have mask[4]?
        uint64_t value;
    };
    
    // If not mask[4], the 
    Translate table[] = 
    {
        {  ERR_VOLT_LOW | ERR_NO_BATTERY | ERR_NOT_CHARGING, 
           // If mask[4] then add 3 more values here - expect typically zeros
           US_ERR_POWER_FAIL },
        ... 
    };
    

    我不确定哪个更有意义,在表中有 4 个不同的值,或者有 4 个不同的表 - 这取决于 LowLevel1 和 LowLevel2、LowLevel2 和 LowLevel4 等的错误映射到的频率同样的错误。但是通过将多个错误的映射存储到一个值,您应该这样做。

    现在,一旦我们有了数据结构,代码就会变成这样:

     for(auto a : table)
     {
         if (a.mask & lowLevelErrors1)
         {
           userErrror |= a.value; 
         }
      }
    

    【讨论】:

    • 虽然巧妙的解决方案,但它并没有减少用于存储变量的空间量。
    猜你喜欢
    • 1970-01-01
    • 2021-05-18
    • 2018-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多