Последовательная связь строк
Я использовал этот простой код, чтобы понять основы последовательной связи. Это обеспечивает простую связь между компьютером и arduino:
String receive_buffer;
void setup() {
Serial.begin(9600);
}
void loop() {
if(Serial.available()>0) //проверка наличия каких-либо полученных данных
{
receive_buffer = Serial.readString(); //read received data
Serial.print("received data is: ");
Serial.println(receive_buffer); //отображение полученных данных
}
}
Это работает. Теперь моей следующей идеей было попытаться связаться между двумя ардуино. Я использовал этот код для приемника arduino.
Отправитель arduino содержит двигатель, оснащенный энкодером, и, используя значение ppr, я вычисляю обороты двигателя. Код для rpm работает отлично. Теперь я хочу передать эти данные получателю.
Проводка: (RX,TX) отправителя, подключенного к (TX,RX) приемника, и GND
становится общим.
А теперь вперед arduino.cc, он говорит, что Serial.write() может иметь строку в качестве входа. Итак, я попробовал ввести значение rpm (которое было int) в строку, а затем отправить эту строку получателю через Serial.write().
float ppr=512.0;
int encpin=3;
volatile long pulsecount=0;
float revs;
float rps;
int rpm;
extern volatile unsigned long timer0_millis;
void setup()
{
pinMode(encpin,INPUT_PULLUP);
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(encpin),function,RISING);
//при обнаружении импульса
//срабатывает прерывание,
//вызывается функция
}
//приращение импульса на одну
void function(){
pulsecount+=1;
}
void loop()
{
revs= pulsecount/ppr ;
if(millis()>=1000)
{
rps= revs;
rpm=rps*60;
pulsecount=0; //сбрасывает pulsecount
String strrpm= (String)rpm;
//Serial.println(rpm);
Serial.write(strrpm);
// Serial.println("string rpm");
//Serial.println(strrpm);
noInterrupts (); //resests millis() to 0
timer0_millis = 0;
interrupts ();
}
}
Однако я получаю ошибку:
43:24: error: no matching function for call to 'HardwareSerial::write(String&)'
Проблема не в типизации. Я попытался просто распечатать strrpm, и это сработало отлично. При попытке Serial.write() с другой и простой строкой, т. е. Serial.write("abcdef");
, он все еще давал ту же ошибку.
Как тогда я должен отправить свое значение strrpm (string rpm) в приемник?
@satan 29, 👍0
1 ответ
Лучший ответ:
Serial.write()
предназначен для отправки двоичных данных. Поэтому, если вы хотите отправить строку с ним, вам нужно предоставить c-строку, а не реализацию Arduino класса String. Это легко сделать с помощью функции-члена этого класса:
Serial.write(strrpm.c_str());
Это успешно компилируется для меня.
Хотя так делать не стоит. Класс String
обычно плохо работает на небольших микроконтроллерах, особенно на микроконтроллерах AVR с малой памятью (например, Uno, Nano, Mega,...), потому что он вызывает фрагментацию памяти (см. Majenkos "The Evils of Arduino Strings").
Вместо этого следует просто использовать соответствующие функции print()
класса Serial. Они сделаны для отправки читаемых человеком строк. Нет необходимости сначала создавать
строковый
объект. Просто сделайте
Serial.println(rpm);
И он будет выполнять само преобразование строк без использования класса String.
Кроме того, у меня есть несколько заметок о вашем коде:
То, как вы используете
функцию millis ()
, немного странно. Нет необходимости на самом деле сбрасывать самозначение millis ()
. Обычно вы держите метку времени в переменной, а затем вычисляете только разницу междуmillis()
и меткой времени. Это также безопасно для переполнения. Вот такunsigned long timestamp = 0; ... if(millis()-timestamp >= 1000){ ... timestamp+=1000; }
Это не использует переменную extern, это не сброс счетчика
millis ()
(который также может быть связан с другими вещами, которые полагаются на него) и является несколько стандартным способом сделать это.Вы используете атомарный раздел для сброса счетчика
millis ()
, но не для доступак pulsecount
. Это на самом деле то место, где вам это абсолютно необходимо.pulsecount
имеет типlong
, поэтому ему потребуется много инструкций для расчетаоборотов
. Процедура обслуживания ваших прерываний может легко испортить данные в этот момент, что приведет к искажению данных. Переместите вычисление в оператор if и используйте атомарный раздел, как со счетчикомmillis ()
, чтобы прочитать его в локальную переменную, тогда вы можете выполнить вычисления. Это сохранит время, когда прерывания выключены очень коротко. Вы также можете - вместо того, чтобы выключать все прерывания, - просто отсоединить прерывание pin на это время, чтобы другие вещи не были затронуты. Вот такой код:void loop(){ if(millis()-timestamp > 1000){ // deactivate our pin interrupt, so it cannot mess with the data detachInterrupt(digitalPinToInterrupt(encpin)); // скопируйте pulsecount в локальную переменную для дальнейшего расчета long local_pulsecount = pulsecount; // повторная активация нашего PIN-прерывания attachInterrupt(digitalPinToInterrupt(encpin),function,RISING); // Сделать расчет и распечатать значение ... timestamp += 1000; } }
- Код не запустится, если Serial Monitor не открыт
- Как скомпилировать программу Arduino для настольного ПК
- Пользовательская реализация assert(): не выводит сообщение об ошибке
- Debug-logging без использования Serial.print и без Wi-Fi
- Как разделить входящую строку?
- Как вывести несколько переменных в строке?
- Как решить проблему «avrdude: stk500_recv(): programmer is not responding»?
- В чем разница между Serial.write и Serial.print? И когда они используются?
"Вместо этого вы должны просто использовать соответствующие функции print() класса Serial. Они созданы для отправки удобочитаемых строк. Нет необходимости сначала создавать строковый объект. Просто сделайте Serial.println(об / мин)" Но я не понимаю, как это заставляет ардуино общаться?, @satan 29
Кроме того, ваше первоначальное предложение: код успешно компилируется и выводит значения на последовательный монитор отправителя: но последовательный монитор получателя пуст, @satan 29
'Serial.println()
уже отправит данные в удобочитаемой для человека форме через serial. Таким образом, это уже общение. Пожалуйста, попробуйте использовать " Serial.readStringUntil('\n')
вместо " Serial.ReadString ()". У последнего есть тайм-аут 1 сек. Поскольку вы отправляете каждую секунду, между каждой передачей менее 1 секунды. Это может привести к тому, что эта функция никогда не выйдет. Предыдущий вызов функции будет считываться только до символа новой строки, который автоматически добавляется функцией `println (), @chrisl