/* --------------------------------------------------------------
Application: 06 - Rev1
Release Type: Use of Memory Based Task Communication
Class: Real Time Systems - Su 2025
Author: Ethan Baker
AI Use: Please commented inline where you use(d) AI
---------------------------------------------------------------*/
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/semphr.h>
#include <driver/gpio.h>
#include <driver/adc.h>
#include <esp_log.h>
#include <I2Cdev.h>
#include <Adafruit_SSD1306.h>
#include <Wire.h>
#include <notes.h>
#include <Servo.h>
#define
#define SpeakerPin 19
#define POT_ADC_CHANNEL ADC1_CHANNEL_6 // GPIO34
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Handles for semaphores and mutex - you'll initialize these in the main program
SemaphoreHandle_t xButtonSem;
SemaphoreHandle_t print_mutex;
SemaphoreHandle_t oled_mutex;
//Create the servo
Servo metronome;
// Queue for sending values to be displayed
QueueHandle_t valueQueue;
#define MAX_COUNT_SEM 1
void displayBPM(void *pvParameters) {
while (1) {
BaseType_t recieveFlag;
double BPM = 0;
recieveFlag = xQueueReceive(valueQueue, &BPM, 0); //recieve values from the queue
if (recieveFlag == pdPASS) {//if the queue has sent values then allow display of them
Serial.println("Sensor Value: %d", recieveVals);
display.clearDisplay();
display.setCursor(20,10);
display.println(int(ceil(BPM)));
display.display();
vTaskDelay(pdMS_TO_TICKS(100));
}
}
}
void playSpeaker(void *pvParameters) {
while (1) {
BaseType_t recieveFlag;
double BPM = 0;
double BPMs = 0;
recieveFlag = xQueueReceive(valueQueue, &BPM, 0); //recieve values from the queue
if (recieveFlag == pdPASS) {//if the queue has sent values then allow display of them
BPMs = BPM/60000
vTaskDelay(pdMS_TO_TICKS(BPM));
}
}
}
void moveMetronome(void *pvParameters){
while(1){
BaseType_t recieveFlag;
double BPM = 0;
double BPMs = 0;
if (recieveFlag == pdPASS) {//if the queue has sent values then allow display of them
BPMs = BPM/60000
vTaskDelay(pdMS_TO_TICKS(BPM));
}
}
}
void readDial(void *pvParameters) {
BaseType_t sendFlag;
while (1) {
double dialVal = adc1_get_raw(POT_ADC_CHANNEL);
//printf("%d\n",val);
bpm = ((dialVal/4095)*140) + 40;
sendFlag = xQueueSendToBack(valueQueue, &val, portMAX_DELAY);
xSemaphoreTake(print_mutex,portMAX_DELAY);
Serial.println("BPM: %d", val);
xSemaphoreGive(print_mutex);
vTaskDelay(pdMS_TO_TICKS(20));
}
}
void setup() {
Serial.begin(9600);
metronome.attach(3);
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println("SSD1306 allocation failed");
for (;;); // Don't proceed, loop forever
}
display.clearDisplay();
display.setTextSize(5);
display.setTextColor(SSD1306_WHITE);
display.setCursor(20,0);
display.println(ceil(bpm));
display.display();
//ADC Config
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(POT_ADC_CHANNEL, ADC_ATTEN_DB_11);
//Declaring semaphores
xButtonSem = xSemaphoreCreateBinary();
print_mutex = xSemaphoreCreateMutex();
oled_mutex = xSemaphoreCreateMutex();
//Queue creation
valueQueue = xQueueCreate(1,sizeof(double)); //reduce the queue size to only send the most recent data
//Task declarations
xTaskCreate(readDial, "sensor", 2048, NULL, 3, NULL); //hard task
xTaskCreate(playSpeaker, "play at bpm", 2048, NULL, 4, NULL); //soft task
xTaskCreate(moveMetronome, "Swing metornome", 2048, NULL, 1, NULL);//hard task
xTaskCreate(displayBPM, "Display", 2048, NULL, 2, NULL); //soft task
}
void loop(){}