繁体   English   中英

Python-Arduino 串行半双工:Arduino 读取之前的串行输入而不是当前的

[英]Python-Arduino Serial Half-Duplex: Arduino reads previous serial input instead of current

我正在使用 Python 3.7.5 和最新版本的串行库。 我正在尝试通过 python 和 arduino 制作一个 RFID 认证设备。 用户必须在连接到 arduino 的 RFID 中扫描他们的 ID,并且 arduino 必须将 UID 发送到 python 软件。 在我的笔记本电脑中,正在运行一个监听串行的线程。 它会检查 UID,如果允许则发送“O”,如果不允许则发送“X”。 在 arduino 中,程序然后等待是否有通过串行发送的数据,然后检查输入是否为“O”。 如果 RX 为“O”,则 LED 必须呈绿色亮起,否则呈红色。

我的问题是,当我第一次扫描正确的 uid 时,它变成绿色,没问题。 如果我扫描另一个正确的 uid,它会再次变为绿色,没问题。 如果我扫描一个 INCORRECT uid,它会变成绿色,但在我的 Python 代码中它应该是红色的。 然后,如果我扫描正确的 uid,它会变成红色,而应该是绿色。 我尝试向 arduino 和 python 添加延迟以等待先前的输入清除,并且还尝试在传输后刷新但没有运气。

tl; dr arduino 正在输出结果 ONE uid scan 很晚,我不知道还能做什么。

Python:

# Reads data from the serial monitor without interrupting the main thread

from serial import Serial
import time
from threading import Thread

class SerialListener:
    def __init__(self, baudrate=9600, timeout=1):
        try:
            self.ser = Serial('/dev/ttyACM0', baudrate, timeout=timeout)
        except:
            self.ser = Serial('/dev/ttyACM1', baudrate, timeout=timeout)

        self.stopped = False
        self.paused = False
        self.stream = ''
        time.sleep(1) # Wait for serial buffer to reset

    def start(self):
        Thread(target=self.update, args=()).start()
        return self

    def update(self):
        if not self.paused:
            while True:
                if self.stopped:
                    self.ser.close()
                    print("Serial Thread Stopped")
                    print("Serial Port Closed")
                    break
                try:
                    self.stream = self.ser.readline().decode('utf-8')
                except:
                    self.stream = self.ser.readline().decode('ascii')
                self.stream = self.stream.rstrip()

    def stop(self):
        self.stopped = True

    def pause(self):
        self.paused = True

    def flush(self):
        self.ser.flush()

    def readDistance(self):
        try:
            return float(self.stream)
        except:
            return -1   # Returns -1 if there is an error in reading

    def readRFID(self):
        return self.stream

    def write(self, msg):
        self.ser.write(msg.encode())

if __name__ == "__main__": # FOR DEBUGGING ONLY
    uno = SerialListener().start()
    uno.flush()
    print("Serial Started")
    uid = ''
    while True:
        uid = uno.readRFID()
        if uid is not '':
            uno.flush()
            time.sleep(0.1)
            if uid == "5BEE9F0D":
                uno.write('O')
                print("SHOULD BE GREEN")
            else:
                uno.write('X')
                print("SHOULD BE RED")
            print(uid)

    uno.stop()

阿杜诺:

#include <MFRC522.h>
#define GREEN_LED 6
#define RED_LED 7
#define BUZZER 8

MFRC522 rfid(10, 9);

unsigned long timer = 0;
bool readStatus = false;

void setup() {
  pinMode(RED_LED, OUTPUT);
  pinMode(GREEN_LED, OUTPUT);
  Serial.begin(9600);
  SPI.begin();
  rfid.PCD_Init();
  for(int i = 0; i < 10; i++)
    Serial.write('\n');
  delay(5);
  digitalWrite(RED_LED, HIGH);
}

void loop() {
  while(!readStatus){
    if(rfid.PICC_IsNewCardPresent()){
      if(rfid.PICC_ReadCardSerial()){
        byte uid[rfid.uid.size];
        if((millis() - timer) > 1000){
          for(int i = 0; i < rfid.uid.size; i++)
            uid[i] = rfid.uid.uidByte[i];

          for(int i = 0; i < sizeof(uid); i++){
            if(uid[i] < 0x10)
              Serial.print('0');

            Serial.print(uid[i], HEX);
          }
          Serial.println();
          readStatus = true;
          timer = millis();
        }
        Serial.flush();
      }
    }
  }

  if(readStatus){
    while(!Serial.available());

    char rx = 'X';

    while(Serial.available()){
      rx = Serial.read();
    }

    if(rx == 'O'){
    digitalWrite(GREEN_LED, HIGH);
    digitalWrite(RED_LED, LOW);
    tone(BUZZER, 2500);
    delay(100);
    noTone(BUZZER);
    readStatus = false;
    }
    else{
      digitalWrite(RED_LED, LOW);
      digitalWrite(GREEN_LED, LOW);
      tone(BUZZER, 1000);
      delay(50);
      noTone(BUZZER);
      delay(30);
      tone(BUZZER, 1000);
      delay(50);
      noTone(BUZZER);
      digitalWrite(RED_LED, HIGH);
      readStatus = false;
    }
  }
}

输出:

Serial Started

SHOULD BE RED
05520320 // it is red

SHOULD BE RED
05520320 // it is red

SHOULD BE GREEN
5BEE9F0D // it is red

SHOULD BE GREEN
5BEE9F0D // it is green

SHOULD BE RED
05520320 // it is green

好的,我通过修改 pyserial 中的超时并在读取之间添加 1 秒延迟解决了该问题。

问题是由于我设置条件的方式,pyserial 不止一次写入串行。

while True:
    uid = uno.readRFID()
    if uid is not '':
        uno.flush()
        time.sleep(0.1)
        if uid == "5BEE9F0D":
            uno.write('O')
            print("SHOULD BE GREEN")
        else:
            uno.write('X')
            print("SHOULD BE RED")
        print(uid)

由于我设置的超时时间为 1,PySerial 将继续读取 UID,直到超时。 这将导致 uid 不等于 '' 一秒钟,并将不必要地多次向串行发送数据。

在 Arduino 中,它只从缓冲区读取一个字节的字符,读取后,从缓冲区中删除读取的内容。 但是,python 并没有只向串行发送 1 个字符,而是不止一次。 这就是为什么 Arduino 在从 PREVIOUS 缓冲区读取字符而不是 python 发送到串行的新字符时输出不正确的原因

为了解决这个问题,我将超时设置得更小,以便在超时达到后串行输入将被清除。 不要将超时值设置得太低,否则可能无法读取数据。

def __init__(self, baudrate=9600, timeout=0.5):

其次,我在主线程上从串行读取之间添加了延迟

uid = ''
while True:
    while uid is '':
        uid = uno.readRFID()
    time.sleep(0.1)

    if uid == "5BEE9F0D":
        uno.write('O')
    else:
        uno.write('X')
    print(uid)
    time.sleep(1)
    uid = ''

Arduino 中的代码有效,所以我没有改变它,唯一的问题是 Python 代码本身。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM