#include <Arduino.h>
#include <string>
#define LED_PIN 39
#define BUTTON_PIN 18
#define CMD_COUNT 4 // Количество комманд сохраняемых в массиве
constexpr unsigned long MAX_MILLIS = ULONG_MAX; // Максимальное значение которо может вернуть millis()
constexpr unsigned long cmd_display_interval = 20000; // Интервал вывода полученных команд
// мощность свечения
int power = 4096;
// буффер для приема сообщений
std::string message = "";
// Массив для храниения полученных команд
std::array<std::string, CMD_COUNT> received_commands;
// индекс в массиве куда будет добавлена текущая команда
size_t current_pos = 0;
bool light_on = false;
/**
* Массив заполняется командами циклически.
* Чтобы каждый раз при добавлении новой команды не сдвигать все предыдущие,
* сохраняем позицию места куда будет добавлена очередная команда.
* Эта позиция (current_pos) может указывать на пустое место, когда с начала работы введено менее CMD_COUNT
* команд, либо на место команды которая будет затерта очередной, добавляемой командой.
*/
void show_commands(void)
{
unsigned long time_current = millis();
size_t first_cmd = current_pos; // Первая команда добавленная в массив, либо пустое место если добавлено менее CMD_COUN команд
Serial.printf(" ***** Last %u commands ( %lu seconds since start) *****\r\n", CMD_COUNT, time_current / 1000);
// Цикл по всему массиву хранимых команд. Когда количество введённых команд меньше CMD_COUN, некоторые итерации будут "вхолостую"
for (size_t i = 0; i < CMD_COUNT; ++i)
{
if ( received_commands[first_cmd].length() > 0)
{
Serial.println( received_commands[first_cmd].c_str() );
}
first_cmd = (first_cmd + 1) % CMD_COUNT;
}
}
void add_commands(std::string s)
{
received_commands[current_pos] = s;
current_pos = (current_pos + 1) % CMD_COUNT;
}
/** Возвращает
* true - Уже прошло time_delay с прошлого вызова is_time_passed()
* false - Ещё не прошло time_delay или более с прошлого вызова is_time_passed()
*/
bool is_time_passed(const unsigned long time_delay)
{
/** Функция millis() возвращает значения от 0 до максимального значения "unsigned long"
*
* Принимаем что время ожидания не может быть больше MAX_MILLIS
*
* ********************************************************************** *
* *** Вычисление времени при "time_current >= time_start" ***
* time_start time_current
* | |
* 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . MAX_MILLIS
* `-----------, .-----------'
* \/
* Время ожидания состоит из одной части - от time_start до time_current
*
* Время ожидания: time_current - time_start
*
* ********************************************************************** *
* *** Вычисление времени при "time_current < time_start" ***
* time_current time_start
* | |
* 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . MAX_MILLIS
* `--, .---' `------, .---------'
* \/ \/
* time_current MAX_MILLIS - time_start
*
* Время ожидания состоит из двух частей:
* 1. часть от time_start до MAX_MILLIS
* 2. часть от 0 до time_current
*
* Время ожидания: (MAX_MILLIS - time_start) + time_current
*
*/
static unsigned long time_start = 0; // Ведём отсчет от времени запуска контроллера
unsigned long time_current = millis(); // Получаем текущее время при каждом вызове is_time_passed()
unsigned long time_waited;
bool return_value;
time_waited = (time_current >= time_start)
? time_current - time_start
: (MAX_MILLIS - time_start) + time_current;
return_value = time_waited >= time_delay;
if ( return_value )
{
time_start = time_current; // сохраняем время вызова
}
return return_value;
}
void setup() {
pinMode(LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLDOWN);
Serial.begin(115200);
// Инициализируем массив полученных комманд
received_commands.fill("");
}
void loop() {
// читаем данные из серийного порта
if (Serial.available() > 0)
{
message = "";
while(Serial.available() > 0)
{
message += std::string(1, char(Serial.read()));
delay(500);
}
power = std::stoi(message);
add_commands(message);
Serial.print("Recieved: power = ");
Serial.println(power);
}
if(digitalRead(BUTTON_PIN) == HIGH)
{
light_on = true;
}
if(light_on == true)
{
light_on = false;
analogWrite(LED_PIN, power);
delay(1000);
}
else{
analogWrite(LED_PIN, 0);
}
if ( is_time_passed(cmd_display_interval) )
{
show_commands();
}
}