Python中的Raspberry Pi UART中断

时间:2018-03-21 14:55:26

标签: python arduino raspberry-pi

我正在尝试通过XBees收集来自3个Arduino节点(连接到某些传感器)的数据。 3个Arduino节点分别连接到XBee Series 1无线电(终端设备),而协调器连接到我的PC(但稍后将连接到Raspberry Pi 2 B型)。

我在想,是否有办法在Raspberry Pi上用Python实现UART中断?这是因为,根据我的下面的代码,我采用轮询方法来读取从我的3个Arduino传感器节点传入的数据。每秒从3个Arduino传感器节点传入的数据,如下面的代码所示。

然而,我的民意调查方法导致了一些问题,因为我只做了#34; arduino.readline()"在我的代码的最开始,之后,我将继续在Python代码中做其他事情。

因此,我想知道是否有任何方法可以用Python实现UART中断,这样每当有传入数据时,我都会执行arduino.readline()并继续处理数据。

我的代码如下:(所有3个节点的Arduino代码大致相同。)

Python代码:

import threading
import logging
import time
import serial
import csv
# Arduino; Arduino is now replaced by XBee modules
arduino = serial.Serial('COM18', 9600, timeout=1)  # Open serial port. By right, should check if it is open
def checker(field):
    if 'b' in field:
        field = field.replace('b', '')
    if 't' in field:
        field = field.replace('t', '')
    return field
def make_backup(finalmatrix, field_send, flag): # Back up the 2 most-recent data.
    matrix1 = []  # declares a list
    matrix1.append(flag) # appends the counter 'flag'
    matrix1.extend(field_send) # attaches the list to the end of current list; doesn't work with int
    # finalmatrix is a list of list; if len(finalmatrix) == 2 means: finalmatrix == [[1,2], [3,4]]
    if (len(finalmatrix) == 2):
        finalmatrix = finalmatrix[1:] # Create a new list, take the 2nd mini-list in the list and put it in the new list
        finalmatrix.append(matrix1) # appends the new matrix1
    else:
        finalmatrix.append(matrix1)
    return finalmatrix
