-
时间: 2024.07.30 作者: Yuan
-
问题简述
这是一个发生在很久之前的问题,但是值得被记录和澄清一下!
在2022年1月份参与的项目中,其中有一个需求是利用 SHT40-AD1B-R2 芯片,读取环境温度。其实就是通过 i2c 与这个温度传感器建立通讯,然后读取温湿度信息。对于上位机的我而言,需要解决的一点就是将从传感器中读回的数据换算为以摄氏度为单位的十进制数值。当时费了一番脑筋,最后找到了一个”解决”的方法。
在2022年6月份,梳理 Python 知识点的过程中,我猛然间发现似乎不用那么复杂,使用Python内建的函数就可以直接转换…… 顿时感觉自己“愚蠢且努力”!
现在是2024年7月份,事情过去两年了,忽然想起需要整理下这个内容。由于当时对“字节字符串”的认识不足,以及对python基础不够清楚,所以走了弯路。现在再次确认,发现两年前的解决办法实际上是有bug的,现在就来解一解这个两年前的bug!
- byte 字符串初见
"""
当时在看到读回的数据为类似 `b'fX'`、`b'f4'`、`b'd\xac\xd6\xa5\x9f\x1e'` 这样的结果时,一时间有点摸不着头脑,
于是请教了客户那边的软件工程师,客户给我做了一个示例。
有了客户的示例和指导后,我就奔着目标开干了:
将遇到的\x开头的2位16进制字符记为16进制,非\x开头的16进制的字符转为 ascii 码!
"""
# Yuan: I2C 读取温度返回的信息, 有点奇怪: b'f4' 、b'fX' 、b'f`5\x95\xA6\xE1'
# Kim: 什麼型號的溫度感測元件
# Yuan: SHT40-AD1B-R2
# Kim: b'f4' 算出來是24.866483558 °C
# 我覺得應該是正常的
# b'f4' = 0x66, 0x34
# 0x6634 = 26164
# ((26164/65535)*175) - 45 = 24.866483558
# b'f'' = 0x66, 0x27
# ' 這個的ascii code應該是0x27
# Yuan: 是用 ascii code 转换成16进制的对吗?
# Kim: Yes,因為那是byte array
# 除非看到\x
# 不然就都要轉ASCII
# Yuan: 好的,\x开头的都是2位16进制, 对吗
# Kim: Yes
- “笨拙的”解决方案
#!/usr/bin/env python3
"""
思路:
将 “\x后跟2位字符” 部分直接记录为 Hex 值,将非“\x后跟2位字符”的单个字符转换为 ASCII 码,
于是,我突发奇想从utf-8中找了几个希腊字母(因为他们不在ascii表中,避免了重复),先将 “\x后跟2位字符” 这类已知的Hex子字符串替换成希腊字母,
然后,再遍历替换后的字符串,遇到的非希腊字母,就将其从 ASCII 码,转换为对应的Hex形式。
最终,将两类Hex字符汇总成纯Hex字符的字符串,再统一转换为十进制数值,再进行下一步温度的计算。
"""
import re
temp_list = [
b'dW',
b'd^',
b'dB',
b'd>',
b'dP',
b'dD',
b'dS',
b'dQ',
b'dP',
b'dO',
b'dK',
b'',
b'dU',
b'df',
b'd_',
b'dd(\xa6\x99\x95',
b'd\xa4o\xa5\xc2,',
b'd\xb0\xe8\xa5\xddA',
b'd\xa3\xf8\xa5\xaa.',
b'd\xb0\xe8\xa5\xac\x88',
b'd\xb8Q\xa5\xb3\xe5',
b'd\xac\xd6\xa5\x8b\x99',
b'd\xaap\xa5\xa41',
b'd\xae\xb4\xa5\xa7b',
b'd\xa7<\xa5\x93c',
b'd\xa5^\xa5\x98\x89',
b'd\xac\xd6\xa5\x9f\x1e',
b'd\xb9`\xa5\x9d|',
b'd\xa7<\xa5\xa3\xa6',
b'd\xb1\xd9\xa5\x9a\xeb',
b'd\xb8Q\xa5\x94\xf4',
b'd\xb9`\xa5\x89\xfb',
b'd\xb8Q\xa5xH',
b'',
b'd\xb3\xbb\xa5\x91\x01',
b'd\xb0\xe8\xa5\x96\x96',
b'd\xba3\xa5\x7f\xdf',
b'd\xb2\x8a\xa5xH',
b'd\xaap\xa5s\xa2',
b'd\xabA\xa5s\xa2',
b'd\xba3\xa5\x81B',
b'd\xb8Q\xa5n\xad',
b'd\xb2\x8a\xa5yy',
b'd\xac\xd6\xa5h\x0b',
b'd\xb6N\xa5n\xad',
b'd\xabA\xa5wf',
b'd\xad\xe7\xa5l\xcf',
b'd\xbc\x95\xa5i:',
b'd\xb3\xbb\xa5];',
b'd\xb1\xd9\xa5eG',
b'd\xbb\x02\xa5s\xa2',
b'd\xac\xd6\xa5p\xf1',
b'',
b'd\xad\xe7\xa5\\\n',
b'\n',
b'd\n',
b'd\xbc\x95\xa5O\x1a',
b'd\xb1\xd9\xa5LI']
def get_temperature(_data):
if _data:
data1 = str(_data).lstrip("b").strip("'")
reg = r'\\x([0-9a-f]{2})'
val_ret = re.findall(reg, data1)
unichr = 'δλξπσω'
unidict = {}
data2 = str(data1)
if val_ret:
for i, ret in enumerate(val_ret):
unidict[unichr[i]] = '0x{}'.format(ret)
data2 = data2.replace('\\x{}'.format(ret), unichr[i])
hex_str = []
for da in data2:
if da in unidict.keys():
hex_str.append(unidict[da])
else:
hex_str.append(hex(ord(da)))
data_pool = hex_str
value1 = int(''.join(data_pool[:2]).replace('0x', ''), 16)
degc = round(((value1 / 65535) * 175) - 45, 2)
# prh = round(((value2 / 65535) * 125) - 6, 2)
# if prh > 100:
# prh = 100
# if prh < 0:
# prh = 0
# unit = chr(8451)
unit = "°C"
if degc > 40 or degc < 10:
result = 'degc: {} {} ({}, {})'.format(degc, unit, _data, val_ret)
else:
result = 'degc: {} {}'.format(degc, unit)
# print('DEG: {} {}'.format(degc, unit), ', PRH: {} {}'.format(prh, '%'))
# print("{} ==> {} ==> Hex: {} ==> DEG: {} {}".format(_data, val_ret, data_pool, degc, unit))
print(f"{str(_data).ljust(25)} ==> hex: {repr(val_ret).ljust(30)} ==> full_hex: {repr(data_pool).ljust(64)} ==> DEG: {degc} {unit}")
else:
result = '-- no data --'
return result
if __name__ == '__main__':
for i, temp in enumerate(temp_list):
# print('{}: {} {}'.format(str(i).zfill(2), get_temperature(temp), temp))
get_temperature(temp)
"""
输出:
b'dW' ==> hex: [] ==> full_hex: ['0x64', '0x57'] ==> DEG: 23.59 °C
b'd^' ==> hex: [] ==> full_hex: ['0x64', '0x5e'] ==> DEG: 23.61 °C
b'dB' ==> hex: [] ==> full_hex: ['0x64', '0x42'] ==> DEG: 23.54 °C
b'd>' ==> hex: [] ==> full_hex: ['0x64', '0x3e'] ==> DEG: 23.53 °C
b'dP' ==> hex: [] ==> full_hex: ['0x64', '0x50'] ==> DEG: 23.57 °C
b'dD' ==> hex: [] ==> full_hex: ['0x64', '0x44'] ==> DEG: 23.54 °C
b'dS' ==> hex: [] ==> full_hex: ['0x64', '0x53'] ==> DEG: 23.58 °C
b'dQ' ==> hex: [] ==> full_hex: ['0x64', '0x51'] ==> DEG: 23.58 °C
b'dP' ==> hex: [] ==> full_hex: ['0x64', '0x50'] ==> DEG: 23.57 °C
b'dO' ==> hex: [] ==> full_hex: ['0x64', '0x4f'] ==> DEG: 23.57 °C
b'dK' ==> hex: [] ==> full_hex: ['0x64', '0x4b'] ==> DEG: 23.56 °C
b'dU' ==> hex: [] ==> full_hex: ['0x64', '0x55'] ==> DEG: 23.59 °C
b'df' ==> hex: [] ==> full_hex: ['0x64', '0x66'] ==> DEG: 23.63 °C
b'd_' ==> hex: [] ==> full_hex: ['0x64', '0x5f'] ==> DEG: 23.61 °C
b'dd(\xa6\x99\x95' ==> hex: ['a6', '99', '95'] ==> full_hex: ['0x64', '0x64', '0x28', '0xa6', '0x99', '0x95'] ==> DEG: 23.63 °C
b'd\xa4o\xa5\xc2,' ==> hex: ['a4', 'a5', 'c2'] ==> full_hex: ['0x64', '0xa4', '0x6f', '0xa5', '0xc2', '0x2c'] ==> DEG: 23.8 °C
b'd\xb0\xe8\xa5\xddA' ==> hex: ['b0', 'e8', 'a5', 'dd'] ==> full_hex: ['0x64', '0xb0', '0xe8', '0xa5', '0xdd', '0x41'] ==> DEG: 23.83 °C
b'd\xa3\xf8\xa5\xaa.' ==> hex: ['a3', 'f8', 'a5', 'aa'] ==> full_hex: ['0x64', '0xa3', '0xf8', '0xa5', '0xaa', '0x2e'] ==> DEG: 23.8 °C
b'd\xb0\xe8\xa5\xac\x88' ==> hex: ['b0', 'e8', 'a5', 'ac', '88'] ==> full_hex: ['0x64', '0xb0', '0xe8', '0xa5', '0xac', '0x88'] ==> DEG: 23.83 °C
b'd\xb8Q\xa5\xb3\xe5' ==> hex: ['b8', 'a5', 'b3', 'e5'] ==> full_hex: ['0x64', '0xb8', '0x51', '0xa5', '0xb3', '0xe5'] ==> DEG: 23.85 °C
b'd\xac\xd6\xa5\x8b\x99' ==> hex: ['ac', 'd6', 'a5', '8b', '99'] ==> full_hex: ['0x64', '0xac', '0xd6', '0xa5', '0x8b', '0x99'] ==> DEG: 23.82 °C
b'd\xaap\xa5\xa41' ==> hex: ['aa', 'a5', 'a4'] ==> full_hex: ['0x64', '0xaa', '0x70', '0xa5', '0xa4', '0x31'] ==> DEG: 23.81 °C
b'd\xae\xb4\xa5\xa7b' ==> hex: ['ae', 'b4', 'a5', 'a7'] ==> full_hex: ['0x64', '0xae', '0xb4', '0xa5', '0xa7', '0x62'] ==> DEG: 23.83 °C
b'd\xa7<\xa5\x93c' ==> hex: ['a7', 'a5', '93'] ==> full_hex: ['0x64', '0xa7', '0x3c', '0xa5', '0x93', '0x63'] ==> DEG: 23.81 °C
b'd\xa5^\xa5\x98\x89' ==> hex: ['a5', 'a5', '98', '89'] ==> full_hex: ['0x64', '0xa5', '0x5e', '0xa5', '0x98', '0x89'] ==> DEG: 23.8 °C
b'd\xac\xd6\xa5\x9f\x1e' ==> hex: ['ac', 'd6', 'a5', '9f', '1e'] ==> full_hex: ['0x64', '0xac', '0xd6', '0xa5', '0x9f', '0x1e'] ==> DEG: 23.82 °C
b'd\xb9`\xa5\x9d|' ==> hex: ['b9', 'a5', '9d'] ==> full_hex: ['0x64', '0xb9', '0x60', '0xa5', '0x9d', '0x7c'] ==> DEG: 23.85 °C
b'd\xa7<\xa5\xa3\xa6' ==> hex: ['a7', 'a5', 'a3', 'a6'] ==> full_hex: ['0x64', '0xa7', '0x3c', '0xa5', '0xa3', '0xa6'] ==> DEG: 23.81 °C
b'd\xb1\xd9\xa5\x9a\xeb' ==> hex: ['b1', 'd9', 'a5', '9a', 'eb'] ==> full_hex: ['0x64', '0xb1', '0xd9', '0xa5', '0x9a', '0xeb'] ==> DEG: 23.83 °C
b'd\xb8Q\xa5\x94\xf4' ==> hex: ['b8', 'a5', '94', 'f4'] ==> full_hex: ['0x64', '0xb8', '0x51', '0xa5', '0x94', '0xf4'] ==> DEG: 23.85 °C
b'd\xb9`\xa5\x89\xfb' ==> hex: ['b9', 'a5', '89', 'fb'] ==> full_hex: ['0x64', '0xb9', '0x60', '0xa5', '0x89', '0xfb'] ==> DEG: 23.85 °C
b'd\xb8Q\xa5xH' ==> hex: ['b8', 'a5'] ==> full_hex: ['0x64', '0xb8', '0x51', '0xa5', '0x78', '0x48'] ==> DEG: 23.85 °C
b'd\xb3\xbb\xa5\x91\x01' ==> hex: ['b3', 'bb', 'a5', '91', '01'] ==> full_hex: ['0x64', '0xb3', '0xbb', '0xa5', '0x91', '0x01'] ==> DEG: 23.84 °C
b'd\xb0\xe8\xa5\x96\x96' ==> hex: ['b0', 'e8', 'a5', '96', '96'] ==> full_hex: ['0x64', '0xb0', '0xe8', '0xa5', '0x96', '0x96'] ==> DEG: 23.83 °C
b'd\xba3\xa5\x7f\xdf' ==> hex: ['ba', 'a5', '7f', 'df'] ==> full_hex: ['0x64', '0xba', '0x33', '0xa5', '0x7f', '0xdf'] ==> DEG: 23.86 °C
b'd\xb2\x8a\xa5xH' ==> hex: ['b2', '8a', 'a5'] ==> full_hex: ['0x64', '0xb2', '0x8a', '0xa5', '0x78', '0x48'] ==> DEG: 23.84 °C
b'd\xaap\xa5s\xa2' ==> hex: ['aa', 'a5', 'a2'] ==> full_hex: ['0x64', '0xaa', '0x70', '0xa5', '0x73', '0xa2'] ==> DEG: 23.81 °C
b'd\xabA\xa5s\xa2' ==> hex: ['ab', 'a5', 'a2'] ==> full_hex: ['0x64', '0xab', '0x41', '0xa5', '0x73', '0xa2'] ==> DEG: 23.82 °C
b'd\xba3\xa5\x81B' ==> hex: ['ba', 'a5', '81'] ==> full_hex: ['0x64', '0xba', '0x33', '0xa5', '0x81', '0x42'] ==> DEG: 23.86 °C
b'd\xb8Q\xa5n\xad' ==> hex: ['b8', 'a5', 'ad'] ==> full_hex: ['0x64', '0xb8', '0x51', '0xa5', '0x6e', '0xad'] ==> DEG: 23.85 °C
b'd\xb2\x8a\xa5yy' ==> hex: ['b2', '8a', 'a5'] ==> full_hex: ['0x64', '0xb2', '0x8a', '0xa5', '0x79', '0x79'] ==> DEG: 23.84 °C
b'd\xac\xd6\xa5h\x0b' ==> hex: ['ac', 'd6', 'a5', '0b'] ==> full_hex: ['0x64', '0xac', '0xd6', '0xa5', '0x68', '0x0b'] ==> DEG: 23.82 °C
b'd\xb6N\xa5n\xad' ==> hex: ['b6', 'a5', 'ad'] ==> full_hex: ['0x64', '0xb6', '0x4e', '0xa5', '0x6e', '0xad'] ==> DEG: 23.85 °C
b'd\xabA\xa5wf' ==> hex: ['ab', 'a5'] ==> full_hex: ['0x64', '0xab', '0x41', '0xa5', '0x77', '0x66'] ==> DEG: 23.82 °C
b'd\xad\xe7\xa5l\xcf' ==> hex: ['ad', 'e7', 'a5', 'cf'] ==> full_hex: ['0x64', '0xad', '0xe7', '0xa5', '0x6c', '0xcf'] ==> DEG: 23.82 °C
b'd\xbc\x95\xa5i:' ==> hex: ['bc', '95', 'a5'] ==> full_hex: ['0x64', '0xbc', '0x95', '0xa5', '0x69', '0x3a'] ==> DEG: 23.86 °C
b'd\xb3\xbb\xa5];' ==> hex: ['b3', 'bb', 'a5'] ==> full_hex: ['0x64', '0xb3', '0xbb', '0xa5', '0x5d', '0x3b'] ==> DEG: 23.84 °C
b'd\xb1\xd9\xa5eG' ==> hex: ['b1', 'd9', 'a5'] ==> full_hex: ['0x64', '0xb1', '0xd9', '0xa5', '0x65', '0x47'] ==> DEG: 23.83 °C
b'd\xbb\x02\xa5s\xa2' ==> hex: ['bb', '02', 'a5', 'a2'] ==> full_hex: ['0x64', '0xbb', '0x02', '0xa5', '0x73', '0xa2'] ==> DEG: 23.86 °C
b'd\xac\xd6\xa5p\xf1' ==> hex: ['ac', 'd6', 'a5', 'f1'] ==> full_hex: ['0x64', '0xac', '0xd6', '0xa5', '0x70', '0xf1'] ==> DEG: 23.82 °C
b'd\xad\xe7\xa5\\\n' ==> hex: ['ad', 'e7', 'a5'] ==> full_hex: ['0x64', '0xad', '0xe7', '0xa5', '0x5c', '0x5c', '0x5c', '0x6e'] ==> DEG: 23.82 °C
b'\n' ==> hex: [] ==> full_hex: ['0x5c', '0x6e'] ==> DEG: 18.19 °C
b'd\n' ==> hex: [] ==> full_hex: ['0x64', '0x5c', '0x6e'] ==> DEG: 23.61 °C
b'd\xbc\x95\xa5O\x1a' ==> hex: ['bc', '95', 'a5', '1a'] ==> full_hex: ['0x64', '0xbc', '0x95', '0xa5', '0x4f', '0x1a'] ==> DEG: 23.86 °C
b'd\xb1\xd9\xa5LI' ==> hex: ['b1', 'd9', 'a5'] ==> full_hex: ['0x64', '0xb1', '0xd9', '0xa5', '0x4c', '0x49'] ==> DEG: 23.83 °C
"""
- 后知后觉的内建函数
# 原始字节数据
byte_data = b'd\xad\xe7\xa5\\\n'
# 转换为十六进制字符串
hex_data = byte_data.hex()
# 打印结果
print(hex_data)
"""
输出:
'64ade7a55c0a'
"""
# 如果需要将十六进制字符串格式化成每个字节两位并用空格分隔的形式,可以使用以下代码
# 原始字节数据
byte_data = b'd\xad\xe7\xa5\\\n'
# 转换为十六进制字符串并分隔每个字节
hex_data = byte_data.hex()
formatted_hex = ' '.join([hex_data[i:i+2] for i in range(0, len(hex_data), 2)])
# 打印结果
print(formatted_hex)
- 两种方案运行结果比对
# 我的方案
def byte_to_hex(_byte_data):
# 去头去尾,转为字符串
data1 = str(_byte_data).lstrip("b").strip("'")
# 匹配\x开头的2位字符
reg = r'\\x([0-9a-f]{2})'
val_ret = re.findall(reg, data1)
# 用拉丁字母替代\x开头的2位字符
unichr = 'δλξπσω'
unidict = {}
data2 = str(data1)
if val_ret:
for i, ret in enumerate(val_ret):
unidict[unichr[i]] = '0x{}'.format(ret)
data2 = data2.replace('\\x{}'.format(ret), unichr[i])
# 遍历加入拉丁字母代替的新字符串, 转换为hex
hex_chr_list = []
for da in data2:
if da in unidict.keys():
hex_chr_list.append(unidict[da])
else:
hex_chr_list.append(hex(ord(da)))
hex_str = ''.join(hex_chr_list).replace('0x', '')
return hex_str
# 新的方案
_byte_data.hex()
- 最终的结论
旧的方法基本可以满足需求; 使用 python 内建方法, 更简单更准确,且有ascii码表作为依据!
# 新、旧方案转换和计算的温度结果,在大部分情况下基本是一致的;
# 在现有的数据中有3笔数据转换存在差异。引起差异的地方是:对 \n 的转换, 比如 \\\n 这样的数据
# 经过查询 Ascii 码表推测,科学的做法是:\n 需要被看成一个整体转换为 ascii 码的 hex 形式,而不是旧的方案中分别对 '\' 和 'n' 进行转换
— the end —
1.本站内容仅供参考,不作为任何法律依据。用户在使用本站内容时,应自行判断其真实性、准确性和完整性,并承担相应风险。
2.本站部分内容来源于互联网,仅用于交流学习研究知识,若侵犯了您的合法权益,请及时邮件或站内私信与本站联系,我们将尽快予以处理。
3.本文采用知识共享 署名4.0国际许可协议 [BY-NC-SA] 进行授权
4.根据《计算机软件保护条例》第十七条规定“为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。”您需知晓本站所有内容资源均来源于网络,仅供用户交流学习与研究使用,版权归属原版权方所有,版权争议与本站无关,用户本人下载后不能用作商业或非法用途,需在24个小时之内从您的电脑中彻底删除上述内容,否则后果均由用户承担责任;如果您访问和下载此文件,表示您同意只将此文件用于参考、学习而非其他用途,否则一切后果请您自行承担,如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
5.本站是非经营性个人站点,所有软件信息均来自网络,所有资源仅供学习参考研究目的,并不贩卖软件,不存在任何商业目的及用途
暂无评论内容