从一个变量的位到另一个变量的有效映射
Efficient mapping from bits of one variable to another
我有 4 个名为 lowLevelErrors1、lowLevelErrors2... 的 Uint32 变量,最多 4 个。它们的每一位都代表一个低级错误。我需要将它们映射到名为 userErrors 的 Uint64 变量。 userError 的每一位代表一个显示给用户的错误,可以设置由于 1 个或多个低级错误。换句话说,每个低级错误都映射到 1 个用户错误。 2 个或更多低级错误可以映射到同一个用户错误。
让我们将其缩小到 2x Uint8 低级错误和 1x Uint8 用户错误,以便我们看一个示例。
示例:如果设置了以下任何低级错误 {ERR_VOLT_LOW || ERR_NO_BATTERY || ERR_NOT_CHARGING}(对应于 lowLevelErrors1 的第 0 位、第 2 位和第 3 位)然后设置用户错误 US_ERR_POWER_FAIL(即 userErrors 的第 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 数组 [32] = 128 uint8 变量,我们 运行 微控制器内存不足。
有没有其他方法可以使用更少的 RAM 实现相同的功能?
由于您没有给出包含所有错误的完整示例,因此很难说 "best" 方法是什么,但我会构造一个 table 的 "mask" 和 "value":
像这样:
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 },
...
};
我不确定哪个更有意义,在 table 中有 4 个不同的值,或者有 4 个不同的 tables - 这取决于你从 LowLevel1 中出错的频率LowLevel2、LowLevel2 和 LowLevel4 等映射到相同的错误。但是通过将多个错误的映射存储到一个值,您应该这样做。
现在,一旦我们有了数据结构,代码就变成了这样:
for(auto a : table)
{
if (a.mask & lowLevelErrors1)
{
userErrror |= a.value;
}
}
你有 128 个输入位,每个都映射到一个从 0 到 63 的位号。所以这是 128 * 6 = 768 位信息,除非有一些规则,否则至少需要 96 个字节的存储空间图案。
所以你至少需要96个字节;即便如此,它仍将存储为压缩的 6 位整数。解压缩这些整数的代码可能比打包它们节省的 32 个字节花费更多。
所以你基本上有三个选择:一个 128 字节的数组,如你所建议的;压缩的 6 字节整数;或者一些更容易解包的错误代码的常规分配(如果特定错误代码映射是固定的,这是不可能的)。
我有 4 个名为 lowLevelErrors1、lowLevelErrors2... 的 Uint32 变量,最多 4 个。它们的每一位都代表一个低级错误。我需要将它们映射到名为 userErrors 的 Uint64 变量。 userError 的每一位代表一个显示给用户的错误,可以设置由于 1 个或多个低级错误。换句话说,每个低级错误都映射到 1 个用户错误。 2 个或更多低级错误可以映射到同一个用户错误。
让我们将其缩小到 2x Uint8 低级错误和 1x Uint8 用户错误,以便我们看一个示例。
示例:如果设置了以下任何低级错误 {ERR_VOLT_LOW || ERR_NO_BATTERY || ERR_NOT_CHARGING}(对应于 lowLevelErrors1 的第 0 位、第 2 位和第 3 位)然后设置用户错误 US_ERR_POWER_FAIL(即 userErrors 的第 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 数组 [32] = 128 uint8 变量,我们 运行 微控制器内存不足。
有没有其他方法可以使用更少的 RAM 实现相同的功能?
由于您没有给出包含所有错误的完整示例,因此很难说 "best" 方法是什么,但我会构造一个 table 的 "mask" 和 "value":
像这样:
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 },
...
};
我不确定哪个更有意义,在 table 中有 4 个不同的值,或者有 4 个不同的 tables - 这取决于你从 LowLevel1 中出错的频率LowLevel2、LowLevel2 和 LowLevel4 等映射到相同的错误。但是通过将多个错误的映射存储到一个值,您应该这样做。
现在,一旦我们有了数据结构,代码就变成了这样:
for(auto a : table)
{
if (a.mask & lowLevelErrors1)
{
userErrror |= a.value;
}
}
你有 128 个输入位,每个都映射到一个从 0 到 63 的位号。所以这是 128 * 6 = 768 位信息,除非有一些规则,否则至少需要 96 个字节的存储空间图案。
所以你至少需要96个字节;即便如此,它仍将存储为压缩的 6 位整数。解压缩这些整数的代码可能比打包它们节省的 32 个字节花费更多。
所以你基本上有三个选择:一个 128 字节的数组,如你所建议的;压缩的 6 字节整数;或者一些更容易解包的错误代码的常规分配(如果特定错误代码映射是固定的,这是不可能的)。