#include
const int BT_RX_PIN = 15; // SoftwareSerial RX
const int BT_TX_PIN = 17; // SoftwareSerial TX
SoftwareSerial BTserial(BT_RX_PIN, BT_TX_PIN);
const unsigned long btSendIntervalMs = 100;
unsigned long lastBtSendTime = 0;
void setup() {
BTserial.begin(9600);
}
void loop() {
unsigned long currentTime = millis();
if (currentTime - lastBtSendTime >= btSendIntervalMs) {
sendBluetoothData();
lastBtSendTime = currentTime;
}
}
void sendBluetoothData() {
int Rand1 = random(10000);
int Rand2 = random(10000);
BTserial.print('$');
BTserial.print(String(Rand1));
BTserial.print('#');
BTserial.print(String(Rand2));
BTserial.print('&');
BTserial.println(); // Newline at the end
}
< /code>
Отправка двух случайных чисел, а не много данных, верно? Я намеренно разбиваю их для каждого вызова печати вместо того, чтобы помещать все в одну строку. < /P>
На моем компьюте />[youtube]hgb8pcww7iq[/youtube]
выглядит так, как будто он отправляет довольно небольшое количество байтов [b] без [/b] loce Latency (100 мс в этом случае, как определено пользователем)
Однако я. BufferedReader
, Line By Line и войдите их в окно отладки. По сути, замазка - это эмуляция для Android здесь, и на замазке она работает так же, как и ожидалось.
private static BluetoothAdapter btAdapter;
private static BluetoothDevice btDevice;
private static BluetoothSocket btSocket;
private static InputStream mmInputStream;
private static BufferedReader bufferedReader;
static boolean connect(BluetoothDevice device) {
try{
if(btAdapter == null) {
Toast.makeText(CurrentContext.get(), "Bluetooth Adapter not found...", Toast.LENGTH_LONG).show();
return false;
}
else if(!btAdapter.isEnabled()) {
Toast.makeText(CurrentContext.get(), "Bluetooth Adapter is not enabled...", Toast.LENGTH_LONG).show();
return false;
}
if(btSocket != null && btSocket.isConnected()) {
if(btDevice == null) {
Toast.makeText(CurrentContext.get(), "Bluetooth Device could not be found...", Toast.LENGTH_LONG).show();
return false;
}
else {
Toast.makeText(CurrentContext.get(), "Already connected to: " + btDevice.getName(), Toast.LENGTH_LONG).show();
return false;
}
}
Toast.makeText(CurrentContext.get(), "Connecting. Please wait...", Toast.LENGTH_LONG);
btDevice = device;
if(btDevice == null) {
Toast.makeText(CurrentContext.get(), "Bluetooth Device could not be found...", Toast.LENGTH_LONG).show();
return false;
}
btSocket = btDevice.createRfcommSocketToServiceRecord(CONNECTION_UUID);
if(btSocket == null) {
Toast.makeText(CurrentContext.get(), "Bluetooth Socket could not be found...", Toast.LENGTH_LONG).show();
return false;
}
btAdapter.cancelDiscovery();
btSocket.connect();
mmInputStream = new DataInputStream(btSocket.getInputStream());
bufferedReader = new BufferedReader(new InputStreamReader(mmInputStream, StandardCharsets.UTF_8)); // Ignore error
beginInputStreamListener(); // Start the thread for reading data
}catch(Exception e){
e.printStackTrace();
Toast.makeText(CurrentContext.get(), "Could not connect to: " + device.getName(), Toast.LENGTH_LONG).show();
return false;
}
Toast.makeText(CurrentContext.get(), "Connected to: " + btDevice.getName(), Toast.LENGTH_LONG).show();
return true;
}
< /code>
А вот отдельный поток, который я вызываю через begininptristerlistener < /code>, чтобы непрерывно считывать данные.
Я хочу избежать использования его в потоке пользовательского интерфейса по всем затратам. < /p>
private static void beginInputStreamListener(){
dataListenerThread = new Thread(new Runnable() {
@Override
public void run() {
dataListenerThreadActive = true; // Just a boolean I can switch to terminate the loop below
while(!Thread.currentThread().isInterrupted() && dataListenerThreadActive) {
try {
if(bufferedReader.ready()) {
String line = bufferedReader.readLine();
if(line != null) {
Log.d("RECEIVED_DATA", line);
}
}
Thread.sleep(10); // Some small delay
} catch (IOException | InterruptedException e) {
Handler mainHandler = new Handler(Looper.getMainLooper());
mainHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(CurrentContext.get(), "An unresolved problem occured...", Toast.LENGTH_LONG).show();
}
});
e.printStackTrace();
dataListenerThreadActive = false;
reset();
}
}
}
});
dataListenerThread.start();
}
< /code>
Я пробовал разные подходы с чтением байто-байтового с .READ (), .aiLable () и т. Д. И они должны работать мгновенно в любом случае, но в конце концов, так как я отправляю строку за линию, что это может решить проблему. Но это не так!
По какой-то причине, когда я подключаю приложение к своему HC-05 (устройство Arduino), оно начинает печатать довольно быстро, как в замазке (как я хочу, чтобы оно работало!), Но через 5 секунд, четко работая правильно, у него есть какая-то задержка, затем напечатает 10 строк за один ход, затем задерживается второй или два, затем напечатает 10 или n, а не в непрерывном целом, просто в целом). Это чрезвычайно разочаровывает, так как я не транслирую видео 4K через это, но посылаю абсолютно мелкие данные, которые хорошо работают на Putty. /> Arduino должен постоянно отправлять данные каждые 100 мс и не должен ждать какой-либо команды. /> Обновление: < /strong> Я что -то понял. Во -первых, в первые пару секунд был виновник, когда приложение Android читает все гладко. Это потому, что я не промыл данные за то время, когда Ардуино потратил их через буфер, прежде чем быть подключенным к. Таким образом, промывка просто устраняет иллюзию первых нескольких секунд и удаляет нежелательные данные. Почему?
Потому что, когда он получает кусок из 5 строк, тогда ожидает вторую или две секунды для другого чанка, вместо того, чтобы немедленно читать следующую строку, я могу сделать ее прочитать строки каждые 100 мс, а когда он заканчивается, он будет получать следующие 5 или около того строк, и так далее. Линии в моем приложении Android, равные интервалу отправки каждой строки в Arduino, обеспечивает наиболее стабильную регистрацию, но есть проблема. Примерно через 5 минут приложение Android не может не отставать и застряло в чтении более старых данных, в то время как более новая впереди. Это подтверждается, позволив ему читать в течение 5 минут, а затем внезапно отключить мой Arduino, где он будет продолжать читать заполненный буфер на несколько секунд. Это делает это, в то время как входной слушатель просто буферирует данные в очереди. < /p>
private static final ConcurrentLinkedQueue dataQueue = new ConcurrentLinkedQueue();
private static void beginInputStreamListener(){
dataListenerThread = new Thread(new Runnable() {
@Override
public void run() {
try {
while (mmInputStream.available() > 0) {
mmInputStream.read();
}
} catch (IOException e) {
e.printStackTrace();
}
dataListenerActive.set(true);
byte[] buffer = new byte[1]; // Read ONE byte at a time
StringBuilder lineBuffer = new StringBuilder();
while (!Thread.currentThread().isInterrupted() && dataListenerActive.get()) {
try {
int bytesRead = mmInputStream.read(buffer);
if (bytesRead > 0) {
char c = (char) buffer[0];
if (c == '\n') {
// Complete line received
String line = lineBuffer.toString().trim();
if (!line.isEmpty()) {
String data = line;
dataQueue.offer(data);
}
lineBuffer.setLength(0);
} else if (c != '\r') { // Ignore carriage returns
lineBuffer.append(c);
}
}
// NO Thread.sleep() - hammer the input stream for maximum responsiveness
} catch (IOException e) {
e.printStackTrace();
dataListenerActive.set(false);
dataProcessorActive.set(false);
DisconnectedAbruptly = true;
reset();
}
}
}
});
dataListenerThread.setPriority(Thread.MAX_PRIORITY); // Set to maximum priority!
dataListenerThread.start();
}
private static void beginDataProcessor() {
dataProcessorThread = new Thread(new Runnable() {
@Override
public void run() {
dataProcessorActive.set(true);
while (!Thread.currentThread().isInterrupted() && dataProcessorActive.get()) {
try {
// Get ONE line from queue
String data = dataQueue.poll();
if (data != null) {
Log.d("RD", data);
}
// Wait exactly 100ms
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
});
dataProcessorThread.start();
}
Это выглядит лучше, но никоим образом я не могу продать истории, как современный смартфон не может обрабатывать небольшие данные в промежутке. Это очень расстраивает, и я уверен, что я не единственный, кто наткнулся на это. Есть еще некоторая задержка. В примере видео интервалы составляют 200 мс для чтения и 230 мс для написания. Выполнение 100/130 дает те же результаты, до 500 мс потери. Мне нужно, чтобы это было так быстро, как могло бы быть. 500 мс для меня слишком медленная, если я должен был заключить свое решение как 500 мс. Это временный обходной путь, но я не принимаю его как окончательное решение, по крайней мере, пока. https://www.dropbox.com/scl/fi/bgwwnnif ... evw&dl=0/p>
int Rand1 = random(10000); int Rand2 = random(10000);
BTserial.print('$'); BTserial.print(String(Rand1)); BTserial.print('#'); BTserial.print(String(Rand2)); BTserial.print('&'); BTserial.println(); // Newline at the end } < /code> Отправка двух случайных чисел, а не много данных, верно? Я намеренно разбиваю их для каждого вызова печати вместо того, чтобы помещать все в одну строку. < /P> На моем компьюте />[youtube]hgb8pcww7iq[/youtube] выглядит так, как будто он отправляет довольно небольшое количество байтов [b] без [/b] loce Latency (100 мс в этом случае, как определено пользователем)
Однако я. BufferedReader [/code], Line By Line и войдите их в окно отладки. По сути, замазка - это эмуляция для Android здесь, и на замазке она работает так же, как и ожидалось.[code]private static BluetoothAdapter btAdapter; private static BluetoothDevice btDevice; private static BluetoothSocket btSocket;
Toast.makeText(CurrentContext.get(), "Bluetooth Socket could not be found...", Toast.LENGTH_LONG).show(); return false; }
btAdapter.cancelDiscovery(); btSocket.connect();
mmInputStream = new DataInputStream(btSocket.getInputStream());
bufferedReader = new BufferedReader(new InputStreamReader(mmInputStream, StandardCharsets.UTF_8)); // Ignore error beginInputStreamListener(); // Start the thread for reading data }catch(Exception e){
e.printStackTrace(); Toast.makeText(CurrentContext.get(), "Could not connect to: " + device.getName(), Toast.LENGTH_LONG).show(); return false; }
Toast.makeText(CurrentContext.get(), "Connected to: " + btDevice.getName(), Toast.LENGTH_LONG).show();
return true; } < /code> А вот отдельный поток, который я вызываю через begininptristerlistener < /code>, чтобы непрерывно считывать данные. Я хочу избежать использования его в потоке пользовательского интерфейса по всем затратам. < /p> private static void beginInputStreamListener(){
dataListenerThread = new Thread(new Runnable() { @Override public void run() {
dataListenerThreadActive = true; // Just a boolean I can switch to terminate the loop below
String line = bufferedReader.readLine(); if(line != null) {
Log.d("RECEIVED_DATA", line); } } Thread.sleep(10); // Some small delay } catch (IOException | InterruptedException e) {
Handler mainHandler = new Handler(Looper.getMainLooper()); mainHandler.post(new Runnable() { @Override public void run() { Toast.makeText(CurrentContext.get(), "An unresolved problem occured...", Toast.LENGTH_LONG).show(); } });
e.printStackTrace(); dataListenerThreadActive = false; reset(); } } } }); dataListenerThread.start(); } < /code> Я пробовал разные подходы с чтением байто-байтового с .READ (), .aiLable () и т. Д. И они должны работать мгновенно в любом случае, но в конце концов, так как я отправляю строку за линию, что это может решить проблему. Но это не так! По какой-то причине, когда я подключаю приложение к своему HC-05 (устройство Arduino), оно начинает печатать довольно быстро, как в замазке (как я хочу, чтобы оно работало!), Но через 5 секунд, четко работая правильно, у него есть какая-то задержка, затем напечатает 10 строк за один ход, затем задерживается второй или два, затем напечатает 10 или n, а не в непрерывном целом, просто в целом). Это чрезвычайно разочаровывает, так как я не транслирую видео 4K через это, но посылаю абсолютно мелкие данные, которые хорошо работают на Putty. /> Arduino должен постоянно отправлять данные каждые 100 мс и не должен ждать какой-либо команды. /> Обновление: < /strong> Я что -то понял. Во -первых, в первые пару секунд был виновник, когда приложение Android читает все гладко. Это потому, что я не промыл данные за то время, когда Ардуино потратил их через буфер, прежде чем быть подключенным к. Таким образом, промывка просто устраняет иллюзию первых нескольких секунд и удаляет нежелательные данные. Почему? Потому что, когда он получает кусок из 5 строк, тогда ожидает вторую или две секунды для другого чанка, вместо того, чтобы немедленно читать следующую строку, я могу сделать ее прочитать строки каждые 100 мс, а когда он заканчивается, он будет получать следующие 5 или около того строк, и так далее. Линии в моем приложении Android, равные интервалу отправки каждой строки в Arduino, обеспечивает наиболее стабильную регистрацию, но есть проблема. Примерно через 5 минут приложение Android не может не отставать и застряло в чтении более старых данных, в то время как более новая впереди. Это подтверждается, позволив ему читать в течение 5 минут, а затем внезапно отключить мой Arduino, где он будет продолжать читать заполненный буфер на несколько секунд. Это делает это, в то время как входной слушатель просто буферирует данные в очереди. < /p> private static final ConcurrentLinkedQueue dataQueue = new ConcurrentLinkedQueue();
private static void beginInputStreamListener(){
dataListenerThread = new Thread(new Runnable() { @Override public void run() {
try {
while (mmInputStream.available() > 0) { mmInputStream.read(); }
} catch (IOException e) {
e.printStackTrace(); }
dataListenerActive.set(true); byte[] buffer = new byte[1]; // Read ONE byte at a time StringBuilder lineBuffer = new StringBuilder();
while (!Thread.currentThread().isInterrupted() && dataListenerActive.get()) {
try {
int bytesRead = mmInputStream.read(buffer); if (bytesRead > 0) {
char c = (char) buffer[0]; if (c == '\n') {
// Complete line received String line = lineBuffer.toString().trim(); if (!line.isEmpty()) {
// NO Thread.sleep() - hammer the input stream for maximum responsiveness } catch (IOException e) {
e.printStackTrace(); dataListenerActive.set(false); dataProcessorActive.set(false); DisconnectedAbruptly = true; reset(); } } } }); dataListenerThread.setPriority(Thread.MAX_PRIORITY); // Set to maximum priority! dataListenerThread.start(); }
private static void beginDataProcessor() {
dataProcessorThread = new Thread(new Runnable() {
@Override public void run() { dataProcessorActive.set(true);
while (!Thread.currentThread().isInterrupted() && dataProcessorActive.get()) { try {
// Get ONE line from queue String data = dataQueue.poll(); if (data != null) {
Log.d("RD", data); }
// Wait exactly 100ms Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace(); break; } } } }); dataProcessorThread.start(); } [/code] [youtube]S0449ndmcty[/youtube] Это выглядит лучше, но никоим образом я не могу продать истории, как современный смартфон не может обрабатывать небольшие данные в промежутке. Это очень расстраивает, и я уверен, что я не единственный, кто наткнулся на это. Есть еще некоторая задержка. В примере видео интервалы составляют 200 мс для чтения и 230 мс для написания. Выполнение 100/130 дает те же результаты, до 500 мс потери. Мне нужно, чтобы это было так быстро, как могло бы быть. 500 мс для меня слишком медленная, если я должен был заключить свое решение как 500 мс. Это временный обходной путь, но я не принимаю его как окончательное решение, по крайней мере, пока. https://www.dropbox.com/scl/fi/bgwwnniffuafvjttzc/androidtest.zip?rlkey=s4Heegugsyffjgbhe7fqyhl8&st=couw1evw&dl=0/p>