这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【BEAGLEBONEBLKREVCAM3358BZCZ】——串口通讯,读取TO

共1条 1/1 1 跳转至

【BEAGLEBONEBLKREVCAM3358BZCZ】——串口通讯,读取TOF测距传感器

工程师
2026-03-18 17:00:43     打赏

这次尝试在BBB板子上驱动串口通讯。

首先先看看板子的操作系统环境。

root@BeagleBone:~/code# lsb_release -a
No LSB modules are available.
Distributor ID:	Debian
Description:	Debian GNU/Linux 12 (bookworm)
Release:	12
Codename:	bookworm

第一步:修改/boot/uEnv.txt文件,让系统在启动时加载串口驱动。

#Docs: http://elinux.org/Beagleboard:U-boot_partitioning_layout_2.0

uname_r=5.10.168-ti-r72
#uuid=
#dtb=

###U-Boot Overlays###
###Documentation: http://elinux.org/Beagleboard:BeagleBoneBlack_Debian#U-Boot_Overlays
###Master Enable
enable_uboot_overlays=1
###
###Overide capes with eeprom
#uboot_overlay_addr0=<file0>.dtbo
#uboot_overlay_addr1=<file1>.dtbo
#uboot_overlay_addr2=<file2>.dtbo
#uboot_overlay_addr3=<file3>.dtbo
###
###Additional custom capes
uboot_overlay_addr4=/lib/firmware/ADAFRUIT-SPI0-00A0.dtbo
#uboot_overlay_addr4=<file4>.dtbo
#uboot_overlay_addr5=<file5>.dtbo
#uboot_overlay_addr6=<file6>.dtbo
#uboot_overlay_addr7=<file7>.dtbo
###
###Custom Cape
#dtb_overlay=<file8>.dtbo
###
###Disable auto loading of virtual capes (emmc/video/wireless/adc)
#disable_uboot_overlay_emmc=1
#disable_uboot_overlay_video=1
#disable_uboot_overlay_audio=1
#disable_uboot_overlay_wireless=1
#disable_uboot_overlay_adc=1
###
###Cape Universal Enable
#enable_uboot_cape_universal=1
###
###Debug: disable uboot autoload of Cape
#disable_uboot_overlay_addr0=1
#disable_uboot_overlay_addr1=1
#disable_uboot_overlay_addr2=1
#disable_uboot_overlay_addr3=1
###
###U-Boot fdt tweaks... (60000 = 384KB)
#uboot_fdt_buffer=0x60000
###U-Boot Overlays###

console=ttyS0,115200n8
cmdline=coherent_pool=1M net.ifnames=0 lpj=1990656 rng_core.default_quality=100 quiet

#In the event of edid real failures, uncomment this next line:
#cmdline=coherent_pool=1M net.ifnames=0 lpj=1990656 rng_core.default_quality=100 quiet video=HDMI-A-1:1024x768@60e

#Use an overlayfs on top of a read-only root filesystem:
#cmdline=coherent_pool=1M net.ifnames=0 lpj=1990656 rng_core.default_quality=100 quiet overlayroot=tmpfs

##enable Generic eMMC Flasher:
#cmdline=init=/usr/sbin/init-beagle-flasher
enable_uboot_overlays=1
uboot_overlay_addr0=/lib/firmware/ADAFRUIT-UART1-00A0.dtbo
enable_uboot_cape_universal=1

留意最后三行,这部分就是让操作系统在启动时加载串口驱动程序,这样系统启动后就启动了串口1(对应管脚p9_24,p9_26)


手头有一个TOF激光测距传感器:SEN0647。TOF激光测距传感器是一款基于dTOF(直接飞行时间)技术的新一代激光测距传感器。在硬件设计与算法层面进行了全面升级,测距盲区小于5cm,最大量程可达25m(具体视环境反射率而定),测距精度在±3cm以内(典型值),尤其在动态环境下表现稳定,抗环境光干扰能力高达100K LUX,适用于室内外强光环境。支持UART、I2C、I/O等多种通信接口,满足不同开发架构需求。

eaa0b1708627155b5f12cd3907f994a6.jpg

将TOF激光测距传感器与BBB板子连接。激光测距传感器是5V供电,从板子的P9_2、P9_8取电。串口线与p9_24,p9_26连接。

首先写一个串口检查代码,用来尝试打开串口。

import serial

# 尝试打开 UART1
try:
    ser = serial.Serial('/dev/ttyS1', 115200, timeout=1)
    print(f"成功打开 {ser.name}")
    ser.write(b'Hello UART1\n')
    ser.close()
