Как лучше всего преобразовать заданное целочисленное значение (refresh_rate) между 0,5 Гц и 64 Гц в 0b000 - 0b111
Один из подходов состоит в том, чтобы увидеть, что целевое значение увеличивается на единицу каждый раз, когда ввод удваивается, то есть оно равно log 2 (Гц) + 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
.
Если вы хотите использовать целое число Гц и игнорировать регистр 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
вместо того, чтобы помнить, какие uint16_t
содержат закодированные с нуля значения Гц и содержащие правильно размеченные управляющие регистры.
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>;