#include <stdio.h> // Включение стандартной библиотеки ввода/вывода
#include <Arduino_FreeRTOS.h> // Включение библиотеки FreeRTOS для Arduino
#include <semphr.h> // Включение библиотеки для семафоров
// Пины для светодиодов и кнопок
#define WHITE_LED 8 // Пин для белого светодиода
#define GREEN_LED 7 // Пин для зеленого светодиода
#define BLUE_LED 6 // Пин для синего светодиода
#define ON_OFF_BUTTON 5 // Пин для кнопки ВКЛ/ВЫКЛ
#define UP_BUTTON 4 // Пин для кнопки ВВЕРХ
#define DOWN_BUTTON 3 // Пин для кнопки ВНИЗ
// Константы для управления миганием светодиодов
#define MAX_COUNT 5 // Максимальное значение для переменной count
#define MIN_COUNT 0 // Минимальное значение для переменной count
#define FREQ 500 // Частота мигания светодиода
// Размер стека для задачи
#define STACK_SIZE 128 // Размер стека задачи в байтах
// Приоритет задачи (чем ниже число, тем выше приоритет)
#define PRIORITY 2 // Приоритет задач
#define BAUD_RATE 9600 // Скорость обмена данными через последовательный порт
// Время обновления состояния кнопок
#define BUTTON_REFRESH_TIME 100 // Интервал обновления состояния кнопок в миллисекундах
// Время выполнения каждой задачи
#define FIRST_TASK_REC 20 // Время выполнения первой задачи
#define SECOND_TASK_REC 20 // Время выполнения второй задачи
#define THIRD_TASK_REC 1000 // Время выполнения третьей задачи
#define FOURTH_TASK_REC 20 // Время выполнения четвертой задачи
#define IDLE_HOOK_REC 500 // Время выполнения функции обратного вызова в режиме простоя
// Используем count для управления частотой мигания
int count = 0;
void io_init();
void variables_init();
void io_init_function(void);
char read_function(FILE *stream);
char write_function(char ch, FILE *stream);
// Прототипы функций задач
void vFirstTask(void);
void vSecondTask(void);
void vThirdTask(void);
void vFourthTask(void);
void vApplicationIdleHook(void);
// Создание семафоров
SemaphoreHandle_t xButtonSemaphore;
SemaphoreHandle_t xIncButtonSemaphore;
SemaphoreHandle_t xDecButtonSemaphore;
void setup()
{
io_init(); // Инициализация пинов
io_init_function(); // Инициализация функций ввода/вывода
// Создание бинарных семафоров и их инициализация
if (xButtonSemaphore == NULL)
{
xButtonSemaphore = xSemaphoreCreateBinary();
if (xButtonSemaphore != NULL)
{
xSemaphoreGive(xButtonSemaphore);
}
}
if (xIncButtonSemaphore == NULL)
{
xIncButtonSemaphore = xSemaphoreCreateBinary();
if (xIncButtonSemaphore != NULL)
{
xSemaphoreGive(xIncButtonSemaphore);
}
}
if (xDecButtonSemaphore == NULL)
{
xDecButtonSemaphore = xSemaphoreCreateBinary();
if (xDecButtonSemaphore != NULL)
{
xSemaphoreGive(xDecButtonSemaphore);
}
}
// Создание задач
xTaskCreate(vFirstTask, "Button", STACK_SIZE, NULL, PRIORITY, NULL);
xTaskCreate(vSecondTask, "GreenLED", STACK_SIZE, NULL, PRIORITY, NULL);
xTaskCreate(vThirdTask, "BlueLED", STACK_SIZE, NULL, PRIORITY, NULL);
xTaskCreate(vFourthTask, "Inc/Dec", STACK_SIZE, NULL, PRIORITY, NULL);
}
void loop()
{
// Пустой цикл, так как управление задачами осуществляется FreeRTOS
}
void vFirstTask(void)
{
// Переменная для отслеживания относительного времени
TickType_t relativeTime = 0;
while (true)
{
if (!digitalRead(ON_OFF_BUTTON))
{
// Проверка, если прошло достаточно времени с момента последнего обновления
if (relativeTime < xTaskGetTickCount())
{
xSemaphoreGive(xButtonSemaphore); // Освобождение семафора для кнопки ON/OFF
}
relativeTime = xTaskGetTickCount() + pdMS_TO_TICKS(BUTTON_REFRESH_TIME);
}
vTaskDelay(pdMS_TO_TICKS(FIRST_TASK_REC)); // Задержка выполнения задачи
}
}
void vSecondTask(void)
{
while (true)
{
// Попытки взятия бинарного семафора (xButtonSemaphore) в течение определенного времени
if (xSemaphoreTake(xButtonSemaphore, pdMS_TO_TICKS(SECOND_TASK_REC)) == pdTRUE)
{
digitalWrite(GREEN_LED, !digitalRead(GREEN_LED)); // Инверсия состояния зеленого светодиода
digitalWrite(BLUE_LED, LOW); // Выключение синего светодиода
}
}
}
void vThirdTask(void)
{
while (true)
{
if (digitalRead(GREEN_LED) == LOW)
{
digitalWrite(BLUE_LED, !digitalRead(BLUE_LED)); // Инверсия состояния синего светодиода
}
while (count > 0 && digitalRead(GREEN_LED) == HIGH)
{
digitalWrite(WHITE_LED, HIGH); // Включение белого светодиода
vTaskDelay(pdMS_TO_TICKS(FREQ / (count + 1))); // Используется переменная count для управления частотой мигания
digitalWrite(WHITE_LED, LOW); // Выключение белого светодиода
vTaskDelay(pdMS_TO_TICKS(FREQ / (count + 1)));
}
vTaskDelay(pdMS_TO_TICKS(THIRD_TASK_REC)); // Задержка выполнения задачи
}
}
void vFourthTask(void)
{
// Переменная для отслеживания относительного времени
TickType_t relativeTime2 = 0;
while (true)
{
if (!digitalRead(UP_BUTTON)) // Проверка, нажата ли кнопка ВВЕРХ
{
// Если прошло достаточно времени с момента последнего обновления
// и семафор xIncButtonSemaphore доступен, то увеличивается значение переменной count, и семафор освобождается
if (relativeTime2 < xTaskGetTickCount() && xSemaphoreTake(xIncButtonSemaphore, pdMS_TO_TICKS(BUTTON_REFRESH_TIME)) == pdTRUE)
{
if (count < MAX_COUNT)
{
count++; // Увеличение значения count
}
xSemaphoreGive(xIncButtonSemaphore); // Освобождение семафора
}
relativeTime2 = xTaskGetTickCount() + pdMS_TO_TICKS(BUTTON_REFRESH_TIME);
}
if (!digitalRead(DOWN_BUTTON))
{
if (relativeTime2 < xTaskGetTickCount() && xSemaphoreTake(xDecButtonSemaphore, pdMS_TO_TICKS(BUTTON_REFRESH_TIME)) == pdTRUE)
{
if (count > MIN_COUNT)
{
count--; // Уменьшение значения count
}
xSemaphoreGive(xDecButtonSemaphore);
}
relativeTime2 = xTaskGetTickCount() + pdMS_TO_TICKS(BUTTON_REFRESH_TIME);
}
vTaskDelay(pdMS_TO_TICKS(FOURTH_TASK_REC)); // Задержка выполнения задачи
}
}
void vApplicationIdleHook(void)
{
printf("OJIDANIE\n"); // Вывод информации о функции простоя
printf("PERVAIA KNOPKA: %s\n", digitalRead(ON_OFF_BUTTON) ? "NAJATA" : "NENAJATA"); // Вывод состояния кнопки ON/OFF
printf("ZELENII LED: %s\n", digitalRead(GREEN_LED) ? "ON" : "OFF"); // Вывод состояния зеленого светодиода
printf("SINII LED: %s\n", digitalRead(BLUE_LED) ? "ON" : "OFF"); // Вывод состояния синего светодиода
printf("4ASTOTA: %i\n", count); // Вывод значения переменной count
printf("\n"); // Пустая строка для разделения вывода
printf("\n"); // Пустая строка для разделения вывода
printf("\n"); // Пустая строка для разделения вывода
}
void io_init()
{
pinMode(GREEN_LED, OUTPUT); // Настройка пина зеленого светодиода как выход
pinMode(BLUE_LED, OUTPUT); // Настройка пина синего светодиода как выход
pinMode(WHITE_LED, OUTPUT); // Настройка пина белого светодиода как выход
pinMode(ON_OFF_BUTTON, INPUT_PULLUP); // Настройка пина кнопки ON/OFF как вход с подтяжкой к питанию
pinMode(UP_BUTTON, INPUT_PULLUP); // Настройка пина кнопки ВВЕРХ как вход с подтяжкой к питанию
pinMode(DOWN_BUTTON, INPUT_PULLUP); // Настройка пина кнопки ВНИЗ как вход с подтяжкой к питанию
}
void io_init_function(void)
{
Serial.begin(BAUD_RATE); // Инициализация последовательного порта с указанной скоростью обмена данными
static FILE stream = {};
// Настройка потока ввода/вывода
fdev_setup_stream(&stream, write_function, read_function, _FDEV_SETUP_RW);
// Установка потока ввода/вывода для стандартных потоков ввода/вывода
stdin = &stream;
stdout = &stream;
}
char read_function(FILE *stream)
{
while (!(Serial.available() > 0)); // Ожидание доступных данных в последовательном порту
return Serial.read(); // Считывание и возврат доступных данных
}
char write_function(char ch, FILE *stream)
{
Serial.write(ch); // Отправка данных в последовательный порт
return 0; // Возврат нуля
}