0% found this document useful (0 votes)
23 views38 pages

Arduino Alarm Clock Code Example

The document is an Arduino sketch that implements a real-time clock and alarm system using FreeRTOS. It includes various tasks for managing time, adjusting settings, and displaying information on an LED matrix. The code also handles button inputs for user interaction and utilizes interrupts for timing and task management.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
23 views38 pages

Arduino Alarm Clock Code Example

The document is an Arduino sketch that implements a real-time clock and alarm system using FreeRTOS. It includes various tasks for managing time, adjusting settings, and displaying information on an LED matrix. The code also handles button inputs for user interaction and utilizes interrupts for timing and task management.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

#include <avr/interrupt.

h>

#include <Arduino.h>

#include <Arduino_FreeRTOS.h>

#include <queue.h>

#include <Wire.h>

#include <stdlib.h>

#include <TimeLib.h>

#include <DS1307RTC.h>

#define R1 4

#define G1 5

#define B1 6

#define R2 7

#define G2 8

#define B2 9

#define CLK 10

#define OE 11

#define STB 12

#define A A0

#define B A1

#define C A2

#define M A3

#define BUZZER_PIN 31

//bao thuc

TaskHandle_t alarmHandle = NULL; // Handle cho taskAlarm

volatile bool alarmSetting = true; // Đang trong chế độ cài đặt hay countdown
volatile int alarmMinutes = 0; // Số phút cài đặt

volatile bool buzzerOn = false; // Buzzer đang kêu hay không

volatile int alarmHour = 0; // Giờ cài báo thức

volatile int alarmMinute = 0; // Phút cài báo thức

volatile int alarmSecond = 0; // Giây còn lại khi countdown

volatile bool alarmFinished = false;

//chinh gio

volatile int adjustIndex = 0; // Vị trí chỉnh: 0,1,2,3

volatile bool adjusting = false; // Đang trong chế độ chỉnh giờ

volatile int editingHour = 0, editingMinute = 0; // Biến tạm để chỉnh

volatile bool blinkState = false; // Trạng thái nhấp nháy

TaskHandle_t adjustHandle = NULL; // Task chỉnh giờ handle

#define BTN_SET 3 // D3 - giữ để vào chế độ chỉnh

#define BTN_BRIGHT 2 // Nút duy nhất để điều chỉnh sáng

volatile int brightnessLevel = 64; // Giá trị từ 16 (sáng) đến 240 (tối)

unsigned long pressStart = 0;

bool isHolding = false;

unsigned char Buffer_display[3][16][4];

TaskHandle_t animationHandle = NULL;

TaskHandle_t realTimeHandle = NULL;

char col[32];

int wday, day1, month1, year1;


char color_row[4] = { 0x01, 0x03, 0x06, 0x02 };

const char font[][7] = {

0x38,0x44,0x4C,0x54,0x64,0x44,0x38, //0 48

0x10,0x30,0x10,0x10,0x10,0x10,0x38, //1 49

0x38,0x44,0x04,0x18,0x20,0x40,0x7C, //2 50

0x38,0x44,0x04,0x38,0x04,0x44,0x38, //3 51

0x08,0x18,0x28,0x48,0x7C,0x08,0x08, //4 52

0x7C,0x40,0x40,0x78,0x04,0x44,0x38, //5 53

0x18,0x20,0x40,0x78,0x44,0x44,0x38, //6 54

0x7C,0x04,0x08,0x10,0x20,0x20,0x20, //7 55

0x38,0x44,0x44,0x38,0x44,0x44,0x38, //8 56

0x38,0x44,0x44,0x3C,0x04,0x08,0x30, //9 57

0x00,0x00,0x00,0x00,0x00,0x00,0x00,

};

