Comunicación de puerto serie USB, Raspberry Pi utiliza el puerto GPIO para enviar y recibir código Python de matriz hexadecimal

La computadora industrial y la Raspberry Pi usan comunicación de puerto serie USB a TTL, y esta última usa el puerto GPIO para enviar y recibir códigos Python de arreglos hexadecimales.

alambrado

Se utiliza el módulo USB a TTL, la computadora industrial del sistema Linux está conectada a la toma USB, el módulo TTL emite RX, TX, VCC y GND, y el puerto GPIO14 de Raspberry Pi está conectado RXD0 al TX de el puerto serie TTL.

Módulo USB a TTL-CH340

Use la biblioteca RPi.GPIO de Python en Raspberry Pi y configure GPIO14 (RXD0) como pin de recepción.
Escriba el código para recibir datos en la Raspberry Pi, verifique el estado de GPIO14 (RXD0) a través de GPIO.input(14), si es alto, significa que hay recepción de datos y luego use ser.read(ser.in_waiting ) para leer los datos de recepción del puerto serie en el búfer.

carta de acuerdo

La comunicación del puerto serie envía una cadena de datos, incluidos 2 encabezados y una matriz de caracteres hexadecimales con una longitud total de 6, expresados ​​como uint8 data[6]. Los primeros 2 bytes de cada dato son 0xAA, el comienzo de 0xAA; el tercer byte es el tipo de instrucción; los bits 4 y 5 son instrucciones, que se codifican como uint8 de 2 bits; los primeros 5 bits se codifican en CRC8 Verifique para obtener el sexto dígito. Un formato de datos típico que se ajusta a la especificación es el siguiente:
0xAA , 0xAA , 0x09 , 0x07 , 0x01 , 0x32
0x07 , 0x01 son instrucciones codificadas.

enviar

¿Existe una versión Python del programa que pueda enviar instrucciones como referencia? Cada subfunción debe escribirse como una función separada, incluida la apertura del puerto serie, el envío de instrucciones, la codificación de instrucciones, la verificación de CRC, etc.

El siguiente es un programa Python de muestra para ChatGPT
, que se usa para enviar datos en serie, realizar la codificación de comandos y la verificación de CRC. El programa asume el uso de la biblioteca pyserial para la comunicación en serie.

# -*- coding: UTF-8 -*-
#!/usr/bin/python3 python3
import serial
import struct
import time


# 配置串口参数
port = '/dev/ttyUSB0'  # 串口设备路径
baudrate = 9600  # 波特率

# 打开串口
ser = serial.Serial(port, baudrate)

# 定义指令类型的常量
INSTRUCTION_TYPE = 0x09

# CRC8校验函数
def crc8(data):
    crc = 0x00
    polynomial = 0x8C  # CRC-8多项式

    for byte in data:
        crc ^= byte
        for _ in range(8):
            if crc & 0x80:
                crc = (crc << 1) ^ polynomial
            else:
                crc <<= 1

    return crc & 0xFF

# 将时间秒数编码为两位16进制数字
def encode_seconds(seconds):
    seconds_hex = hex(seconds)[2:].zfill(2)  # 将秒数转换为两位的十六进制字符串
    return int(seconds_hex, 16)  # 将十六进制字符串转换为整数


# 编码指令
def encode_instruction(data):
    encoded_data = []
    for value in data:
        encoded_data.append(value & 0xFF)
    return encoded_data

# 发送指令
def send_instruction(instruction):
    # 构建指令
    data = bytearray()
    data.extend([0xAA, 0xAA])  # 前导字节
    data.append(INSTRUCTION_TYPE)  # 指令类型
    data.extend(encode_instruction(instruction))  # 编码后的指令数据
    
    # 计算校验码
    crc = crc8(data[:5])  # 计算校验码时不包括最后一个字节(校验码本身)
    data.append(crc)  # 添加校验码的低字节

    return data


try:
    # 主循环
    while True:
        # 测试发送指令

        # instruction = [0x07, 0x08]  # 指令数据
        # 获取当前时间的秒数
        seconds = int(time.time())
        # print(seconds)
        # 发送时间秒数编码
        instruction = encode_seconds(seconds).to_bytes(4, 'big')# 发送一个字节的数据,高位在前


        data = send_instruction(instruction[2:4])
        formatted = ' '.join(f'{
      
      byte:02X}' for byte in data)
        print(formatted)
        # 发送指令
        ser.write(data)

        # # 接收指令
        # response = receive_command()
        # if response:
        #     print('Received:', response)

        # 休眠一段时间,控制发送频率
        time.sleep(0.2)  # 休眠0.2秒

