Ви не увійшли.
Сторінки 1
Старался все рассказать в видео.
#include <TFT_ST7735.h> // Библиотека для работы с экраном
#include <SPI.h>
// Параметры подключения
#define CS_PIN 10
#define DC_PIN 9
#define RST_PIN 8
TFT_ST7735 tft = TFT_ST7735();
// Глобальные переменные
int activeFunction = 1; // Выбор функции: 1 или 2
// ФУНКЦИЯ 1: Отображение данных при изменении (исключение повторов)
// ФУНКЦИЯ 2: Отображение данных с заданным интервалом времени
float previousVoltage = -1; // Предыдущее значение напряжения
unsigned long lastUpdateTime = 0; // Время последнего обновления графика
unsigned long startTime; // Время начала работы программы
const int updateInterval = 100; // Интервал времени для функции 2 (в миллисекундах)
// Начало координат в нижнем левом углу
int originX = 0; // Начало координат по X (левый край экрана)
int endX = 158; // Окончание координат по X (правый край экрана)
int originY = 125; // Начало координат по Y (нижний край экрана)
int endY = 0; // Окончание координат по Y (верхний край экрана)
int x = originX; // Текущее положение по оси X для Ф2
int prev_X = originX; // Предыдущее значение для отрисовки линии
int prev_Y = originY; // Предыдущее значение для отрисовки линии
unsigned long totalSeconds = 0; // Для преобразования миллисекунды в секунды
unsigned long hours = 0; // Для вычисления часов
unsigned long minutes = 0; // Для вычисления минут
unsigned long seconds = 0; // Для вычисления секунд
// Работаем с отображением напряжения (для демонстрации)
int analogValue = 0;
float voltage = 0.0; // Текущее значение напряжения
const float Vref = 4.76;
const float R1 = 10000.0; // Верхний резистор, в Омах
const float R2 = 4700.0; // Нижний резистор, в Омах
const float dividerFactor = (R1 + R2) / R2;
const float pip_Volt = (Vref * dividerFactor) / originY; // значение одного пикселя
const float Vmax = Vref * dividerFactor; // значение максимального напряжения
boolean real_time = true;
// Инициализация экрана
void setup(void) {
tft.init(); // Инициализация экрана
tft.setRotation(3); // Установка ориентации экрана
tft.fillScreen(TFT_NAVY); // Установка начального цвета фона
drawAxes(); // Построение осей координат
}
// Основной цикл
void loop() {
if (activeFunction == 1) {
readAnalogAndDrawGraphNoRepeat(); // Функция 1
} else if (activeFunction == 2) {
readAnalogAndDrawGraphWithInterval(); // Функция 2
}
}
// ФУНКЦИЯ ОТРИСОВКИ БАЗОВОГО ЭКРАНА
void drawAxes() {
tft.drawLine(originX, originY, endX, originY, TFT_WHITE); // Горизонтальная ось
tft.drawLine(originX, originY, originX, endY, TFT_WHITE); // Вертикальная ось
tft.drawLine(endX, originY, endX - 3, originY - 3, TFT_WHITE); // Стрелка по X
tft.drawLine(originX, endY, originX + 3, endY + 3, TFT_WHITE); // Стрелка по Y
tft.setTextColor(TFT_CYAN);
tft.setTextSize(1);
tft.setCursor(134, 115);
tft.print("Time");
tft.setCursor(5, 1);
tft.print(Vmax); tft.print("/"); tft.print(pip_Volt);
}
// ФУНКЦИЯ 1: Считывание напряжения, исключение повторов
void readAnalogAndDrawGraphNoRepeat() {
delay (250); // для теста !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
analogValue = analogRead(A0); // Чтение аналогового значения
// Перевод в Вольты
voltage = analogValue * (Vref / 1023.0) * dividerFactor;
// Вывод цифрового значения напряжения
tft.setTextColor(TFT_WHITE, TFT_NAVY);
tft.setTextSize(1);
tft.setCursor(110, 5);
if (voltage < 10) tft.print("0"); tft.print(voltage, 2); tft.print(" V");
// Вывод цифрового значения времени с начала работы программы
tft.setCursor(110, 15);
real_time = true;
displayFormattedTime(); // Функция формата времени
float temp_V = voltage - previousVoltage;
temp_V = abs(temp_V);
// =======> Построение графика
if (temp_V > pip_Volt) {
previousVoltage = voltage; // Обновляем предыдущее значение
int y = map(voltage*100, 0, Vmax*100, originY, endY); // Масштабирование в пиксели
//tft.drawPixel(x, y, TFT_GREEN); // Отрисовка пикселями
tft.drawLine(prev_X, prev_Y, x, y, TFT_GREEN); // Отрисовка линиями
// Сохраняем текущие координаты как предыдущие для следующей линии
prev_X = x;
prev_Y = y;
// Увеличиваем X для следующего пикселя
x++;
// Вывод цифрового значения времени с момента изменения значения напряжения
tft.setCursor(110, 25);
real_time = false;
displayFormattedTime(); // Функция формата времени
lastUpdateTime = millis(); // Обновляем время
// Если дошли до правого края экрана, обнуляем X и очищаем график
if (x >= endX) { x = originX; prev_X = originX; prev_Y = originY;
tft.fillRect(0, 0, endX, originY, TFT_NAVY); // Очищаем область графика
drawAxes(); // Повторно рисуем оси
}
}
}
// ФУНКЦИЯ 2: Считывание напряжения с интервалом времени
void readAnalogAndDrawGraphWithInterval() {
// =======> Построение графика
if (millis() - lastUpdateTime > updateInterval) {
analogValue = analogRead(A0); // Чтение аналогового значения
// Перевод в Вольты
voltage = analogValue * (Vref / 1023.0) * dividerFactor;
previousVoltage = voltage; // Обновляем предыдущее значение
int y = map(voltage*100, 0, Vmax*100, originY, endY); // Масштабирование в пиксели
//tft.drawPixel(x, y, TFT_GREEN); // Отрисовка пикселями
tft.drawLine(prev_X, prev_Y, x, y, TFT_GREEN); // Отрисовка линиями
// Сохраняем текущие координаты как предыдущие для следующей линии
prev_X = x;
prev_Y = y;
// Увеличиваем X для следующего пикселя
x++;
// Вывод цифрового значения времени с начала работы программы
tft.setTextColor(TFT_WHITE, TFT_NAVY);
tft.setTextSize(1);
tft.setCursor(110, 5);
if (voltage < 10) tft.print("0"); tft.print(voltage, 2); tft.print(" V");
tft.setCursor(110, 15);
real_time = true;
displayFormattedTime(); // Функция формата времени
lastUpdateTime = millis(); // Обновляем время
// Если дошли до правого края экрана, обнуляем X и очищаем график
if (x >= endX) { x = originX; prev_X = originX; prev_Y = originY;
tft.fillRect(0, 0, endX, originY, TFT_NAVY); // Очищаем область графика
drawAxes(); // Повторно рисуем оси
}
}
}
void displayFormattedTime() {
// Преобразуем миллисекунды в секунды
if (!real_time) totalSeconds = ((millis() - lastUpdateTime) / 1000);
if (real_time) totalSeconds = millis() / 1000;
hours = totalSeconds / 3600; // Вычисляем часы
minutes = (totalSeconds % 3600) / 60; // Минуты
seconds = totalSeconds % 60; // Секунды
if (hours < 10) tft.print("0"); tft.print(hours); tft.print(":");
if (minutes < 10) tft.print("0"); tft.print(minutes); tft.print(":");
if (seconds < 10) tft.print("0"); tft.print(seconds);
}
//======================================================//
/*
TFT_BLACK // Черный
TFT_BLUE // Синий
TFT_RED // Красный
TFT_GREEN // Зеленый
TFT_CYAN // Циан (бирюзовый)
TFT_MAGENTA // Пурпурный
TFT_YELLOW // Желтый
TFT_WHITE // Белый
TFT_DARKGREEN // Темно-зеленый
TFT_NAVY // Темно-синий
TFT_GREY // Серый
TFT_ORANGE // Оранжевый
TFT_VIOLET // Лиловый (фиолетовый)
1. tft.init(): Инициализация дисплея.
2. tft.fillScreen(color): Заполнение экрана указанным цветом.
3. drawPixel(x, y, color): Рисование пикселя в заданной координате (x, y) с указанным цветом.
4. drawLine(x0, y0, x1, y1, color):Рисование линии между точками (x0, y0) и (x1, y1).
5. drawRect(x, y, w, h, color): Рисование прямоугольника с верхним левым углом (x, y), шириной w и высотой h.
6. fillRect(x, y, w, h, color): Заполнение прямоугольника указанным цветом.
7. drawCircle(x, y, r, color): Рисование окружности с центром (x, y) и радиусом r.
8. fillCircle(x, y, r, color): Заполнение окружности указанным цветом.
9. setCursor(x, y): Установка курсора для вывода текста.
10. setTextColor(color): Установка цвета текста.
11. setTextSize(size): Установка размера текста.
12. print(text): Вывод текста на экран.
13. println(text): Вывод текста с переходом на новую строку.
*/
Неактивний
А тепер непогано було б цей графік згладити. Сплайном наприклад.
ну, рваний графік це не дуже красиво
На відео наче б то суцільні темні лінії. Тільки незрозуміло, чи то TFT_GREEN такий темний (звідки тоді яскраві кінцеві точки?), чи то воно тільки кінцеві точки малює (звідки тоді суцільні темні лінії?).
Навіщо там сплайни? Щоб графік виглядав красиво, потрібно або малювати лінії алгоритмом Ву (якщо доступні градації яскравості), або взагалі малювати строго вертикальні лінії, тобто щоб початкова та кінцева точки мали однакову координату X. Тільки тоді початкову точку потрібно розраховувати на основі попередньої кінцевої.
Неактивний
На відео наче б то суцільні темні лінії. Тільки незрозуміло, чи то TFT_GREEN такий темний (звідки тоді яскраві кінцеві точки?), чи то воно тільки кінцеві точки малює (звідки тоді суцільні темні лінії?).
Сам не розумію чому так, іноді лінії мають рандомний колір хоча колір заданий зелений ...
tft.drawLine(prev_X, prev_Y, x, y, TFT_GREEN); // Отрисовка линиями
Неактивний
Ну це ваш проект, вам видніше що графік показує
Що до кольору ліній - подивіться всередині тієї ліби, може там магія того ж Брезенхейма некоректно працює з кольором.
Ну це ваш проект, вам видніше що графік показує
Що до кольору ліній - подивіться всередині тієї ліби, може там магія того ж Брезенхейма некоректно працює з кольором.
До чого тут видніше чи ні ? Тут справа в доцільності (в даному випадку) дій. З такою роздільною здатністю екрану у любому проекті застосовувати сплайн немає сенсу.
Для більшого екрану я згоден, що зі сплайном буде красивіше.
В лібі поки нічого підозрілого не знайшов...
Неактивний
Я б ввімкнув debug, якщо він там є, вивів би якусь мінімальну картинку з неправильним кольором і подивився що воно насправді виводить на екран.
В лібі поки нічого підозрілого не знайшов...
Ця ліба? Там два варіанта реалізації drawLine(), з FAST_LINE і без.
Якщо у вас 158x125, то
int endX = 158; // Окончание координат по X (правый край экрана)
int originY = 125; // Начало координат по Y (нижний край экрана)
мало би бути
int endX = 157;
int originY = 124;
хіба ні?
Остання редакція dimich (2025-04-01 23:00:57)
Неактивний
renoshnik пише:В лібі поки нічого підозрілого не знайшов...
Ця ліба? Там два варіанта реалізації drawLine(), з FAST_LINE і без.
Якщо у вас 158x125, то
int endX = 158; // Окончание координат по X (правый край экрана) int originY = 125; // Начало координат по Y (нижний край экрана)
мало би бути
int endX = 157; int originY = 124;
хіба ні?
Так FAST_LINE застосовується для прямих ліній, дійсно так правильніше було малювати осі координат...
tft.drawFastHLine(0, y, w, color1);
tft.drawFastVLine(x, 0, h, color2);
Що до розміру екрану, то кінцеві точки я визначив візуально підбором, бо параметрів екрану я не знав.
Неактивний
Так FAST_LINE застосовується для прямих ліній, дійсно так правильніше було малювати осі координат...
Я маю на увазі, що в залежності від значення макроса FAST_LINE під час компіляції використовується або одна, або інша реалізація TFT_ST7735::drawLine().
Що до розміру екрану, то кінцеві точки я визначив візуально підбором, бо параметрів екрану я не знав.
Там розмір екрана задається параметрами конструктора:
TFT_ST7735(int16_t _W = ST7735_TFTWIDTH, int16_t _H = ST7735_TFTHEIGHT);
і за замовчуванням це 128x160.
Враховуючи всю ту "магію" з MADCTL та іншими параметрами, а також зоопарком варіантів модулів з клонами ST7735, при некоректній ініціалізації можуть невірно розраховуватись адреси пікселів, які попадають в середину пікселя, що виглядає як спотворення кольорів.
Я би для початку повиводив прості тестові зображення, щоб побачити закономірність.
Неактивний
renoshnik пише:Так FAST_LINE застосовується для прямих ліній, дійсно так правильніше було малювати осі координат...
Я маю на увазі, що в залежності від значення макроса FAST_LINE під час компіляції використовується або одна, або інша реалізація TFT_ST7735::drawLine().
renoshnik пише:Що до розміру екрану, то кінцеві точки я визначив візуально підбором, бо параметрів екрану я не знав.
Там розмір екрана задається параметрами конструктора:
TFT_ST7735(int16_t _W = ST7735_TFTWIDTH, int16_t _H = ST7735_TFTHEIGHT);
і за замовчуванням це 128x160.
Враховуючи всю ту "магію" з MADCTL та іншими параметрами, а також зоопарком варіантів модулів з клонами ST7735, при некоректній ініціалізації можуть невірно розраховуватись адреси пікселів, які попадають в середину пікселя, що виглядає як спотворення кольорів.
Я би для початку повиводив прості тестові зображення, щоб побачити закономірність.
З розміром екрану розібрався.
tft.drawFastHLine(0, originY, tft.width(), TFT_WHITE); // Горизонтальная линия вправо
tft.drawFastVLine(originX, 0, tft.height(), TFT_WHITE); // Вертикальная линия вверх
// tft.drawLine(endX, originY, endX - 3, originY - 3, TFT_WHITE); // Стрелка по X
// tft.drawLine(originX, endY, originX + 3, endY + 3, TFT_WHITE); // Стрелка по Y
FAST використовується тільки для горизонтальних і вертикальних ліній у графіку мені не вдалося використати FAST
*** може проблеми з кольором через орієнтацію екрану
tft.setRotation(3); // Установка ориентации экрана
Неактивний
FAST використовується тільки для горизонтальних і вертикальних ліній у графіку мені не вдалося використати FAST
Там же в коді все написано. Якщо макрос FAST_LINE визначений, то звичайна drawLine() використовує оптимізований алгорим, який вертикальні та горизонтальні сегменти більше двох пікселів малює за допомогою Fast Line, тому працює швидше. Але код функції на 116 байтів більший. Якщо FAST_LINE не визначений, то drawLine() використовує класичну реалізацію алгоритму Брезенхема, яка повільніша, але менша за розміром.
*** може проблеми з кольором через орієнтацію екрану
Все може бути. Якщо ця конфігурація впливає на обчислення адреси (хоч програмно, хоч апаратно в самому контроллері), то теж може. Потрібно повиводити тестові зображення. Спочатку просто пікселі різних кольорів. З парними та непарними координатами. Якщо все ок, тоді лінії, теж різних кольорів, з парними і непарними координатами початку та кінця. Потім, по результатам, дивитись в реалізацію бібліотеки та документацію на контроллер.
Неактивний
Дебажити чужу лібу це цікаве зайняття. Я б запропонував або дуже уважно подивитися на приклади до неї, якщо вони є, і працюють коректно - шукати різницю. Або пошукати, може є інші рішення.
Для тесту запустив таку програмку
#include <TFT_ST7735.h> // Библиотека для работы с экраном
#include <SPI.h>
// Параметры подключения (замените на ваши пины)
#define CS_PIN 10
#define DC_PIN 9
#define RST_PIN 8
TFT_ST7735 tft = TFT_ST7735(); // Инициализация экрана
void setup(void) {
tft.init(); // Инициализация экрана
tft.setRotation(3); // Установка ориентации экрана
tft.fillScreen(TFT_NAVY); // Установка начального цвета фона
drawAxes(); // Построение осей координат
}
void loop() {
delay(50);
tft.drawLine(75, 0, 75, 75, TFT_GREEN); // цвет изменяется
delay(50);
tft.drawLine(55, 120, 55, 20, TFT_GREEN); // цвет изменяется
delay(50);
tft.drawFastVLine(25, 0, 90, TFT_GREEN); // стабильный цвет
delay(50);
drawAxes(); // Построение осей координат
}
// ФУНКЦИЯ ОТРИСОВКИ БАЗОВОГО ЭКРАНА
void drawAxes() {
// Начало координат в нижнем левом углу
int originX = 1; // Начало координат по X (левый край экрана)
int endX = 158; // Окончание координат по X (правый край экрана)
int originY = 125; // Начало координат по Y (нижний край экрана)
int endY = 0; // Окончание координат по Y (верхний край экрана)
// Рисуем оси X и Y
tft.drawFastHLine(0, originY, tft.width(), TFT_WHITE); // Горизонтальная линия вправо
tft.drawFastVLine(originX, 0, tft.height(), TFT_WHITE); // Вертикальная линия вверх
// Добавляем стрелки на концах осей
tft.drawLine(endX, originY, endX - 3, originY - 3, TFT_WHITE); // Стрелка вправо
tft.drawLine(originX, endY, originX + 3, endY + 3, TFT_WHITE); // Стрелка вверх
// Подписи осей
tft.setTextColor(TFT_CYAN);
tft.setTextSize(1);
tft.setCursor(139, 115); // Подпись оси X
unsigned long _x = tft.width();
tft.print(_x);
unsigned long _y = tft.height();
tft.setCursor(5, 1); // Подпись оси Y
tft.print(_y);
}
tft.drawLine(75, 0, 75, 75, TFT_GREEN); // цвет изменяется
tft.drawLine(55, 120, 55, 20, TFT_GREEN); // цвет изменяется
tft.drawFastVLine(25, 0, 90, TFT_GREEN); // стабильный цвет
якщо за коментувати рядок tft.setRotation(3); // Установка ориентации экрана
результат не змінюється
Остання редакція renoshnik (2025-04-02 13:14:13)
Неактивний
В прикладах бібліотеки взяв скетч аналогового годинника
/*
An example analogue clock using a TFT LCD screen to show the time
use of some of the drawing commands with the ST7735 library.
For a more accurate clock, it would be better to use the RTClib library.
But this is just a demo.
This examples uses the hardware SPI only. Non-hardware SPI
is just too slow (~8 times slower!)
Gilchrist 6/2/2014 1.0
Updated by Bodmer
*/
#include <TFT_ST7735.h> // Graphics and font library for ST7735 driver chip
#include <SPI.h>
TFT_ST7735 tft = TFT_ST7735(); // Invoke library, pins defined in User_Setup.h
#define ST7735_GREY 0xBDF7
float sx = 0, sy = 1, mx = 1, my = 0, hx = -1, hy = 0; // Saved H, M, S x & y multipliers
float sdeg=0, mdeg=0, hdeg=0;
uint16_t osx=64, osy=64, omx=64, omy=64, ohx=64, ohy=64; // Saved H, M, S x & y coords
uint16_t x0=0, x1=0, y0=0, y1=0;
uint32_t targetTime = 0; // for next 1 second timeout
static uint8_t conv2d(const char* p) {
uint8_t v = 0;
if ('0' <= *p && *p <= '9')
v = *p - '0';
return 10 * v + *++p - '0';
}
uint8_t hh=conv2d(__TIME__), mm=conv2d(__TIME__+3), ss=conv2d(__TIME__+6); // Get H, M, S from compile time
boolean initial = 1;
void setup(void) {
tft.init();
tft.setRotation(0);
tft.fillScreen(ST7735_GREY);
tft.setTextColor(ST7735_GREEN, ST7735_GREY); // Adding a black background colour erases previous text automatically
// Draw clock face
tft.fillCircle(64, 64, 61, ST7735_BLUE);
tft.fillCircle(64, 64, 57, ST7735_BLACK);
// Draw 12 lines
for(int i = 0; i<360; i+= 30) {
sx = cos((i-90)*0.0174532925);
sy = sin((i-90)*0.0174532925);
x0 = sx*57+64;
y0 = sy*57+64;
x1 = sx*50+64;
y1 = sy*50+64;
tft.drawLine(x0, y0, x1, y1, ST7735_BLUE);
}
// Draw 60 dots
for(int i = 0; i<360; i+= 6) {
sx = cos((i-90)*0.0174532925);
sy = sin((i-90)*0.0174532925);
x0 = sx*53+64;
y0 = sy*53+64;
tft.drawPixel(x0, y0, ST7735_BLUE);
if(i==0 || i==180) tft.fillCircle(x0, y0, 1, ST7735_CYAN);
if(i==0 || i==180) tft.fillCircle(x0+1, y0, 1, ST7735_CYAN);
if(i==90 || i==270) tft.fillCircle(x0, y0, 1, ST7735_CYAN);
if(i==90 || i==270) tft.fillCircle(x0+1, y0, 1, ST7735_CYAN);
}
tft.fillCircle(65, 65, 3, ST7735_RED);
// Draw text at position 64,125 using fonts 4
// Only font numbers 2,4,6,7 are valid. Font 6 only contains characters [space] 0 1 2 3 4 5 6 7 8 9 : . a p m
// Font 7 is a 7 segment font and only contains characters [space] 0 1 2 3 4 5 6 7 8 9 : .
tft.drawCentreString("Time flies",64,130,4);
targetTime = millis() + 1000;
}
void loop() {
if (targetTime < millis()) {
targetTime = millis()+1000;
ss++; // Advance second
if (ss==60) {
ss=0;
mm++; // Advance minute
if(mm>59) {
mm=0;
hh++; // Advance hour
if (hh>23) {
hh=0;
}
}
}
// Pre-compute hand degrees, x & y coords for a fast screen update
sdeg = ss*6; // 0-59 -> 0-354
mdeg = mm*6+sdeg*0.01666667; // 0-59 -> 0-360 - includes seconds
hdeg = hh*30+mdeg*0.0833333; // 0-11 -> 0-360 - includes minutes and seconds
hx = cos((hdeg-90)*0.0174532925);
hy = sin((hdeg-90)*0.0174532925);
mx = cos((mdeg-90)*0.0174532925);
my = sin((mdeg-90)*0.0174532925);
sx = cos((sdeg-90)*0.0174532925);
sy = sin((sdeg-90)*0.0174532925);
if (ss==0 || initial) {
initial = 0;
// Erase hour and minute hand positions every minute
tft.drawLine(ohx, ohy, 65, 65, ST7735_BLACK);
ohx = hx*33+65;
ohy = hy*33+65;
tft.drawLine(omx, omy, 65, 65, ST7735_BLACK);
omx = mx*44+65;
omy = my*44+65;
}
// Redraw new hand positions, hour and minute hands not erased here to avoid flicker
tft.drawLine(osx, osy, 65, 65, ST7735_BLACK);
tft.drawLine(ohx, ohy, 65, 65, ST7735_WHITE);
tft.drawLine(omx, omy, 65, 65, ST7735_WHITE);
osx = sx*47+65;
osy = sy*47+65;
tft.drawLine(osx, osy, 65, 65, ST7735_RED);
tft.fillCircle(65, 65, 3, ST7735_RED);
}
}
секундна стрілка рандомно залишає артифакти жовтого кольору ....
можливо дійсно то якість самого екрану така ...
Неактивний
В мене до графіка зауважень і не було тут таке.. якщо чужий код працює якось не так, то або копати даташіти, або спробувати іншу реалізацію.
В мене до графіка зауважень і не було
тут таке.. якщо чужий код працює якось не так, то або копати даташіти, або спробувати іншу реалізацію.
то я ще не відвик від служби..
маю на увазі, що графік з цією лібою малюється одним кольором без змін ...
стара ліба пішла в смітник ...
Неактивний
Сторінки 1