我是编程和串行通信的新手,所以原谅我可能会弄乱一些简单的东西。
我写的脚本是读取Arduino通过串口发送的温度数据。首次加载时,Arduino草图会发送一个"菜单"具有读取,写入和清除EEPROM的选项。
当我加载python脚本时,有时它运行得很好。其他时候,它只是没有阅读任何东西。有时候,它会给我的终端充斥温度读数数据约5秒钟,然后发送菜单并正常运行。
我已经添加了flushinput和时间延迟,但无济于事。
另一个快速问题:如果我在while循环中从串口收集数据,这是无止境的,我怎么能输入一个命令暂停并切换到程序的另一部分而不中断数据流?例如,如果我从温度传感器收集数据并使用串行来实时绘制温度与时间的关系,但我希望能够在任何时候中断此操作以停止写入并切换到读取(保存数据)到.txt文件)。怎么可以这样做?
非常感谢任何帮助。
这是Python代码:
import serial
import time
import numpy as np
import matplotlib.pyplot as plt
ser = serial.Serial('/dev/tty.usbmodem1421', 9600, timeout = 5)
ser.flushInput()
ser.flushOutput()
time.sleep(0.1)
print ("Connected to serial port: {}".format(ser.name))
def Menu():
data_left = 1
while (data_left != 0):
print(ser.readline())
time.sleep(.1)
data_left = ser.inWaiting()
return
def RealTimePlot(y, count, k, minPlot, maxPlot):
//stuff
def WriteData(mode, plotData = 'n'):
//stuff
def ReadData(mode):
//stuff
def main():
launch = 0
plotData = ProgramIntro()
time.sleep(1)
Menu()
mode = raw_input("> ")
while (1):
if ((mode == "end") or (mode == 'exit')) :
ser.close()
exit()
elif (mode == 'm'):
ser.write(mode)
time.sleep(1)
Menu()
mode = raw_input("> ")
if (mode == 'm'):
print("Already at menu. Would you like to:")
print("[w]rite")
print("[r]ead")
print("[c]lear")
elif (mode == 'w'):
count = 0
WriteData(mode, plotData)
#mode = PauseProgram()
elif (mode == 'r'):
ReadData(mode)
#mode = PauseProgram()
elif (mode == 'c'):
ser.write(mode)
time.sleep(1)
while ser.inWaiting() > 0:
out = ser.readline()
print(out)
time.sleep(0.1)
mode = 'm'
print("Goodbye!")
#Closes the connection
ser.close()
和Arduino代码:
// References
// https://learn.sparkfun.com/tutorials/sik-experiment-guide-for-arduino---v32/experiment-7-reading-a-temperature-sensor
// https://www.arduino.cc/en/Tutorial/EEPROMWrite
// https://www.arduino.cc/en/Tutorial/EEPROMRead
//
// The following may be useful to read on storing EEPROM data:
// http://www.vernier.com/engineering/arduino/store-data-eeprom/
//
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
#include <EEPROM.h>
// Define pins
const int writePin = 5;
const int readPin = 9;
const int pausePin = 7;
const int collectDataBtn = 11;
const int RTPin = 3;
const int sensorPin = A0; // Temperature Pin
char RTData;
int j = 0;
// SETUP of Serial port and PINS for LED
void setup() {
Serial.begin(9600);
pinMode(writePin, OUTPUT);
pinMode(RTPin, OUTPUT);
pinMode(readPin, OUTPUT);
pinMode(pausePin, OUTPUT);
pinMode(sensorPin, INPUT);
pinMode(collectDataBtn, INPUT);
while(Serial.available())
Serial.read();
}
char mode = 'm';
char prevMode = 'm';
int k = 0;
// MAIN LOOP
void loop() {
while (j == 0) {
if (k == 0) {
Serial.print("Would you like to plot real-time data? (y/n) ");
k++;
}
if (Serial.available() > 0) {
RTData = Serial.read();
if (RTData == 'y') {
digitalWrite(RTPin, HIGH);
j++;
}
else {
j++;
}
}
return;
}
switch (mode) {
// MENU mode
case 'm':
case 'M':
// Set LEDs to indicate menu mode
digitalWrite(writePin, HIGH);
digitalWrite(readPin, HIGH);
digitalWrite(pausePin, LOW);
// Print menu to serial port
PrintMenu();
while (mode == 'm') {
if (Serial.available() > 0) {
prevMode = mode;
mode = Serial.read();
}
}
break;
// WRITE mode
case 'w':
case 'W':
Serial.println("Entering WRITE mode...");
mode = WriteData(sensorPin, collectDataBtn);
break;
// READ mode
case 'r':
case 'R':
// Sets LEDs to indicate READ mode
digitalWrite(writePin, LOW);
digitalWrite(readPin, HIGH);
digitalWrite(pausePin, LOW);
Serial.println("Entering READ mode...");
mode = ReadData(sensorPin, prevMode);
break;
// CLEAR eeprom mode
case 'c':
case 'C':
Serial.println("Clearing EEPROM...");
ClearEEPROM();
Serial.println("EEPROM cleared!");
Serial.println("Returning to menu...\n\n");
mode = 'm';
break;
// PAUSE mode
default:
// Sets LEDs to indicate PAUSE mode
digitalWrite(writePin, LOW);
digitalWrite(readPin, LOW);
digitalWrite(pausePin, HIGH);
mode = 'p';
mode = PauseMode(mode);
break;
}
} // END void loop
void ClearEEPROM(void) {
for (int i = 0 ; i < EEPROM.length() ; i++) {
if ((i % 100 == 0) || (i % 50 == 0)) {
digitalWrite(writePin, HIGH);
digitalWrite(readPin, LOW);
digitalWrite(pausePin, LOW);
}
else {
digitalWrite(writePin, LOW);
digitalWrite(readPin, LOW);
digitalWrite(pausePin, HIGH);
}
EEPROM.write(i, 0);
}
return;
}
char CheckModeChange(void) {
if (Serial.available() > 0) {
// read the incoming char:
prevMode = mode;
mode = Serial.read();
}
return mode;
}
void PrintMenu(void) {
Serial.println("\n");
Serial.println(" ** Menu ** ");
Serial.println("------------------");
Serial.println("| [W]rite Data |");
Serial.println("| [R]ead Data |");
Serial.println("| [C]lear Data |");
Serial.println("------------------");
Serial.println("Enter [m]enu to return to menu at any point,");
Serial.println("or press any other key to pause during any point of the program.");
return;
}
char PauseMode(char mode){
Serial.println("Program Paused. Choose an option from the following to continue: ");
Serial.println("[m]enu");
Serial.println("[w]rite");
Serial.println("[r]ead");
Serial.println("[c]lear \n");
while (mode == 'p') {
if (Serial.available() > 0) {
mode = Serial.read();
}
}
return mode;
}
char WriteData(int sensorPin, int collectDataBtn) {
// Declarations
int cnt, voltVal;
int addr = 0; // Initializes address at 0 for EEPROM
int beginData = 0;
float voltage, degreesC;
char mode = 'w';
// Collect data when button pushed. This will be replaced by z-axis acceleration threshold
// of rocket.
Serial.println("Waiting for launch to begin...");
while (beginData == 0) {
if (cnt > 20000) {
cnt = 0;
}
else if (cnt < 10000) {
digitalWrite(writePin, LOW);
digitalWrite(readPin, LOW);
digitalWrite(pausePin, LOW);
}
else {
digitalWrite(writePin, HIGH);
digitalWrite(readPin, LOW);
digitalWrite(pausePin, LOW);
}
cnt++;
if (digitalRead(collectDataBtn) == HIGH) {
beginData = 1;
}
prevMode = mode;
mode = CheckModeChange();
if (prevMode != mode) {
beginData = 1;
}
}
digitalWrite(writePin, HIGH);
digitalWrite(readPin, LOW);
digitalWrite(pausePin, LOW);
// Write Data loop
while (mode == 'w') {
// First we'll measure the voltage at the analog pin. Normally
// we'd use analogRead(), which returns a number from 0 to 1023.
// Here we've written a function (further down) called
// getVoltage() that returns the true voltage (0 to 5 Volts)
// present on an analog input pin.
voltage = getVoltage(sensorPin);
// Now we'll convert the voltage to degrees Celsius.
// This formula comes from the temperature sensor datasheet:
// CONVERT IN PYTHON SCRIPT
// degreesC = (voltage - 0.5) * 100.0;
//Serial.print("Address[");
//Serial.print(addr);
//Serial.print("]: \t");
Serial.println(voltage);
/***
Write the value to the appropriate byte of the EEPROM.
these values will remain there when the board is
turned off.
***/
// Convert for storage to EEPROM
voltVal = (voltage * 10000) / 4;
// Write to EEPROM
EEPROM.write(addr, voltVal);
/***
Advance to the next address, when at the end restart at the beginning.
Larger AVR processors have larger EEPROM sizes, E.g:
- Arduno Duemilanove: 512b EEPROM storage.
- Arduino Uno: 1kb EEPROM storage.
- Arduino Mega: 4kb EEPROM storage.
Rather than hard-coding the length, you should use the pre-provided length function.
This will make your code portable to all AVR processors.
***/
addr = addr + 1;
/***
As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an
EEPROM address is also doable by a bitwise and of the length - 1.
++addr &= EEPROM.length() - 1;
***/
// Check for mode change
mode = CheckModeChange();
delay(100);
}
return mode;
}
char ReadData(int Pin, char prevMode) {
// Declarations
byte value;
float voltageVal, voltage, degreesC;
int addr = 0;
char mode = 'r';
// Checks previous mode. If previous mode was write, now that we are reading
// we should reset the EEPROM address to 0 so we can read from the beginning.
if ( (prevMode == 'w') || (prevMode == 'W') ) {
addr = 0;
}
while (mode == 'r') {
value = EEPROM.read(addr);
voltageVal = value;
voltage = voltageVal * 4 / 10000;
//Serial.print("Voltage: ");
//Serial.print("\t");
//Serial.println(voltage);
degreesC = (voltage - 0.5) * 100.0;
//Serial.print("Degrees C: ");
//Serial.print("\t");
//Serial.print("Address[");
//Serial.print(addr);
//Serial.print("]: \t");
Serial.println(degreesC);
/***
Advance to the next address, when at the end restart at the beginning.
Larger AVR processors have larger EEPROM sizes, E.g:
- Arduno Duemilanove: 512b EEPROM storage.
- Arduino Uno: 1kb EEPROM storage.
- Arduino Mega: 4kb EEPROM storage.
Rather than hard-coding the length, you should use the pre-provided length function.
This will make your code portable to all AVR processors.
***/
addr = addr + 1;
if (addr == EEPROM.length()) {
addr = 0;
}
// Check for mode change
mode = CheckModeChange();
delay(100);
}
return mode;
}
float getVoltage(int pin) {
// This function has one input parameter, the analog pin number
// to read. You might notice that this function does not have
// "void" in front of it; this is because it returns a floating-
// point value, which is the true voltage on that pin (0 to 5V).
return (analogRead(pin) * 0.004882814);
// This equation converts the 0 to 1023 value that analogRead()
// returns, into a 0.0 to 5.0 value that is the true voltage
// being read at that pin.
}