我正在为红外摄像机编程。但是用于存储刷新率的内部寄存器(共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。
答案 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
一种方法是,每次输入加倍,目标值就会增加一个,这就是
所以,你可以写
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;
}