//===================================================================
// ILI9341 НА BLUE PILL - СИНУСОИДА ЛИНИЯМИ ПОЛОСАМИ
//===================================================================
#include <SPI.h>
// Пины дисплея для Blue Pill
#define TFT_CS PB10
#define TFT_DC PB1
#define TFT_RES PB0
#define TFT_MOSI PA7
#define TFT_SCLK PA5
// Размеры экрана
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
// Цвета (RGB565)
#define BLACK 0x0000
#define RED 0xF800
#define GREEN 0x07E0
#define BLUE 0x001F
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#define GRAY 0x8410
#define DARKGRAY 0x3186
// Параметры полос
#define STRIP_HEIGHT 20 // Высота полосы
#define STRIP_SIZE (SCREEN_WIDTH * STRIP_HEIGHT * 2)
// Буфер для полосы
uint8_t strip_buffer[STRIP_SIZE];
// Константа PI
#define PI 3.14159
// ================== SPI ИНИЦИАЛИЗАЦИЯ ==================
void spi_init() {
SPI.setMOSI(TFT_MOSI);
SPI.setSCLK(TFT_SCLK);
SPI.begin();
SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
pinMode(TFT_CS, OUTPUT);
pinMode(TFT_DC, OUTPUT);
pinMode(TFT_RES, OUTPUT);
digitalWrite(TFT_CS, HIGH);
digitalWrite(TFT_DC, HIGH);
digitalWrite(TFT_RES, HIGH);
}
// ================== ОТПРАВКА ДАННЫХ ==================
void send_cmd(uint8_t cmd) {
digitalWrite(TFT_DC, LOW);
digitalWrite(TFT_CS, LOW);
SPI.transfer(cmd);
digitalWrite(TFT_CS, HIGH);
}
void send_data(uint8_t data) {
digitalWrite(TFT_DC, HIGH);
digitalWrite(TFT_CS, LOW);
SPI.transfer(data);
digitalWrite(TFT_CS, HIGH);
}
// ================== ИНИЦИАЛИЗАЦИЯ ДИСПЛЕЯ ==================
void ili9341_init() {
digitalWrite(TFT_RES, LOW);
delay(100);
digitalWrite(TFT_RES, HIGH);
delay(100);
send_cmd(0x01); // Software Reset
delay(100);
send_cmd(0x36); // Memory Access Control
send_data(0xE8); // Горизонтальная ориентация
send_cmd(0x3A); // Pixel Format Set
send_data(0x55); // 16-bit color
send_cmd(0x11); // Sleep Out
delay(100);
send_cmd(0x29); // Display On
delay(10);
}
// ================== УПРАВЛЕНИЕ ОКНОМ ==================
void set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
send_cmd(0x2A);
send_data(x0 >> 8);
send_data(x0 & 0xFF);
send_data(x1 >> 8);
send_data(x1 & 0xFF);
send_cmd(0x2B);
send_data(y0 >> 8);
send_data(y0 & 0xFF);
send_data(y1 >> 8);
send_data(y1 & 0xFF);
send_cmd(0x2C);
}
// ================== ОТПРАВКА ПОЛОСЫ ==================
void send_strip(uint16_t y_start, uint16_t y_end) {
set_window(0, y_start, SCREEN_WIDTH - 1, y_end);
digitalWrite(TFT_DC, HIGH);
digitalWrite(TFT_CS, LOW);
int bytes_to_send = SCREEN_WIDTH * (y_end - y_start + 1) * 2;
for(int i = 0; i < bytes_to_send; i++) {
SPI.transfer(strip_buffer[i]);
}
digitalWrite(TFT_CS, HIGH);
}
// ================== РАБОТА С БУФЕРОМ ==================
void set_pixel_in_strip(uint16_t x, uint16_t y_rel, uint16_t color) {
if(x >= SCREEN_WIDTH || y_rel >= STRIP_HEIGHT) return;
int index = (y_rel * SCREEN_WIDTH + x) * 2;
strip_buffer[index] = color >> 8;
strip_buffer[index + 1] = color & 0xFF;
}
void clear_strip_buffer() {
for(int i = 0; i < STRIP_SIZE; i++) {
strip_buffer[i] = 0;
}
}
// ================== МАТЕМАТИКА ==================
float mySin(float x) {
while(x > PI) x -= 2*PI;
while(x < -PI) x += 2*PI;
float x2 = x * x;
float x3 = x2 * x;
float x5 = x3 * x2;
float x7 = x5 * x2;
return x - x3/6.0 + x5/120.0 - x7/5040.0;
}
// ================== РИСОВАНИЕ ЛИНИИ В БУФЕРЕ ==================
void draw_line_in_buffer(int x0, int y0, int x1, int y1, uint16_t color) {
int dx = abs(x1 - x0);
int dy = abs(y1 - y0);
int sx = x0 < x1 ? 1 : -1;
int sy = y0 < y1 ? 1 : -1;
int err = dx - dy;
while(1) {
if(x0 >= 0 && x0 < SCREEN_WIDTH && y0 >= 0 && y0 < STRIP_HEIGHT) {
set_pixel_in_strip(x0, y0, color);
}
if(x0 == x1 && y0 == y1) break;
int e2 = 2 * err;
if(e2 > -dy) {
err -= dy;
x0 += sx;
}
if(e2 < dx) {
err += dx;
y0 += sy;
}
}
}
// ================== ГЕНЕРАЦИЯ СИНУСОИДЫ ЛИНИЯМИ ==================
void generate_sine_strip(int strip_y, int centerY, int amplitude) {
int y_start = strip_y * STRIP_HEIGHT;
int y_end = y_start + STRIP_HEIGHT - 1;
if(y_end >= SCREEN_HEIGHT) y_end = SCREEN_HEIGHT - 1;
clear_strip_buffer();
// Массивы для хранения точек синусоиды в этой полосе
int points_x[SCREEN_WIDTH];
int points_y[SCREEN_WIDTH];
int point_count = 0;
// Собираем все точки синусоиды, попадающие в текущую полосу
for(int x = 0; x < SCREEN_WIDTH; x++) {
float rad = (x - SCREEN_WIDTH/2) * (8 * PI / SCREEN_WIDTH);
int y_abs = (int)(centerY + amplitude * mySin(rad));
if(y_abs >= y_start && y_abs <= y_end) {
points_x[point_count] = x;
points_y[point_count] = y_abs - y_start;
point_count++;
}
}
// Рисуем линии между соседними точками
for(int i = 0; i < point_count - 1; i++) {
// Проверяем, что точки рядом (нет разрыва)
if(points_x[i + 1] - points_x[i] <= 2) {
draw_line_in_buffer(points_x[i], points_y[i],
points_x[i + 1], points_y[i + 1], CYAN);
} else {
// Если разрыв большой, рисуем толстую точку
set_pixel_in_strip(points_x[i], points_y[i], CYAN);
set_pixel_in_strip(points_x[i + 1], points_y[i + 1], CYAN);
}
}
// Если есть хотя бы одна точка, обрабатываем её
if(point_count > 0) {
// Делаем линию потолще - добавляем соседние пиксели
for(int i = 0; i < point_count; i++) {
int y = points_y[i];
if(y > 0) set_pixel_in_strip(points_x[i], y - 1, CYAN);
if(y < STRIP_HEIGHT - 1) set_pixel_in_strip(points_x[i], y + 1, CYAN);
}
}
send_strip(y_start, y_end);
}
// ================== РИСОВАНИЕ СЕТКИ ==================
void draw_grid() {
int centerX = SCREEN_WIDTH / 2;
int centerY = SCREEN_HEIGHT / 2;
// Вертикальные линии сетки
for(int x = 30; x < SCREEN_WIDTH; x += 40) {
if(x != centerX) {
set_window(x, 0, x, SCREEN_HEIGHT - 1);
digitalWrite(TFT_DC, HIGH);
digitalWrite(TFT_CS, LOW);
for(int i = 0; i < SCREEN_HEIGHT; i++) {
SPI.transfer(DARKGRAY >> 8);
SPI.transfer(DARKGRAY & 0xFF);
}
digitalWrite(TFT_CS, HIGH);
}
}
// Горизонтальные линии сетки
for(int y = 20; y < SCREEN_HEIGHT; y += 30) {
if(y != centerY) {
set_window(0, y, SCREEN_WIDTH - 1, y);
digitalWrite(TFT_DC, HIGH);
digitalWrite(TFT_CS, LOW);
for(int i = 0; i < SCREEN_WIDTH; i++) {
SPI.transfer(DARKGRAY >> 8);
SPI.transfer(DARKGRAY & 0xFF);
}
digitalWrite(TFT_CS, HIGH);
}
}
// Ось Y (вертикальная)
set_window(centerX, 0, centerX, SCREEN_HEIGHT - 1);
digitalWrite(TFT_DC, HIGH);
digitalWrite(TFT_CS, LOW);
for(int i = 0; i < SCREEN_HEIGHT; i++) {
SPI.transfer(GRAY >> 8);
SPI.transfer(GRAY & 0xFF);
}
digitalWrite(TFT_CS, HIGH);
// Ось X (горизонтальная)
set_window(0, centerY, SCREEN_WIDTH - 1, centerY);
digitalWrite(TFT_DC, HIGH);
digitalWrite(TFT_CS, LOW);
for(int i = 0; i < SCREEN_WIDTH; i++) {
SPI.transfer(GRAY >> 8);
SPI.transfer(GRAY & 0xFF);
}
digitalWrite(TFT_CS, HIGH);
}
// ================== РИСОВАНИЕ СТРЕЛОК ==================
void draw_arrow(int x0, int y0, int x1, int y1, uint16_t color) {
int dx = abs(x1 - x0);
int dy = abs(y1 - y0);
int sx = x0 < x1 ? 1 : -1;
int sy = y0 < y1 ? 1 : -1;
int err = dx - dy;
while(1) {
set_window(x0, y0, x0, y0);
digitalWrite(TFT_DC, HIGH);
digitalWrite(TFT_CS, LOW);
SPI.transfer(color >> 8);
SPI.transfer(color & 0xFF);
digitalWrite(TFT_CS, HIGH);
if(x0 == x1 && y0 == y1) break;
int e2 = 2 * err;
if(e2 > -dy) {
err -= dy;
x0 += sx;
}
if(e2 < dx) {
err += dx;
y0 += sy;
}
}
}
// ================== ОТРИСОВКА ВСЕГО ЭКРАНА ==================
void draw_full_screen() {
int centerX = SCREEN_WIDTH / 2;
int centerY = SCREEN_HEIGHT / 2;
int num_strips = (SCREEN_HEIGHT + STRIP_HEIGHT - 1) / STRIP_HEIGHT;
// Сначала рисуем синусоиду полосами
for(int strip = 0; strip < num_strips; strip++) {
generate_sine_strip(strip, centerY, 80);
}
// Потом сетку поверх
draw_grid();
// Стрелочки на осях
draw_arrow(centerX - 5, 10, centerX, 0, GRAY);
draw_arrow(centerX + 5, 10, centerX, 0, GRAY);
draw_arrow(SCREEN_WIDTH - 10, centerY - 5, SCREEN_WIDTH - 1, centerY, GRAY);
draw_arrow(SCREEN_WIDTH - 10, centerY + 5, SCREEN_WIDTH - 1, centerY, GRAY);
}
// ================== ЗАЛИВКА ЭКРАНА ==================
void fill_screen(uint16_t color) {
set_window(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
digitalWrite(TFT_DC, HIGH);
digitalWrite(TFT_CS, LOW);
uint8_t hi = color >> 8;
uint8_t lo = color & 0xFF;
for(int i = 0; i < SCREEN_WIDTH * SCREEN_HEIGHT; i++) {
SPI.transfer(hi);
SPI.transfer(lo);
}
digitalWrite(TFT_CS, HIGH);
}
// ================== SETUP И LOOP ==================
void setup() {
spi_init();
ili9341_init();
}
void loop() {
// Черный фон
fill_screen(BLACK);
draw_full_screen();
delay(4000);
// Синий фон
fill_screen(BLUE);
draw_full_screen();
delay(4000);
// Красный фон
fill_screen(RED);
draw_full_screen();
delay(4000);
// Зеленый фон
fill_screen(GREEN);
draw_full_screen();
delay(4000);
}