如何将 'convert' 的 Hz 量转换为适当的 byte/bit 格式?

How to 'convert' amount of Hz to appropriate byte/bit format?

我正在为红外摄像机编程。但是用于存储刷新率的内部寄存器(总共 16 个中的第 9、8 和 7 位)当然只接受 1 和 0。例如,值 0b110 表示 32Hz,0b111 表示 64Hz。查看刷新率控制图片时,如何最好地将 0.5Hz 和 64Hz 之间的给定整数 (refresh_rate) 值转换为 0b000 - 0b111?

老实说,我还没有尝试过任何东西,因为我认为这需要一个奇怪的技巧。然而,我一直在考虑查找表,我认为这是可能的,但需要更多的内存,而且它必须是内存高效的,因为它是在 Arduino Due 上编程的。

注意:您可以看到 refresh_rate 是一个 uint16_t,它不接受浮点值,例如 0.5Hz,但是,我可能不会使用 0.5Hz 设置。

// the end-user currently has to pass a value between 7 and 0
void mlx90650::set_refresh_rate(uint16_t refresh_rate) {
    // So the refresh rate may not be higher than 7 (0b111) since this register only 
accepts 3 bits. The memory map is:
/*
    | decimal | bits  |  
    (decimal 0) 0 0 0 IR refresh rate = 0.5Hz 
    (decimal 1) 0 0 1 IR refresh rate = 1Hz 
    (decimal 2) 0 1 0 IR refresh rate = 2Hz (default) 
    (decimal 3) 0 1 1 IR refresh rate = 4Hz 
    (decimal 4) 1 0 0 IR refresh rate = 8Hz 
    (decimal 5) 1 0 1 IR refresh rate = 16Hz 
    (decimal 6) 1 1 0 IR refresh rate = 32Hz 
    (decimal 7) 1 1 1 IR refresh rate = 64H
*/
}

我希望此函数将例如 64Hz 转换为 0b111。

先将寄存器中的Hz值转换成数字:

register_value >>= 7;  // Shift right 7 bits.
register_value &= 7;  // Keep remaining 3 bits. 

接下来,通过左移计算赫兹。

herz = (1 << register_value) / 2.;

要设置赫兹值,请执行相反(反向)步骤。

无论您将实际的 Hz 映射到位模式,您都可以像这样设置它们:

void set_hz(uint16_t& control_reg, uint8_t hz)  // here hz is 0 for .5 Hz, 1 for 1Hz,.. 7 for 64Hz
{
     constexpr int hz_shift = 7;
     constexpr uint16_t hz_mask = static_cast<uint16_t>(0x07) << hz_shift;
     control_reg &= ~hz_mask;
     control_reg |= static_cast<uint16_t>(hz) << hz_shift;
} 

How can I best convert a given integer (refresh_rate) value between 0.5Hz and 64Hz to 0b000 - 0b111

一种方法是看到输入每增加一倍目标值就增加一个,意思是log2(Hz) + 1.

所以,你可以这样写

uint16_t hz_bits(float hz) {
    return static_cast<uint16_t>(round(1.0f + log2(hz)));
}

诚然需要 floating-point 而不是 highly-optimized。反之,

float hz_from_bits(uint16_t hzB) {
    return 0.5f * (1 << hzB);
}

这两个都将您关心的三位作为 uint16_t 的最低有效位。

如果你想使用整数赫兹数,而忽略 0.5 的情况,那么 log2 就是最高设置位的编号:例如,64 = 0b1000000,最高设置位为 6(您仍然需要加 1 以获得 7 = 0b111)。

然后你可以将它们与

之类的东西结合起来
static const uint16_t HZ_START = 7;
static const uint16_t HZ_LEN = 3;
static const uint16_t HZ_MASK = ((1 << HZ_LEN)-1) << HZ_START;

uint16_t set_hz_bits(uint16_t control, uint16_t hzB) {
    return (control & ~HZ_MASK) | (hzB << HZ_START);
}
uint16_t get_hz_bits(uint16_t control) {
    return (control & HZ_MASK) >> HZ_START;
}

进入

uint16_t set_hz(uint16_t control, float hz) {
    return set_hz_bits(control, hz_bits(hz));
}
float get_hz(uint16_t control) {
    return hz_from_bits(get_hz_bits(control));
}

请注意,实际的位屏蔽和移位是非常机械的 - 您可以很容易地为您的各个领域自动化这些东西,使用类似下面的东西,并传递 HzField 个对象,而不必记住哪个uint16_t 包含 zero-based 编码的 Hz 值,并且正确包含 layed-out 控制寄存器。

template <size_t Bstart, size_t Blen, typename T = uint16_t>
struct BitField
{
    T value; // zero-based, not shifted

    static constexpr T mask() { return ((1 << Blen)-1) << Bstart; }

    static T clear(T r) { return r & ~mask(); }

    void decode(T r) { value = (r & mask()) >> Bstart; }
    T encode(T r) { return clear(r) | ((value << Bstart) & mask()); }
    // etc.
};
using HzField = BitField<7, 3>;