BCD формат

<< Click to Display Table of Contents >>

Navigation:  Modbus Universal MasterOPC Server > Руководство по языку Lua 5.1 > Примеры и полезности > Преобразование данных >

BCD формат

В BCD-формате каждый десятичный разряд числа записывается в виде его четырёхбитного двоичного кода (Википедия:Двоично-десятичный код). То есть, каждый полубайт содержит по одному числу. Данный формат имеет ряд недостатков (больший объем используемой памяти, усложненные математические операции и т.д.) и является устаревшим, однако во многих контроллерах он продолжает применяться. Для преобразования его целочисленному виду можно применить ряд несложных функций в скрипте.

Функция преобразования BCD в int число.

Для примера, мы произвели из прибора считывание Modbus регистра (2 байта) - преобразуем его в 4-х знаковое BCD число.

Пример функции

function FromBCD(register)

   local shift=register;

   local bytes={};

   local exp=1;

   local number=0;

   for i=1,4,1 do

       local byte=bit.BitAnd(shift,0xF);--получаем правый полубайт маскированием

       number=number+byte*exp; --умножаем число и прибавляем к сохраненному

       exp=exp*10; --увеличиваем степень умножения

       shift=bit.BitRshift(shift,4); --делаем сдвиг вправо

   end

   return number; --возвращаем число

end

Если число имеет большую размерность (например 4 байта), достаточно заменить изменить число 4 на 8 в цикле for (по количеству BCD чисел).

Пример вызова функции:

val=4660; --в BCD это число равно 1234

BCD=FromBCD(val);

Функция преобразования int в BCD число.

Теперь рассмотрим обратную функцию - преобразуем из int числа в BCD формат (например, для отправки в прибор). При этом нужно учитывать, что BCD имеет меньшую "емкость", по сравнению в обычным числом такой же размерности. То есть если число формата uint16 может иметь принимать значения от 0 до 65535, то BCD только 9999.

Пример функции

function ToBCD(number)

local val=number;

if val>9999 or val<0 then return nil; end; --проверяем что число в допустимых предалах

local shift=0;

   for i=1,4,1 do        

       shift=bit.BitRshift(shift,4); --смещаем вправо наш регистр            

       local ost;

       val,ost=math.modf(val*0.1); --умножаем число на 0.1 и берем целую и дробную часть

       ost=bit.BitAnd(ost*10,0xF); --маскируем дробную часть

       ost=bit.BitLshift(ost,12); --смещаем влево на 12 бит - в старший байт

       ost=bit.BitAnd(ost,0xF000); --маскируем - убираем лишние биты

       shift=bit.BitOr(ost,shift); --применяем к текущему регистру      

   end;

return shift;

end;