// simple project using Arduino UNO and Matrix LED Display MAX7219 with u8g2 library
// to create a counter for example for counting youtube subscribers
// created by upir, 2023
// youtube channel: https://www.youtube.com/upir_upir
// YOUTUBE VIDEO: https://youtu.be/jlhcDzS17vU
// links from the video:
// LED Matrix display: https://s.click.aliexpress.com/e/_DlnFAYz
// Arduino UNO: https://s.click.aliexpress.com/e/_AXDw1h
// Arduino UNO MINI: https://store.arduino.cc/products/uno-mini-le
// Arduino breadboard prototyping shield: https://s.click.aliexpress.com/e/_ApbCwx
// Photopea (online Photoshop-like tool): https://www.photopea.com/
// image2cpp (convert images into C code): https://javl.github.io/image2cpp/
// Starting sketch: https://github.com/olikraus/u8g2/blob/master/sys/arduino/u8g2_full_buffer/MAX7219_U8g2/MAX7219_U8g2.ino
// WOKWI display documentation: https://docs.wokwi.com/parts/wokwi-max7219-matrix
// U8g2 + Matrix display screenshot: https://github.com/olikraus/u8g2/wiki/gallery#28-may-2017-max7219-32x8-led-matrix
// U8g2 fonts: https://github.com/olikraus/u8g2/wiki/fntlist8#7-pixel-height
// Desmos online graphs: https://www.desmos.com/calculator?lang=en
// LCD Image converter: https://lcd-image-converter.riuson.com/en/about/
// Related videos with similar dot matrix displays:
// 51 years old display! - https://youtu.be/PBaL9w5w-2c
// 1 DISPLAY 3 SENSORS - https://youtu.be/lj_7UmM0EPY
// DIY Battery Indicator - https://youtu.be/Mq0WBPKGRew
// Smooth Arduino 16x2 Gauge - https://youtu.be/cx9CoGqpsfg
// Arduino Gauge in 11 Minutes - https://youtu.be/upE17NHrdPc
#include <Arduino.h>
#include <U8g2lib.h>
U8G2_MAX7219_32X8_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 11, /* data=*/ 12, /* cs=*/ 10, /* dc=*/ U8X8_PIN_NONE, /* reset=*/ U8X8_PIN_NONE);
// 'matrix_display_counter', 32x8px
const unsigned char epd_bitmap_matrix_display_counter [] = {
0x7e, 0x67, 0x75, 0x77, 0xef, 0x21, 0x15, 0x44, 0xe7, 0x21, 0x15, 0x44, 0xe3, 0x27, 0x77, 0x77,
0xe7, 0x24, 0x11, 0x15, 0xef, 0x24, 0x11, 0x15, 0x7e, 0x77, 0x71, 0x77, 0x00, 0x00, 0x00, 0x00
};
const unsigned char youtube_logo_bitmap [] = { // youtube bitmap logo, 8x7 px
B01111110,
B11101111,
B11100111,
B11100011,
B11100111,
B11101111,
B01111110
};
byte digits[6] = {0, 0, 9, 9, 9, 8}; // 要在矩阵显示器上显示的单个数字
byte digits_offset_perc[6] = {0, 0, 0, 0, 0, 0}; // 单个数字的y偏移量-百分比0-100%
char digit_char[2]; // 用于存储C样式字符串的帮助器数组
char digit_char_next[2]; // 用于存储C样式字符串的帮助器数组
float y_offset; // 数字的y像素偏移量
void setup(void) {
u8g2.begin(); // begin function is required for u8g2 library
u8g2.setContrast(10*16); // 设置显示对比度0-255
pinMode(7, INPUT_PULLUP);
}
void loop(void) {
if (digitalRead(7) == LOW) { // 按钮被按下
if (digits_offset_perc[5] == 0) { // 最后一位数字当前没有播放动画
digits_offset_perc[5] = 2; // 在这种情况下,动画显示最后一位数字(递增最后一位数字)
}
}
u8g2.clearBuffer(); // 清除内部u8g2存储器
u8g2.setFont(u8g2_font_minuteconsole_tr); // 选择一种合适的字体,宽度为3像素
u8g2.drawBitmap(0, 0, 8/8, 7, youtube_logo_bitmap); // draw youtube logo on top left corner
for (int i=5; i>=0; i--) { // 从最后一位数到第一位数
if (digits_offset_perc[i] > 0) { // 动画显示手指
digits_offset_perc[i] = digits_offset_perc[i] + 2; // 增加百分比偏移量
if ((digits[i] == 9) && (digits_offset_perc[i-1] == 0) && (digits_offset_perc[i] > 20)) {
digits_offset_perc[i-1] = 2; // 数字是9转到0 =增加左侧的数字
}
if (digits_offset_perc[i] >= 100) { // 动画完成后,切换到下一个数字
digits_offset_perc[i] = 0; // 停止动画
digits[i] = digits[i] + 1; // 切换到下一个数字
if (digits[i] == 10) { // 如果数字超过9,回到0
digits[i] = 0;
}
}
}
// linear movement of digits - looks boring
//y_offset = round((digits_offset_perc[i] / 100.0) * 8.0); // calculate the Y pixel offset
// easing using the power function - looks strange for continuous animation
//y_offset = round(pow((digits_offset_perc[i] / 100.0), 0.4) * 8.0);
// easing using the cosine function - looks great
y_offset = round((1-((cos(digits_offset_perc[i] / 100.0 * 3.141592654) / 2.0)+0.5)) * 8.0);
itoa(digits[i], digit_char, 10); // 将数字转换为辅助C风格字符串数组
itoa((digits[i]+1) % 10, digit_char_next, 10); // 将下一个数字转换为辅助C样式字符串数组
u8g2.drawStr(9 + i*4, 7 - y_offset, digit_char); // 将当前字符绘制到显示器上
u8g2.drawStr(9 + i*4, 7 - y_offset + 8, digit_char_next); // 将下一个字符绘制到显示屏上
}
u8g2.sendBuffer(); // 将内部存储器传输到显示器
}