Почему моя задержка становится неточной через одну минуту ? Это заставляет мой сервопривод вибрировать

У меня есть необычная установка для охлаждения моего пива при контролируемой температуре (вы можете найти подробности и фото здесь, если хотите). Входным сигналом моей системы является температура, выходным сигналом - положение сервопривода.

Короче говоря, длинная история

При запуске сервопривод работает достаточно стабильно, но каждый раз после 67 секунд работы сервопривод внезапно начинает вибрировать. У меня есть осциллограф, и я вижу, что после 67 секунд вместо постоянных 2,3 мс длительность импульсов колеблется в небольшом диапазоне, например, между 2,300 и 2,320 мс, и этого диапазона достаточно, чтобы стать проблемой.

Что происходит в возрасте 67 лет ?? Есть ли какой - то перелив ? Я очень озадачен, потому что в целом мой код для pulse очень прост.

У меня возникла проблема с этим кодом, ветвью bs18b20 моего репо. Импульс генерируется в строке 293 с пользовательским кодом.

Больше контекста

Я уже обращался за помощью прямо здесь с моей настройкой. Мы определили, что использование Servo.h наряду с протоколом 1Wire приводит к тому, что прерывания, используемые обеими библиотеками, мешают друг другу, поэтому сервопривод получает неверные значения и тоже вибрирует. В моем последнем комментарии в этой теме я сказал, что проблема была решена, но позже я обнаружил проблему нестабильности сервопривода через некоторое время, как показано выше.

Чтобы преодолеть это, я сменил тактику, заменил свой bs18b20 на lm35, которому не нужен 1Wire, и снова переключился на Servo.h. Это сработало очень хорошо... в моей лаборатории электроники. Но тогда (реальность отстой) Я обнаружил, когда фактически использовал свое устройство на кухне, что иногда температура становится очень неправильной, и я подозреваю, что влажность изменяет показания напряжения моего lm35. И именно поэтому я пытаюсь снова вернуться к своему предыдущему решению с водонепроницаемым bs18b20.

Во время написания этой статьи stackexchange предложила этот поток с очень многообещающим решением, я обязательно попробую это сделать. Тем не менее, ради этого мне все еще интересно узнать, что вызывает мою проблему выше, поэтому я все равно публикую это.

, 👍1

Обсуждение

пожалуйста, добавьте код к вопросу, @jsotola

попробуйте поставить timer_20 = now; в начале блока if, @jsotola

десятичные 67 000 000 микросекунд равны шестнадцатеричным 3FE56C0 ... это очень близко к шестнадцатеричному значению 4000000 ... это может быть некоторый ролловер, но это не имеет никакого смысла, потому что это 27-битное число, @jsotola

Есть ли у вас такая же проблема, если вы используете delayMicroseconds () вместо while (micros () < time_micros)цикл?, @Edgar Bonet

Да @jsotola micros() переполняется примерно через 70 минут, а millis(), я думаю, через 70 000 минут. Так что это не должно быть моей проблемой. Я попробую переместить аффектацию timer_20, вы правы, но я не понимаю, как это может помочь., @Guillaume Deshors

@edgar-bonet Я действительно пробовал это, и проблемы усугубились! Сервопривод работает нестабильно с самого начала., @Guillaume Deshors

@jsotola Я попробовал переместить строку в начале блока if, и она ведет себя точно так же., @Guillaume Deshors

На первый взгляд мне кажется очень подозрительным, что двигатель начинает вибрировать через 67 секунд, что очень близко к 2 ^ 16 = 65536 миллисекунд..., @Sim Son


1 ответ


1

Не вдаваясь в детали вашего кода, похоже, что у вас возникли проблемы с прерываниями. Согласно вашему комментарию, этот простой код дает очень неравномерную длину импульса:

digitalWrite(SERVO_PIN, HIGH);
delayMicroseconds(servo_value*1000);
digitalWrite(SERVO_PIN, LOW);

Функция delayMicroseconds() задерживает на запрошенное время, плюс любое время, затраченное на прерывания. Таким образом, если задержка является непоследовательной во время servo_value не изменяется, это может быть только из-за прерываний. Попытка понять точные симптомы, вероятно, будет довольно сложной, так как пришлось бы копаться в источниках библиотек, которые вы используете, и просматривать каждый ISR там. Тот факт, что версия, затягивающая с micros() начинает плохо себя вести только через некоторое время, вероятно, из-за очень медленного “биения” между синхронизацией вашего сервопривода и синхронизацией прерывания. Тот факт, что импульс иногда длится на 20 мкс дольше, согласуется с тем, что он прерывался на 20 мкс, что для ISR было бы довольно долго, но не безумно долго.

Вместо того, чтобы пытаться детально анализировать, как прерывания мешают вашему сервоприводу, я бы рекомендовал полностью обойти проблему и управлять сервоприводом с помощью ШИМ-сигнала, генерируемого аппаратно. Это дало бы очень постоянную длину импульса, полностью защищенную от прерывания прерываниями. Вы можете достичь разрешения 0,5 мкс с периодом 20 мс, установив таймер 1 на быструю ШИМ и синхронизируя его на частоте 2 МГц, например:

// Настройка таймера 1 для управления сервоприводом
// на выводе OC1A = PB1 = цифровой 9.
void setup_timer()
{
    TCCR1A = 0;           // отменить конфигурацию ядра Arduino
    TCCR1B = 0;           // то же самое
    ICR1   = 40000 - 1;   // период = 20 мс = 40000 тактов таймера
    OCR1A  =  3000 - 1;   // длительность импульса = 1,5 мс = 3000 тактов таймера
    TCCR1A = _BV(COM1A1)  // неинвертирующий ШИМ на OC1A
           | _BV(WGM11);  // режим 14: быстрая ШИМ, TOP = ICR1
    TCCR1B = _BV(WGM12)   // то же самое
           | _BV(WGM13)   // то же самое
           | _BV(CS11);   // тактовая частота @ F_CPU/8 = 2 МГц
}

Затем вы можете изменить длительность импульса, просто записав в OCR1A: запишите на единицу меньше желаемой длительности импульса, в единицах измерения 0,5 мкс.

,

Скорее всего, вы правы, и ваше решение - это то, которое я принял, хотя мне нравится, что некоторые люди из nices сделали уродливую часть, я использовал это: https://learn.adafruit.com/neopixels-and-servos/the-ticoservo-library и это действует как заклинание. Он делает под капотом именно то, что вы предлагаете, статья отличная. Тем не менее, мне бы хотелось понять порог в 67 (на самом деле больше похоже на 66) секунд., @Guillaume Deshors