Всем примет
Не так давно начал плотно изучать ардуино, сейчас переключился на адресные матрицы ws2812b 8x8. Смог разобраться и вывести работу светофора (Красный, желтый, зелёный) по времени и понял как отдельно выводить время. Но уже 2ю неделю не могу понять где ошибка и как сделать что бы на светофоре выводилось время и цвета светофора.
Все матрицы подключены последовательно, на один пин. Части кода взяты из разных проектов (Алекс Гайвер, vvip-68)
Пытаюсь реализовать следующий алгоритм:
Матрицы расположены сверху вниз
На 1й матрице горит красный
На второй идет отсчет времени красным цветом
На второй матрице отсчет доходит до 3, вторая матрица загорается желтый, отсчет на ней перестает идти, но функция считает. Когда в функции счет доходит до 0, первая и вторая матрицы гаснут, загорается 3я матрица зеленым светом и на 2й снова идет отсчет времени. Когда на 2й матрице отсчет времени доходит до 5, начинает мигать зелёный свет на третей матрице, дошел отсчет до 0 на 3 секунды загорается желтый свет, потом красный и так по кругу.
Если горит красный, то отсчет идет красным цветом, если зелёный то отсчет идет зелёным. При желтом цвете счет времени идет только в контроллере, на матрице не отображается.
В приведённом ниже коде, по отдельности работают только отсчет времени и автоматический алгоритм светофора, заливка цвета без счета.
Так же там таймер считает с 96 до 0 и свет отсчета синий, это делал на время тестов, пока пытался все объединить в одно. Ещё в результате недостатка знаний со временем алгоритм зависает и цвета переключаются с задержкой. Например желтый, включается зелёный, и спустя несколько секунд гаснет желтый.
Буду признателен за объяснения где ошибки и как их исправить
Не так давно начал плотно изучать ардуино, сейчас переключился на адресные матрицы ws2812b 8x8. Смог разобраться и вывести работу светофора (Красный, желтый, зелёный) по времени и понял как отдельно выводить время. Но уже 2ю неделю не могу понять где ошибка и как сделать что бы на светофоре выводилось время и цвета светофора.
Все матрицы подключены последовательно, на один пин. Части кода взяты из разных проектов (Алекс Гайвер, vvip-68)
Пытаюсь реализовать следующий алгоритм:
Матрицы расположены сверху вниз
На 1й матрице горит красный
На второй идет отсчет времени красным цветом
На второй матрице отсчет доходит до 3, вторая матрица загорается желтый, отсчет на ней перестает идти, но функция считает. Когда в функции счет доходит до 0, первая и вторая матрицы гаснут, загорается 3я матрица зеленым светом и на 2й снова идет отсчет времени. Когда на 2й матрице отсчет времени доходит до 5, начинает мигать зелёный свет на третей матрице, дошел отсчет до 0 на 3 секунды загорается желтый свет, потом красный и так по кругу.
Если горит красный, то отсчет идет красным цветом, если зелёный то отсчет идет зелёным. При желтом цвете счет времени идет только в контроллере, на матрице не отображается.
В приведённом ниже коде, по отдельности работают только отсчет времени и автоматический алгоритм светофора, заливка цвета без счета.
Так же там таймер считает с 96 до 0 и свет отсчета синий, это делал на время тестов, пока пытался все объединить в одно. Ещё в результате недостатка знаний со временем алгоритм зависает и цвета переключаются с задержкой. Например желтый, включается зелёный, и спустя несколько секунд гаснет желтый.
1:
#define TIME_RED 7 // секунды работы
#define TIME_YELLOW 3
#define TIME_GREEN 15
#define COLOR_RED CRGB::Red // быстрые цвета
#define COLOR_YELLOW CRGB::Yellow
#define COLOR_GREEN CRGB::Green
// Переменные для таймера
int8_t newSecs = 96;
uint32_t newColor;
uint32_t timeCounter = 0;
uint32_t RED_DURATION = TIME_RED * 1000; // перевод в секунды для millis
uint32_t YELLOW_DURATION = TIME_YELLOW * 1000;
uint32_t GREEN_DURATION = TIME_GREEN * 1000;
#define BRIGHTNESS 7 // Яркость матрицы по-умолчанию 0..255
//////////////////////////////////////////////////
#define COLOR_ORDER GRB // Порядок цветов на ленте. Если цвет отображается некорректно - меняйте. Начать можно с RGB
#define WIDTH 8 // ширина одного сегмента матрицы
#define HEIGHT 8 // высота одного сегмента матрицы
#define MATRIX_TYPE 0 // тип соединения диодов в сегменте матрицы: 0 - зигзаг, 1 - параллельная
#define CONNECTION_ANGLE 3 // угол подключения диодов в сегменте: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
#define STRIP_DIRECTION 1 // направление ленты из угла сегмента: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз
#define META_MATRIX_WIDTH 1 // количество сегментов в ширину сборной матрицы
#define META_MATRIX_HEIGHT 3 // количество сегментов в высоту сборной матрицы
#define META_MATRIX_TYPE 0 // тип сборной матрицы: 0 - зигзаг, 1 - параллельная
#define META_MATRIX_ANGLE 3 // угол 1-го сегмента сборной матрицы: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
#define META_MATRIX_DIRECTION 3 // направление следующих сегментов сборной матрицы из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз
#define LED_PIN 13 // пин ленты
// =======================================================
// ************** ИСПОЛЬЗУЕМЫЕ БИБЛИОТЕКИ ****************
#include <FastLED.h> // Установите в менеджере библиотек стандартную библиотеку FastLED
// =======================================================
// ************************* УПРАВЛЕНИЕ МАТРИЦЕЙ *******************************
uint16_t CURRENT_LIMIT = 500; // лимит по току в миллиамперах, автоматически управляет яркостью (пожалей свой блок питания!) 0 - выключить лимит
uint8_t sWIDTH = WIDTH; // ширина одного сегмента матрицы 1..127
uint8_t sHEIGHT = HEIGHT; // высота одного сегмента матрицы 1..127
uint8_t sMATRIX_TYPE = MATRIX_TYPE; // тип соединения диодов в сегменте матрицы: 0 - зигзаг, 1 - параллельная, 2 - карта индексов
uint8_t sCONNECTION_ANGLE = CONNECTION_ANGLE; // угол подключения диодов в сегменте: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
uint8_t sSTRIP_DIRECTION = STRIP_DIRECTION; // направление ленты из угла сегмента: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз
uint8_t mWIDTH = META_MATRIX_WIDTH; // количество сегментов в ширину 1..9
uint8_t mHEIGHT = META_MATRIX_HEIGHT; // количество сегментов в высоту 1..9
uint8_t mTYPE = META_MATRIX_TYPE; // соединение сегментов мета-матрицы: 0 - зигзаг, 1 - параллельная
uint8_t mANGLE = META_MATRIX_ANGLE; // угол 1-го сегмента мета-матрицы: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
uint8_t mDIRECTION = META_MATRIX_DIRECTION; // направление следующих сегментов мета-матрицы из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз
uint8_t pWIDTH = sWIDTH * mWIDTH; // Равна ширене одного сегмента * на количество сегментов в ширину 8*1=8
uint8_t pHEIGHT = sHEIGHT * mHEIGHT; // Равна высоте одного сегмента * на количество сегментов в высоту 8*3=24
uint32_t NUM_LEDS = pWIDTH * pHEIGHT;
uint8_t maxDim = max(pWIDTH, pHEIGHT);
uint8_t minDim = min(pWIDTH, pHEIGHT);
CRGB *leds; // обращение к светодиодам матрицы через этот массив
// ------------------- ВРЕМЕННЫЕ ПЕРЕМЕННЫЕ ----------------------
uint8_t globalBrightness = BRIGHTNESS; // текущая яркость (общая)
// ---------------------------------------------------------------
void setup()
{
Serial.begin(9600);
pWIDTH = sWIDTH * mWIDTH;
pHEIGHT = sHEIGHT * mHEIGHT;
NUM_LEDS = pWIDTH * pHEIGHT;
maxDim = max(pWIDTH, pHEIGHT);
minDim = min(pWIDTH, pHEIGHT);
// Настройки ленты
leds = new CRGB[NUM_LEDS];
FastLED.addLeds<WS2812, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
FastLED.setBrightness(globalBrightness);
if (CURRENT_LIMIT > 0) {
FastLED.setMaxPowerInVoltsAndMilliamps(5, CURRENT_LIMIT);
}
FastLED.clear();
FastLED.show();
newColor = CRGB::Yellow;
}
void loop()
{
handleTime();
}
custom:
enum LightState {RED, YELLOW, GREEN};
LightState currentLight = RED;
uint32_t redTime = 0;
uint32_t yellowTime = 0;
uint32_t greenTime = 0;
boolean Flag = true;
void light() {
//FastLED.clear();
switch (currentLight)
{
case RED:
if (millis() - redTime >= RED_DURATION)
{
currentLight = YELLOW;
redTime = millis();
}
break;
case YELLOW:
if (millis() - redTime >= YELLOW_DURATION)
{
if (Flag)
{
currentLight = GREEN;
}
else
{
currentLight = RED;
}
Flag = !Flag;
redTime = millis();
}
break;
case GREEN:
if (millis() - redTime >= GREEN_DURATION)
{
currentLight = YELLOW;
redTime = millis();
}
break;
}
switch (currentLight) {
case RED:
newColor = COLOR_RED;
fillGreenBlack();
fillRed();
break;
case YELLOW:
if (Flag) {
fillRedBlack();
}
else {
fillGreenBlack();
}
fillYellow();
break;
case GREEN:
newColor = COLOR_GREEN;
fillGreen();
break;
}
//FastLED.clear();
}
effects:
// Отсчет времени
void handleTime()
{
light();
if (millis() - timeCounter >= 1000L && newSecs > 0) {
timeCounter = millis();
//FastLED.clear();
--newSecs;
if (currentLight != 1)
{
showClear();
displayScore(newSecs, newColor);
}
Serial.println(newSecs);
if (newSecs == 0) newSecs = 96;
}
FastLED.show();
}
// вывод цифр
void displayScore(byte score, CRGB color) {
if (score > 9)
{
drawDigit3x5(score / 10, 1, 10, color);
drawDigit3x5(score % 10, 5, 10, color);
}
else
{
drawDigit3x5(score % 10, 3, 10, color);
}
FastLED.show();
}
void showClear() {
for (int i = 64; i < 128; i++) {
leds[i] = CRGB::Black;
}
//FastLED.show();
}
void fillRed() {
for (int i = 0; i < 64; i++) {
leds[i] = CRGB::Red;
}
FastLED.show();
}
void fillRedBlack() {
for (int i = 0; i < 64; i++) {
leds[i] = CRGB::Black;
}
FastLED.show();
}
void fillYellow() {
for (int i = 64; i < 128; i++) {
leds[i] = CRGB::Yellow;
}
FastLED.show();
}
void fillYellowBlack() {
for (int i = 64; i < 128; i++) {
leds[i] = CRGB::Black;
}
FastLED.show();
}
void fillGreen() {
for (int i = 128; i < 192; i++) {
leds[i] = CRGB::Green;
}
FastLED.show();
}
void fillGreenBlack() {
for (int i = 128; i < 192; i++) {
leds[i] = CRGB::Black;
}
FastLED.show();
}
boolean pulseFlag = true;
uint32_t pulseTime;
void fillYellowPulse()
{
if (millis() - pulseTime >= 1000)
{
if (pulseFlag) {
fillYellow();
} else {
fillYellowBlack();
}
pulseTime = millis();
pulseFlag = !pulseFlag;
}
}
void fillGreenPulse()
{
if (millis() - pulseTime >= 1000)
{
if (pulseFlag) {
fillGreen();
}
else {
fillGreenBlack();
}
pulseTime = millis();
pulseFlag = !pulseFlag;
}
}
utility:
// служебные функции
// шрифт 3х5 квадратный
const uint8_t font3x5[][3] PROGMEM = {
{0b11111, 0b10001, 0b11111}, // 0
{0b00000, 0b11111, 0b00000}, // 1
{0b10111, 0b10101, 0b11101}, // 2
{0b10101, 0b10101, 0b11111}, // 3
{0b11100, 0b00100, 0b11111}, // 4
{0b11101, 0b10101, 0b10111}, // 5
{0b11111, 0b10101, 0b10111}, // 6
{0b10000, 0b10000, 0b11111}, // 7
{0b11111, 0b10101, 0b11111}, // 8
{0b11101, 0b10101, 0b11111}, // 9
};
// нарисовать цифру шрифт 3х5 квадратный
void drawDigit3x5(uint8_t digit, int8_t X, int8_t Y, CRGB color) {
if (digit > 9) return;
for (uint8_t x = 0; x < 3; x++) {
uint8_t thisByte = pgm_read_byte(&(font3x5[digit][x]));
for (uint8_t y = 0; y < 5; y++) {
if (y + Y > pHEIGHT) continue;
if (thisByte & (1 << y)) drawPixelXY(x + X, y + Y, color);
}
}
}
void fillAll(uint32_t color) {
fill_solid(leds, NUM_LEDS, color);
}
// залить все
void fillAll(CRGB color) {
fill_solid(leds, NUM_LEDS, color);
}
// функция получения цвета пикселя по его номеру
uint32_t getPixColor(int16_t thisPixel) {
if (thisPixel < 0 || thisPixel > NUM_LEDS - 1) return 0;
return (((uint32_t)leds[thisPixel].r << 16) | ((uint32_t)leds[thisPixel].g << 8 ) | (uint32_t)leds[thisPixel].b);
}
// функция получения цвета пикселя в матрице по его координатам
uint32_t getPixColorXY(int8_t x, int8_t y) {
return getPixColor(getPixelNumber(x, y));
}
// функция отрисовки точки по координатам X Y
void drawPixelXY(int8_t x, int8_t y, CRGB color) {
if (x < 0 || x > pWIDTH - 1 || y < 0 || y > pHEIGHT - 1) return;
int16_t thisPixel = getPixelNumber(x, y);
if (thisPixel >= 0) leds[thisPixel] = color;
}
void drawPixelXYF(float x, float y, CRGB color) {
// extract the fractional parts and derive their inverses
uint8_t xx = (x - (int)x) * 255, yy = (y - (int)y) * 255, ix = 255 - xx, iy = 255 - yy;
// calculate the intensities for each affected pixel
#define WU_WEIGHT(a,b) ((uint8_t) (((a)*(b)+(a)+(b))>>8))
uint8_t wu[4] = {WU_WEIGHT(ix, iy), WU_WEIGHT(xx, iy),
WU_WEIGHT(ix, yy), WU_WEIGHT(xx, yy)
};
// multiply the intensities by the colour, and saturating-add them to the pixels
for (uint8_t i = 0; i < 4; i++) {
int16_t xn = x + (i & 1), yn = y + ((i >> 1) & 1);
CRGB clr = getPixColorXY(xn, yn);
clr.r = qadd8(clr.r, (color.r * wu[i]) >> 8);
clr.g = qadd8(clr.g, (color.g * wu[i]) >> 8);
clr.b = qadd8(clr.b, (color.b * wu[i]) >> 8);
drawPixelXY(xn, yn, clr);
}
}
// получить номер пикселя в ленте по координатам
int16_t getPixelNumber(int8_t x, int8_t y) {
if (x < 0 || x >= pWIDTH || y < 0 || y >= pHEIGHT) return -1;
uint8_t xx, yy, ww, sx, sy, mx, my, mw, snum, num;
if (sMATRIX_TYPE == 0 || sMATRIX_TYPE == 1) {
// --------------------------------------------------
// Матрица состоит из одного сегмента, адресация по углу подключения, типу, направлению
// --------------------------------------------------
if (mWIDTH == 1 && mHEIGHT == 1) {
xx = THIS_X(x, y);
yy = THIS_Y(x, y);
ww = THIS_W();
return (yy % 2 == 0 || sMATRIX_TYPE == 1)
? yy * ww + xx // если чётная строка
: yy * ww + ww - xx - 1; // если нечётная строка
}
// --------------------------------------------------
// Матрица - сборная, состоит из нескольких сегментов, адресация по углу подключения, типу, направлению
// --------------------------------------------------
sx = x / sWIDTH; // номер сегмента по ширине
sy = y / sHEIGHT; // номер сегмента по высоте
x = x % sWIDTH; // позиция x относительно сегмента
y = y % sHEIGHT; // позиция y относительно сегмента
// Номер сегмента в последовательности сборной матрицы
mx = THIS_SX(sx, sy);
my = THIS_SY(sx, sy);
mw = THIS_SW();
snum = (my % 2 == 0 || mTYPE == 1)
? my * mw + mx // если чётная строка мета-матрицы
: my * mw + mw - mx - 1; // если нечётная строка мета-матрицы
// Номер дода в сегменте
xx = THIS_X(x, y);
yy = THIS_Y(x, y);
ww = THIS_W();
num = (yy % 2 == 0 || sMATRIX_TYPE == 1)
? yy * ww + xx // если чётная строка
: yy * ww + ww - xx - 1; // если нечётная строка
return snum * sWIDTH * sHEIGHT + num;
}
return -1;
}
uint8_t THIS_X(uint8_t x, uint8_t y) {
/*
CONNECTION_ANGLE; // угол подключения: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
STRIP_DIRECTION; // направление ленты из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз
*/
if (sCONNECTION_ANGLE == 0 && sSTRIP_DIRECTION == 0) return x;
if (sCONNECTION_ANGLE == 0 && sSTRIP_DIRECTION == 1) return y;
if (sCONNECTION_ANGLE == 1 && sSTRIP_DIRECTION == 0) return x;
if (sCONNECTION_ANGLE == 1 && sSTRIP_DIRECTION == 3) return sHEIGHT - y - 1;
if (sCONNECTION_ANGLE == 2 && sSTRIP_DIRECTION == 2) return sWIDTH - x - 1;
if (sCONNECTION_ANGLE == 2 && sSTRIP_DIRECTION == 3) return sHEIGHT - y - 1;
if (sCONNECTION_ANGLE == 3 && sSTRIP_DIRECTION == 2) return sWIDTH - x - 1;
if (sCONNECTION_ANGLE == 3 && sSTRIP_DIRECTION == 1) return y;
return x;
}
uint8_t THIS_Y(uint8_t x, uint8_t y) {
/*
CONNECTION_ANGLE; // угол подключения: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
STRIP_DIRECTION; // направление ленты из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз
*/
if (sCONNECTION_ANGLE == 0 && sSTRIP_DIRECTION == 0) return y;
if (sCONNECTION_ANGLE == 0 && sSTRIP_DIRECTION == 1) return x;
if (sCONNECTION_ANGLE == 1 && sSTRIP_DIRECTION == 0) return sHEIGHT - y - 1;
if (sCONNECTION_ANGLE == 1 && sSTRIP_DIRECTION == 3) return x;
if (sCONNECTION_ANGLE == 2 && sSTRIP_DIRECTION == 2) return sHEIGHT - y - 1;
if (sCONNECTION_ANGLE == 2 && sSTRIP_DIRECTION == 3) return sWIDTH - x - 1;
if (sCONNECTION_ANGLE == 3 && sSTRIP_DIRECTION == 2) return y;
if (sCONNECTION_ANGLE == 3 && sSTRIP_DIRECTION == 1) return sWIDTH - x - 1;
return y;
}
uint8_t THIS_W() {
/*
CONNECTION_ANGLE; // угол подключения: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
STRIP_DIRECTION; // направление ленты из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз
*/
if (sCONNECTION_ANGLE == 0 && sSTRIP_DIRECTION == 0) return sWIDTH;
if (sCONNECTION_ANGLE == 0 && sSTRIP_DIRECTION == 1) return sHEIGHT;
if (sCONNECTION_ANGLE == 1 && sSTRIP_DIRECTION == 0) return sWIDTH;
if (sCONNECTION_ANGLE == 1 && sSTRIP_DIRECTION == 3) return sHEIGHT;
if (sCONNECTION_ANGLE == 2 && sSTRIP_DIRECTION == 2) return sWIDTH;
if (sCONNECTION_ANGLE == 2 && sSTRIP_DIRECTION == 3) return sHEIGHT;
if (sCONNECTION_ANGLE == 3 && sSTRIP_DIRECTION == 2) return sWIDTH;
if (sCONNECTION_ANGLE == 3 && sSTRIP_DIRECTION == 1) return sHEIGHT;
return sWIDTH;
}
uint8_t THIS_SX(uint8_t x, uint8_t y) {
/*
CONNECTION_ANGLE; // угол подключения: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
STRIP_DIRECTION; // направление ленты из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз
*/
if (mANGLE == 0 && mDIRECTION == 0) return x;
if (mANGLE == 0 && mDIRECTION == 1) return y;
if (mANGLE == 1 && mDIRECTION == 0) return x;
if (mANGLE == 1 && mDIRECTION == 3) return mHEIGHT - y - 1;
if (mANGLE == 2 && mDIRECTION == 2) return mWIDTH - x - 1;
if (mANGLE == 2 && mDIRECTION == 3) return mHEIGHT - y - 1;
if (mANGLE == 3 && mDIRECTION == 2) return mWIDTH - x - 1;
if (mANGLE == 3 && mDIRECTION == 1) return y;
return x;
}
uint8_t THIS_SY(uint8_t x, uint8_t y) {
/*
CONNECTION_ANGLE; // угол подключения: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
STRIP_DIRECTION; // направление ленты из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз
*/
if (mANGLE == 0 && mDIRECTION == 0) return y;
if (mANGLE == 0 && mDIRECTION == 1) return x;
if (mANGLE == 1 && mDIRECTION == 0) return mHEIGHT - y - 1;
if (mANGLE == 1 && mDIRECTION == 3) return x;
if (mANGLE == 2 && mDIRECTION == 2) return mHEIGHT - y - 1;
if (mANGLE == 2 && mDIRECTION == 3) return mWIDTH - x - 1;
if (mANGLE == 3 && mDIRECTION == 2) return y;
if (mANGLE == 3 && mDIRECTION == 1) return mWIDTH - x - 1;
return y;
}
uint8_t THIS_SW() {
/*
CONNECTION_ANGLE; // угол подключения: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний
STRIP_DIRECTION; // направление ленты из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз
*/
if (mANGLE == 0 && mDIRECTION == 0) return mWIDTH;
if (mANGLE == 0 && mDIRECTION == 1) return mHEIGHT;
if (mANGLE == 1 && mDIRECTION == 0) return mWIDTH;
if (mANGLE == 1 && mDIRECTION == 3) return mHEIGHT;
if (mANGLE == 2 && mDIRECTION == 2) return mWIDTH;
if (mANGLE == 2 && mDIRECTION == 3) return mHEIGHT;
if (mANGLE == 3 && mDIRECTION == 2) return mWIDTH;
if (mANGLE == 3 && mDIRECTION == 1) return mHEIGHT;
return mWIDTH;
}