#include <Wire.h>
#include <U8g2lib.h>
#include <RTClib.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
// OLED display initialization (SH1107, 128x128)
U8G2_SH1107_128X128_1_HW_I2C u8g2(U8G2_R0);
// RTC initialization
RTC_DS1307 rtc;
// Button pin definition (e.g., GPIO 14)
#define BUTTON_PIN 14
// Queue to communicate time data between tasks
QueueHandle_t timeQueue;
// Structure to hold time data
struct TimeData {
int hours;
int minutes;
int seconds;
};
// Setup function
void setup() {
// Initialize the Serial for Wokwi's serial monitor
Serial.begin(115200);
// Initialize OLED display
if (!u8g2.begin()) {
Serial.println("OLED initialization failed!");
while (1); // Stop further execution if initialization fails
}
u8g2.setContrast(255); // Set display contrast
// Initialize button pin as input
pinMode(BUTTON_PIN, INPUT_PULLUP); // Use internal pull-up resistor
// Initialize RTC module
if (!rtc.begin()) {
Serial.println("RTC initialization failed!");
while (1);
}
if (!rtc.isrunning()) {
Serial.println("RTC is not running, setting the time...");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
// Create a queue to hold time data (size of 10, enough to store time information)
timeQueue = xQueueCreate(10, sizeof(TimeData));
// Create FreeRTOS tasks
xTaskCreate(update_time_task, "Update Time Task", 2048, NULL, 1, NULL);
xTaskCreate(draw_clock_task, "Draw Clock Task", 2048, NULL, 1, NULL);
xTaskCreate(button_press_task, "Button Press Task", 2048, NULL, 1, NULL);
}
// Function to draw the clock background
void draw_clock_background() {
int center_x = 64;
int center_y = 64;
// Draw circle for the clock
u8g2.setDrawColor(1);
u8g2.drawCircle(center_x, center_y, 60, U8G2_DRAW_ALL);
// Draw tick marks and numbers
for (int i = 0; i < 12; i++) {
int xpos = round(center_x + sin(radians(i * 30)) * 54);
int ypos = round(center_y - cos(radians(i * 30)) * 54);
u8g2.setFont(u8g2_font_8x13B_mn);
if (i == 0) u8g2.drawStr(xpos - 5, ypos + 5, "12");
if (i == 3) u8g2.drawStr(xpos - 5, ypos + 5, "3");
if (i == 6) u8g2.drawStr(xpos - 5, ypos + 5, "6");
if (i == 9) u8g2.drawStr(xpos - 5, ypos + 5, "9");
}
}
// Function to draw clock hands
void draw_clock_hands(int hour, int minute, int second) {
int center_x = 64;
int center_y = 64;
// Draw hour hand
int hour_angle = (hour % 12) * 30 + (minute / 2);
int hour_length = 40;
int hour_x = round(center_x + sin(radians(hour_angle)) * hour_length);
int hour_y = round(center_y - cos(radians(hour_angle)) * hour_length);
u8g2.drawLine(center_x, center_y, hour_x, hour_y);
// Draw minute hand
int minute_angle = minute * 6;
int minute_length = 50;
int minute_x = round(center_x + sin(radians(minute_angle)) * minute_length);
int minute_y = round(center_y - cos(radians(minute_angle)) * minute_length);
u8g2.drawLine(center_x, center_y, minute_x, minute_y);
// Draw second hand
int second_angle = second * 6;
int second_length = 60;
int second_x = round(center_x + sin(radians(second_angle)) * second_length);
int second_y = round(center_y - cos(radians(second_angle)) * second_length);
u8g2.drawLine(center_x, center_y, second_x, second_y);
}
// Task to update time from RTC
void update_time_task(void* pvParameters) {
while (true) {
// Fetch the current time from RTC
DateTime now = rtc.now();
// Create a TimeData struct to send the updated time to the queue
TimeData currentTime = {now.hour(), now.minute(), now.second()};
xQueueSend(timeQueue, ¤tTime, portMAX_DELAY);
// Delay for 1 second
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
// Task to draw the clock on the OLED display
void draw_clock_task(void* pvParameters) {
while (true) {
TimeData receivedTime;
// Wait for time data from the queue
if (xQueueReceive(timeQueue, &receivedTime, portMAX_DELAY) == pdTRUE) {
// Draw clock background
u8g2.firstPage();
do {
draw_clock_background(); // Draw background
draw_clock_hands(receivedTime.hours, receivedTime.minutes, receivedTime.seconds); // Draw hands
} while (u8g2.nextPage()); // Continue drawing to the next page
}
// Add a small delay before the next iteration
vTaskDelay(50 / portTICK_PERIOD_MS);
}
}
// Task to handle button press and print time to console
void button_press_task(void* pvParameters) {
static unsigned long lastButtonPressTime = 0;
while (true) {
// Check for button press
if (digitalRead(BUTTON_PIN) == LOW) { // Button is pressed (active low)
unsigned long currentMillis = millis();
// Debounce the button press (e.g., wait 200ms)
if (currentMillis - lastButtonPressTime > 200) {
// Fetch the current time from RTC
DateTime now = rtc.now();
// Send current time to the Wokwi serial monitor
printf("Current time: %02d:%02d:%02d\n", now.hour(), now.minute(), now.second());
lastButtonPressTime = currentMillis;
}
}
vTaskDelay(10 / portTICK_PERIOD_MS); // Delay for a short while to avoid busy-waiting
}
}
// Main loop (not used as tasks run independently)
void loop() {
// Nothing is needed here since tasks are handling the work
}
Loading
grove-oled-sh1107
grove-oled-sh1107