<< 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;