【问题标题】:Lua: Hexadecimal Word to Binary ConversionLua:十六进制字到二进制的转换
【发布时间】:2015-04-14 20:03:46
【问题描述】:

我正在尝试创建一个 Lua 程序来监视从设备的周期性状态 ping。从设备以 16 位十六进制字发送其状态,我需要将其转换为二进制字符串,因为每个位都与设备的属性有关。我可以接收输入字符串,并且我有一个包含每个参数的 16 个键的表。但我很难理解如何将十六进制字转换为 16 位字符串以便我可以对其进行监控。

这是我开始工作的一个基本功能。

function slave_Status(IP,Port,Name)
    status = path:read(IP,Port)
    sTable = {}
    if status then
        sTable.ready=bit32.rshift(status:byte(1), 0)
        sTable.paused=bit32.rshift(status:byte(1), 1)
        sTable.emergency=bit32.rshift(status:byte(1), 2)
        sTable.started=bit32.rshift(status:byte(1), 3)
        sTable.busy=bit32.rshift(status:byte(1), 4)
        sTable.reserved1=bit32.rshift(status:byte(1), 5)
        sTable.reserved2=bit32.rshift(status:byte(1), 6)
        sTable.reserved3=bit32.rshift(status:byte(1), 7)
        sTable.reserved4=bit32.rshift(status:byte(2), 0)
        sTable.delay1=bit32.rshift(status:byte(2), 1)
        sTable.delay2=bit32.rshift(status:byte(2), 2)
        sTable.armoff=bit32.rshift(status:byte(2), 3)
        sTable.shieldoff=bit32.rshift(status:byte(2), 4)
        sTable.diskerror=bit32.rshift(status:byte(2), 5)
        sTable.conoff=bit32.rshift(status:byte(2), 6)
        sTable.envoff=bit32.rshift(status:byte(2), 7)
    end
end

我希望这种方法是可以理解的?我想接收十六进制字符串,例如0x18C2 并将其转换为0001 1000 1100 0010,将最右边的位向右移动并将其放入正确的键中。然后在函数的稍后部分,我将监控该位是否发生了更好或更坏的变化。

如果我在 Linux 的 Terminator 中运行类似的函数,并打印出对,我会得到以下返回:

49
24
12
6
3
1
0
0
56
28
14
7
3
1
0
0

这是我不明白如何获取每个值并将其设置为位的地方

我对此很陌生,所以我不怀疑有一种更简单的方法可以做到这一点。如果我需要进一步解释,我会尝试。

【问题讨论】:

    标签: lua hex byte bit data-conversion


    【解决方案1】:

    tonumber(s, 16) 将十六进制表示转换为十进制,string.char 将返回数字的符号/字节表示。查看此recent SO answer 以了解如何使用它们;答案中的解决方案可能对您有用。

    【讨论】:

    • 感谢您的建议。我查看了链接并了解您提供它的原因。但我更喜欢 hjpotter 的方法。抱歉,感谢您的意见!
    【解决方案2】:

    我会以一种不同于 Paul 建议的方式来处理这个问题。

    首先,创建一个存储设备属性的表:

    local tProperty = {
        "ready",
        "paused",
        "emergency",
        "started",
        "busy",
        "reserved1",
        "reserved2",
        "reserved3",
        "reserved4",
        "delay1",
        "delay2",
        "armoff",
        "shieldoff",
        "diskerror",
        "conoff",
        "envoff",
    }
    

    然后,由于您的设备以0xYYYY 发送数据,因此您可以直接调用tonumber(如果不是字符串)。使用函数将每个位存储在一个表中:

    function BitConvert( sInput )
        local tReturn, iNum = {}, tonumber( sInput ) -- optionally pass 16 as second argument to tonumber
        while iNum > 0 do
            table.insert( tReturn, 1, iNum % 2 )
            iNum = math.floor( iNum / 2 )
        end
        for i = #tProperty - #tReturn, 1, -1 do
            table.insert( tReturn, 1, 0 )
        end
        return tReturn
    end
    

    然后,将两个表映射在一起:

    function Map( tKeys, tValues )
        local tReturn = {}
        for i = 1, #tKeys do
            tReturn[ tKeys[i] ] = tValues[i]
        end
        return tReturn
    end
    

    最后,你会:

    function slave_Status( IP, Port, Name )
        local status = path:read( IP, Port )
        local sTable = Map( tProperty, BitConvert(status) )
    end
    

    【讨论】:

    • 我分离了你的代码并在终结者中运行它,以更好地理解你疯狂背后的方法。我只运行了BitConvert(sInput) 并打印了tReturn{} 的键值项。它确实将其分解为二进制,这很棒。但是当它分配二进制项时,它似乎是相反的。我喜欢你的方法,因为它明确地向我展示了你将如何有条不紊地进行这种转换。但我需要切换它看起来的顺序。我会看到关于翻转订单。否则,我喜欢你的方法 hjpotter92!谢谢。
    • @Pwrcdr87 如果顺序颠倒;将所有table.insert( tReturn, 1, val ) 更改为table.insert( tReturn, val )
    • table.insert(tReturn, 1, iNum%2) 更改为table.insert(tReturn,iNum%2)table.insert( tReturn, 1, 0 ) 更改为table.insert( tReturn, 0 )。如您所说,订单已翻转!我知道我是新手,但我应该注意到每个条目都被放在每个列表的第一个位置!非常感谢hjpotter!很好的答案!
    猜你喜欢
    • 2016-02-09
    • 1970-01-01
    • 1970-01-01
    • 2014-10-30
    • 2020-06-27
    • 2012-05-28
    • 2011-10-11
    • 1970-01-01
    相关资源
    最近更新 更多