const char dayOfTheWeek[7][3][7] = {

0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00, 0x00, 0x48, 0x48, 0x48, 0x58, 0x28, 0x00,
0x00, 0x70, 0x48, 0x48, 0x48, 0x48, // Su

0x44, 0x6C, 0x54, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00,
0x00, 0x70, 0x48, 0x48, 0x48, 0x48, // Mo

0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x48, 0x48, 0x48, 0x58, 0x28, 0x00,
0x00, 0x38, 0x40, 0x38, 0x04, 0x38, // Tu

0x44, 0x44, 0x54, 0x54, 0x54, 0x54, 0x28, 0x00, 0x00, 0x38, 0x44, 0x78, 0x40, 0x38, 0x00,
0x00, 0x70, 0x48, 0x48, 0x48, 0x48, // We

0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x40, 0x40, 0x70, 0x48, 0x48, 0x48, 0x48, 0x00,
0x00, 0x48, 0x48, 0x48, 0x58, 0x28, // Th
0x7C, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x00, 0x00, 0x58, 0x24, 0x20, 0x20, 0x70, 0x10,
0x00, 0x10, 0x10, 0x10, 0x10, 0x18, // Fr

0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00,
0x20, 0x78, 0x20, 0x20, 0x28, 0x10, // Sa

};

const char miniFont[][3] = {

0xf8, 0x88, 0xf8, // 0

0x40, 0xf8, 0x00, // 1

0xb8, 0xa8, 0xe8, // 2

0xa8, 0xa8, 0xf8, // 3

0xe0, 0x20, 0xf8, // 4

0xe8, 0xa8, 0xb8, // 5

0xf8, 0xa8, 0xb8, // 6

0x80, 0x80, 0xf8, // 7

0xf8, 0xa8, 0xf8, // 8

0xe8, 0xa8, 0xf8 // 9

};

const char *monthName[12] = {

"Jan", "Feb", "Mar", "Apr", "May", "Jun",

"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"

};

tmElements_t tm;

QueueHandle_t mode = NULL;