def acquire_data():
    flag = 1
    finalmatrix = []
    count = 0
    while True:
        # data_in
        start_time = time.time()
        try:
            data_in = arduino.readline()  # read serial data from Arduino
            # logging.warning(data_in) # debugger
        except:
            pass
        global data_stripped
        data_stripped = data_in.strip()  # Removes spaces and \n
        for data_stripped in arduino:
            if data_stripped.startswith('b') and data_stripped.count(
                    ',') == 3:  # first char identifies where data is coming from; count commas to double-check incoming string
                field = data_stripped.split(',')  # split data to be put into 'boxes'
                bed_sen = field[0] + ',' + field[1] + ',' + field[2]  # We have 3 data sensor fields
                bed_sen_fill = True  # A flag to show that this if-statement has been completed
            if data_stripped.startswith('t') and data_stripped.count(',') == 3:
                field = data_stripped.split(',')
                table_sen = field[0] + ',' + field[1] + ',' + field[2]
                table_sen_fill = True
            if data_stripped.startswith('d') and data_stripped.count(',') == 3:
                field = data_stripped.split(',')
                door_sen = field[0] + ',' + field[1] + ',' + field[2]
                door_sen_fill = True
            try:
                if bed_sen_fill == True and table_sen_fill == True and door_sen_fill == True:
                    data_combi = bed_sen + ',' + table_sen + ',' + door_sen
                    break
            except:
                pass
        if data_combi:
            datasplit = data_combi.split(",")
            field1 = datasplit[0]
            field2 = datasplit[1]
            field3 = datasplit[2]
            field4 = datasplit[3]
            field5 = datasplit[4]
            field6 = datasplit[5]
           field7 = datasplit[6]  # To be deprecated in future; IR sensor no longer in use.
            field8 = datasplit[7]
            field9 = datasplit[8]
        # Removes 'b', 't' chars in strings
        field1 = checker(field1)
        field2 = checker(field2)
        field3 = checker(field3)
        field4 = checker(field4)
        field5 = checker(field5)
        field6 = checker(field6)
        field8 = checker(field8)
        field9 = checker(field9)
        ##### Data Validity Check #####
        field_send = []  # rearrange into list
        field_send.append(field1)
        field_send.append(field2)
        field_send.append(field3)
        field_send.append(field4)
        field_send.append(field5)
        field_send.append(field6)
        field_send.append(field7)
        field_send.append(field8)
        field_send.append(field9)
        if flag == 1:
            finalmatrix = make_backup(finalmatrix, field_send, flag)
            flag = flag + 1
        else:
            finalmatrix = make_backup(finalmatrix, field_send, flag)
            flag = 1
        # print finalmatrix
        if (count == 2 and int(field1) > 1000 or field1 == ''):  # If re-sends, 'b' will appear twice; light_val<1000 always.
            field1 = (int(finalmatrix[0][1]) + int(finalmatrix[1][1])) / 2
            # print ("Error1!")
        if (count == 2 and field2.count('-') == 2 or len(field2) > 3 or field2 == ''):  # If re-send, '-' will appear twice; field2 max 3 digits
            field2 = (int(finalmatrix[0][2]) + int(finalmatrix[1][2])) / 2
            # print ("Error2!")
        if (count == 2 and len(field3) > 1 or field3.count('01') == 1 or field3.count('10') == 1 or field3.count('-') == 1 or field3 == ''):  # Motion_sen is purely binary.
            field3 = (int(finalmatrix[0][3]) + int(finalmatrix[1][3])) / 2
            # print ("Error3!")
        if (count == 2 and int(field4) > 1000 or field4 == ''):  # If re-sends, 't' will appear twice; light_val<1000 always.
            field4 = (int(finalmatrix[0][4]) + int(finalmatrix[1][4])) / 2
            # print ("Error4!")
        if (count == 2 and field5.count('-') == 2 or len(field5) > 3 or field5 == ''):  # If re-send, '-' will appear twice; field5 max 3 digits
            field5 = (int(finalmatrix[0][5]) + int(finalmatrix[1][5])) / 2
            # print ("Error5!")
        if (count == 2 and len(field6) > 1 or field6.count('01') == 1 or field6.count('10') == 1 or field6.count('-') == 1 or field6 == ''):  # Motion_sen is purely binary.
            field6 = (int(finalmatrix[0][6]) + int(finalmatrix[1][6])) / 2
            # print ("Error6!")
        if (count == 2 and len(field8) > 1 or field8.count('01') == 1 or field8.count('10') == 1 or field8.count('-') == 1 or field8 == ''):  # Motion_sen is binary.
            field8 = (int(finalmatrix[0][8]) + int(finalmatrix[1][8])) / 2
            # print ("Error7!")
        if (count == 2 and len(field9) > 1 or field9.count('01') == 1 or field9.count('10') == 1 or field9.count('-') == 1 or field9 == ''):  # SW is binary too!
            field9 = (int(finalmatrix[0][9]) + int(finalmatrix[1][9])) / 2
            # print ("Error8!")
        with open('abs_testdatadiscrep4.csv', 'ab') as csvfile:  # 'ab' to remove newline char after each print
            writer = csv.writer(csvfile)
            sensor_fields = [field1, field2, field3, field4, field5, field6, field7, field8, field9,
                             time.strftime("%H%M%S")]
            if time.time() - start_time >= 1:
                writer.writerow(sensor_fields)
        count = count + 1
        if count == 2:
            count = 2
        print "My program took", time.time() - start_time, "to run"
        time.sleep(0.5)
        # print "My program took", time.time() - start_time, "to run"
def counting():
    while True:
        sum = 3 + 2
        sum2 = sum * 8
        time.sleep(0.2)
def on_light():
    strin = '1'
    arduino.write(strin.encode())
    print "Confirm ON"
def off_light():
    strin = '0'
    arduino.write(strin.encode())
    print "Confirm OFF"
# now threading1 runs regardless of user input
threading1 = threading.Thread(target = acquire_data)
threading2 = threading.Thread(target = counting)
threading1.start()
threading2.start()
while True:
    if raw_input() == 't':
        on_light()
        print "ON"
    if raw_input() == 'r':
        off_light()
        print "OFF"
    time.sleep(1)

