/*
Use of MAX72XX, DS1307 and DTH22 components to
print some information on the display.
for more examples:
https://github.com/MajicDesigns/MD_Parola/tree/main/examples
https://github.com/MajicDesigns/MD_MAX72XX/tree/main/examples
*/
// Header file includes
#include <Wire.h>
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <RTClib.h>
#include <DHT.h>
#include <SPI.h>
#include <Ticker.h>
#include "Font.h"
#define WIFI_SSID "Wokwi-GUEST"
#define WIFI_PASS ""
#define NTP_SERVER "time.nist.gov" // "pool.ntp.org"
#define UTC_OFFSET 7 * 3600 //ตั้งค่า TimeZone ตามเวลาประเทศไทย
#define UTC_OFFSET_DST 0 //กำหนดค่า Date Swing Time
// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW
#define MAX_ZONES 3
#define ZONE_SIZE 4
#define MAX_DEVICES (MAX_ZONES * ZONE_SIZE)
#define CLK_PIN 18 // CLK or SCK
#define DATA_PIN 23 // DATA or MOSI
#define CS_PIN 5 // CS or SS
#define SPEED_TIME 75 // Speed of the transition
#define PAUSE_TIME 0
// These are for the clock
#define DS1307_ADDRESS 0x68
// These are for the temperature
#define DHTPIN 12
#define DHTTYPE DHT22
#define TIMEDHT 1000
// Global variables
uint16_t year;
uint8_t wday, mday, month;
uint8_t hours, minutes, seconds;
#define MAX_MESG 100
char szTime[30 + 1] = ""; // mm:ss\0
char szMsgH[30 + 1] = "";
char szMesg[MAX_MESG + 1] = "";
float humidity, celsius, fahrenheit;
uint8_t degC[] = { 6, 3, 3, 56, 68, 68, 68 }; // Deg C
uint8_t degF[] = { 6, 3, 3, 124, 20, 20, 4 }; // Deg F
uint8_t clear = 0x00;
uint32_t timerDHT = TIMEDHT;
DHT dht(DHTPIN, DHTTYPE);
// Hardware SPI connection
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
RTC_DS1307 rtc;
void beginDS1307()
{
DateTime now = rtc.now();
seconds = now.second();
minutes = now.minute();
hours = now.hour();
wday = now.dayOfTheWeek();
mday = now.day();
month = now.month();
year = now.year();
}
uint8_t decToBcd(uint8_t value)
{
return ((value / 10 * 16) + (value % 10));
}
uint8_t bcdToDec(uint8_t value)
{
return ((value / 16 * 10) + (value % 16));
}
// Code for reading clock time
void getTime(char *psz, bool f = true)
{
sprintf(psz, "%d%c%02d", hours, (f ? ':' : ' '), minutes);
}
// Code for reading clock date
void getDate(char *psz)
{
char szBuf[10];
sprintf(psz, "%d %s %04d", mday, mon2str(month, szBuf, sizeof(szBuf) - 1), (year));
//sprintf(psz, "%02d/%02d/%04d", mday, month, year);
}
// Code for get Temperature
void getTemperature()
{
// Wait for a time between measurements
if ((millis() - timerDHT) > TIMEDHT) {
// Update the timer
timerDHT = millis();
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
humidity = dht.readHumidity();
// Read temperature as Celsius (the default)
celsius = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
fahrenheit = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again)
if (isnan(humidity) || isnan(celsius) || isnan(fahrenheit)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
}
}
// Get a label from PROGMEM into a char array
char *mon2str(uint8_t mon, char *psz, uint8_t len)
{
static const __FlashStringHelper* str[] =
{
F("Jan"), F("Feb"), F("Mar"), F("Apr"),
F("May"), F("Jun"), F("Jul"), F("Aug"),
F("Sep"), F("Oct"), F("Nov"), F("Dec")
};
strncpy_P(psz, (const char PROGMEM *)str[mon - 1], len);
psz[len] = '\0';
return (psz);
}
char *dow2str(uint8_t code, char *psz, uint8_t len)
{
static const __FlashStringHelper* str[] =
{
F("Sunday"), F("Monday"), F("Tuesday"),
F("Wednesday"), F("Thursday"), F("Friday"),
F("Saturday")
};
strncpy_P(psz, (const char PROGMEM *)str[code - 1], len);
psz[len] = '\0';
//Serial.println(psz);
return (psz);
}
void createHString(char *pH, const char *pL)
{
for (; *pL != '\0'; pL++)
*pH++ = *pL | 0x80; // offset character
*pH = '\0'; // terminate the string
}
#define LED2 2
Ticker ticker;
void vdTickLed2()
{
//Serial.println("--- LED --- ");
//Serial.println(digitalRead(LED2) );
digitalWrite(LED2, !digitalRead(LED2) );
}
// สร้างตัวแปรเก็บค่าเป็น integer เพื่อเอาไปใช้ใน Task
int passValue = 0;
// สร้างตัวแปร TaskHandle สำหรับแต่ละ Task
TaskHandle_t Task0 = NULL;
TaskHandle_t Task1 = NULL;
TaskHandle_t Task2 = NULL;
int inRunTask0 = 0;
int inRunTask1 = 0;
int inRunTask2 = 0;
void setup(void)
{
Serial.begin(115200);
Serial.println("--- dot matix CLOCK ---");
pinMode(LED2, OUTPUT);
digitalWrite(LED2, HIGH);
ticker.attach(1, vdTickLed2);
// rtc
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
abort();
}
if (! rtc.isrunning()) {
Serial.println("RTC is NOT running, let's set the time!");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
// DOT MATIX
//#define MAX_ZONES 3
//#define ZONE_SIZE 4
P.begin();
P.setInvert(false);
P.begin(MAX_ZONES);
P.setInvert(false);
P.setZone(1, 0, 3);
P.setZone(2, 4, 7);
P.setZone(0, 8, 11);
//P.setFont(0, FontSmall);
P.setFont(1, FontBig);
P.setFont(2, FontBig);
P.displayZoneText(0, szMesg, PA_CENTER, SPEED_TIME, 0, PA_PRINT, PA_NO_EFFECT);
P.displayZoneText(1, szMsgH, PA_CENTER, SPEED_TIME, 0, PA_PRINT, PA_NO_EFFECT);
P.displayZoneText(2, szTime, PA_CENTER, SPEED_TIME, 0, PA_PRINT, PA_NO_EFFECT);
P.addChar('$', degC);
P.addChar('&', degF);
P.setIntensity(2);
// DHT
dht.begin();
// create task
xTaskCreatePinnedToCore(vdTask_DisplayClock, "_Display0", 1000, (void*) passValue, 1, &Task0, 0);
//xTaskCreatePinnedToCore(vdTask_Wifi, "_Wifi", 1000, (void*) passValue, 1, &Task1, 0);
inRunTask0 = 0;
inRunTask1 = 0;
//xTaskCreatePinnedToCore(vdTask_DisplayClock, "_Display0", 1000, (void*) passValue, 1, &Task0, 0);
}
#define RUN_INIT_WIFI 1
#define RUN_CLOCK 2
void loop(void)
{
static int inRun = RUN_INIT_WIFI;
beginDS1307();
getTemperature();
P.displayAnimate();
/*
// wifi
if (inRun == RUN_INIT_WIFI) {
if (vdTask_Wifi() == 1) {
inRun = RUN_CLOCK;
}
}
else if (inRun == RUN_CLOCK) {
vdTask_DisplayClock();
}
*/
//delay(200);
return;
}
void vdTask_DisplayClock(void *pvvalue)
//void vdTask_DisplayClock(void)
{
static uint32_t lastTime = 0; // Memory (ms)
static uint8_t display = 0; // Current display mode
static bool flasher = false; // Seconds passing flasher
P.setFont(1, FontBig);
P.setFont(2, FontBig);
while (1)
{
if (P.getZoneStatus(0))
{
// if (inRunTask0 == 0) {
// continue;
// P.setFont(1, FontBig);
// P.setFont(2, FontBig);
// inRunTask0 = 1;
// }
switch (display)
{
case 0: // Temperature deg Celsius
P.setPause(0, 1000);
P.setTextEffect(0, PA_SCROLL_LEFT, PA_SCROLL_UP);
display++;
dtostrf(celsius, 3, 1, szMesg);
strcat(szMesg, "$");
break;
case 1: // Humidity
P.setPause(0, 1000);
P.setTextEffect(0, PA_SCROLL_DOWN, PA_SCROLL_LEFT);
display++;
dtostrf(humidity, 3, 0, szMesg);
//strcat(szMesg, "%UR");
strcat(szMesg, "%");
break;
case 2: // Day of week
P.setPause(0, 100);
//P.setFont(0, FontSmall);
P.setTextEffect(0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
display++;
dow2str(wday, szMesg, MAX_MESG);
break;
case 3: // Calendar
P.setPause(0, 1000);
P.setTextEffect(0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
display = 0;;
getDate(szMesg);
break;
}
P.displayReset(0); // Rest zone zero
}
if (P.getZoneStatus(1) && P.getZoneStatus(2)) // Clock
{
P.setTextEffect(1, PA_PRINT, PA_NO_EFFECT);
P.setTextEffect(2, PA_PRINT, PA_NO_EFFECT);
if ((millis() - lastTime) >= 1000)
{
lastTime = millis();
getTime(szTime, flasher);
flasher = !flasher;
//strcpy(szTime, "23:56");
//strcpy(szTime, "0123456789");
//P.setTextEffect(2, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
//P.setTextEffect(1, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
}
createHString(szMsgH, szTime);
//if (seconds % 10 == 00) {
// vdTask_UpdateTime();
//P.setTextEffect(1, PA_PRINT, PA_SCROLL_LEFT);
//P.setTextEffect(2, PA_PRINT, PA_SCROLL_RIGHT);
//P.setInvert(1, true);
//P.setInvert(2, true);
//P.setPause(1, 1000);
//P.setPause(2, 1000);
//}
P.displayReset(1); // Rest zone 1
P.displayReset(2); // Rest zone 2
}
delay(200);
}
}