TLC5940, запись значений,
- Войдите на сайт для отправки комментариев
Добрый день.
И вновь столкнулся с непонятной вещью при работе с TLC5940.
Вот тут свернутый скетч.
// "Недорогой контроллер на Ардуино нано + TLC5940 + DALLAS-DS18B20"
// шести канальный контроллер, 12-bit шим
// Комплектация: Arduino nano, RTC-modul, TLC5940, DALLAS-DS18B20.
// перед началом компиляции откройте монитор порта в правом верхнем углу окна программы
#include "Tlc5940.h"
#include <OneWire.h>
OneWire ds(5); // Температурный сенсор DALLAS-DS18B20 подключен к D5
#include <DS1307.h>
DS1307 rtc(A0, A1); //RTC-модуль подключен к: SDA - > A0, SCL -> A1
Time t;
int ventpin = 6; // управление вентилятором осуществляется с D6
byte tic[6][5];
int long Value[6];
int long Array[6][6];
uint32_t Event[6][3];
float power = 100; // общая мощность освещения [0 - 100]
int long time_all;
int long last_time_all;
byte temp = 0;
int long level; // значение уровня канала в цикле периода (рассвет, закат)
void setup() {
Serial.begin ( 115200 ); // Указвать скорость на которой работает Ваш COM-порт
Tlc.init();
Tlc.clear();
pinMode (ventpin, OUTPUT);
rtc.halt(false);
/* MONDEY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
Три строчки ниже необходимо раскомментировать (убрать двойную дробь) при стартовой загрузки программы.
Сразу после первой загрузки, нужно закомментировать данные строки и
обращаться к этой процедуре в случае сбоя в работе часов. RTC-модуль запомнит время. */
// rtc.setDOW(SUNDAY); // изменить день недели. примеры указаны на четыре строчки выше
// rtc.setTime(11, 41, 0); // время
// rtc.setDate(13, 9, 2015); // дата
// Настройки светильника: <время восхода>, <продолжительность рассвета>, <мощность канала в течении "дня">, <время заката>, <продолжительность заката>
// первый канал
Array[0][0] = 875; // начало рассвета первого канала в минутах. например: 10:00 записывается как <600> (в минутах)
Array[0][1] = 895; // конец рассвета первого канала. например: 11:15 записывается как <675> (в минутах)
Array[0][2] = 1020; // начало заката первого канала. например: 20:50 записывается как <1250> (в минутах)
Array[0][3] = 1080; // окончание заката первого канала. например: 21:50 записывается как <1310> (в минутах)
Array[0][4] = 100; // мощность первого канала в процентах в течении "дня" (в процентах). не может быть больше 100
Array[0][5] = 0; // инвертор драйвера. Имеет значения 0 и 1. 0 - прямая логика, 1 - обратная логика
// второй канал
Array[1][0] = 811; // начало рассвета второго канала в минутах. например: 10:00 записывается как <600> (в минутах)
Array[1][1] = 831; // конец рассвета второго канала. например: 11:15 записывается как <675> (в минутах)
Array[1][2] = 1030; // начало заката второго канала. например: 20:50 записывается как <1250> (в минутах)
Array[1][3] = 1080; // окончание заката второго канала. например: 21:50 записывается как <1310> (в минутах)
Array[1][4] = 100; // мощность второго канала в процентах в течении "дня" (в процентах). не может быть больше 100
Array[1][5] = 0; // инвертор драйвера. Имеет значения 0 и 1. 0 - прямая логика, 1 - обратная логика
// третий канал
Array[2][0] = 812; // начало рассвета тертьего канала в минутах. например: 10:00 записывается как <600> (в минутах)
Array[2][1] = 832; // конец рассвета тертьего канала. например: 11:15 записывается как <675> (в минутах)
Array[2][2] = 1040; // начало заката тертьего канала. например: 20:50 записывается как <1250> (в минутах)
Array[2][3] = 1080; // окончание заката тертьего канала. например: 21:50 записывается как <1310> (в минутах)
Array[2][4] = 100; // мощность тертьего канала в процентах в течении "дня" (в процентах). не может быть больше 100
Array[2][5] = 0; // инвертор драйвера. Имеет значения 0 и 1. 0 - прямая логика, 1 - обратная логика
// четвертый канал
Array[3][0] = 813; // начало рассвета четвертого канала в минутах. например: 10:00 записывается как <600> (в минутах)
Array[3][1] = 833; // конец рассвета четвертого канала. например: 11:15 записывается как <675> (в минутах)
Array[3][2] = 1050; // начало заката четвертого канала. например: 20:50 записывается как <1250> (в минутах)
Array[3][3] = 1080; // окончание заката четвертого канала. например: 21:50 записывается как <1310> (в минутах)
Array[3][4] = 100; // мощность четвертого канала в процентах в течении "дня" (в процентах). не может быть больше 100
Array[3][5] = 0; // инвертор драйвера. Имеет значения 0 и 1. 0 - прямая логика, 1 - обратная логика
// пятый канал
Array[4][0] = 814; // начало рассвета пятого канала в минутах. например: 10:00 записывается как <600> (в минутах)
Array[4][1] = 834; // конец рассвета пятого канала. например: 11:15 записывается как <675> (в минутах)
Array[4][2] = 1060; // начало заката пятого канала. например: 20:50 записывается как <1250> (в минутах)
Array[4][3] = 1080; // окончание заката пятого канала. например: 21:50 записывается как <1310> (в минутах)
Array[4][4] = 100; // мощность пятого канала в процентах в течении "дня" (в процентах). не может быть больше 100
Array[4][5] = 0; // инвертор драйвера. Имеет значения 0 и 1. 0 - прямая логика, 1 - обратная логика
// шестой канал
Array[5][0] = 815; // начало рассвета шестого канала в минутах. например: 10:00 записывается как <600> (в минутах)
Array[5][1] = 835; // конец рассвета шестого канала. например: 11:15 записывается как <675> (в минутах)
Array[5][2] = 1070; // начало заката шестого канала. например: 20:50 записывается как <1250> (в минутах)
Array[5][3] = 1080; // окончание заката шестого канала. например: 21:50 записывается как <1310> (в минутах)
Array[5][4] = 100; // мощность шестого канала в процентах в течении "дня" (в процентах). не может быть больше 100
Array[5][5] = 0; // инвертор драйвера. Имеет значения 0 и 1. 0 - прямая логика, 1 - обратная логика
// Перевод массива в секунды
for (int q=0; q<6; q++) {
for (int w=0; w<4; w++) {
Array[q][w] = Array[q][w] * 60;
}
}
// Сброс суточного массива
for (int q=0; q<6; q++) {
for (int w=0; w<5; w++) {
tic[q][w] = 0;
}
}
// Вывод проверочной стартовой таблицы
Serial.println ( "" );Serial.println ( "" );
Serial.print ( " Time: " ); Serial.print ( rtc.getTimeStr() ); Serial.println ( " <- Check this after reset." );Serial.println ( "" );
Serial.println ( " Chanal : Sanrise : Day : Sanset : Night : Led chanal: Inverse" );
for (int q=0; q<6; q++) {
Serial.print ( " PWM" );
Serial.print ( q+1 );
for (int w=0; w<5; w++) {
Serial.print ( " : " );
if (w < 4) {
if ( ( Array[q][w]/3600 ) < 10) {Serial.print ( "0" ); Serial.print ( Array[q][w]/3600 );
} else {Serial.print ( Array[q][w]/3600 );}
Serial.print ( ":" );
if ((( Array[q][w]-((Array[q][w]/3600)*3600))/60) < 10) {Serial.print ( "0" );Serial.print (( Array[q][w]-((Array[q][w]/3600)*3600))/60 );
} else {Serial.print (( Array[q][w]-((Array[q][w]/3600)*3600))/60 );}
} else {
if (Array[q][w] < 100) {Serial.print ( " ");}
Serial.print ( Array[q][w]);Serial.print ( "%");Serial.print ( " : ");
Serial.print ( Array[q][w+1]);
}
}
Serial.println ( "" );
}
Serial.println ( "-------------------------------------------------" );
// Проверка корректности ввода исходных данных
for (int q=0; q<6; q++) {if (Array[q][4] >= 86400) {Array[q][4] = 86399; Serial.print ( "Error, check PWM" ); Serial.print ( q+1 ); Serial.println ( ", fixed the end of the sunset to 24:00" );}}
for (int q=0; q<6; q++) {if (Array[q][5] >= 101) {Array[q][5] = 100; Serial.print ( "Error, check PWM" ); Serial.print ( q+1 ); Serial.println ( ", fixed the power led to 100%" ); }}
for (int q=0; q<6; q++) {
for (int w=0; w<3; w++) {
if ( Array[q][w] > Array[q][w+1] ) {Serial.print ( "Error, check PWM" ); Serial.print ( q+1 ); Serial.println ( ", not continuity sanrise and sanset. Controller will not work correctly. Check setup. " );
}
}
}
Serial.print ( " All powerful LEDs: " ); Serial.print ( power ); Serial.println ( "%" );
Serial.println ( " In service. OK." );
// Изменение мощности из процентов в значение
for (int q=0; q<6; q++) {
Value[q] = map (Array[q][4], 0, 100, 0, 4095) * (power/ 100);
}
}
void loop() {
// Константы температуры
float tmin = 26.00; // минитальное значение на датчике, при достижении которого запускается вентилятор. Указывается значение в градусах. Например: "32", означает 32градуса цельсия
float tmax = 31.00; // максимальное значение на датчике, служит для плавного увеличения скорости вращения вентилятора. Указывается значение в градусах. Например: "36", означает 36градуса цельсия. На превышающих значениях вентилятор работает на 100% мощности
// Блок программы работающий с температурным датчиком и вентилятором
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float celsius;
ds.search(addr);
ds.reset();
ds.select(addr);
ds.write(0x44, 1);
ds.reset();
present = ds.reset();
ds.select(addr);
ds.write(0xBE);
for ( i = 0; i < 9; i++) {
data[i] = ds.read();
}
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; //
if (data[7] == 0x10) {
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
byte cfg = (data[4] & 0x60);
if (cfg == 0x00) raw = raw & ~7;
else if (cfg == 0x20) raw = raw & ~3;
else if (cfg == 0x40) raw = raw & ~1;
}
celsius = (float)raw / 16.0;
if (temp == 0) {
Serial.print(" Temperature = ");
Serial.print(celsius);
Serial.println(" Celsius \n ");
temp = 1;}
if ( tmin > celsius ) analogWrite (ventpin, 0);
if ( tmin <= celsius && tmax >= celsius ) analogWrite (ventpin, map(celsius, tmin , tmax, 0, 255));
if ( tmax < celsius) analogWrite (ventpin,255);
// конец блока температуры
t = rtc.getTime();
int long h = t.hour;
int long m = t.min;
int long s = t.sec;
time_all = ( (h * 3600)+(m * 60)+ s );
// Сброс состояния контроллера на новый день.
if (time_all < last_time_all) {
// Сброс суточного массива
for (int q=0; q<6; q++) {
for (int w=0; w<5; w++) {
tic[q][w] = 0;
}
}
}
last_time_all = time_all;
// Контроллер
for (int q=0; q<6; q++) {
if (time_all >= 0 && time_all <= Array[q][0] && tic[q][0] == 0) {
if (Array[q][5]==0)Tlc.set (q, 0);
if (Array[q][5]==1)Tlc.set (q, 4095);
tic[q][0] = 1;
Serial.print ( rtc.getTimeStr() );Serial.print ( " PWM:" );Serial.print ( q+1 ); Serial.println ( " - mon" );
}
if (time_all >= Array[q][0] && time_all <= Array[q][1] ) {
if (tic[q][1] == 0){Event[q][0] = (time_all - Array[q][0])*1000;
Event[q][1] = ((Array[q][1]-Array[q][0])*1000);
Event[q][2] = millis() - Event[q][0];
Serial.print ( rtc.getTimeStr() );Serial.print ( " PWM:" );Serial.print ( q+1 ); Serial.println ( " - on" );
tic[q][1] = 1;}
level = ((millis() - Event[q][2])*Value[q])/(Event[q][1]);
if(level <= 0) level = 0; if(level >= Value[q]) level = Value[q];
if (Array[q][5]==0)Tlc.set (q, level);
if (Array[q][5]==1)Tlc.set (q, 4095-level);
Serial.print ( q );Serial.print ( " " );Serial.print ( level );Serial.print ( " " );Serial.print ( millis() );Serial.print ( " " );Serial.print ( Event[q][2] );Serial.print ( " " );Serial.print ( Value[q] );Serial.print ( " " );Serial.println ( Event[q][1] );
}
if (time_all >= Array[q][1] && time_all <= Array[q][2] && tic[q][2] == 0) {
if (Array[q][5]==0)Tlc.set (q, 4095);
if (Array[q][5]==1)Tlc.set (q, 0);
tic[q][2] = 1 ;
Serial.print ( rtc.getTimeStr() );Serial.print ( " PWM:" );Serial.print ( q+1 ); Serial.println ( " - day " );
}
if (time_all >= Array[q][2] && time_all <= Array[q][3] ) {
if (tic[q][3] == 0){ Event[q][0] = (time_all - Array[q][2])*1000;
Event[q][1] = ((Array[q][3]-Array[q][2])*1000);
Event[q][2] = millis();
Serial.print ( rtc.getTimeStr() );Serial.print ( " PWM:" );Serial.print ( q+1 ); Serial.println ( " - off" );
tic[q][3] = 1;}
level = ((millis() - Event[q][2])*Value[q])/(Event[q][1]);
if(level <= 0) level = 0; if(level >= Value[q]) level = Value[q];
if (Array[q][5]==0)Tlc.set (q, 4095-level); // Закат сделан по принципу рассвета.
if (Array[q][5]==1)Tlc.set (q, level); // Разница в этих двух строках.
}
if (time_all >= Array[q][3] && time_all <= 86399 && tic[q][4] == 0) {
if (Array[q][5]==0)Tlc.set (q, 0);
if (Array[q][5]==1)Tlc.set (q, 4095);
tic[q][4] = 1 ;
Serial.print ( rtc.getTimeStr() );Serial.print ( " PWM:" );Serial.print ( q+1 ); Serial.println ( " - nig" );
}
}
Tlc.update();
}
В массиве Arrey[0][0] указываю время начала расвета в минутах, в Arrey[0][1] - время окончания рассвета.
Далее уже методом подобия треугольников расчитывается значение, которое записывается в канал TLC5940
И где то на 90% он у меня все равно сбрасывается в ноль и начинается все сначала!!!
Я прописал тестовую строку, которая у меня выводит формулу.
level = ((millis() - Event[q][2])*Value[q])/(Event[q][1]);
Первая цифра - "0" - это канал, в данном случае первый
Вторая цифра - это значение шим, записываемое в канал 0-4095
Третий столбей - это millis()
Четвертый столбец Event[q][2]
пятый Value[q]
Шестой Event[q][1]
И эта информация просто спамится во время рассвета.
И вот до куда она доходит при двадцатиминутном периоде рассвета

