Библиотека Protothread останавливается на одном потоке
Я пытаюсь использовать библиотеку protothreading, найденную здесь
http://harteware.blogspot.com/2010/11/protothread-powerfull-library.html
для выполнения protothreading с моим Arduino, чтобы я мог «одновременно» считывать данные со входа чипа Bluetooth HC-05 для получения информации с главного компьютера, к которому я подключен по Bluetooth, а также обрабатывать и передавать данные с датчиков по Bluetooth.
Мой код выглядит так
/*
Этот модуль использует чип L293D для модуляции и питания
два двигателя постоянного тока, управляющие колесами FryeBot
*/
#include <Time-1.5.0\Time.h>
#include <WiShield\pt.h>
/*L293D INPUT 7*/
const int YELLOW_GEAR_MOTOR_BACK = 8;
/*L293D INPUT 2*/
const int YELLOW_GEAR_MOTOR_FORWARD = 9;
/*L293D INPUT 10*/
const int RED_GEAR_MOTOR_BACK = 10;
/*L293D INPUT 15*/
const int RED_GEAR_MOTOR_FORWARD = 11;
/*
Establish ratio os the rate of the faster slower gear
to the faster gear to scale the duty cycle of the
faster gear
*/
const float RED_GEAR_SPEED_TO_YELLOW = 0.97;
/*Constant for full duty cycle for analogWrite*/
const int FULL_ANALOG_MOTOR_SPEED = 255;
/* HC05 Setup Data */
const int pingPin = 7;
const int HC05PowerPin = 2;
/* Distance data */
long duration, cm;
/* Values for Bluetooth RX/TX */
char buf[25];
char current;
String messageHolder;
String message;
/* Protothreads */
static struct pt pt1, pt2;
void setup() {
Serial.begin(9600);
Serial1.begin(9600);
/* add setup code here */
pinMode(YELLOW_GEAR_MOTOR_FORWARD, OUTPUT);
pinMode(YELLOW_GEAR_MOTOR_BACK, OUTPUT);
pinMode(RED_GEAR_MOTOR_BACK, OUTPUT);
pinMode(RED_GEAR_MOTOR_FORWARD, OUTPUT);
pinMode(HC05PowerPin, OUTPUT);
PT_INIT(&pt1);
PT_INIT(&pt2);
}
static int protothreadCollectAndTransmitData(struct pt* pt, int interval) {
static unsigned long timestamp = 0;
PT_BEGIN(pt);
while (1) {
collectAndTransmitData();
PT_WAIT_UNTIL(pt, millis() - timestamp > interval);
}
PT_END(pt);
}
void collectAndTransmitData() {
digitalWrite(HC05PowerPin, HIGH);
pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(5);
digitalWrite(pingPin, LOW);
pinMode(pingPin, INPUT);
duration = pulseIn(pingPin, HIGH);
cm = microsecondsToCentimeters(duration);
Serial.print("TX: ");
Serial.print(cm);
Serial.println();
if (message.indexOf("G") > 0) {
analogWrite(YELLOW_GEAR_MOTOR_FORWARD, (int)(RED_GEAR_SPEED_TO_YELLOW * (float)FULL_ANALOG_MOTOR_SPEED));
digitalWrite(YELLOW_GEAR_MOTOR_BACK, LOW);
digitalWrite(RED_GEAR_MOTOR_BACK, LOW);
digitalWrite(RED_GEAR_MOTOR_FORWARD, HIGH);
}
else if (message.indexOf("S") > 0) {
digitalWrite(YELLOW_GEAR_MOTOR_FORWARD, 0);
digitalWrite(YELLOW_GEAR_MOTOR_BACK, LOW);
digitalWrite(RED_GEAR_MOTOR_BACK, LOW);
digitalWrite(RED_GEAR_MOTOR_FORWARD, LOW);
}
/* Load the distance value into a buffer */
String sendValue = String(cm);
sendValue.toCharArray(buf, sizeof(buf));
/* Write the buffer with a space after for parsing*/
Serial1.write(buf);
Serial1.write(' ');
}
long microsecondsToCentimeters(long microseconds) {
// The speed of sound is 340 m/s or 29 microseconds per centimeter.
// The ping travels out and back, so to find the distance of the
// object we take half of the distance travelled.
return microseconds / 29 / 2;
}
static int protothreadReadAndParseData(struct pt* pt, int interval) {
static unsigned long timestamp = 0;
PT_BEGIN(pt);
while (1) {
readAndParseData();
PT_WAIT_UNTIL(pt, millis() - timestamp > interval);
}
PT_END(pt);
}
void readAndParseData() {
Serial.println("HERE");
current = Serial1.read();
Serial.print("RX: ");
Serial.print(current);
Serial.println();
if (current == ' ') {
message = messageHolder;
messageHolder = "";
Serial.print("message: ");
Serial.print(message);
Serial.println();
}
else {
messageHolder += current;
}
}
void loop() {
Serial.println("A");
protothreadReadAndParseData(&pt2, 20); // by calling them infinitely
Serial.println("B");
protothreadCollectAndTransmitData(&pt1, 20); // schedule the two protothreads
}
При выполнении код выводит на консоль следующее.
A
HERE
RX: �
B
TX: 522
TX: 524
TX: 524
TX: 524
TX: 524
TX: 524
Затем продолжается TX: ### навсегда.
Я не уверен, почему код не возвращается к первой функции или хотя бы не запускает ее во второй раз. Я не совсем понимаю, как именно использовать эту библиотеку или кто ее поддерживает. Документация на их странице Github для библиотеки WiShield, частью которой является этот pt.h, не слишком полезна. Если у вас есть опыт работы с другими библиотеками Arduino protothreading, дайте мне знать, чтобы я мог попробовать их. Я не уверен, где я ошибся с этой библиотекой в своей реализации.
Вот репозиторий, содержащий пакет, который я использую
https://github.com/nicolaskruchten/arduino/tree/master/libraries/WiShield
@Jack Frye, 👍1
1 ответ
В protothreadCollectAndTransmitData есть переменная timestamp, которая никогда не обновляется:
static int protothreadCollectAndTransmitData(struct pt* pt, int interval) {
static unsigned long timestamp = 0; // <- Это никогда не меняется
....
Когда условие истинно, вам нужно будет обновить timestamp = millis();.
static int protothreadCollectAndTransmitData(struct pt* pt, int interval) {
static unsigned long timestamp = 0;
PT_BEGIN(pt);
while (1) {
PT_WAIT_UNTIL(pt, millis() - timestamp > interval);
// Обновлено. Переместите это сюда, иначе оно ВСЕГДА будет вызываться!
collectAndTransmitData();
timestamp = millis(); // <- Обновить временную метку для следующего раза
}
PT_END(pt);
}
Но чтобы убедиться, что это правильно, вам следует взглянуть на макрос:
#define PT_WAIT_UNTIL(pt, condition) \
do { \
LC_SET((pt)->lc); \
if(!(condition)) { \
return PT_WAITING; \
} \
} while(0)
(Вы можете игнорировать do/while — он там только для того, чтобы вы могли использовать точку с запятой.) Как видите, когда условие false, выдается return. Так что, похоже, делать это таким образом безопасно.
Отказ от ответственности: я никогда не использовал эту потоковую библиотеку. Я работаю с исходным кодом, который нашел здесь: https://github.com/fernandomalmeida/protothreads-arduino/blob/master/pt.h
- Модуль HC-05 не получает команд и не спаривается
- Обеспечиваем более быстрое и точное обнаружение MindWave Mobile
- Код CRC8 не работает должным образом
- Какие накладные расходы и другие соображения существуют при использовании структуры по сравнению с классом?
- Что лучше использовать: #define или const int для констант?
- Функции со строковыми параметрами
- Как работать с аналоговыми контактами в цикле?
- Проблемы с надежным подключением с использованием HC-05 в качестве ведущего устройства Bluetooth
Если бы вам пришлось угадывать, какой аргумент миллисекунды вы бы передали в функции loop() для оптимизации производительности каждого потока? У меня скорость последовательного порта 9600 бод, поэтому, думаю, имеет смысл попробовать установить значение 1. Похоже, что после этого он хочет запустить только этот поток. Другой, работающий с частотой 20 мс, почти не трогает., @Jack Frye
работает ли эта библиотека с ардуино?, @Jack Frye
Похоже, я ошибся ссылкой. Обновил, похоже, для порта Arduino., @Johnny Mopp
Тайм-аут для
collectAndTransmitDataдолжен соответствовать вашей частоте дискретизации. Как часто нужно проверять датчик? ДляreadAndParseData()я бы добавилif (!Serial.available()) return;в первую строку, чтобы функция не запускалась, пока не появится сообщение., @Johnny MoppПохоже, он будет работать только один поток какое-то время, а затем переключится. Попробую вашу библиотеку., @Jack Frye
глядя на это, я думаю, что это другой источник, но тот же файл, @Jack Frye
он все еще просто передает, @Jack Frye
О, я только что заметил, что
collectAndTransmitData();должно идти _после_PT_WAIT_UNTIL(....)., @Johnny MoppДавайте [продолжим это обсуждение в чате](http://chat.stackexchange.com/rooms/65663/discussion-between-jack-frye-and-johnny-mopp)., @Jack Frye