Communication par port série USB, Raspberry Pi utilise le port GPIO pour envoyer et recevoir le code Python du tableau hexadécimal

L'ordinateur industriel et le Raspberry Pi utilisent une communication de port série USB vers TTL, et ce dernier utilise le port GPIO pour envoyer et recevoir des codes Python de tableaux hexadécimaux

câblage

Le module USB vers TTL est utilisé, l'ordinateur industriel du système Linux est connecté à la prise USB, les sorties du module TTL RX, TX, VCC et GND, et le port GPIO14 du Raspberry Pi est RXD0 connecté au TX de le port série TTL.

Module USB vers TTL-CH340

Utilisez la bibliothèque RPi.GPIO de Python sur le Raspberry Pi et configurez GPIO14 (RXD0) comme broche de réception.
Écrivez le code pour recevoir des données sur le Raspberry Pi, vérifiez l'état de GPIO14 (RXD0) via GPIO.input(14), s'il est haut, cela signifie qu'il y a une réception de données, puis utilisez ser.read(ser.in_waiting ) pour lire les données de réception du port série dans le tampon.

lettre d'accord

La communication par port série envoie une chaîne de données, comprenant 2 en-têtes et un tableau de caractères hexadécimaux d'une longueur totale de 6, exprimés en données uint8[6]. Les 2 premiers octets de chaque élément de données sont 0xAA, le début de 0xAA ; le troisième octet est le type d'instruction ; les 4e et 5e bits sont des instructions, qui sont codées en uint8 à 2 bits ; les 5 premiers bits sont codés en CRC8 Cochez pour obtenir le 6e chiffre. Un format de données typique conforme à la spécification est le suivant :
0xAA , 0xAA , 0x09 , 0x07 , 0x01 , 0x32
0x07 , 0x01 sont des instructions codées.

envoyer

Existe-t-il une version python du programme qui peut envoyer des instructions pour référence. Chaque sous-fonction doit être écrite comme une fonction distincte, y compris l'ouverture du port série, l'envoi d'instructions, l'encodage des instructions, la vérification CRC, etc.

Voici un exemple de programme Python pour ChatGPT
, qui est utilisé pour envoyer des données série, effectuer un codage de commande et une vérification CRC. Le programme suppose l'utilisation de la bibliothèque pyserial pour la communication série.

# -*- 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()

Dans l'exemple ci-dessus, nous définissons une encode_instruction()fonction pour encoder les données d'instruction, limiter chaque élément à la plage de 0 à 255 et renvoyer les données encodées. Ensuite, nous construisons l'instruction, ajoutons les octets de tête, le type d'instruction, les données d'instruction codées et calculons la somme de contrôle. Enfin, nous utilisons ser.write()la fonction pour envoyer les données d'instruction au port série.

Veuillez noter que dans les applications pratiques, vous devrez peut-être également ajouter des fonctions telles que la gestion des erreurs, le réglage du délai d'attente, le traitement des données, etc. pour assurer une communication série stable et fiable. L'exemple ci-dessus ne fournit qu'un cadre de base, et la mise en œuvre spécifique peut devoir être ajustée et étendue en fonction de vos besoins spécifiques.

reprendre

La communication par port série reçoit une chaîne de données, comprenant 2 en-têtes et un tableau de caractères hexadécimaux d'une longueur totale de 6, exprimés en données uint8[6]. Les 2 premiers octets de chaque élément de données sont 0xAA, le début de 0xAA ; le troisième octet est le type d'instruction ; les 4e et 5e bits sont des instructions codées, qui doivent être analysées en nombres int16 ; CRC16 est utilisé pour comparer les somme de contrôle à 5 chiffres avant, obtenez le 6ème chiffre, algorithme MODBUS.

Existe-t-il une version python du programme à laquelle on peut se référer. Chaque sous-fonction doit être écrite comme une fonction distincte, y compris
ChatGPT comme l'ouverture du port série, la réception d'instructions, l'analyse des instructions, la vérification CRC, etc.

Ce qui suit est un exemple de programme Python pour recevoir des données de port série, effectuer une vérification CRC et des instructions d'analyse. Le programme suppose l'utilisation de la bibliothèque pyserial pour la communication série.

# -*- 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()

Dans l'exemple ci-dessus, nous avons défini une parse_instruction()fonction pour analyser les données de commande reçues. Tout d'abord, nous vérifions si la longueur de l'instruction est de 6 octets et effectuons une vérification CRC. Si la vérification échoue ou si le type de commande ne correspond pas, le message d'erreur correspondant sera émis. Si la vérification est réussie, nous analysons les données d'instruction et appelons process_instruction()la fonction pour exécuter la logique d'instruction correspondante.

Veuillez noter que les exemples ci-dessus ne fournissent qu'un cadre de base, vous devrez peut-être ajuster et développer en fonction de vos besoins spécifiques. Dans les applications pratiques, vous devrez peut-être également ajouter des fonctions telles que la gestion des erreurs, le réglage du délai d'attente et le traitement des données pour assurer une communication série stable et fiable.

Comment la communication série contrôle-t-elle la fréquence d'envoi et d'analyse des données ?

ChatGPT

Dans la communication série, vous pouvez utiliser différentes méthodes pour contrôler la fréquence de transmission des données. Voici quelques méthodes courantes :

  • Envoi différé : ajoute un délai fixe entre l'envoi de chaque paquet. Vous pouvez utiliser time.sleep()des fonctions pour ajouter un délai entre l'envoi de paquets afin de contrôler la fréquence à laquelle vous les envoyez. Par exemple, time.sleep(0.1)retardera de 100 millisecondes après l'envoi d'un paquet. Cette méthode n'est pas recommandée.

  • Envoi programmé : utilisez des minuteries pour envoyer des données périodiquement. Vous pouvez utiliser threading.Timerdes classes Python pour créer un minuteur et envoyer des données dans la fonction de rappel du minuteur.

Dans la communication série, l'utilisation threading.Timerde la fréquence de réception et d'analyse des données de contrôle peut être réalisée par les étapes suivantes :

  • Créez un objet minuterie et spécifiez l'intervalle de minuterie.
  • Exécutez la logique de réception et d'analyse des données dans la fonction de rappel du minuteur.
  • Démarrez le minuteur pour qu'il commence à exécuter la fonction de rappel régulièrement.

Voici un exemple qui montre comment utiliser threading.Timer pour contrôler la fréquence de réception et d'analyse des données du port série :


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()

Dans l'exemple ci-dessus, receive_and_parse_data()la fonction est appelée par le temporisateur pour recevoir et analyser régulièrement les données du port série. L'intervalle de la minuterie est de 1,0 seconde, vous pouvez l'ajuster en fonction de vos besoins.

Indépendamment de l'utilisation de l'envoi différé ou de l'envoi temporel, la fréquence d'envoi des données peut être ajustée en fonction des besoins réels. Veuillez noter que la fréquence d'envoi réelle peut être limitée par des facteurs tels que le débit de transmission du port série, la taille des paquets et la puissance de traitement de l'appareil cible. Par conséquent, il doit être ajusté et testé en fonction de scénarios et d'exigences d'application spécifiques.

Je suppose que tu aimes

Origine blog.csdn.net/NICAI001/article/details/131617817
conseillé
Classement