except Exception as e:
    print(f"错误: {e}")

如果运行后提示:ModuleNotFoundError: No module named 'serial',则需要安装串口的python包。

sudo apt install python3-serial

确定串口打开成功后,编辑python代码。

#!/usr/bin/env python3
import serial
import time
import struct
class TOFSense:
    """
    TOFSense 激光测距传感器驱动
    协议: 16字节帧, 921600bps, 8N1
    """
    def __init__(self, port='/dev/ttyS1', baudrate=921600, timeout=1):
        self.port = port
        self.baudrate = baudrate
        self.timeout = timeout
        self.serial = None
    def open(self):
        """打开串口"""
        try:
            self.serial = serial.Serial(
                port=self.port,
                baudrate=self.baudrate,
                bytesize=serial.EIGHTBITS,
                parity=serial.PARITY_NONE,
                stopbits=serial.STOPBITS_ONE,
                timeout=0.1
            )
            time.sleep(0.2)
            self.serial.flushInput()
            print(f"串口 {self.port} @ {self.baudrate}bps")
            return True
        except Exception as e:
            print(f"错误: {e}")
            return False

    def close(self):
        """关闭串口"""
        if self.serial and self.serial.is_open:
            self.serial.close()

    def read_frame(self):
        """读取一帧16字节数据"""
        if not self.serial:
            return None

        # 清空旧数据,避免积压
        if self.serial.in_waiting > 100:
            self.serial.flushInput()

        start_time = time.time()

        while time.time() - start_time < self.timeout:
            # 找帧头 0x57
            byte = self.serial.read(1)
            if not byte:
                continue

            if byte[0] == 0x57:
                # 检查第二个字节 0x00
                byte2 = self.serial.read(1)
                if not byte2 or byte2[0] != 0x00:
                    continue

                # 读取剩余14字节
                remaining = self.serial.read(14)
                if len(remaining) != 14:
                    continue

                # 组装完整帧
                frame = bytes([0x57, 0x00]) + remaining

                # 校验和检查
                calc_sum = sum(frame[:-1]) & 0xFF
                if calc_sum != frame[15]:
                    continue

                return frame

        return None

    def parse_frame(self, frame):
        """
        解析16字节帧

        Returns:
            dict: 包含id, system_time, distance(m), status, signal_strength, precision
        """
        if not frame or len(frame) != 16:
            return None

        result = {}

        # ID (字节3)
        result['id'] = frame[3]

        # System Time (字节4-7, 小端32位)
        result['system_time'] = struct.unpack('<I', frame[4:8])[0]

        # Distance (字节8-10, 特殊处理)
        # 公式: ((buf[10]<<24 | buf[9]<<16 | buf[8]<<8) / 256) / 1000.0
        dist_raw = (frame[10] << 24) | (frame[9] << 16) | (frame[8] << 8)
        # 有符号处理
        if dist_raw & 0x80000000:
            dist_raw -= 0x100000000
        result['distance'] = (dist_raw / 256.0) / 1000.0  # 转换为米

        # 距离状态 (字节11)
        result['status'] = frame[11]

        # 信号强度 (字节12-13, 小端16位)
        result['signal_strength'] = struct.unpack('<H', frame[12:14])[0]

        # 重复测距精度 (字节14)
        result['precision'] = frame[14]

        return result

    def read(self):
        """读取并解析一帧数据"""
        frame = self.read_frame()
        if frame:
            return self.parse_frame(frame)
        return None


def status_text(status_code):
    """距离状态说明"""
    status_map = {
        0: "正常",
        1: "超量程",
        2: "信号弱",
        3: "环境光强",
        4: "相位差",
        5: "硬件错误",
    }
    return status_map.get(status_code, f"未知({status_code})")


if __name__ == "__main__":
    tof = TOFSense('/dev/ttyS1', 921600)

    if not tof.open():
        exit(1)
    try:
        while True:
            data = tof.read()

            if data:
                # print(f"{data['id']:>3} | {data['system_time']:>10} | "
                #       f"{data['distance']:>8.3f} | {status_text(data['status']):>8} | "
                #       f"{data['signal_strength']:>6} | {data['precision']:>8}")
                print(str(round(data['distance']*10,2))+"cm")
            else:
                print("读取超时")

            time.sleep(0.1)

    except KeyboardInterrupt:
        print("\n停止")
    finally:
        tof.close()

4da433c994522e1f0f150294f931e07c.jpg

成功读取到数据。

image.png




共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]