Я не понимаю!
Я в ручную посчитал столбец, где в ШИМ появился ноль, там должен быть 3579.14 !!!!
ППЦ, чё делать?
level = ((millis() - Event[q][2])*Value[q])/(Event[q][1]);
Я не понимаю!
ППЦ, чё делать?
плакать :) и считать... дальше нужно объяснять?
Реально, ничего не понял (((
Хм... странно, как у Вас ноль получается, эксель дает вот это:
Реально, ничего не понял (((
Хм... странно, как у Вас ноль получается, эксель дает вот это:
я же нарисовал картинки калькулятора!!! там идет переполнение 2 байт!!!! просто нужна переменная на 4 байта и все, сам код не смотрел - переполнение идет в процессе вычислений, по тому и не очевидно!!! т.е. в процессе вычислений негде хранить числитель дроби :)
Если не трудно, посмотри пожалуйста, я совсем плохо в этом разбираюсь... в коде много комментариев.
Просто если в коде, там все переменные вверху, если в библиотеках что то править нужно, то я ваще ноль.
По сути код работает. Но работает при периоде рассвета до пяти минут. Если это действие проходит дОльше по времени, то начинается такая фигня.
поменяйте все int long на:
unsigned long
Описание типа
Unsigned long используется для хранения положительных целых чисел в диапазоне от 0 до 4,294,967,295 (2^32 - 1) и занимает 32 бита (4 байта) в памяти.
Вам ведь знак "-" не нужен?
Вам ведь знак "-" не нужен?
Спасибо большое!!!
Нет, знак "-" не нужен
больше нет времени сидеть за компом, буду очень поздно вечером
Запустил тест. Спасибо еще раз.
Закменил
Не помогло (
Ну хорошо, что скриншоты, а не фотографии.
Поржал над 12 строкой. Аппаратного i2c мало?
.....
.....
.....
ППЦ, чё делать?
Так попробуйте:
Но я сам не проверял, если что - я не виноват. :)
.....
.....
.....
ППЦ, чё делать?
Так попробуйте:
Но я сам не проверял, если что - я не виноват. :)
Ты Бог! )))
Спасибо!!!!!!!!
Прошло, как по маслу. Ща потестирую на разных временных диапазонах.
sinnpriest, загляните в программирование и почитайте о типах данных. Здесь именно ошибка в переполнении, на будущее может пригодиться… Старайтесь избегать громоздких вычислений и больших величин
Так попробуйте:
Но я сам не проверял, если что - я не виноват. :)
Datak, если я правильно понял, это выражение означает выполнять вычисления с плавающей запятаой (float) а результат записывать в типе данных level ?
Ну да. Во всяком случае, я так планировал. Вот, sinnpriest говорит что получилось.
Насколько я понимаю, компилятор, встретив первый операнд типа float, обязан (в данном случае) второй операнд преобразовать к тому же типу. Результат операции, соответственно, тоже будет float, и значит все последующие операции будут выполняться по тому же правилу.
А при присвоении значения переменной level - да, тип опять преобразуется в целочисленный.
Да уж, никак не меньше. Всеми этими рассветами-закатами рулить - шутка ли... :)
Да, все заработало. Протестил при разной длительности по всем каналам. И по отдельности и вместе. Теперь все работает, как и задумывалось. Сейчас на работе оставил контроллер на питании. Он штатно отработал закат по всем каналам. Завтра с утра посмотрю, как он "пережил" ночь и как он так же правильно отработает рассветы.
Просто я в упор не понял, как тут float поможет, но мне было не трудно это проверить, т.к. все равно был в ступоре, ибо не понимал нюансы. Поэтому моему удивлению не было предела ))).
Да, все заработало. Протестил при разной длительности по всем каналам. И по отдельности и вместе. Теперь все работает, как и задумывалось. Сейчас на работе оставил контроллер на питании. Он штатно отработал закат по всем каналам. Завтра с утра посмотрю, как он "пережил" ночь и как он так же правильно отработает рассветы.
Просто я в упор не понял, как тут float поможет, но мне было не трудно это проверить, т.к. все равно был в ступоре, ибо не понимал нюансы. Поэтому моему удивлению не было предела ))).
Тут то как раз все просто, шло переполнение переменной по типу, т.е. переменная не может хранить по каким-то причинам больше 2 байт (согласно выбранному типу) и калькулятор это подтвердил (см. скрины). А вот почему мое предложение не помогло нужно детально разбираться в коде. И почему помог совет Datak написано им чуть выше. float позволяет хранить ОЧЕНЬ большие значения - это не просто 4 байта. Но и вычисляется он ООООЧЕНЬ долго.