如何将一定数量的Hz“转换”为适当的字节/位格式?

时间:2019-05-29 16:54:18

标签: c++ bit-shift hardware-programming

我正在为红外摄像机编程。但是用于存储刷新率的内部寄存器(共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。

3 个答案:

答案 0 :(得分:2)

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

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

接下来,通过左移计算Hz。

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

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

答案 1 :(得分:1)

  

如何最好地将介于0.5Hz和64Hz之间的给定整数(refresh_rate)值转换为0b000-0b111

一种方法是,每次输入加倍,目标值就会增加一个,这就是 log 2 (Hz)+ 1 。

所以,你可以写

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

不可否认,它需要浮点运算,并且没有高度优化。相反,

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

这两个位中的三个都是uint16_t的最低有效位。

如果要使用整数Hz数,而忽略0.5的情况,则 log 2 只是最高设置位的数字:例如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对象,而不必记住哪个{{ 1}}包含从零开始的已编码Hz值,并且包含正确布局的控制寄存器。

uint16_t

答案 2 :(得分:0)

但是,将实际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;
}