系列文章目录
前言
本文主要提供基于Thonny编译器下的micropython+ESP32串口接收数据的类型转换,并提供一下直来直往超声波模块的代码,代码并不复杂,但是数据类型转换过程很折磨人,ESP32串口传输是bytes类型,经常需要转成str或者int,清明在实验室呆了一天,终于给整出来了,满心欢喜,想着总结分享一下,让初学者能够不被这种问题耽误时间。
一、数据传输类型为什么用bytes
首先来看看bytes是怎么存储数据的:bytes是以二进制形式来存储数据(如下图),"\x"符号可以视为“0x”(我个人是这么理解的),也就是十六进制的开头。至于这些数据到底表示什么内容(字符串、数字、图片、音频等),就取决于解析这段bytes数据的方式了。打个比方;bytes类型就是书上的文字,用来记录计算机内存中的原始数据,解析这段文字具有不同的方式,也就类似于解析bytes数据了。
计算机传输数据时,是以字节为单位传输的,而bytes类型数据和一个字节数据等大,因此采用bytes类型不会造成空间浪费
b1 = b'\xe8\xaf\xad\xb2\x81\xe4\xba\x86'
b2 = b'\x00\x01\x02\x03'
二、bytes转为str、int类型
这里随意在浏览器一搜索,有很多
可以参考大佬方案,比较齐全:Python中int、str、bytes相互转化,还有2进制、16进制表示,你想要的都在这里了_python 'int' and 'bytes-优快云博客
这里简单整理我自己觉得很好用并且没有报错的:
1.bytes转str
比较好用的是:xxx.decode('utf-8')
此方法成功率高,在thonny中大多数情况下都能使用,将bytes转为str类型,个人理解:其中 decode()就是解码,传输数据时候需要编码encode()成bytes类型,传输完成后解析数据,就可以用decode()解码
#串口接收部分
if uart.any():
text = uart.read(20) #最多读取20个字符
print("text--type")
print(type(text)) #打印输出的是bytes类型
str_test=text.decode('utf-8')
print(("str_test--type")
print(str_test) #打印输出的是str类型
2.bytes转int
我试了试:比较喜欢用int.from_bytes()函数
需要注意:大佬的int.from_bytes(byte_val, byteorder='big', signed=False) 在thonny中报错,大概意思就是参数问题,直接使用int.from_bytes(byte_val, 'big')就够用了
bytes是要转换的十六进制;
byteorder:选'big'和'little',以上例为例,其中big代表正常顺序,即f1ff。little反之,代表反序fff1;
signed:选True、Flase表示是否要区分二进制的正负数含义。即是否要对原二进制数进行原码反码 补码操作。
可以参考:python之将byte转换为int类型函数 int.from_bytes 详解与原码反码补码的简单介绍-优快云博客
byte_val = b'\x00\x10'
int_val = int.from_bytes(byte_val, "little")
print(int_val)
#输出结果:4096
三、直来直往超声波
1.模块介绍:
我买的是某宝的大鱼电子的直来直往超声波模块,好处是模块自带了MCU,使用简单,发送接收模块上电就能使用
模块通信波特率:115200;发送频率:50Hz;工作电压:5V;测量距离单位:mm
需要注意的是:发送模块没有发送时,接收模块会默认收到 bytes_distance = b'\xa5\x00\xC8',转换成十进制是6800
thonny下收到的bytes数据计算成十进制的方法:
int_distance = int.from_bytes(bytes_distance [1:3],'big') 这里在代码部分讲解
当接收超声波已经接收到发送超声波的数据后,接收超声波模块上的 LED 灯会快速闪烁,会通过串口以 50Hz 的频率发送出距离数据。我用的是定时器接收,定时器时间设置为20ms,正好和接收模块发送给ESP32的频率一样,数据传输不会产生错误,尽量接收频率大于发送频率(我用两块ESP32试了一下串口传输,接收端将接受的数据存入列表,如果接收频率低于发送频率,就容易导致数据上一次数据和下一次数据拼接到一起产生数据错乱)
每次收到一个数据帧,这个数据的格式为 A5 xx xx ,A5是帧头,是用来鉴别数据的
2.代码
现象:左右超声波接收,而后在终端打印距离
代码如下:
""" 成功了,很开心"""
import time
from machine import Pin, Timer
from machine import UART
from machine import PWM
distance_left = 0
distance_right = 0
# 定义 UART 控制对象
uart1 = UART(1, baudrate=115200, rx=22, tx=23)
uart2 = UART(2, baudrate=115200, rx=18, tx=19)
"""计算左右距离"""
def get_distance():
global distance_right
global distance_left
if uart1.any(): #如果接收到就执行,未接受到就跳过
buf1 = uart1.read(20) #最多读取20个字符
distance_left = int.from_bytes(buf1[1:3],"big")
if uart2.any():
buf2 = uart2.read(20) #最多读取20个字符
distance_right = int.from_bytes(buf2[1:3],"big")
print("左超声波距离:{} 右超声波距离:{}".format(distance_left,distance_right))
# 定义定时器对象
timer = Timer(0)
def timer_irq(timer_obj):
get_distance()
# 初始化定时器对象 周期20ms 超声波频率50Hz 20ms
timer.init(mode=Timer.PERIODIC, period=20, callback=timer_irq)
led2 = PWM(Pin(2, Pin.OUT), freq=1000)
#主循环随便放了个呼吸灯
while True:
for i in range(0, 1024):
led2.duty(i)
time.sleep_ms(1)
关于bytes类型切片操作 bytes_distance [1:3]-->截取索引1-3(不包含3)
我犯的错是这样的:误认为每一个字符,都有一个索引
a = b'\xa5\x00\xC8'
print(a.split('\x'))
#输出结果: b''
#没错,就是空字节
这个其实类似于列表,列表中不同数据是用逗号“,”分开的,而bytes中使用"\x",也就是说,b'\xa5\x00\xC8'中,其实a5是一个整体,00是一个整体,c8是一个整体。可以复制以下代码验证一下,理解理解:
c=b'\xa5\x00\xC8'
print(c[1:3])
str_buf1 = int.from_bytes(c[1:3],'big')
print(str_buf1)
输出:
b'\x00\xC8' #c[1:3]
200 #str_buf1
总结
本人大二本科在读,电子信息小白,因此文章一些内容可能不严谨,或者有错误,欢迎大家评论区批评指正。
如果侵权请联系删除。