ISR(TIMER1_OVF_vect) {

static unsigned char z = 0;


static unsigned long tStart = 0;

digitalWrite(OE, HIGH); // tắt LED

unsigned char i;

for (i = 0; i < 4; i++) {

data_transfet(Buffer_display[0][z][i], Buffer_display[1][z][i],

Buffer_display[2][z][i], Buffer_display[0][z + 8][i],

Buffer_display[1][z + 8][i], Buffer_display[2][z + 8][i]);

rows(z);

digitalWrite(STB, LOW);

digitalWrite(STB, HIGH);

tStart = micros();

while ((micros() - tStart) < brightnessLevel)

; // giữ OE = HIGH trong thời gian brightnessLevel

digitalWrite(OE, LOW); // bật LED

z++;

if (z == 8) z = 0;

TCNT1 = 64000;

}
bool getTime(const char *str) {

int Hour, Min, Sec;

if (sscanf(str, "%d:%d:%d", &Hour, &Min, &Sec) != 3) return false;

[Link] = Hour;

[Link] = Min;

[Link] = Sec;

return true;

bool getDate(const char *str) {

char Month[12];

int Day, Year;

uint8_t monthIndex;

if (sscanf(str, "%s %d %d", Month, &Day, &Year) != 3) return false;

for (monthIndex = 0; monthIndex < 12; monthIndex++) {

if (strcmp(Month, monthName[monthIndex]) == 0) break;

if (monthIndex >= 12) return false;

[Link] = Day;

[Link] = monthIndex + 1;

[Link] = CalendarYrToTm(Year);

return true;

}
void setup() {

[Link](9600);

[Link]();

pinMode(G1, OUTPUT); // cài đặt chế độ hoạt động của các chân

pinMode(R1, OUTPUT);

pinMode(B1, OUTPUT);

pinMode(R2, OUTPUT);

pinMode(G2, OUTPUT);

pinMode(B2, OUTPUT);

pinMode(A, OUTPUT);

pinMode(B, OUTPUT);

pinMode(C, OUTPUT);

pinMode(CLK, OUTPUT);

pinMode(OE, OUTPUT);

pinMode(STB, OUTPUT);

pinMode(M, INPUT);

pinMode(BTN_BRIGHT, INPUT_PULLUP);

pinMode(BUZZER_PIN, OUTPUT);

digitalWrite(BUZZER_PIN, LOW); // Buzzer OFF ban đầu

pinMode(30, INPUT_PULLUP); // Nút D30 chống nhảy loạn

mode = xQueueCreate(1, sizeof(int));

int status = 0;
xQueueSend(mode, &status, 0);

pinMode(3, INPUT_PULLUP);

attachInterrupt(digitalPinToInterrupt(3), changeOnMode, RISING);

getDate();

cli(); //Tắt ngắt toàn cục

TCCR1A = 0; //Reset Timer1

TCCR1B = 0;

TIMSK1 = 0;

TCCR1B |= (1 << CS11);

TCNT1 = 64000;

TIMSK1 |= (1 << TOIE1);

sei();

xTaskCreate(taskRealTime, "2", 128, NULL, 2, &realTimeHandle);

xTaskCreate(animation, "3", 256, NULL, 2, &animationHandle);

xTaskCreate(taskAdjustTime, "AdjustTime", 256, NULL, 2, &adjustHandle);

vTaskSuspend(adjustHandle); // Ban đầu tạm ngưng task chỉnh giờ

xTaskCreate(taskAlarm, "AlarmTask", 256, NULL, 2, &alarmHandle);

vTaskSuspend(alarmHandle);

vTaskStartScheduler();

void loop() {
}

void changeOnMode() {

static int moe = 0;

moe = (++moe) % 7;

xQueueOverwriteFromISR(mode, &moe, 0);

vTaskResume(realTimeHandle);

if (moe == 5) {

vTaskResume(adjustHandle); // Nếu vào mode chỉnh giờ, kích hoạt task chỉnh giờ

} else {

vTaskSuspend(adjustHandle); // Nếu ra khỏi mode chỉnh giờ, tạm ngưng task chỉnh giờ

if (moe == 6) {

vTaskResume(alarmHandle);

} else {

vTaskSuspend(alarmHandle);

void animation(void *pv) {

int x, y = 0, b;

int last_b = -1;

while (1) {

xQueuePeek(mode, &b, 0);


if (b != last_b) {

if (b == 4) {

showBrightnessBar2(); // Vào chế độ chỉnh sáng thì vẽ luôn

last_b = b;

if (b == 1) {

for (x = 0; x < 16; x++) {

draw_icon(x * 4, 0, (y + x) % 3 + 1);

draw_icon1(32 - x * 4, 15, (y + x) % 3 + 1);

y++;

delay(100);

} else if (b == 0) {

for (y = 0; y < 7; y++) {

for (x = 0; x < 5; x++) {

if ((dayOfTheWeek[wday - 1][0][y] & (0x40 >> x)) != 0) set_pixel(x + 0, y + 9, 0x05);

else set_pixel(x + 0, y + 9, 0x00);

vTaskDelay(20);

for (y = 0; y < 7; y++) {

for (x = 0; x < 5; x++) {

if ((dayOfTheWeek[wday - 1][1][y] & (0x40 >> x)) != 0) set_pixel(x + 5, y + 9, 0x05);

else set_pixel(x + 5, y + 9, 0x00);


}

vTaskDelay(20);

for (y = 0; y < 7; y++) {

for (x = 0; x < 5; x++) {

if ((dayOfTheWeek[wday - 1][2][y] & (0x40 >> x)) != 0) set_pixel(x + 10, y + 9, 0x05);

else set_pixel(x + 10, y + 9, 0x00);

vTaskDelay(20);

put_mini_number(16, 11, day1 / 10, 0x04);

put_mini_number(20, 11, day1 % 10, 0x04);

vTaskDelay(20);

put_mini_number(25, 11, month1 / 10, 0x07);

put_mini_number(29, 11, month1 % 10, 0x07);

delay(5000);

for (x = 31; x >= 0; x--) {

for (y = 9; y < 16; y++) {

set_pixel(x, y, 0x00);

vTaskDelay(5);

put_char(4, 9, 2, 0x04);

vTaskDelay(20);

put_char(10, 9, 0, 0x04);

vTaskDelay(20);
put_char(16, 9, year1 / 10, 0x04);

vTaskDelay(20);

put_char(22, 9, year1 % 10, 0x04);

delay(5000);

for (x = 31; x >= 0; x--) {

for (y = 8; y < 16; y++) {

set_pixel(x, y, 0x00);

vTaskDelay(5);

} else if (b == 2) {

delay(50);

for (x = 0; x < 31; x++) {

y = analogRead(M);

y = abs(y - 133);

if (y < 5) y = 0;

drawRowFalling(x, sqrt(y) * 5);

} else if (b == 3) {

delay(50);

for (x = 0; x < 31; x++) {

y = analogRead(M);

y = abs(y - 133);

if (y < 5) y = 0;

drawRowFallingTopDown(x, sqrt(y) * 5);

}
} else if (b == 4) {

if (digitalRead(BTN_BRIGHT) == LOW) {

if (!isHolding) {

pressStart = millis(); // lưu thời điểm bắt đầu nhấn

isHolding = true;

// Nếu giữ lâu hơn 0.5 giây

if (millis() - pressStart > 500) {

brightnessLevel -= 8; // tăng độ sáng (giảm giá trị)

if (brightnessLevel < 16) brightnessLevel = 16;

showBrightnessBar2(); // nếu có hàm hiển thị

vTaskDelay(200 / portTICK_PERIOD_MS); // delay để tăng dần

} else {

// Nếu vừa nhả nút và thời gian giữ < 500ms ⇒ nhấn nhanh

if (isHolding && millis() - pressStart <= 500) {

brightnessLevel += 16; // giảm độ sáng

if (brightnessLevel > 240) brightnessLevel = 240;

showBrightnessBar2();

isHolding = false;

vTaskDelay(50 / portTICK_PERIOD_MS);

}else if (b == 5){
vTaskDelay(100 / portTICK_PERIOD_MS);

}else if (b == 6){

vTaskDelay(100 / portTICK_PERIOD_MS);

void taskRealTime(void *pv) {

int nowStatus, nextStatus;

xQueuePeek(mode, &nowStatus, 0);

while (1) {

xQueuePeek(mode, &nextStatus, 0);

if (nowStatus != nextStatus) {

nowStatus = nextStatus;

vTaskDelete(animationHandle);

clear_display();

xTaskCreate(animation, "3", 128, NULL, 2, &animationHandle);

if (nowStatus == 0) {

getTime();

} else if (nowStatus == 1) {

getTime1();

} else {

vTaskSuspend(realTimeHandle);

}
}

void showBrightnessBar2() {

// Xóa toàn bộ màn hình trước

for (int x = 0; x < 32; x++) {

for (int y = 0; y < 16; y++) {

set_pixel(x, y, 0x00);

// Vẽ viền hình chữ nhật (cột và hàng thứ 2 ngoài cùng)

for (int y = 1; y <= 14; y++) {

set_pixel(1, y, 0x04); // Cột bên trái

set_pixel(30, y, 0x04); // Cột bên phải

for (int x = 1; x <= 30; x++) {

set_pixel(x, 1, 0x04); // Hàng trên

set_pixel(x, 14, 0x04); // Hàng dưới

// Ánh xạ brightnessLevel (0~255) -> số lượng cột sáng (0~26)

int numColumns = map(brightnessLevel, 0, 255, 0, 26);

// Vẽ các cột sáng bên trong hình chữ nhật

for (int x = 0; x < numColumns; x++) {

for (int y = 3; y <= 12; y++) { // Bỏ cột và hàng thứ 3, chỉ vẽ trong vùng sạch

set_pixel(x + 3, y, 0x04); // x+3 để bắt đầu từ cột 3


}

void taskAdjustTime(void *pv) {

unsigned long lastBlink = 0;

unsigned long pressStart = 0;

bool isHolding = false;

static bool lastD30State = HIGH;

int nowMode;

while (1) {

xQueuePeek(mode, &nowMode, 0);

if (nowMode != 5) {

vTaskSuspend(NULL);

if (!adjusting) {

// Lấy giờ phút từ DS1307

[Link](0x68);

[Link]((byte)0x00);

[Link]();

[Link](0x68, 7);

[Link](); // bỏ giây

editingMinute = bcd2dec([Link]());
editingHour = bcd2dec([Link]());

adjusting = true;

adjustIndex = 0;

// Mỗi vòng đều clear màn hình và vẽ lại

clear_display();

// Vẽ giờ phút màu xanh dương

put_mini_number_2(1, 0, editingHour / 10, (adjustIndex == 0 && blinkState) ? 0x00 : 0x04);

put_mini_number_2(8, 0, editingHour % 10, (adjustIndex == 1 && blinkState) ? 0x00 : 0x04);

draw_point(15, 5, 0x07);

draw_point(15, 9, 0x07);

put_mini_number_2(18, 0, editingMinute / 10, (adjustIndex == 2 && blinkState) ? 0x00 :


0x04);

put_mini_number_2(25, 0, editingMinute % 10, (adjustIndex == 3 && blinkState) ? 0x00 :


0x04);

// Blink số đang chỉnh mỗi 500ms

if (millis() - lastBlink >= 500) {

blinkState = !blinkState;

lastBlink = millis();

// Xử lý nút D2 tăng giảm


if (digitalRead(BTN_BRIGHT) == LOW) {

if (!isHolding) {

pressStart = millis();

isHolding = true;

if (millis() - pressStart > 500) { // Giữ lâu để giảm

adjust_value(-1);

vTaskDelay(200 / portTICK_PERIOD_MS);

} else {

if (isHolding && millis() - pressStart <= 500) { // Nhấn nhanh để tăng

adjust_value(1);

isHolding = false;

// Xử lý nút D30 đổi vị trí chỉnh

bool currentD30State = digitalRead(30);

if (lastD30State == HIGH && currentD30State == LOW) {

adjustIndex = (adjustIndex + 1) % 4;

lastD30State = currentD30State;

// Xử lý nút D3 lưu và thoát

if (digitalRead(3) == LOW) {

[Link](0x68);
[Link]((byte)0x00);

[Link](dec2bcd(0)); // Reset giây

[Link](dec2bcd(editingMinute));

[Link](dec2bcd(editingHour));

[Link]();

adjusting = false;

int backToMode = 0;

xQueueOverwrite(mode, &backToMode);

vTaskResume(realTimeHandle);

vTaskSuspend(NULL);

vTaskDelay(50 / portTICK_PERIOD_MS);

void adjust_value(int delta) {

switch (adjustIndex) {

case 0: editingHour += delta * 10; break; // Hàng chục giờ

case 1: editingHour += delta; break; // Đơn vị giờ

case 2: editingMinute += delta * 10; break; // Hàng chục phút

case 3: editingMinute += delta; break; // Đơn vị phút

// Giới hạn hợp lệ

if (editingHour > 23) editingHour = 0;


if (editingHour < 0) editingHour = 23;

if (editingMinute > 59) editingMinute = 0;

if (editingMinute < 0) editingMinute = 59;

void taskAlarm(void *pv) {

unsigned long lastMillis = 0;

unsigned long pressStart = 0;

bool isHolding = false;

static bool lastD30State = HIGH;

int nowMode;

while (1) {

xQueuePeek(mode, &nowMode, 0);

if (nowMode != 6) {

vTaskSuspend(NULL); // Không phải mode 6 thì ngủ

if (alarmSetting) {

// Đang trong chế độ cài đặt giờ phút báo thức

getTime(); // Lấy giờ thực tế hiển thị (đồng hồ b == 0)

// In giờ:phút mini font

put_mini_number(1, 11, alarmHour / 10, 0x05);


put_mini_number(5, 11, alarmHour % 10, 0x05);

draw_icon3(9, 12, 0x05); // chấm trên

draw_icon3(9, 14, 0x05); // chấm dưới

put_mini_number(11, 11, alarmMinute / 10, 0x05);

put_mini_number(15, 11, alarmMinute % 10, 0x05);

// Xử lý nút D2: tăng phút (giữ để tăng nhanh)

if (digitalRead(BTN_BRIGHT) == LOW) {

if (!isHolding) {

pressStart = millis();

isHolding = true;

if (millis() - pressStart > 500) { // Giữ lâu

alarmMinute++;

if (alarmMinute >= 60) {

alarmMinute = 0;

alarmHour++;

if (alarmHour >= 24) alarmHour = 0;

vTaskDelay(200 / portTICK_PERIOD_MS);

} else {

if (isHolding && millis() - pressStart <= 500) { // Nhấn nhanh

alarmMinute++;
if (alarmMinute >= 60) {

alarmMinute = 0;

alarmHour++;

if (alarmHour >= 24) alarmHour = 0;

isHolding = false;

// Xử lý nút D30 để xác nhận bắt đầu countdown

bool currentD30State = digitalRead(30);

if (lastD30State == HIGH && currentD30State == LOW) {

alarmSetting = false; // Xác nhận cài đặt

alarmSecond = 0; // Bắt đầu từ giây 0

alarmFinished = false; // Reset trạng thái hoàn thành

lastMillis = millis();

lastD30State = currentD30State;

} else {

// Đang trong chế độ đếm ngược giờ phút giây

getTime(); // Vẫn hiển thị giờ thực

// In giờ:phút:giây mini font

put_mini_number(1, 11, alarmHour / 10, 0x04);


put_mini_number(5, 11, alarmHour % 10, 0x04);

draw_icon3(9, 12, 0x04);

draw_icon3(9, 14, 0x04);

put_mini_number(11, 11, alarmMinute / 10, 0x04);

put_mini_number(15, 11, alarmMinute % 10, 0x04);

draw_icon3(19, 12, 0x04);

draw_icon3(19, 14, 0x04);

put_mini_number(21, 11, alarmSecond / 10, 0x04);

put_mini_number(25, 11, alarmSecond % 10, 0x04);

// Countdown mỗi giây

if (millis() - lastMillis >= 1000) {

lastMillis = millis();

if (!alarmFinished) { // Chỉ đếm khi chưa kết thúc

if (alarmSecond == 0) {

if (alarmMinute == 0) {

if (alarmHour == 0) {

// Hết giờ: bật buzzer 1 lần duy nhất

buzzerOn = true;

digitalWrite(BUZZER_PIN, HIGH);

alarmFinished = true; // Khóa, không cho buzzer bật lại


} else {

alarmHour--;

alarmMinute = 59;

alarmSecond = 59;

} else {

alarmMinute--;

alarmSecond = 59;

} else {

alarmSecond--;

// Ấn nút D30 để tắt buzzer

bool currentD30State = digitalRead(30);

if (lastD30State == HIGH && currentD30State == LOW && buzzerOn) {

buzzerOn = false;

digitalWrite(BUZZER_PIN, LOW);

lastD30State = currentD30State;

// Nếu ấn nút D3 để đổi mode thì reset mọi thứ

if (digitalRead(3) == LOW) {
alarmSetting = true;

alarmHour = 0;

alarmMinute = 0;

alarmSecond = 0;

buzzerOn = false;

alarmFinished = false;

digitalWrite(BUZZER_PIN, LOW);

int backToMode = 0;

xQueueOverwrite(mode, &backToMode);

vTaskResume(realTimeHandle);

vTaskSuspend(NULL);

vTaskDelay(50 / portTICK_PERIOD_MS);

void data_transfet(char byte_r1, char byte_g1, char byte_b1, char byte_r2, char byte_g2, char
byte_b2) { // chyển dữ liệu vào màn hình

unsigned char i, mask;

for (i = 0; i < 8; i++) {

mask = 0x80 >> i;

digitalWrite(R1, byte_r1 & mask);

digitalWrite(G1, byte_g1 & mask);

digitalWrite(B1, byte_b1 & mask);

digitalWrite(R2, byte_r2 & mask);


digitalWrite(G2, byte_g2 & mask);

digitalWrite(B2, byte_b2 & mask);

digitalWrite(CLK, LOW);

digitalWrite(CLK, HIGH); // tạo xung clk cho phép chuyển dữ liệu

void displayDayOfWeek(int wday, uint8_t color) {

int x_offset = 0; // Vị trí bắt đầu X

int y_offset = 9; // Vị trí bắt đầu Y (hàng dưới LED)

for (int letter = 0; letter < 3; letter++) { // Duyệt 3 chữ cái

for (int y = 0; y < 7; y++) { // Duyệt 7 hàng pixel

for (int x = 0; x < 5; x++) { // Duyệt 5 cột pixel mỗi chữ

if ((dayOfTheWeek[wday - 1][letter][y] & (0x40 >> x)) != 0) {

set_pixel(x + x_offset, y + y_offset, color);

} else {

set_pixel(x + x_offset, y + y_offset, 0x00); // Tắt pixel nền

x_offset += 6; // Sau mỗi chữ cái cách nhau 6 pixel

void rows(unsigned char row_number) { // chọn hàng được sáng


switch (row_number) {

case 0:

digitalWrite(A, LOW);

digitalWrite(B, LOW);

digitalWrite(C, LOW);

break;

case 1:

digitalWrite(A, HIGH);

digitalWrite(B, LOW);

digitalWrite(C, LOW);

break;

case 2:

digitalWrite(A, LOW);

digitalWrite(B, HIGH);

digitalWrite(C, LOW);

break;

case 3:

digitalWrite(A, HIGH);

digitalWrite(B, HIGH);
digitalWrite(C, LOW);

break;

case 4:

digitalWrite(A, LOW);

digitalWrite(B, LOW);

digitalWrite(C, HIGH);

break;

case 5:

digitalWrite(A, HIGH);

digitalWrite(B, LOW);

digitalWrite(C, HIGH);

break;

case 6:

digitalWrite(A, LOW);

digitalWrite(B, HIGH);

digitalWrite(C, HIGH);

break;

case 7:

{
digitalWrite(A, HIGH);

digitalWrite(B, HIGH);

digitalWrite(C, HIGH);

break;

void set_pixel(unsigned char x, unsigned char y, unsigned char color) {

if (x > 31 || x < 0 || y > 15 || y < 0) return;

if ((color & 0x01) != 0) Buffer_display[0][y][x / 8] = Buffer_display[0][y][x / 8] | (0x80 >> (x %


8));

else Buffer_display[0][y][x / 8] = Buffer_display[0][y][x / 8] & (~(0x80 >> (x % 8)));

if ((color & 0x02) != 0) Buffer_display[1][y][x / 8] = Buffer_display[1][y][x / 8] | (0x80 >> (x %


8));

else Buffer_display[1][y][x / 8] = Buffer_display[1][y][x / 8] & (~(0x80 >> (x % 8)));

if ((color & 0x04) != 0) Buffer_display[2][y][x / 8] = Buffer_display[2][y][x / 8] | (0x80 >> (x %


8));

else Buffer_display[2][y][x / 8] = Buffer_display[2][y][x / 8] & (~(0x80 >> (x % 8)));

void put_char(int i, int j, char txt, char color) {

char x = 0, y = 0, z = txt;

for (y = 0; y < 7; y++) {

for (x = 0; x < 5; x++) {


if ((font[txt][y] & (0x40 >> x)) != 0) set_pixel(x + i, y + j, color);

else set_pixel(x + i, y + j, 0x00);

void drawRowFalling(int x, int inputHeight) {

// Giới hạn chiều cao đầu vào

if (x < 10 && inputHeight > 14) inputHeight = 14;

else if (x < 20 && inputHeight > 10) inputHeight = 10;

else if (inputHeight > 6) inputHeight = 6;

// Lật ngược hệ trục: 0 ở trên → 15 ở dưới

inputHeight = 15 - inputHeight;

// Nếu input cao hơn → cập nhật ngay

if (inputHeight < col[x]) {

col[x] = inputHeight;

} else if (col[x] < 15) {

col[x]++; // Rơi từ từ xuống

// Vẽ cột sáng

int i = 14;

for (; i > col[x] + 1; i--) {

set_pixel(x, i, 0x02); // xanh lá


}

// Vệt sáng trên đỉnh

if (i <= 14) {

set_pixel(x, i, 0x03); // cam

i--;

if (i < 13) {

set_pixel(x, i, 0x01); // đỏ

i--;

// Tắt phần dưới

for (; i >= 0; i--) {

set_pixel(x, i, 0x00);

void drawRowFallingTopDown(int x, int inputHeight) {

// Giới hạn chiều cao đầu vào

if (x < 10 && inputHeight > 14) inputHeight = 14;

else if (x < 20 && inputHeight > 10) inputHeight = 10;

else if (inputHeight > 6) inputHeight = 6;

// Không cần lật trục


// Vì bây giờ 0 ở trên, 15 ở dưới

// Nếu input cao hơn → cập nhật ngay

if (inputHeight > col[x]) {

col[x] = inputHeight;

} else if (col[x] > 0) {

col[x]--; // Rút ngược lên từ từ

// Vẽ cột sáng

int i = 0;

for (; i < col[x] - 1; i++) {

set_pixel(x, i, 0x02); // xanh lá (giữa cột)

// Vệt sáng đầu đỉnh

if (i < 15) {

set_pixel(x, i, 0x03); // cam (đỉnh)

i++;

if (i < 15) {

set_pixel(x, i, 0x01); // đỏ (đuôi)

i++;

}
// Tắt phần dưới

for (; i < 15; i++) {

set_pixel(x, i, 0x00);

int bcd2dec(byte num) {

return ((num / 16 * 10) + (num % 16));

int dec2bcd(byte num) {

return ((num / 10 * 16) + (num % 10));

void getDate() {

[Link](0x68);

[Link]((byte)0x00);

[Link]();

[Link](0x68, 7);

day1 = [Link]();

day1 = [Link]();

day1 = [Link]();

wday = bcd2dec([Link]());

day1 = bcd2dec([Link]());

month1 = bcd2dec([Link]());

year1 = bcd2dec([Link]());
}

void getTime() {

[Link](0x68);

[Link]((byte)0x00);

[Link]();

[Link](0x68, 7);

int x;

x = bcd2dec([Link]() & 0x7f);

put_mini_number(24, 3, x / 10, 0x03);

put_mini_number(28, 3, x % 10, 0x03);

if (x % 2 == 0) {

draw_point(11, 2, 0x01);

draw_point(11, 5, 0x01);

} else {

draw_point(11, 2, 0x00);

draw_point(11, 5, 0x00);

x = bcd2dec([Link]());

put_char(13, 1, x / 10, 0x02);

put_char(18, 1, x % 10, 0x02);

x = bcd2dec([Link]());

put_char(1, 1, x / 10, 0x02);

put_char(6, 1, x % 10, 0x02);

if (x == 0) {

getDate();
}

void getTime1() {

[Link](0x68);

[Link]((byte)0x00);

[Link]();

[Link](0x68, 7);

int x;

x = bcd2dec([Link]() & 0x7f);

if (x % 2 == 0) {

draw_point(15, 5, 0x02);

draw_point(15, 9, 0x02);

} else {

draw_point(15, 5, 0x00);

draw_point(15, 9, 0x00);

x = bcd2dec([Link]());

put_mini_number_2(18, 3, x / 10, 0x01);

put_mini_number_2(25, 3, x % 10, 0x01);

x = bcd2dec([Link]());

put_mini_number_2(1, 3, x / 10, 0x01);

put_mini_number_2(8, 3, x % 10, 0x01);

if (x == 0) {

getDate();

}
}

void draw_point(int x, int y, char color) {

set_pixel(x, y, color);

set_pixel(x + 1, y, color);

set_pixel(x + 1, y + 1, color);

set_pixel(x, y + 1, color);

void put_mini_number(int i, int j, char txt, char color) {

char x, y;

for (y = 0; y < 3; y++) {

for (x = 0; x < 5; x++) {

if ((miniFont[txt][y] & (0x80 >> x)) != 0) set_pixel(y + i, x + j, color);

else set_pixel(y + i, x + j, 0x00);

void put_mini_number_2(int i, int j, char txt, char color) {

char x, y;

for (y = 0; y < 3; y++) {

for (x = 0; x < 5; x++) {

int px = 2 * y + i;

int py = x * 2 + j;
// Bỏ qua nếu px, py vượt quá phạm vi

if (px > 31 || py > 14) continue;

if ((miniFont[txt][y] & (0x80 >> x)) != 0) {

draw_point(px, py, color);

} else draw_point(px, py, 0x00);

void draw_icon(int x, int y, char color) {

set_pixel(x, y, color);

set_pixel(x + 1, y + 1, color);

set_pixel(x + 1, y, color);

set_pixel(x + 2, y, color);

void draw_icon3(int x, int y, char color) {

set_pixel(x, y, color);

void draw_icon1(int x, int y, char color) {

set_pixel(x, y, color);

set_pixel(x + 1, y - 1, color);

set_pixel(x + 1, y, color);

set_pixel(x + 2, y, color);
}

void clear_display() {

unsigned char i, j;

for (i = 0; i < 16; i++)

for (j = 0; j < 32; j++) {

set_pixel(j, i, 0x00);

You might also like