/* СВЕТОДИОДЫ В СЕМИСЕГМЕНТНОМ ИНДИКАТОРЕ БЕГАЮТ ПО КОЛЬЦУ. ПРИМЕНЯЕТСЯ М/СХ 74HC595.
1). ЕСЛИ ВРАЩАЕМ ОСЬ ПОТЕНЦИОМЕТРА НАПРАВО, ТО БЕГАЮТ НАПРАВО.
ЕСЛИ ВРАЩАЕМ НАЛЕВО, ТО БЕГАЮТ НАЛЕВО.
2). ЧЕМ ВЫШЕ СЧИТАННОЕ НАПРЯЖЕНИЕ ПРИ ВРАЩЕНИИ ОСИ НАПРАВО, ТЕМ БЫСТРЕЕ БЕГАЮТ НАПРАВО.
3). ЧЕМ НИЖЕ СЧИТАННОЕ НАПРЯЖЕНИЕ ПРИ ВРАЩЕНИИ НАЛЕВО, ТЕМ МЕДЛЕННЕЕ БЕГАЮТ НАЛЕВО.
4). ЕСЛИ ЗНАЧЕНИЯ ПОЧТИ РАВНЫ (С НЕКОТОРЫМ ДОПУСКОМ), ТО ГОРИТ ОДИН СВЕТОДИОД.
РАБОТАЕТ КРАЙНЕ НЕСТАБИЛЬНО. И ПОБЕДИТЬ ЭТО НЕ УДАЁТСЯ!
*/
#define DATA 8 // данные
#define CLOCK 9 // тактовая частота
#define LATCH 10 // разрешение на параллельный вывод байта с защелки по высокому уровню
#define POT A5 // аналоговый вход Ардуино с потенциометра
#define PERIOD 200 // период чтения значения val (подбирать эмпирически)
#define lower_LIMIT 600 // нижняя граница значения val_NEW, влияет на скорость перемещения включённого светодиода
#define apper_LIMIT 100 // верхняя граница значения val_NEW, влияет на скорость перемещения включённого светодиода
int Digits[]{ 0b00000001, 0b00000010, 0b00000100,
0b00001000, 0b00010000, 0b00100000 }; // массив байтов для включения конкретного светодиода
uint32_t timer = 0; // переменная таймера в функциях вращения
uint32_t timer_read = 0; // переменная таймера для считывания значения val
int val, val_NEW = 0; // переменные значения напряжения на аналоговом входе A5
bool flag = 0; // флаг разрешения/запрета считывания значения val
#define Histerezis 10 // Ширина окна гистерезиса в единицах АЦП
void setup() {
pinMode(DATA, OUTPUT);
pinMode(CLOCK, OUTPUT);
pinMode(LATCH, OUTPUT);
Serial.begin(9600);
}
void loop() {
read_POT();
debug();
}
// Флагом разношу во времени считывание значений val и val_NEW
void read_POT() {
if (flag) { // разрешаем читать значение val_NEW при flag == 1
val_NEW = analogRead(POT); // читаем текущее значение 0....1023
flag = 0; // запрещаем читать значение val_NEW, пока не пройдёт PERIOD и прочитается значение val
}
if (millis() - timer_read >= PERIOD) { // через PERIOD читаем значение val
timer_read = millis();
val = analogRead(POT);
flag = 1; // поднимаем флаг после PERIOD и разрешаем прочитать значение val_NEW
}
if (val_NEW > (val + Histerezis)) // если новое значение больше, чем (предыдущее + гистерезис), то вращаемся направо
{
to_the_Right();
} else if (val_NEW < (val - Histerezis)) // если новое значение больше, чем (предыдущее + гистерезис), то вращаемся налево
{
to_the_Left();
} else { // а если ни то, ни другое, то просто горит светодиод А.
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, MSBFIRST, 0b00000001);
digitalWrite(LATCH, HIGH);
}
}
// функция вращения направо
void to_the_Right() {
val_NEW = map(val_NEW, 0, 1023, lower_LIMIT, apper_LIMIT); // теперь val от lower_LIMIT до apper_LIMIT (для ускорения вращения при перемещении по case)
static int i = 0; // место двоичного числа в массиве Digits
switch (i) {
case 0:
case 1:
case 2:
case 3:
case 4:
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, MSBFIRST, Digits[i]); // старший бит первый
digitalWrite(LATCH, HIGH);
if (millis() - timer >= (uint32_t)val_NEW) { // с ростом val уменьшается период свечения светодиода
digitalWrite(LATCH, LOW);
timer = millis();
shiftOut(DATA, CLOCK, MSBFIRST, 0b00000000); // старший бит первый
digitalWrite(LATCH, HIGH);
i++;
}
break;
case 5:
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, MSBFIRST, Digits[i]); // старший бит первый
digitalWrite(LATCH, HIGH);
if (millis() - timer >= (uint32_t)val_NEW) {
digitalWrite(LATCH, LOW);
timer = millis();
shiftOut(DATA, CLOCK, MSBFIRST, 0b00000000); // старший бит первый
digitalWrite(LATCH, HIGH);
i = 0;
}
break;
}
}
// функция вращения налево
void to_the_Left() {
val_NEW = map(val_NEW, 0, 1023, apper_LIMIT, lower_LIMIT); // теперь val от apper_LIMIT до lower_LIMIT (для замедления вращения при перемещении по case)
static int i = 5; // место двоичного числа в массиве Digits
switch (i) {
case 5:
case 4:
case 3:
case 2:
case 1:
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, MSBFIRST, Digits[i]); // старший бит первый
digitalWrite(LATCH, HIGH);
if (millis() - timer >= (uint32_t)val_NEW) { // с уменьшением val_NEW уменьшается период горения светодиодов при перемещении по case
digitalWrite(LATCH, LOW);
timer = millis();
shiftOut(DATA, CLOCK, MSBFIRST, 0b00000000);
digitalWrite(LATCH, HIGH);
i--;
}
break;
case 0:
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, MSBFIRST, Digits[i]); // старший бит первый
digitalWrite(LATCH, HIGH);
if (millis() - timer >= (uint32_t)val_NEW) {
digitalWrite(LATCH, LOW);
timer = millis();
shiftOut(DATA, CLOCK, MSBFIRST, 0b00000000);
digitalWrite(LATCH, HIGH);
i = 5;
}
break;
}
}
void debug() {
Serial.print("val: ");
Serial.print(val);
Serial.print("\t");
Serial.print("val_NEW: ");
Serial.println(val_NEW);
}