簡體   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