except KeyboardInterrupt:
    # Ctrl+C被按下,执行异常处理
    
    ser.close()
    print("程序终止,关闭串口")

except Exception as e:
    # 其他异常处理
    
    print("发生异常:", str(e))
    ser.close()

En el ejemplo anterior, definimos una encode_instruction()función para codificar los datos de instrucción, limitamos cada elemento al rango de 0-255 y devolvemos los datos codificados. Luego construimos la instrucción, agregamos los bytes iniciales, el tipo de instrucción, los datos de instrucción codificados y calculamos la suma de verificación. Finalmente, usamos ser.write()la función para enviar los datos de instrucción al puerto serie.

Tenga en cuenta que en las aplicaciones prácticas, es posible que también deba agregar funciones como el manejo de errores, la configuración del tiempo de espera, el procesamiento de datos, etc. para garantizar una comunicación en serie estable y confiable. El ejemplo anterior solo proporciona un marco básico, y es posible que la implementación específica deba ajustarse y ampliarse de acuerdo con sus necesidades específicas.

tomar el control

La comunicación del puerto serie recibe una cadena de datos, incluidos 2 encabezados y una matriz de caracteres hexadecimales con una longitud total de 6, expresados ​​como uint8 data[6]. Los primeros 2 bytes de cada pieza de datos son 0xAA, el comienzo de 0xAA; el tercer byte es el tipo de instrucción; los bits 4 y 5 son instrucciones codificadas, que deben analizarse en números int16; CRC16 se usa para comparar el Suma de verificación frontal de 5 dígitos, obtenga el algoritmo MODBUS del sexto dígito.

¿Hay alguna versión de Python del programa a la que se pueda hacer referencia? Cada subfunción debe escribirse como una función separada, incluido
ChatGPT , como abrir el puerto serie, recibir instrucciones, análisis de instrucciones, verificación de CRC, etc.

El siguiente es un programa Python de muestra para recibir datos del puerto serie, realizar la verificación de CRC y analizar las instrucciones. El programa asume el uso de la biblioteca pyserial para la comunicación en serie.

# -*- coding: UTF-8 -*-
#!/usr/bin/python3 python3
import serial
import struct
import RPi.GPIO as GPIO


# 配置GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(14, GPIO.IN)  # GPIO14作为接收引脚

# 配置串口参数
port = '/dev/serial0'  # 树莓派上UART接口所对应的串口设备路径
baudrate = 9600  # 波特率
# 打开串口
ser = serial.Serial(port, baudrate)

# 配置GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(14, GPIO.IN)  # GPIO14作为接收引脚

# 定义指令类型的常量
INSTRUCTION_TYPE = 0x09

# CRC8校验
def crc8(data):
    crc = 0x00
    polynomial = 0x8C  # CRC-8多项式
    
    for byte in data:
        crc ^= byte
        for _ in range(8):
            if crc & 0x80:
                crc = (crc << 1) ^ polynomial
            else:
                crc <<= 1
    
    return crc & 0xFF

# 解析指令
def parse_instruction(data):
    if len(data) != 6:
        print("Invalid instruction length")
        return
    
    # 校验头部
    if data[0] != 0xAA or data[1] != 0xAA:
        print("Invalid header")
        return

    # 校验指令类型
    if data[2] != INSTRUCTION_TYPE:
        print("Invalid instruction type")
        return

    # 校验CRC
    crc = crc8(data[:5])  # 计算校验码时不包括最后一个字节(校验码本身)
    if crc != data[5]:
        print("CRC check failed")
        return
    
    # 获取指令数据
    instruction = data[3:5]
    
    # 执行相应的指令逻辑
    process_instruction(instruction)

# 处理指令逻辑
def process_instruction(instruction):
    # 按照具体需求进行指令处理
    cmd16 = struct.unpack('<h', bytearray(instruction))[0]  # 解析为int16数字
    print("Received Instruction:", cmd16)

try:
    # 接收数据
    while True:
        if GPIO.input(14):  # 检查GPIO14状态,判断是否有数据接收
            # data = ser.read(ser.in_waiting)  # 一直读取数据
            data = ser.read(6)  # 读取固定长度的数据
            # 接收数据
            if len(data) == 6 and data[:2] == b'\xAA\xAA':
                parse_instruction(data)

except KeyboardInterrupt:
    # Ctrl+C被按下,执行异常处理
    
    ser.close()
    print("程序终止,关闭串口")

except Exception as e:
    # 其他异常处理
    
    print("发生异常:", str(e))
    ser.close()

En el ejemplo anterior, definimos una parse_instruction()función para analizar los datos de comando recibidos. Primero, verificamos si la longitud de la instrucción es de 6 bytes y hacemos una verificación de CRC. Si la verificación falla o el tipo de comando no coincide, aparecerá el mensaje de error correspondiente. Si se pasa la verificación, analizamos los datos de la instrucción y llamamos process_instruction()a la función para ejecutar la lógica de instrucción correspondiente.

Tenga en cuenta que los ejemplos anteriores solo proporcionan un marco básico, es posible que deba ajustarlos y ampliarlos según sus necesidades específicas. En aplicaciones prácticas, es posible que también deba agregar funciones como manejo de errores, configuración de tiempo de espera y procesamiento de datos para garantizar una comunicación en serie estable y confiable.

¿Cómo controla la comunicación serie la frecuencia de envío y análisis de datos?

ChatGPT

En la comunicación en serie, puede utilizar diferentes métodos para controlar la frecuencia de transmisión de datos. Aquí hay algunos métodos comunes:

  • Envío retrasado: agrega un retraso fijo entre el envío de cada paquete. Puede usar time.sleep()funciones para agregar un retraso entre el envío de paquetes para controlar la frecuencia con la que los envía. Por ejemplo, time.sleep(0.1)demorará 100 milisegundos después de enviar un paquete. No se recomienda este método.

  • Envío programado: use temporizadores para enviar datos periódicamente. Puede usar threading.Timerlas clases de Python para crear un temporizador y enviar datos en la función de devolución de llamada del temporizador.

En la comunicación en serie, el uso threading.Timerde la frecuencia de recepción y análisis de datos de control se puede lograr a través de los siguientes pasos:

  • Cree un objeto de temporizador y especifique el intervalo del temporizador.
  • Ejecute la lógica de recepción y análisis de datos en la función de devolución de llamada del temporizador.
  • Inicie el temporizador para que comience a ejecutar la función de devolución de llamada regularmente.

El siguiente es un ejemplo que demuestra cómo usar threading.Timer para controlar la frecuencia de recepción y análisis de datos del puerto serie:


import serial
import threading

# 配置串口参数
port = '/dev/ttyUSB0'  # 串口设备路径
baudrate = 9600  # 波特率

# 打开串口
ser = serial.Serial(port, baudrate)

# 定义数据接收和解析的函数
def receive_and_parse_data():
    # 接收数据
    data = ser.readline().strip()

    # 解析数据
    # TODO: 在这里添加你的数据解析逻辑
    print("Received data:", data)

    # 重新启动定时器,控制数据接收和解析的频率
    timer = threading.Timer(1.0, receive_and_parse_data)
    timer.start()

# 启动定时器,控制数据接收和解析的频率
timer = threading.Timer(1.0, receive_and_parse_data)
timer.start()

# 阻塞主线程,保持程序运行
while True:
    pass

# 关闭串口
ser.close()

En el ejemplo anterior, receive_and_parse_data()el temporizador llama a la función para recibir y analizar los datos del puerto serie con regularidad. El intervalo del temporizador es de 1,0 segundos, puede ajustarlo según sus necesidades.

Independientemente de utilizar el envío diferido o el envío temporizado, la frecuencia de envío de datos se puede ajustar de acuerdo con las necesidades reales. Tenga en cuenta que la frecuencia de envío real puede estar limitada por factores como la velocidad de transmisión del puerto serie, el tamaño del paquete y la potencia de procesamiento del dispositivo de destino. Por lo tanto, debe ajustarse y probarse de acuerdo con los requisitos y los escenarios de aplicación específicos.

Supongo que te gusta

Origin blog.csdn.net/NICAI001/article/details/131617817
Recomendado
Clasificación