Как добавить гистерезис к пороговым значениям?
Этот код сравнивает аналоговое входное значение с двумя порогами, имеющими три области напряжения. Затем он включит светодиод в соответствии с областью, в которой находится считанное напряжение.
Проблема в том, что когда измеренное напряжение очень близко к пороговому значению, шум будет мешать выходу, что приведет к неконтролируемому переключению между светодиодами.
Мне нужно было бы добавить что-то вроде ГИСТЕРЕЗИСА вокруг моих порогов, чтобы избежать неконтролируемого переключения, но я понятия не имею, как это записать на языке кода. Может ли кто-нибудь помочь мне написать бит порога?
Вот полный код:
// эти константы не изменятся:
const int BatteryVoltagePin = 14; // контакт, к которому подключено напряжение батареи
const int GreenLedPin = 3; // контакт, к которому подключен зеленый светодиод (на зарядке)
const int OrangeLedPin = 4; // контакт, к которому подключен оранжевый светодиод (без риска)
const int RedLedPin = 5; // контакт, к которому подключен красный светодиод (низкий заряд батареи)
// Переменные изменятся:
int currentVoltage ; // текущее значение напряжения
int previousVoltage ; // предыдущее значение напряжения
void setup() {
// инициализируем вывод напряжения батареи как вход:
pinMode(BatteryVoltagePin, INPUT);
// инициализируем зеленый светодиод как выход:
pinMode(GreenLedPin, OUTPUT);
// инициализируем оранжевый светодиод как выход:
pinMode(OrangeLedPin, OUTPUT);
// инициализируем красный светодиод как выход:
pinMode(RedLedPin, OUTPUT);
}
void loop() {
// считываем напряжение на выводе напряжения батареи:
currentVoltage = digitalRead(BatteryVoltagePin);
// сравнить текущее значение напряжения с предыдущим значением
if (currentVoltage != previousVoltage)
delay(10);
// значение выше максимального порога
{
if ((( ( analogRead(BatteryVoltagePin) ) > ( 699 ) ))
{
digitalWrite(GreenLedPin, HIGH);
}
else
{
digitalWrite(GreenLedPin, LOW );
}
}
//значение между двумя порогами (средняя область)
{
if (( ( ( analogRead(BatteryVoltagePin) ) <= ( 699 ) ) && ( ( analogRead(BatteryVoltagePin) ) >= ( 628 ) ) ))
{
digitalWrite(OrangeLedPin, HIGH );
}
else
{
digitalWrite(OrangeLedPin, LOW );
}
}
// значение ниже минимального порога
{
if (( ( analogRead(BatteryVoltagePin) ) < ( 628 ) ))
{
digitalWrite(RedLedPin, HIGH);
}
else
{
digitalWrite(RedLedPin, LOW );
}
}
// сохранить текущее состояние как последнее состояние,
//для следующего раза в цикле
previousVoltage = currentVoltage;
}
@Andy, 👍7
4 ответа
Добавить поведение гистерезиса в ваш код несложно. Вам просто нужно сохранить состояние, в котором вы находитесь, и сделать пороги перехода в другое состояние зависимыми от этого.
Вы можете использовать перечисление для хранения состояния:
enum BatteryStates {
Red, Orange, Green
};
Затем вместо определения и проверки одного порогового значения определите два пороговых значения для каждого перехода, разнесенных на такое расстояние, чтобы не наблюдать нежелательного поведения переключения.
Например, при переходе от зеленого к оранжевому вы можете сделать что-то вроде этого:
if ((state == Green) && (battery < 690))
state = Orange;
А в другом направлении будет использоваться немного более высокий порог
if ((state == Orange) && (battery > 700))
state = Green;
чтобы небольшие колебания напряжения не вызывали переворотов.
(Обратите внимание, что мой код предполагает
int battery = analogRead(BatteryVoltagePin);
Переменная state
должна быть объявлена и инициализирована следующим образом:
enum BatteryStates state = Green;
Вместо enum
вы можете использовать простое int
и сопоставить каждое состояние с числом (например, красный = 1, оранжевый = 2, зеленый = 3), но использование enum
упрощает чтение и написание кода. (На самом деле enum
использует целые числа.)
Я также мог бы использовать оператор switch
вместо цепочки if
для реализации переходов, но это дело вкуса.)
Это включает гистерезис и использует некоторые циклы и массивы для упрощения и сжатия кода, поскольку логика для каждого диапазона по сути та же самая. Больше диапазонов легко включить, расширив массивы Cutoffs и LedPins (на один светодиод больше, чем cutoff).
const int VoltagePin = 14;
const int Cutoffs[] = { 628 , 699 };
const int NumCutoffs = sizeof(Cutoffs)/sizeof(int);
const int Hysteresis = 5;
const int LedPins[NumCutoffs+1] = {5,4,3};
int Level = 0;
int Voltage = 0;
void setup()
{
for (int i=0; i<=NumCutoffs; ++i) {
pinMode(LedPins[i],OUTPUT);
}
}
void loop()
{
Voltage = analogRead(VoltagePin);
while (Level < NumCutoffs && Voltage >= Cutoffs[Level]) {
++Level;
}
while (Level > 0 && Voltage < Cutoffs[Level-1] - Hysteresis) {
--Level;
}
for (int i=0; i<=NumCutoffs; ++i) {
digitalWrite(LedPins[i], i == Level);
}
delay(20);
}
Вот что я делаю. Я определяю, растет или падает напряжение, и на основе этого регулирую порог.
int ledPin = 13; //контакт 13 будет подключен к реле MOSFET SS
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
}
void loop() {
int sensorValue = analogRead(A0); // Это датчик напряжения основного аккумулятора
int RLA1; //это будет подключено к реле MOSFET SS
float threshold; // Чтобы включить некоторый гистерезис и предотвратить дребезжание реле, мы перемещаем порог в зависимости от того, идем ли мы вверх или вниз
float Vmainold; // Используется для определения того, идем ли мы вверх или вниз
float Vmain; // Напряжение основного аккумулятора.
float Vaux; // Напряжение вспомогательной батареи
Vmain = sensorValue / 204.6 + 9.8; // Добавьте обратно ~10 В, которые сдвигает стабилитрон для более высокого разрешения
if (Vmain > Vmainold) threshold = 13.2; // Если напряжение растет, устанавливаем порог 13.2
else
if (Vmain < Vmainold) && (Vmainold > 12.8) threshold = 12.8 // Если напряжение падает и предыдущее напряжение выше TH, установить theshhold на 12.8
else
if (Vmain = Vmainold) threshold = 13.2; // Если напряжение стабильно, устанавливаем порог 13.2
if (Vmain >= threshold) RLA1 = 1; // Зарядка
else
if (Vmain < threshold) { RLA1 = 0; Vmainold = Vmain; } // Не подключено
delay(1000);
Serial.print(Vmain);
Serial.print(" Main ");
Serial.print(Vmainold);
Serial.print(" old ");
Serial.println();
Vmainold = Vmain;
digitalWrite(ledPin, RLA1);
}
`
Государственная машина — это надежный подход.
Для этого простого случая вы также можете решить эту проблему, реализовав небольшие мертвые зоны вокруг уровней изменения. Когда значение находится в диапазоне около порога перехода, ничего не делайте. Только когда значение определенно выше или ниже перехода, вносите изменения. Ваш код будет таким:
// Переменные будут изменены:
int currentVoltage = 0; // текущее значение напряжения
int previousVoltage = 0; // предыдущее значение напряжения
void loop() {
int deadband = 5;
// в самом первом цикле, начать без мертвой зоны
// это необходимо в случае, если пусковое напряжение находится в
// середина диапазона перехода
if (0 == previousVoltage) {
deadband = 0;
}
// считываем напряжение на выводе напряжения батареи:
currentVoltage = analogRead(BatteryVoltagePin);
// проверить напряжение по трем диапазонам
// значение выше максимального порога
if ((699+deadband) < currentVoltage) {
digitalWrite(GreenLedPin, HIGH);
digitalWrite(OrangeLedPin, LOW );
digitalWrite(RedLedPin, LOW );
}
//значение между двумя порогами (средняя область)
if (((628+deadband) < currentVoltage) && (currentVoltage <= (699-deadband))) {
digitalWrite(GreenLedPin, LOW);
digitalWrite(OrangeLedPin, HIGH);
digitalWrite(RedLedPin, LOW);
}
// значение ниже минимального порога
if (currentVoltage < (628-deadband)) {
digitalWrite(GreenLedPin, LOW);
digitalWrite(OrangeLedPin, LOW );
digitalWrite(RedLedPin, HIGH);
}
// Обратите внимание, что на данный момент ни один из случаев if, описанных выше, не выполняется.
// может быть правдой. Когда напряжение находится прямо около
// пороги, ничего не делать. Только когда напряжение окончательно
// в этом диапазоне изменяется состояние светодиода.
// сохранить текущее состояние как последнее состояние,
//для следующего раза в цикле
previousVoltage = currentVoltage;
delay(10);
return;
}
Функционально это даст тот же результат, что и гистерезис.
- Реализовать связь Visible Light с помощью Arduino
- Скетч мигания ESP8266 не мигает светодиодом
- Использование Arduino в качестве автономного компилятора
- Отправка аналоговых входных данных из последовательного порта в Google Таблицы
- Как запрограммировать nodeMCU через OTA с помощью GPRS?
- Декодирование порта VGA с помощью Arduino
- Что касается обхода PGA в ADS1262
- Новый код приводит к звуковому шуму