Зачем вы это делаете, мне не понятно. И целесообразность такого подхода сомнительна. Но если делаете так, то надо учитывать, что Servo для своей работы использует Таймер 1, использовать его для других целей, или (и) менять его настройки через регистры можно только полностью разобравшись в в работе Servo и таймера. Если у вас свободен Timer 2, то можно использовать его.
В контроллере может быть запущено только одно прерывание одновременно. Из этого следует, что в прерывании других прерываний использовать нельзя. И нельзя запускать операции, использующие прерывания. А печать в порт оператором Serial.print() как раз-таки использует. Поэтому ваша программа виснет.
Я не знаю точно, используются ли прерывания при работе Серво, если да - то тогда и серво запускать в прерывании нельзя.
Почему вы не хотите делать через миллис?
Еще как используются, старинная проблема что SoftwareSerial на AVR выдерживая паузы через холостые циклы с запретом прерываний вызывает нешуточные подёргивания механики из-за пропуска прерываний.
Да я конда приду домой так и сделаю, скорее всего вы правы, нельзя менять настройки регистров таймера 1 при использовании servo.
Ладно, либо у меня руки кривые, либо сервопривод за ночь успел очухаться, но у меня все заработало на millis().вот код, если кому надо
#include <Wire.h>
#include <VL53L1X.h>
#include <QMC5883LCompass.h>
#include <Servo.h>
#define I2C_FREQ 400000
#define NUM_VLS 2
#define DISTANCE_BETWEEN_VLS 14 // mm
#define SERVO_PIN 4
QMC5883LCompass compass;
Servo servo;
const uint8_t xshut_pins[NUM_VLS] = {2, 3};
VL53L1X sensors[NUM_VLS];
uint16_t read_distance();
uint16_t get_heading_degrees();
int8_t servo_speed = 1;
uint8_t servo_pos = 0;
uint16_t distance = 0, heading_degrees = 0;
void setup() {
while (!Serial) {}
Serial.begin(115200);
servo.attach(SERVO_PIN);
servo.write(0);
Wire.begin();
Wire.setClock(I2C_FREQ);
for (uint8_t i = 0; i < NUM_VLS; i++)
{
pinMode(xshut_pins[i], OUTPUT);
digitalWrite(xshut_pins[i], LOW);
}
for (uint8_t i = 0; i < NUM_VLS; i++)
{
pinMode(xshut_pins[i], INPUT);
delay(10);
sensors[i].setTimeout(500);
if (!sensors[i].init())
{
Serial.print("Failed to detect and initialize sensor ");
Serial.println(i);
while (1);
}
sensors[i].setAddress(0x2A + i);
sensors[i].startContinuous(50);
compass.init();
}
}
// с ардуино на пк
// 0 - угол сервы
// 1 - дистанция
// 2 - угол относительно севера
void loop() {
static uint32_t timer = 0;
if (millis() - timer >= 10) {
timer = millis();
servo.write(servo_pos);
servo_pos += servo_speed;
distance = read_distance();
heading_degrees = get_heading_degrees();
if (servo_pos == 180) servo_speed *= -1;
if(servo_pos == 0) servo_speed *= -1;
//Serial.print('0');
Serial.print(servo_pos);
Serial.print(' ');
//Serial.print('1');
Serial.print(distance);
Serial.print(' ');
//Serial.print('2');
Serial.println(heading_degrees);
}
}
uint16_t read_distance() {
static uint16_t distance;
for (uint8_t i = 0; i < NUM_VLS; i++)
{
distance += sensors[i].read();
if (sensors[i].timeoutOccurred()) {
Serial.print(" TIMEOUT");
}
}
return distance + DISTANCE_BETWEEN_VLS;
}
uint16_t get_heading_degrees() {
int x, y;
compass.read();
x = compass.getX();
y = compass.getY();
float heading_degrees = atan2(x, y) / 0.0174532925;
if (heading_degrees < 0) heading_degrees += 360;
heading_degrees = 360 - heading_degrees;
return heading_degrees;
}```
Строчку 25 лучше убрать. Во-первых, она на АВР не особо и нужна, а во-вторых она у вас стоит не там, где надо.
Что касается цикла миллис - вы уверены, что операторы с 63 по 81 строку - успеют выполнится за 10 миллисекунд?
с ожиданием serial я решу, а вот эти операторы успеют обработаться, при мне только что всё заработало.
ну как хотите.
Просто так, как у вас сейчас написано, условие
совершенно лишнее.
Его и всю работу с миллис можно смело выкинуть - ничего не изменится
то есть вы хотите сказать что мне таймер на миллис вообще не нужен в этом случае?
Да, вашем коде он лишний.
loop() это и так цикл.
Там нет ожидания, объект Serial
создан без вашего участия и не равен нулю уже при старте ардуины, поэтому эта строка реально не имеет смысла
а если будет не один а два сервопривода то миллис уже нужен?
Если сервоприводы будут работать последовательно - ну вот например так, как у вас сейчас опрашиваются два датчика - то не нужен.
А если вы захотите, чтобы сервы работали одновременно, то для каждого нужен свой цикл миллис.
А на каком-нибудь 2560 или 32u4 имеет смысл ставить ожидание? просто из всяких примеров библиотек для чипов с аппаратным сериал пишется такая строчка.
понял
Это зависит от грамотности авторов библиотеки.
обратите внимание, где эта строчка стоит, когда она есть - после Serial.begin()
. А у вас до.
Ждать чего-то, пока Сериал еще не инициализирован - как-то странно.
Вот мануал
Точно.
На esp как-то пытался понять, почему если МК воткнуть в комп, все работает, а если в розетку, ничего не работает. Оказалось, из-за while(!Serial);
Ну да, ты же не смодешь общаться с розеткой по серал)