Arduino代码:

#include <SoftwareSerial.h>

#define lightPin A0 // Light Sensor at Arduino A0 pin
#define echoPin 7 // Echo Pin
#define trigPin 8 // Trigger Pin
#define LEDPinUS 13 // LED at Pin 13 (Ultrasound)
#define pirPin 9 // Input for HC-S501
#define LEDPinPIR 12 // LED at Pin 12 (PIR)

SoftwareSerial xbee(2, 3); // RX, TX
int light ; //Value from light sensor
String lightID = "0";
String distanceUS = "0";
String pirID = "0";
String comma = ",";
int maximumRange = 150; // Maximum range needed
int minimumRange = 0; // Minimum range needed
long duration, distance; // Duration used to calculate distance
int OOR = 0; // OOR = Out of Range

int pirValue; // Place to store read PIR Value
int pirNum = 0;
int pirNumyes = 0;
int pirNumno = 0;

void setup() {
  Serial.begin(9600); //Baud rate must be the same as is on xBee module
  xbee.begin(9600);
  pinMode(lightPin, INPUT); // Light sensor
  pinMode(trigPin, OUTPUT); // Ultrasound sensor
  pinMode(echoPin, INPUT); // Ultrasound sensor
  pinMode(LEDPinUS, OUTPUT); // Ultrasound sensor indicator
  pinMode(pirPin, INPUT); // PIR sensor
  pinMode(LEDPinPIR, OUTPUT); // Ultrasound sensor indicator
  digitalWrite(LEDPinUS, LOW);
  digitalWrite(LEDPinPIR, LOW);
}

void loop() {
  // Light Sensor, "t" = table_sensors
  light = analogRead(lightPin);
  String ID = "t";
  lightID = ID + light + comma; //20-Mar-18: Added ","; disabled ',' printed serially
  // Ultrasound Sensor
  digitalWrite(trigPin, LOW); // clears Trigger pin
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  // Calculate the distance (in cm) based on the speed of sound.
  distance = duration / 58.2;
  if (distance >= maximumRange || distance <= minimumRange) {
    /* Send a negative number to computer and Turn LED ON
      to indicate "out of range" */
    OOR = -1;
    distanceUS = OOR + comma; //20-Mar-18: Added ","; disabled ',' printed serially; removed "+ ID"
    digitalWrite(LEDPinUS, HIGH);
  } else {
    /* Send the distance to the computer using Serial protocol, and
      turn LED OFF to indicate successful reading. */
    distanceUS = distance + comma; //20-Mar-18: Added ","; disabled ',' printed serially; removed "+ ID"
    digitalWrite(LEDPinUS, LOW);
  }
  // Motion sensor
  pirValue = digitalRead(pirPin);
  if (pirValue == HIGH) {
    pirNumyes = 1;
    pirID = pirNumyes + comma; //20-Mar-18: Added ","; disabled ',' printed serially; removed "+ ID"
    digitalWrite(LEDPinPIR, HIGH);
  } else {
    pirNumno = 0;
    pirID = pirNumno + comma; //20-Mar-18: Added ","; disabled ',' printed serially; removed "+ ID"
    digitalWrite(LEDPinPIR, LOW);
  }
  String together = lightID + distanceUS + pirID;
  //Serial.println(together);
  xbee.println(together);
  delay(1000);
}

我试过在谷歌搜索答案,但我似乎找不到任何答案。我最接近的是来自Read serial data without high CPU use的类似StackOverflow帖子的答案。

但是,我可以问一下Raspberry Pi上是否有针对UART中断的Python实现?

非常感谢你的帮助! :)

1 个答案:

答案 0 :(得分:0)

如果从RX引脚到任何可用的GPIO引脚都安装了一条额外的导线,则可以至少使用RpiGPIO模块边缘中断来提醒您正在进行传输。它不会告诉您缓冲区已满,因此在服务GPIO中断时必须检查缓冲区。至少这可以让您执行其他操作,而不是等待循环和/或轮询UART以获取缓冲区数据。