所以我正在编写一个应用程序,用于读取串行端口中的数据读取。这个数据来自一个连接到力传感器的arduino - 本质上,应用程序用于测量某物的重量。我在这里找到了串口代码:https://www.allaboutcircuits.com/projects/communicate-with-your-arduino-through-android/,我在多个不同的活动中使用它(因为我需要一个校准活动,一个实际测量活动等)。我的问题是,相同的串行端口代码在一个活动中工作,而在另一个活动中不起作用。它适用于此活动,例如:
public class EnterDataActivity extends AppCompatActivity {
private static final long TIMER_DELAY = 5000;
private static final long TIMER_LENGTH = 15000;
EditText enterMax, enterMin;
Button submitMax, submitMin, continueButton;
Chronometer emptyBagTimer;
boolean firstMeasure, getEmptyBagData, canEnterMax, canEnterMin;
ArrayList<String> emptyBagData;
float maxLoad, minLoad;
// serial port variables:
public final String ACTION_USB_PERMISSION = "com.example.jake.USB_PERMISSION";
UsbManager usbManager;
UsbDevice device;
UsbSerialDevice serialPort;
UsbDeviceConnection connection;
UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() { //Defining a Callback which triggers whenever data is read.
@Override
public void onReceivedData(byte[] arg0) {
String data;
try {
data = new String(arg0, "UTF-8");
if(getEmptyBagData)
emptyBagData.add(data);
} catch (UnsupportedEncodingException e) {}
}
};
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { //Broadcast Receiver to automatically start and stop the Serial connection.
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_USB_PERMISSION)) {
boolean granted = intent.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED);
if (granted) {
connection = usbManager.openDevice(device);
serialPort = UsbSerialDevice.createUsbSerialDevice(device, connection);
if (serialPort != null) {
if (serialPort.open()) { //Set Serial Connection Parameters.
serialPort.setBaudRate(9600);
serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
serialPort.setParity(UsbSerialInterface.PARITY_NONE);
serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
serialPort.read(mCallback);
} else {
Log.d("SERIAL", "PORT NOT OPEN");
}
} else {
Log.d("SERIAL", "PORT IS NULL");
}
} else {
Log.d("SERIAL", "PERM NOT GRANTED");
}
} else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
start();
} else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
stop();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_enter_data);
usbManager = (UsbManager) getSystemService(USB_SERVICE);
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_USB_PERMISSION);
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(broadcastReceiver, filter);
enterMax = (EditText) findViewById(R.id.enterMax);
enterMin = (EditText) findViewById(R.id.enterMin);
submitMax = (Button) findViewById(R.id.submitMax);
submitMin = (Button) findViewById(R.id.submitMin);
continueButton = (Button) findViewById(R.id.continueButton);
emptyBagTimer = (Chronometer) findViewById(R.id.emptyBagTimer);
firstMeasure = true;
getEmptyBagData = false;
canEnterMax = true;
canEnterMin = true;
emptyBagData = new ArrayList<>();
start();
}
// method: measureEmptyBag
// description: this method is called when the button to measure the mass of the empty bag is
// pressed. It starts the chronometer and serial port, first waiting TIMER_DELAY milliseconds
// from the button press, then sets a boolean to true that causes the serial data to be added to
// an arraylist over the next TIMER_LENGTH milliseconds. It then sets the next views in the
// enter data process to visible. The firstMeasure boolean is to prevent spamming.
public void measureEmptyBag(View view){
if(firstMeasure) {
firstMeasure = false;
start();
emptyBagTimer.setBase(SystemClock.elapsedRealtime());
emptyBagTimer.start();
emptyBagTimer.setFormat("Waiting - %s");
emptyBagTimer.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
@Override
public void onChronometerTick(Chronometer chronometer) {
if (SystemClock.elapsedRealtime() - emptyBagTimer.getBase() <= TIMER_DELAY)
emptyBagTimer.setFormat("Waiting - %s");
else if (SystemClock.elapsedRealtime() - emptyBagTimer.getBase() <= TIMER_DELAY + TIMER_LENGTH) {
emptyBagTimer.setFormat("Calculating - %s");
getEmptyBagData = true;
}
else if (SystemClock.elapsedRealtime() - emptyBagTimer.getBase() > TIMER_DELAY + TIMER_LENGTH) {
getEmptyBagData = false;
emptyBagTimer.stop();
enterMax.setVisibility(View.VISIBLE);
submitMax.setVisibility(View.VISIBLE);
}
else
emptyBagTimer.setFormat("Waiting - %s");
}
});
}
}
// method: setMaxLoad
// description: called when the submit button is pressed for the max load, this method trys to
// pull the max load value from it edit text and store it. If that is successful (the user has
// entered in a number) then it sets the next views in the enter data process to visible.
public void setMaxLoad(View view){
if(canEnterMax){
try {
canEnterMax = false;
maxLoad = Float.parseFloat(enterMax.getText().toString());
enterMin.setVisibility(View.VISIBLE);
submitMin.setVisibility(View.VISIBLE);
} catch (Exception e) {} // in case the user enters a non number
}
}
// method: setMinLoad
// description: called when the submit button is pressed for the min load, this method trys to
// pull the min load value from its edit text and store it. If that is successful (the user has
// entered in a number) then it sets the next view in the enter data process to visible.
public void setMinLoad(View view){
if(canEnterMin){
try {
canEnterMin = false;
minLoad = Float.parseFloat(enterMin.getText().toString());
continueButton.setVisibility(View.VISIBLE);
} catch (Exception e) {} // in case the user enters a non number
}
}
// method: continuePressed
// description: this method is called when the continue button is pressed. It averages all of the
// data read in over the measure empty mass period to find the mass when empty, then writes that
// value along with maxLoad and minLoad to a file for later use. Finally it starts the pump
// activity
public void continuePressed(View view){
int emptyMassSum = 0;
int emptyMass;
// cleaning up emptyBagData to only include 3,2, or 1 digit numbers (the serial output gets
// wonky sometimes and spits out weird numbers that would throw off the calculations below,
// so those numbers need to be removed)
for (int i = emptyBagData.size() - 1; i >= 0; i--)
if (emptyBagData.get(i).length() != 3)
emptyBagData.remove(i);
// add up all the values in emptyBagData (try catch in case a non-number was read in)
for (int i = emptyBagData.size() - 1; i >= 0; i--) {
try {
emptyMassSum += Integer.parseInt(emptyBagData.get(i));
} catch (Exception e) {
emptyBagData.remove(i);
}
}
emptyMass = emptyMassSum / emptyBagData.size();
FileOutputStream outputStream;
String dataOut = "E" + emptyMass + "Mx" + maxLoad + "Mn" + minLoad + ";";
try {
outputStream = openFileOutput("BagData.txt", Context.MODE_PRIVATE);
outputStream.write(dataOut.getBytes());
outputStream.close();
} catch (Exception e) {
continueButton.setText(R.string.file_write_error_message);
}
Intent intent = new Intent(this, PumpActivity.class);
startActivity(intent);
}
// serial port methods:
public void start() {
HashMap<String, UsbDevice> usbDevices = usbManager.getDeviceList();
if (!usbDevices.isEmpty()) {
boolean keep = true;
for (Map.Entry<String, UsbDevice> entry : usbDevices.entrySet()) {
device = entry.getValue();
int deviceVID = device.getVendorId();
if (deviceVID == 10755 || deviceVID == 9025)//Arduino Vendor ID
{
PendingIntent pi = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
usbManager.requestPermission(device, pi);
keep = false;
} else {
connection = null;
device = null;
}
if (!keep)
break;
}
}
}
public void stop() {
if(serialPort!=null)
serialPort.close();
}
}
通过“它工作”,我的意思是我可以从串口获取数据并使用它。但是,相同的代码在这里不起作用:
public class PumpActivity extends AppCompatActivity {
File calibrationData, bagData;
int mass1, mass2, read1, read2, emptyMassNum;
float maxLoad, minLoad;
double slope, currentMassVal, emptyMass;
boolean status, runTimer;
TextView statusTextView, currentMassTextView;
Button stop;
Thread updateMass;
ArrayList<String> inData;
// this does two things when the handleMessage method is called:
// 1) it takes the most recent data read in and calculates the current mass from it, then updates
// the current mass text view to reflect that
// 2) it takes that newly calculated mass and sees if status should change, depending on how much
// mass there currently is. It also writes a value to the serial port (back to the arduino)
// depending on that status. It then updates the status text view to reflect this
Handler updateMassHandler = new Handler(){
public void handleMessage(Message msg){
// mass calculation
try{currentMassVal = calculateMass(Integer.parseInt(inData.get(inData.size()-1)));} catch (Exception e){} // try-catch in case data isn't an int
inData.clear();
currentMassTextView.setText(String.format(getResources().getString(R.string.current_mass_string), currentMassVal));
// status check with new mass
if (currentMassVal >= maxLoad)
status = true;
else if (currentMassVal <= minLoad)
status = false;
statusTextView.setText(String.format(getResources().getString(R.string.pump_status), getStatus()));
// writing back to arduino
if (serialPort != null) {
if (status)
serialPort.write("1".getBytes());
else
serialPort.write("0".getBytes());
}
}
};
// serial port variables:
public final String ACTION_USB_PERMISSION = "com.example.jake.USB_PERMISSION";
UsbManager usbManager;
UsbDevice device;
UsbSerialDevice serialPort;
UsbDeviceConnection connection;
UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() { //Defining a Callback which triggers whenever data is read.
@Override
public void onReceivedData(byte[] arg0) {
String data;
try {
data = new String(arg0, "UTF-8");
inData.add(data);
} catch (UnsupportedEncodingException e) {}
}
};
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { //Broadcast Receiver to automatically start and stop the Serial connection.
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_USB_PERMISSION)) {
boolean granted = intent.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED);
if (granted) {
connection = usbManager.openDevice(device);
serialPort = UsbSerialDevice.createUsbSerialDevice(device, connection);
if (serialPort != null) {
if (serialPort.open()) { //Set Serial Connection Parameters.
serialPort.setBaudRate(9600);
serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
serialPort.setParity(UsbSerialInterface.PARITY_NONE);
serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
serialPort.read(mCallback);
} else {
Log.d("SERIAL", "PORT NOT OPEN");
}
} else {
Log.d("SERIAL", "PORT IS NULL");
}
} else {
Log.d("SERIAL", "PERM NOT GRANTED");
}
} else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
start();
} else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
stop();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pump);
usbManager = (UsbManager) getSystemService(USB_SERVICE);
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_USB_PERMISSION);
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(broadcastReceiver, filter);
status = false;
statusTextView = (TextView) findViewById(R.id.statusTextView);
statusTextView.setText(String.format(getResources().getString(R.string.pump_status), getStatus()));
currentMassTextView = (TextView) findViewById(R.id.currentMassTextView);
currentMassTextView.setText(R.string.calculating_text);
stop = (Button) findViewById(R.id.stopButton);
runTimer = true;
currentMassVal = 0;
inData = new ArrayList<>();
// thread that "calls" the handleMessage method in the upDateMassHandler every 100 milliseconds
updateMass = new Thread(new Runnable() {
@Override
public void run() {
while(runTimer){
updateMassHandler.sendEmptyMessage(0);
try{Thread.sleep(100);} catch (InterruptedException e){}
}
}
});
// thanks to stackOverflow for the file reading code
// reading and parsing from calibration data
calibrationData = new File(getFilesDir(), "CalibrationData.txt");
StringBuilder text = new StringBuilder();
// reading in the calibration data from the file (of the same name)
try {
BufferedReader br = new BufferedReader(new FileReader(calibrationData));
String line;
while ((line = br.readLine()) != null) {
text.append(line);
text.append('\n');
}
br.close();
} catch (IOException e) {}
// parsing values from calibration data
String calibData = text.toString();
calibData = calibData.substring(3);
mass1 = Integer.parseInt(calibData.substring(0, calibData.indexOf('R')));
calibData = calibData.substring(calibData.indexOf(':') + 1);
read1 = Integer.parseInt(calibData.substring(0, calibData.indexOf('M')));
calibData = calibData.substring(calibData.indexOf(':') + 1);
mass2 = Integer.parseInt(calibData.substring(0, calibData.indexOf('R')));
calibData = calibData.substring(calibData.indexOf(':') + 1);
read2 = Integer.parseInt(calibData.substring(0, calibData.indexOf('.')));
slope = ((double) (mass2 - mass1) / (read2 - read1)); // calculating slope of masses and reads to allow
// calculation of mass of an unknown read
// reading and parsing from bag data
bagData = new File(getFilesDir(), "BagData.txt");
StringBuilder text2 = new StringBuilder();
// reading in the bag data from the file (of the same name)
try {
BufferedReader br = new BufferedReader(new FileReader(bagData));
String line;
while ((line = br.readLine()) != null) {
text2.append(line);
text2.append('\n');
}
br.close();
} catch (IOException e) {}
// parsing values frm bag data
String bagData = text2.toString();
bagData = bagData.substring(1);
emptyMassNum = Integer.parseInt(bagData.substring(0, bagData.indexOf('M')));
bagData = bagData.substring(bagData.indexOf('x') + 1);
maxLoad = Float.parseFloat(bagData.substring(0, bagData.indexOf('M')));
bagData = bagData.substring(bagData.indexOf('n') + 1);
minLoad = Float.parseFloat(bagData.substring(0, bagData.indexOf(';')));
emptyMass = calculateMass(emptyMassNum); // emptyMassNum is the values read in from the arduino
// this converts it to a mass
updateMass.start();
start();
}
// method: calculateMass
// description: calculates the mass of the object on the transducer based off of the value read
// in and the data gotten from calibration
// input: int readVal - the value read in
// output: double - the calculated mass
public double calculateMass(int readVal){
return (slope * (readVal-read1)) + mass1;
}
// method: getStatus
// description: returns a string representation of the status
public String getStatus(){
if(status)
return "running";
else
return "stopped";
}
// method: stop
// description: stops everything when the stop button is pressed
public void stop(View view){
status = false;
runTimer = false;
stop();
stop.setText(R.string.button_stopped);
}
// serial port methods:
public void start() {
HashMap<String, UsbDevice> usbDevices = usbManager.getDeviceList();
if (!usbDevices.isEmpty()) {
boolean keep = true;
for (Map.Entry<String, UsbDevice> entry : usbDevices.entrySet()) {
device = entry.getValue();
int deviceVID = device.getVendorId();
if (deviceVID == 10755 || deviceVID == 9025)//Arduino Vendor ID
{
PendingIntent pi = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
usbManager.requestPermission(device, pi);
keep = false;
} else {
connection = null;
device = null;
}
if (!keep)
break;
}
}
}
public void stop() {
if(serialPort!=null)
serialPort.close();
}
}
由于某种原因,mCallback变量中的onReceivedData方法似乎没有在第二个活动中调用(不活动的那个)。我很确定这是问题,我只是不确定为什么在一个活动中调用它而不是在另一个活动中调用相同的代码。如果没有调用该方法,那么我无法访问进来的数据,这是我的问题。
此外,这是我的清单:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.stylosa.hangingtransducer">
<uses-feature android:name="android.hardware.usb.host" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
</intent-filter>
</activity>
<activity
android:name=".CalibrateActivity">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
</intent-filter>
</activity>
<activity
android:name=".InputActivity"
android:parentActivityName=".MainActivity">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
</intent-filter>
</activity>
<activity
android:name=".EnterDataActivity">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
</intent-filter>
</activity>
<activity
android:name=".PumpActivity">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
</intent-filter>
</activity>
</application>
非常感谢任何和所有帮助!