Предполагал использовать часы на DS1307. Устанавливать их пока при включении:
DS1307 clock; //define a object of DS1307 class
void setup()
{
clock.fillByYMD(2013,1,19);//Jan 19,2013
clock.fillByHMS(15,28,30);//15:28 30"
clock.fillDayOfWeek(SAT);//Saturday
clock.setTime();//write time to the RTC chip
}
clock.getTime();
В дальнейшем #18 думал получать от центрального таймера по SPI:
lazy-fox пишет:
Например, если у меня будет центральный таймер в коридоре с выходом в интернет, и я захочу с него обмениваться информацией с периферийными таймерами - кухонным (сварились ли пельмени), комнатным(будильник прикроватный с монитором сна), и балконным(телескоп следящий за положением тел в альфа-центавре), а так же таймерами робота-пылесоса и робота-пивовара, - тогда да без SPI не обойтись, а тут?
zero_trigger, вы молодец! Сделано красиво, аккуратно и с любовью к мелочам. Скажите, после некоторой тренеровки удается с одного взгляда определять время по таким часам, или все равно нужно тупить полминуты, переводя в уме bin->dec?
За неделю можно научиться определять секунд за 5-15. Честно говоря, я немного тормоз, поэтому наверняка у многих получится быстрее. Собственно, создание часов, таки преследовало цель научиться быстро понимать бин =). Спасибо)
А это мысль! Давай как во всех электронных будильниках при включении если (clock.getTime() = 0,0,0,0,0,0) тогда горят пробелы (- - . - -), мы вводим номеронабирателем время (17.46) и часы запускаются: rtc.adjust(DateTime(2014,0,0,17,46,0)); Год нужен что бы каждую полночь в этот режим не вываливались. А в дальнейшем я заменю этот блок на авто коррекцию.
Про время. Нужно при включении установить текущее время с номеронабирателя. Я предложил по условию что год не заполнен (неважно какой, хоть 1234), после набора пишем в поле год - какой угодно год. И когда наступит полночь, то условие 0,0,0,0,0,0 не выполнится, по тому что будет 1234,0,0,0,0,0!
Напиши пока в setup{}, это не главный вопрос. Я пока не получил с ебея DS1307 толком не знаю подводных камней. Просто выведи статичное время. Пусть get time получает 0,0,0,18,12,0. Получу часы - буду думать.
Изначально предполагалось текущее время. Как именно с ним работать я пока точно не знаю, и буду дорабатывать его на финальном этапе разработки. Пока выведем статичное число 00.00 и все. Как его устанавливать и как корректировать на данном этапе не важно.
Сам концепт подразумевает собой исключительную простоту конструкции (как утюг или дисковый телефон). По этому регулировочные и корректирующие инструменты должны быть скрыты от неподготовленного пользователя.
Я часа четыре провозился сегодня с долбаными прерываниями.
При вращении диска цикл loop{} останавливается и выполняется подпрограмма номеронабирателя. Но обратно возвращается единица, а не количество единиц. Видимо прерыванием считается каждый импульс номеронабирателя. Такое ощущение что нужно считать количество вызовов подпрограммы номеронабирателя. В общем это возможно(count запихнуть внутрь подпрограммы прерывания), но как тогда разделять цифры номера (сбрасывать count)? По разнице во времени?
хотелось бы доказательств. напишите код и проверим так ли все хорошо без прерываний и индикация при этом не портится
доказательства выложу, когда на кухне приколочу к стене, на фоне пельменей.
Пока меня смущает тот факт что прерывания могут использоваться только для получения импульса, а не для получения цифры номера. Думается возврат к millis() сведет на нет все старания.
Вспоминается правило Парето: 20% затрат дают 80% результата, и наоборот.
//Объявление глобальных переменных
//Сегменты табло через сдвиговый регистр 74HC595:
const int latchPin = 7; //to ST_CP
const int clockPin = 6; //to SH_CP
const int dataPin = 5; //to DS
//Выводы выбора разряда индикатора
const int digit1Pin = 9; //еденицы
const int digit2Pin = 10; //десятки
const int digit3Pin = 11; //сотни
const int digit4Pin = 12; //тысячи
//звуковая индикация
const int buzzerPin = 3;
//номеронабиратель
const int dialPin = 2;
//рычаг
const int switchPin = 8;
//термодатчик
//const int termoPin = ;
//varDisplayRefreshTime - время индикации символа в микросекундах
//чем больше тем ярче, при значительно больших значениях - проявиться мерцание
const unsigned int varDisplayRefreshTime = 5000;
//varDisplayNextTime - расчетное время очередной индикации
unsigned long varDisplayNextTime = 0;
//varDysplayPosition - отображаемый разряд
byte varDysplayPosition = 0;
//varMode - режим работы
//0 - температура
//1 - N/U
//2 - таймер
//3 - часы
//4 - N/U
byte varMode = 3;
//varModeOld - предыдущий режим работы
byte varModeOld = 3;
//varSetMode - ожидание установки таймера
byte varSetMode = 0;
//Десятки секунд
unsigned long varTenSec;
//последнее состояние десятков секунд
byte varTenSecLast;
//минута
byte varMinuteCounter = 0;
//arrDysplaySymbols[11] - массив знакосинтезирующий
const byte arrDysplaySymbols[11] =
{
252,
96,
218,
242,
102,
182,
190,
224,
254,
246,
0
};
//arrCounter[5] - массив показаний для различных режимов работы
long arrCounter[5];
//vardialPinState - состояние на входе dialPin
byte vardialPinState = 1;
//vardialPinLastState - последнее состояние на входе dialPin
byte vardialPinLastState = 1;
//vardialReadyDigitNext - готовность к вводу следующего разряда
byte vardialReadyDigitNext = 0;
//vardialPinPulseLock - имульс зафиксирован
byte vardialPinPulseLock = 0;
//vardialCount - текущее количество циклов опроса dialPin
word vardialCount = 0;
//vardialCountMin - минимальное количество циклов для защиты от дребезга контактов
const word vardialCountMin = 3;
//vardialCountDigitNext - минимальное количество циклов для перехода к следующему разряду
const word vardialCountDigitNext = 100;
//vardialCountEndOfSet - минимальное количество циклов для завершения ввода
const word vardialCountEndOfSet = 15000;
//vardialChangeTime
long vardialChangeTime = 0;
void setup()
{
//конфигурирование портов ввода/вывода
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(digit1Pin, OUTPUT);
pinMode(digit2Pin, OUTPUT);
pinMode(digit3Pin, OUTPUT);
pinMode(digit4Pin, OUTPUT);
pinMode(buzzerPin, OUTPUT);
pinMode(dialPin, INPUT_PULLUP);
pinMode(switchPin, INPUT_PULLUP);
//формирование на выводах начальных состояний
digitalWrite(digit1Pin, HIGH);
digitalWrite(digit2Pin, HIGH);
digitalWrite(digit3Pin, HIGH);
digitalWrite(digit4Pin, HIGH);
Serial.begin(9600); //отладка
//arrCounter[2] = 1234; //отладка
//varMode = 2; //отладка
//установка часов
do
{
Display();
dial(3);
if (arrCounter[3] == 0) varSetMode = 1;
} while (varSetMode == 1);
}
void loop()
{
varTenSec = millis()/10000;
varTenSec = varTenSec%10;
Display();
Clock();
thermo();
Display();
dial(2);
//checkDialer(); //отладка
//out2con(); //отладка
}
//dial(*) - подпрограмма номеронабирателя
//* - режим работы для которого осуществляется ввод
void dial(byte varModeDial)
{
vardialPinState = digitalRead(dialPin);
if (vardialPinState != vardialPinLastState)
{
vardialChangeTime = millis();
}
if (vardialPinState == 1)
{// вход врежим установки и подсчет импульсов
if (varSetMode == 0)
{// вход врежим установки
varSetMode = 1;
varMode = varModeDial;
vardialCount = 0;
arrCounter[varModeDial] = 0;
}
else
{// подсчет импульсов
if ((millis() - vardialChangeTime) > vardialCountMin && vardialPinPulseLock == 0)
{
if (vardialReadyDigitNext == 0 && varModeDial == 3)
{
arrCounter[varModeDial] *= 10;
}
arrCounter[varModeDial] ++;
word varCounterDigitZero = arrCounter[varModeDial]%10;
if (varCounterDigitZero == 0)
{
arrCounter[varModeDial] = arrCounter[varModeDial] - 10;
}
vardialPinPulseLock = 1;
vardialReadyDigitNext = 1;
}
}
}
else
{
if (varSetMode == 0)
{
return;
}
else
{// паузы и выход из режима установки
if ((millis() - vardialChangeTime) > vardialCountMin)
{
vardialPinPulseLock = 0;
}
if ((millis() - vardialChangeTime) > vardialCountEndOfSet)
{// выход из режима установки
varSetMode = 0;
}
else if ((millis() - vardialChangeTime) > vardialCountDigitNext && vardialReadyDigitNext == 1)
{// паузы
if (varModeDial == 2)
{
arrCounter[varModeDial] *= 10;
}
//выполнить усечение arrCounter[varModeDial] до трех разрядов
arrCounter[varModeDial] = arrCounter[varModeDial]%10000;
vardialReadyDigitNext = 0;
}
}
}
vardialPinLastState = vardialPinState;
}
//thermo() - подпрограмма измерения температуры
void thermo()
{
if (varSetMode == 1)
{
return;
}
//контроль снятия с рычага
if (digitalRead(switchPin) == LOW)
{
if (varMode != 0)
{
varModeOld = varMode;
varMode = 0;
}
//подпрограммы измерения температуры
}
else
{
if (varMode == 0)
{
varMode = varModeOld;
}
}
}
//Clock() - подпрограмма часов
void Clock()
{
if (varTenSecLast != varTenSec)
{
varTenSecLast = varTenSec;
varMinuteCounter ++;
if (varMinuteCounter == 6)
{
varMinuteCounter = 0;
arrCounter[3] ++;
if (arrCounter[3]/10%10 == 6)
{
arrCounter[3] += 40;
}
if (arrCounter[3] >= 2400)
{
arrCounter[3] = 0;
}
}
if (arrCounter[2] != 0)
{
if (varSetMode == 0)
{
Timer();
}
}
else
{
if (varMode == 2)
{
varMode = 3;
}
}
}
}
//Timer() - подпрограмма таймера
void Timer()
{
arrCounter[2] --;
if (arrCounter[2]%10 >= 6)
{
arrCounter[2] = arrCounter[2] - 4;
}
if (arrCounter[2] == 20)
{
beepOn();
}
if (arrCounter[2] == 14)
{
beepOff();
}
if (arrCounter[2] < 1)
{
beepOn();
}
if (arrCounter[2] == 0)
{
// varMode = 3;
beepOff();
}
}
//beepOn() - подпрограмма звуковой индикации
void beepOn()
{
analogWrite(buzzerPin, 127);
}
//beepOff() - подпрограмма звуковой индикации
void beepOff()
{
analogWrite(buzzerPin, 0);
}
//Display() - подпрограмма индикации
void Display()
{
int digitPinOff;
int digitPinOn;
int DisplayDigital;
// if (varDisplayNextTime <= micros() && varDisplayNextTime > micros() - varDisplayRefreshTime)
if (varDisplayNextTime <= micros())
{
varDisplayNextTime += varDisplayRefreshTime;
varDysplayPosition = varDysplayPosition + 1;
if (varDysplayPosition > 4)
{
varDysplayPosition = 1;
}
switch (varDysplayPosition)
{
case 1:
DisplayDigital = arrCounter[varMode]%10;
DisplayDigital = arrDysplaySymbols[DisplayDigital];
digitPinOff = digit4Pin;
digitPinOn = digit1Pin;
break;
case 2:
if (arrCounter[varMode] > 9 || varMode == 3)
{
DisplayDigital = arrCounter[varMode]/10%10;
DisplayDigital = arrDysplaySymbols[DisplayDigital];
}
else
{
DisplayDigital = arrDysplaySymbols[11];
}
digitPinOff = digit1Pin;
digitPinOn = digit2Pin;
break;
case 3:
if (arrCounter[varMode] > 99 || varMode == 3)
{
DisplayDigital = arrCounter[varMode]/100%10;
DisplayDigital = arrDysplaySymbols[DisplayDigital];
}
else
{
DisplayDigital = arrDysplaySymbols[11];
}
digitPinOff = digit2Pin;
digitPinOn = digit3Pin;
break;
case 4:
if (arrCounter[varMode] > 999)
{
DisplayDigital = arrCounter[varMode]/1000%10;
DisplayDigital = arrDysplaySymbols[DisplayDigital];
}
else
{
DisplayDigital = arrDysplaySymbols[11];
}
digitPinOff = digit3Pin;
digitPinOn = digit4Pin;
break;
}
if (varMode == varDysplayPosition)
{
unsigned long varPointBlinkTime = millis()/500;
varPointBlinkTime = varPointBlinkTime%10;
varPointBlinkTime = varPointBlinkTime & B00000001;
if (varPointBlinkTime == 1 || varSetMode == 1)
{
DisplayDigital = DisplayDigital ^ B00000001;
}
}
digitalWrite(digitPinOff, HIGH);
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, DisplayDigital);
digitalWrite(latchPin, HIGH);
digitalWrite(digitPinOn, LOW);
}
}
//отладка
void checkDialer()
{
if (digitalRead(dialPin) == LOW)
{
arrCounter[1] ++;
arrCounter[4] = 0;
}
else
{
arrCounter[1] = 0;
arrCounter[4] ++;
}
Serial.print (arrCounter[1]);
Serial.print ("\t");
Serial.println (arrCounter[4]);
}
//отладка
void out2con()
{
Serial.print ("Mode=");
Serial.print (varMode);
Serial.print ("\tt=");
Serial.print (arrCounter[0]);
Serial.print ("\tTimer=");
Serial.print (arrCounter[2]);
Serial.print ("\tClock=");
Serial.print (arrCounter[3]);
Serial.print ("\tSetMode=");
Serial.print (varSetMode);
Serial.print ("\tdialCount=");
Serial.print (vardialCount);
Serial.print ("\tdialPinLS=");
Serial.print (vardialPinLastState);
Serial.print ("\tdialPinS=");
Serial.print (vardialPinState);
Serial.print ("\t");
Serial.println ();
}
После включения ждет установки часов. После установки часов переходит в основной режим работы (на дисплэе время). Точка не мигает в режиме ввода. Для часов точка после второго разряда, для таймера после третьего. При наборе в основном цикле автоматически переходим в режим таймера. По истечении таймера возвращаемся в режим отображения времени. При нажатии на "рычаг" в любом режиме кроме "установки" (когда точка светиться постоянно), выводится "температура".
Опытный аппарат собран и запущен. Проводятся проверки работы точности часов на встроенном таймере, точности отсчёта таймера, общего энергопотребеления устройства, стабильности работы в целом.
Результаты: часы убегают незначительно, точность отсчёта и работа индикации на высоте, но за сутки батарея 9V 6LR61 была посажена с 9,21 до 6,53 вольта.
По питанию предполагалось два варианта: первый - автономное от кроны на год, второе - встроенный блок питания от 220V.
Первый был предпочтительнее, с экономической точки зрения, не смотря на то что при втором варианте можно перейти к более раритетным индикаторам ИН-12Б. С индикаторами тоже не всё оптимистично. время наработки на отказ 5000 часов = 208 дней. Для увеличения ресурса нужно гасить индикацию. Тогда фактически мы теряем функцию отображения часов. Пример газоразрядной индикации:
Батарея типа "крона" имеет емкость (по паспорту) 0,5 А*ч. А у тебя фонарик на светодиодах работающий круглосуточно... Выход: внешнее питание или переход на ЖКИ. На форуме где-то видел предложение использовать несколько батареек АА - это вариант удвоения/утроения времени эксплуатации (у разных батареек емкость разная). Еще можно немного растянуть время работы уйдя на более низкие частоты, но тогда вопрос с индикацией, возможно, возникнет, но тогда можно метнуться в сторону SPI или исключить регистр...
А что конкретно понравилось? корпус - прозрачная "хлебница", синяя светодиодная подсветка, сами индикаторы или фоновый фольгированный текстолит к которому припаяны лампы?
Я сейчас прорабатываю свой корпус и ломаю голову над тем как в 19 веке могли бы оформить индикацию будь у них лампы и светодиоды.
Вряд ли в 19 веке рескнули сделать прозрачные стенки "кишки наружу", медь/латунь/бронза на худой конец жесть... но светодиодный индикатор не впишется - люменисцентный еще куда нешло. Отвлекись от того что есть, возми чистый лист и простой карандаш, сделай серию набросков - посмотрим может чего и выйдет из этого.
"... чем-то на казино. Чем-то на караван-сарай, чем-то – на отряды Махно."
Придя к ламповой индикации, я не смог пройти мимо соблазна встроить что нибудь этакое в функционал своего девайса. Такой изюминкой мог стать FM-радиоприёмник. Ламповый. Но после непродолжительного гугления выяснилось что смогу собрать лишь ламповый усилитель типа, но не тюнер с синтезатором частот. И пока решил воздержаться.
"... чем-то на казино. Чем-то на караван-сарай, чем-то – на отряды Махно."
Придя к ламповой индикации, я не смог пройти мимо соблазна встроить что нибудь этакое в функционал своего девайса. Такой изюминкой мог стать FM-радиоприёмник. Ламповый. Но после непродолжительного гугления выяснилось что смогу собрать лишь ламповый усилитель типа, но не тюнер с синтезатором частот. И пока решил воздержаться.
но можно же сделать цифровой и замаскировать под ламповый, или УНЧ сделать ламповым, ВЧ части на однокристальном FM приемнике
но можно же сделать цифровой и замаскировать под ламповый, или УНЧ сделать ламповым, ВЧ части на однокристальном FM приемнике
Это будет зависеть от того смогу ли увеличить ресурс ИН-12Б скажем до 25 лет. Корпус должен соответствовать содержанию. Может в полнакала тлеть пока газоанализатор на нуле, или гасить ночью или днём по будням.
а как предполагается устанавливать время?
Предполагал использовать часы на DS1307. Устанавливать их пока при включении:
DS1307 clock; //define a object of DS1307 class void setup() { clock.fillByYMD(2013,1,19);//Jan 19,2013 clock.fillByHMS(15,28,30);//15:28 30" clock.fillDayOfWeek(SAT);//Saturday clock.setTime();//write time to the RTC chip } clock.getTime();В дальнейшем #18 думал получать от центрального таймера по SPI:
Например, если у меня будет центральный таймер в коридоре с выходом в интернет, и я захочу с него обмениваться информацией с периферийными таймерами - кухонным (сварились ли пельмени), комнатным(будильник прикроватный с монитором сна), и балконным(телескоп следящий за положением тел в альфа-центавре), а так же таймерами робота-пылесоса и робота-пивовара, - тогда да без SPI не обойтись, а тут?
Нет, ты меня не понял: Как войти в режим установки времени?
Понял. Повторяю: в модуле setup {} мы устанавливаем время. Один раз. И больше прибор не выключаем. До тех пор пока не приделаю коррекцию по SPI.
Так короче. Только сегодня 27 августа... Или это с учётом дня на размышления ;)
с учетом конечно)) хотя может мало добавил
Про представление времени и альтернативные (бинарные) часы была хорошая статья на Хабре, и не менее чудные комменты:
↑
↑
↑
А это мысль! Давай как во всех электронных будильниках при включении если (clock.getTime() = 0,0,0,0,0,0) тогда горят пробелы (- - . - -), мы вводим номеронабирателем время (17.46) и часы запускаются: rtc.adjust(DateTime(2014,0,0,17,46,0)); Год нужен что бы каждую полночь в этот режим не вываливались. А в дальнейшем я заменю этот блок на авто коррекцию.
Так короче. Только сегодня 27 августа... Или это с учётом дня на размышления ;)
Эй, а про календарь ты ничего не говорил.
И если я тебя правильно понял, то часы устанавливаются при первом включении и если ты захочешь перевести время не фига не западло передернуть питание?
да можно в любой момент изменить время не беспокойтесь. необязательно дергать питание
календарь можно не использовать если он так пугает))
Календарь не нужен.
Про время. Нужно при включении установить текущее время с номеронабирателя. Я предложил по условию что год не заполнен (неважно какой, хоть 1234), после набора пишем в поле год - какой угодно год. И когда наступит полночь, то условие 0,0,0,0,0,0 не выполнится, по тому что будет 1234,0,0,0,0,0!
как это сделать в смысле где этому место в алгоритме?
Напиши пока в setup{}, это не главный вопрос. Я пока не получил с ебея DS1307 толком не знаю подводных камней. Просто выведи статичное время. Пусть get time получает 0,0,0,18,12,0. Получу часы - буду думать.
Я кодить не успеваю, в то время как новые функции меняют алгоритмы, а изменения схемы рушат всю концепцию.
Изначально предполагалось текущее время. Как именно с ним работать я пока точно не знаю, и буду дорабатывать его на финальном этапе разработки. Пока выведем статичное число 00.00 и все. Как его устанавливать и как корректировать на данном этапе не важно.
Сам концепт подразумевает собой исключительную простоту конструкции (как утюг или дисковый телефон). По этому регулировочные и корректирующие инструменты должны быть скрыты от неподготовленного пользователя.
Закодил часы. Если сегодня доделаю таймер, то завтра дам на тестирование в железе
Я часа четыре провозился сегодня с долбаными прерываниями.
При вращении диска цикл loop{} останавливается и выполняется подпрограмма номеронабирателя. Но обратно возвращается единица, а не количество единиц. Видимо прерыванием считается каждый импульс номеронабирателя. Такое ощущение что нужно считать количество вызовов подпрограммы номеронабирателя. В общем это возможно(count запихнуть внутрь подпрограммы прерывания), но как тогда разделять цифры номера (сбрасывать count)? По разнице во времени?
конечно по времени
отвечаю не вникая - возможно проблема в областе видимости переменных...
Я могу реализовать это без прерываний.
и при этом будет работать не останавливаясь динамическая инидикация индикатора?
и при этом будет работать не останавливаясь динамическая инидикация индикатора?
конечно
А пусть останавливается на время набора номера. Я про прерывания думал, что бы это красиво оформить. Ну и пропусков избежать ;)
чтобы не было пропусков конечно
хотелось бы доказательств. напишите код и проверим так ли все хорошо без прерываний и индикация при этом не портится
Закодил часы. Если сегодня доделаю таймер, то завтра дам на тестирование в железе
По ходу занял я тебя сверхурочно своим прожектом.
чтобы не было пропусков конечно
хотелось бы доказательств. напишите код и проверим так ли все хорошо без прерываний и индикация при этом не портится
доказательства выложу, когда на кухне приколочу к стене, на фоне пельменей.
Пока меня смущает тот факт что прерывания могут использоваться только для получения импульса, а не для получения цифры номера. Думается возврат к millis() сведет на нет все старания.
Вспоминается правило Парето: 20% затрат дают 80% результата, и наоборот.
да зачем на стене. прямо на столе видео с сводом цифр и чтобы было видно индикатор и какие цифры вводятся
в целях тестирования таймер выставлен на 3 минуты, по истечении выводяться часы
Тест завтра, в два по полудни!
В строке 157 неправильно отрабатывает правило
if (varDisplayNextTime <= micros() && varDisplayNextTime > micros() - varDisplayRefreshTime)
если заменить на
if (varDisplayNextTime <= micros())
должно работать, но небудет защиты от переполнения счетчика micros()
//Объявление глобальных переменных //Сегменты табло через сдвиговый регистр 74HC595: int latchPin = 7; //to ST_CP int clockPin = 6; //to SH_CP int dataPin = 5; //to DS //Выводы выбора разряда индикатора int digit1Pin = 12; //еденицы int digit2Pin = 11; //десятки int digit3Pin = 10; //сотни int digit4Pin = 9; //тысячи //звуковая индикация int buzzerPin = 3; //номеронабиратель int dialPin = 2; //рычаг int switchPin = 8; //термодатчик //int termoPin = ; //varDisplayRefreshTime - время индикации символа в микросекундах //чем больше тем ярче, при значительно больших значениях - проявиться мерцание unsigned int varDisplayRefreshTime = 5000; //varDisplayNextTime - расчетное время очередной индикации unsigned long varDisplayNextTime = 0; //varDysplayPosition - отображаемый разряд byte varDysplayPosition = 0; //varMode - режим работы //0 - температура //1 - N/U //2 - таймер //3 - часы //4 - N/U byte varMode = 3; //varModeOld - предыдущий режим работы byte varModeOld = 3; //varSetMode - ожидание установки таймера byte varSetMode = 0; //Десятки секунд unsigned long varTenSec; //последнее состояние десятков секунд byte varTenSecLast; //минута byte varMinuteCounter = 0; //arrDysplaySymbols[11] - массив знакосинтезирующий byte arrDysplaySymbols[11] = { 252, 96, 218, 242, 102, 182, 190, 224, 254, 246, 0 }; //arrCounter[5] - массив показаний для различных режимов работы int arrCounter[5]; //vardialPinState - состояние на входе dialPin byte vardialPinState = 1; //vardialPinLastState - последнее состояние на входе dialPin byte vardialPinLastState = 1; //vardialCount - текущее количество циклов опроса dialPin int vardialCount = 0; //vardialCountMin - минимальное количество циклов для защиты от дребезга контактов int vardialCountMin = 10; //vardialCountDigitNext - минимальное количество циклов для перехода к следующему разряду int vardialCountDigitNext = 100; //vardialCountEndOfSet - минимальное количество циклов для завершения ввода int vardialCountEndOfSet = 500; void setup() { //конфигурирование портов ввода/вывода pinMode(latchPin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT); pinMode(digit1Pin, OUTPUT); pinMode(digit2Pin, OUTPUT); pinMode(digit3Pin, OUTPUT); pinMode(digit4Pin, OUTPUT); pinMode(buzzerPin, OUTPUT); pinMode(dialPin, INPUT_PULLUP); pinMode(switchPin, INPUT_PULLUP); //формирование на выводах начальных состояний digitalWrite(digit1Pin, HIGH); digitalWrite(digit2Pin, HIGH); digitalWrite(digit3Pin, HIGH); digitalWrite(digit4Pin, HIGH); Serial.begin(9600); //отладка // arrCounter[2] = 20; //отладка // dial(3); } void loop() { varTenSec = millis()/10000; varTenSec = varTenSec%10; Display(); Clock(); //контроль снятия с рычага if (digitalRead(switchPin) == LOW && varSetMode == 0) { if (varMode != 0) { varModeOld = varMode; } varMode = 0; //вызов подпрограммы измерения температуры } else { varMode = varModeOld; } // dial(2); //отладка> if (digitalRead(dialPin) == LOW) { arrCounter[1] ++; arrCounter[4] = 0; } else { arrCounter[1] = 0; arrCounter[4] ++; } Serial.print (arrCounter[1]); Serial.print ("\t"); Serial.println (arrCounter[4]); //<отладка } //dial() - подпрограмма номеронабирателя void dial(byte varModeDial) { if (digitalRead(dialPin) == LOW) { if (varSetMode == 0) { varSetMode = 1; varMode = varModeDial; vardialCount = 0; } vardialPinState = 1; } else { if (varSetMode == 0) { return; } vardialPinState = 0; } //определение импульса if (vardialPinLastState == vardialPinState) { vardialCount ++; } else { vardialCount = 0; } if (vardialPinLastState == 0 && vardialPinState == 1 && vardialCount > vardialCountMin) { //увеличить показания arrCounter[varModeDial] += 10; //если десять импульсов, то ноль int varCounterDigitZero = arrCounter[varMode]%10; if (varCounterDigitZero == 0) { arrCounter[varModeDial] = arrCounter[varModeDial] - 100; } vardialPinLastState = 1; } //переход к следующему разряду if (vardialPinLastState == 1 && vardialPinState == 0 && vardialCount > vardialCountDigitNext) { arrCounter[varModeDial] *= 10; vardialPinLastState = 0; } //определение конца ввода if (vardialPinLastState == 0 && vardialPinState == 0 && vardialCount > vardialCountEndOfSet) { varSetMode = 0; } } //Clock() - подпрограмма часов void Clock() { if (varTenSecLast != varTenSec) { varTenSecLast = varTenSec; varMinuteCounter += 10; if (varMinuteCounter == 6) { varMinuteCounter = 0; arrCounter[3] ++; if (arrCounter[3]/10%10 == 6) { arrCounter[3] += 40; } if (arrCounter[3]/100%10 == 4 && arrCounter[3]/1000%10 == 2) { arrCounter[3] = 0; } } if (arrCounter[2] != 0 && varSetMode == 0) { Timer(); } } } //Timer() - подпрограмма таймера void Timer() { arrCounter[2] --; if (arrCounter[2]%10 >= 6) { arrCounter[2] = arrCounter[2] - 4; } if (arrCounter[2] == 20) { beepOn(); } if (arrCounter[2] == 14) { beepOff(); } if (arrCounter[2] < 2) { beepOn(); } if (arrCounter[2] == 0) { varMode = 3; beepOff(); } } //beepOn() - подпрограмма звуковой индикации void beepOn() { analogWrite(buzzerPin, 127); } //beepOff() - подпрограмма звуковой индикации void beepOff() { analogWrite(buzzerPin, 0); } //Display() - подпрограмма индикации void Display() { int digitPinOff; int digitPinOn; int DisplayDigital; // if (varDisplayNextTime <= micros() && varDisplayNextTime > micros() - varDisplayRefreshTime) if (varDisplayNextTime <= micros()) { varDisplayNextTime += varDisplayRefreshTime; varDysplayPosition = varDysplayPosition + 1; if (varDysplayPosition > 4) { varDysplayPosition = 1; } switch (varDysplayPosition) { case 1: DisplayDigital = arrCounter[varMode]*10%10; DisplayDigital = arrDysplaySymbols[DisplayDigital]; digitPinOff = digit4Pin; digitPinOn = digit1Pin; break; case 2: if (arrCounter[varMode] > 9 || varMode == 3) { DisplayDigital = arrCounter[varMode]%10; DisplayDigital = arrDysplaySymbols[DisplayDigital]; } else { DisplayDigital = arrDysplaySymbols[11]; } digitPinOff = digit1Pin; digitPinOn = digit2Pin; break; case 3: if (arrCounter[varMode] > 99 || varMode == 3) { DisplayDigital = arrCounter[varMode]/10%10; DisplayDigital = arrDysplaySymbols[DisplayDigital]; } else { DisplayDigital = arrDysplaySymbols[11]; } digitPinOff = digit2Pin; digitPinOn = digit3Pin; break; case 4: if (arrCounter[varMode] > 999) { DisplayDigital = arrCounter[varMode]/100%10; DisplayDigital = arrDysplaySymbols[DisplayDigital]; } else { DisplayDigital = arrDysplaySymbols[11]; } digitPinOff = digit3Pin; digitPinOn = digit4Pin; break; } if (varMode == varDysplayPosition) { unsigned long varPointBlinkTime = millis()/500; varPointBlinkTime = varPointBlinkTime%10; varPointBlinkTime = varPointBlinkTime & B00000001; if (varPointBlinkTime == 1 || varSetMode == 1) { DisplayDigital = DisplayDigital ^ B00000001; } } digitalWrite(digitPinOff, HIGH); digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, LSBFIRST, DisplayDigital); digitalWrite(latchPin, HIGH); digitalWrite(digitPinOn, LOW); } }нужно сделать натурное испытание:
1. подключить номеронабиратель между землей и pin 2
2. набрать 1 и посотреть в консоли какое число будет выведено последним
Исправил ошибки.
когда испытания?
нужно сделать натурное испытание:
Кстати разряды, перевернуть? ;)
//Объявление глобальных переменных //Сегменты табло через сдвиговый регистр 74HC595: const int latchPin = 7; //to ST_CP const int clockPin = 6; //to SH_CP const int dataPin = 5; //to DS //Выводы выбора разряда индикатора const int digit1Pin = 9; //еденицы const int digit2Pin = 10; //десятки const int digit3Pin = 11; //сотни const int digit4Pin = 12; //тысячи //звуковая индикация const int buzzerPin = 3; //номеронабиратель const int dialPin = 2; //рычаг const int switchPin = 8; //термодатчик //const int termoPin = ; //varDisplayRefreshTime - время индикации символа в микросекундах //чем больше тем ярче, при значительно больших значениях - проявиться мерцание const unsigned int varDisplayRefreshTime = 5000; //varDisplayNextTime - расчетное время очередной индикации unsigned long varDisplayNextTime = 0; //varDysplayPosition - отображаемый разряд byte varDysplayPosition = 0; //varMode - режим работы //0 - температура //1 - N/U //2 - таймер //3 - часы //4 - N/U byte varMode = 3; //varModeOld - предыдущий режим работы byte varModeOld = 3; //varSetMode - ожидание установки таймера byte varSetMode = 0; //Десятки секунд unsigned long varTenSec; //последнее состояние десятков секунд byte varTenSecLast; //минута byte varMinuteCounter = 0; //arrDysplaySymbols[11] - массив знакосинтезирующий const byte arrDysplaySymbols[11] = { 252, 96, 218, 242, 102, 182, 190, 224, 254, 246, 0 }; //arrCounter[5] - массив показаний для различных режимов работы long arrCounter[5]; //vardialPinState - состояние на входе dialPin byte vardialPinState = 1; //vardialPinLastState - последнее состояние на входе dialPin byte vardialPinLastState = 1; //vardialReadyDigitNext - готовность к вводу следующего разряда byte vardialReadyDigitNext = 0; //vardialPinPulseLock - имульс зафиксирован byte vardialPinPulseLock = 0; //vardialCount - текущее количество циклов опроса dialPin word vardialCount = 0; //vardialCountMin - минимальное количество циклов для защиты от дребезга контактов const word vardialCountMin = 3; //vardialCountDigitNext - минимальное количество циклов для перехода к следующему разряду const word vardialCountDigitNext = 100; //vardialCountEndOfSet - минимальное количество циклов для завершения ввода const word vardialCountEndOfSet = 15000; //vardialChangeTime long vardialChangeTime = 0; void setup() { //конфигурирование портов ввода/вывода pinMode(latchPin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT); pinMode(digit1Pin, OUTPUT); pinMode(digit2Pin, OUTPUT); pinMode(digit3Pin, OUTPUT); pinMode(digit4Pin, OUTPUT); pinMode(buzzerPin, OUTPUT); pinMode(dialPin, INPUT_PULLUP); pinMode(switchPin, INPUT_PULLUP); //формирование на выводах начальных состояний digitalWrite(digit1Pin, HIGH); digitalWrite(digit2Pin, HIGH); digitalWrite(digit3Pin, HIGH); digitalWrite(digit4Pin, HIGH); Serial.begin(9600); //отладка //arrCounter[2] = 1234; //отладка //varMode = 2; //отладка //установка часов do { Display(); dial(3); if (arrCounter[3] == 0) varSetMode = 1; } while (varSetMode == 1); } void loop() { varTenSec = millis()/10000; varTenSec = varTenSec%10; Display(); Clock(); thermo(); Display(); dial(2); //checkDialer(); //отладка //out2con(); //отладка } //dial(*) - подпрограмма номеронабирателя //* - режим работы для которого осуществляется ввод void dial(byte varModeDial) { vardialPinState = digitalRead(dialPin); if (vardialPinState != vardialPinLastState) { vardialChangeTime = millis(); } if (vardialPinState == 1) {// вход врежим установки и подсчет импульсов if (varSetMode == 0) {// вход врежим установки varSetMode = 1; varMode = varModeDial; vardialCount = 0; arrCounter[varModeDial] = 0; } else {// подсчет импульсов if ((millis() - vardialChangeTime) > vardialCountMin && vardialPinPulseLock == 0) { if (vardialReadyDigitNext == 0 && varModeDial == 3) { arrCounter[varModeDial] *= 10; } arrCounter[varModeDial] ++; word varCounterDigitZero = arrCounter[varModeDial]%10; if (varCounterDigitZero == 0) { arrCounter[varModeDial] = arrCounter[varModeDial] - 10; } vardialPinPulseLock = 1; vardialReadyDigitNext = 1; } } } else { if (varSetMode == 0) { return; } else {// паузы и выход из режима установки if ((millis() - vardialChangeTime) > vardialCountMin) { vardialPinPulseLock = 0; } if ((millis() - vardialChangeTime) > vardialCountEndOfSet) {// выход из режима установки varSetMode = 0; } else if ((millis() - vardialChangeTime) > vardialCountDigitNext && vardialReadyDigitNext == 1) {// паузы if (varModeDial == 2) { arrCounter[varModeDial] *= 10; } //выполнить усечение arrCounter[varModeDial] до трех разрядов arrCounter[varModeDial] = arrCounter[varModeDial]%10000; vardialReadyDigitNext = 0; } } } vardialPinLastState = vardialPinState; } //thermo() - подпрограмма измерения температуры void thermo() { if (varSetMode == 1) { return; } //контроль снятия с рычага if (digitalRead(switchPin) == LOW) { if (varMode != 0) { varModeOld = varMode; varMode = 0; } //подпрограммы измерения температуры } else { if (varMode == 0) { varMode = varModeOld; } } } //Clock() - подпрограмма часов void Clock() { if (varTenSecLast != varTenSec) { varTenSecLast = varTenSec; varMinuteCounter ++; if (varMinuteCounter == 6) { varMinuteCounter = 0; arrCounter[3] ++; if (arrCounter[3]/10%10 == 6) { arrCounter[3] += 40; } if (arrCounter[3] >= 2400) { arrCounter[3] = 0; } } if (arrCounter[2] != 0) { if (varSetMode == 0) { Timer(); } } else { if (varMode == 2) { varMode = 3; } } } } //Timer() - подпрограмма таймера void Timer() { arrCounter[2] --; if (arrCounter[2]%10 >= 6) { arrCounter[2] = arrCounter[2] - 4; } if (arrCounter[2] == 20) { beepOn(); } if (arrCounter[2] == 14) { beepOff(); } if (arrCounter[2] < 1) { beepOn(); } if (arrCounter[2] == 0) { // varMode = 3; beepOff(); } } //beepOn() - подпрограмма звуковой индикации void beepOn() { analogWrite(buzzerPin, 127); } //beepOff() - подпрограмма звуковой индикации void beepOff() { analogWrite(buzzerPin, 0); } //Display() - подпрограмма индикации void Display() { int digitPinOff; int digitPinOn; int DisplayDigital; // if (varDisplayNextTime <= micros() && varDisplayNextTime > micros() - varDisplayRefreshTime) if (varDisplayNextTime <= micros()) { varDisplayNextTime += varDisplayRefreshTime; varDysplayPosition = varDysplayPosition + 1; if (varDysplayPosition > 4) { varDysplayPosition = 1; } switch (varDysplayPosition) { case 1: DisplayDigital = arrCounter[varMode]%10; DisplayDigital = arrDysplaySymbols[DisplayDigital]; digitPinOff = digit4Pin; digitPinOn = digit1Pin; break; case 2: if (arrCounter[varMode] > 9 || varMode == 3) { DisplayDigital = arrCounter[varMode]/10%10; DisplayDigital = arrDysplaySymbols[DisplayDigital]; } else { DisplayDigital = arrDysplaySymbols[11]; } digitPinOff = digit1Pin; digitPinOn = digit2Pin; break; case 3: if (arrCounter[varMode] > 99 || varMode == 3) { DisplayDigital = arrCounter[varMode]/100%10; DisplayDigital = arrDysplaySymbols[DisplayDigital]; } else { DisplayDigital = arrDysplaySymbols[11]; } digitPinOff = digit2Pin; digitPinOn = digit3Pin; break; case 4: if (arrCounter[varMode] > 999) { DisplayDigital = arrCounter[varMode]/1000%10; DisplayDigital = arrDysplaySymbols[DisplayDigital]; } else { DisplayDigital = arrDysplaySymbols[11]; } digitPinOff = digit3Pin; digitPinOn = digit4Pin; break; } if (varMode == varDysplayPosition) { unsigned long varPointBlinkTime = millis()/500; varPointBlinkTime = varPointBlinkTime%10; varPointBlinkTime = varPointBlinkTime & B00000001; if (varPointBlinkTime == 1 || varSetMode == 1) { DisplayDigital = DisplayDigital ^ B00000001; } } digitalWrite(digitPinOff, HIGH); digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, LSBFIRST, DisplayDigital); digitalWrite(latchPin, HIGH); digitalWrite(digitPinOn, LOW); } } //отладка void checkDialer() { if (digitalRead(dialPin) == LOW) { arrCounter[1] ++; arrCounter[4] = 0; } else { arrCounter[1] = 0; arrCounter[4] ++; } Serial.print (arrCounter[1]); Serial.print ("\t"); Serial.println (arrCounter[4]); } //отладка void out2con() { Serial.print ("Mode="); Serial.print (varMode); Serial.print ("\tt="); Serial.print (arrCounter[0]); Serial.print ("\tTimer="); Serial.print (arrCounter[2]); Serial.print ("\tClock="); Serial.print (arrCounter[3]); Serial.print ("\tSetMode="); Serial.print (varSetMode); Serial.print ("\tdialCount="); Serial.print (vardialCount); Serial.print ("\tdialPinLS="); Serial.print (vardialPinLastState); Serial.print ("\tdialPinS="); Serial.print (vardialPinState); Serial.print ("\t"); Serial.println (); }После включения ждет установки часов. После установки часов переходит в основной режим работы (на дисплэе время). Точка не мигает в режиме ввода. Для часов точка после второго разряда, для таймера после третьего. При наборе в основном цикле автоматически переходим в режим таймера. По истечении таймера возвращаемся в режим отображения времени. При нажатии на "рычаг" в любом режиме кроме "установки" (когда точка светиться постоянно), выводится "температура".
Собственно долгожданные результаты испытания на видео. http://youtu.be/rNMIFLJr7cg
За разработку кода благодарю уважаемого 18GT19HT, ибо он решил задачу не используя SPI и прерывания.
Далее перехожу от настольного прототипа к опытной модели.
Доработаю напильником корпус аппарата и засуну внутрь имеющиеся прибамбасы, включая серву и градусник.
Это позволит в полевых условиях определить параметры функций и элементов конструкции прибора.
Опытный аппарат собран и запущен. Проводятся проверки работы точности часов на встроенном таймере, точности отсчёта таймера, общего энергопотребеления устройства, стабильности работы в целом.
Результаты: часы убегают незначительно, точность отсчёта и работа индикации на высоте, но за сутки батарея 9V 6LR61 была посажена с 9,21 до 6,53 вольта.
По питанию предполагалось два варианта: первый - автономное от кроны на год, второе - встроенный блок питания от 220V.
Первый был предпочтительнее, с экономической точки зрения, не смотря на то что при втором варианте можно перейти к более раритетным индикаторам ИН-12Б. С индикаторами тоже не всё оптимистично. время наработки на отказ 5000 часов = 208 дней. Для увеличения ресурса нужно гасить индикацию. Тогда фактически мы теряем функцию отображения часов. Пример газоразрядной индикации:
Батарея типа "крона" имеет емкость (по паспорту) 0,5 А*ч. А у тебя фонарик на светодиодах работающий круглосуточно... Выход: внешнее питание или переход на ЖКИ. На форуме где-то видел предложение использовать несколько батареек АА - это вариант удвоения/утроения времени эксплуатации (у разных батареек емкость разная). Еще можно немного растянуть время работы уйдя на более низкие частоты, но тогда вопрос с индикацией, возможно, возникнет, но тогда можно метнуться в сторону SPI или исключить регистр...
выложи куда нибудь фото часов в более высоком качетве. по моему классно смотрится. хочу получше рассмотреть
выложи куда нибудь фото часов в более высоком качетве. по моему классно смотрится. хочу получше рассмотреть
Первая картинка по поиску ИН-12Б на яндексе. 500х265.
да тоже мелко)) как на форуме
А что конкретно понравилось? корпус - прозрачная "хлебница", синяя светодиодная подсветка, сами индикаторы или фоновый фольгированный текстолит к которому припаяны лампы?
Я сейчас прорабатываю свой корпус и ломаю голову над тем как в 19 веке могли бы оформить индикацию будь у них лампы и светодиоды.
чем то похоже на ламповый усилитель
Вряд ли в 19 веке рескнули сделать прозрачные стенки "кишки наружу", медь/латунь/бронза на худой конец жесть... но светодиодный индикатор не впишется - люменисцентный еще куда нешло. Отвлекись от того что есть, возми чистый лист и простой карандаш, сделай серию набросков - посмотрим может чего и выйдет из этого.
чем то похоже на ламповый усилитель
"... чем-то на казино. Чем-то на караван-сарай, чем-то – на отряды Махно."
Придя к ламповой индикации, я не смог пройти мимо соблазна встроить что нибудь этакое в функционал своего девайса. Такой изюминкой мог стать FM-радиоприёмник. Ламповый. Но после непродолжительного гугления выяснилось что смогу собрать лишь ламповый усилитель типа, но не тюнер с синтезатором частот. И пока решил воздержаться.
чем то похоже на ламповый усилитель
"... чем-то на казино. Чем-то на караван-сарай, чем-то – на отряды Махно."
Придя к ламповой индикации, я не смог пройти мимо соблазна встроить что нибудь этакое в функционал своего девайса. Такой изюминкой мог стать FM-радиоприёмник. Ламповый. Но после непродолжительного гугления выяснилось что смогу собрать лишь ламповый усилитель типа, но не тюнер с синтезатором частот. И пока решил воздержаться.
но можно же сделать цифровой и замаскировать под ламповый, или УНЧ сделать ламповым, ВЧ части на однокристальном FM приемнике
А если говорить про ретро, часы и лампы - то 18GT19HT как никогда прав:
Наручные часы на газоразрядных индикаторах
а при чем тут 19 век
http://radioskot.ru/_fr/4/7860783.jpg
красиво же. именно чтобы было похоже на часы не нашел
но можно же сделать цифровой и замаскировать под ламповый, или УНЧ сделать ламповым, ВЧ части на однокристальном FM приемнике
Это будет зависеть от того смогу ли увеличить ресурс ИН-12Б скажем до 25 лет. Корпус должен соответствовать содержанию. Может в полнакала тлеть пока газоанализатор на нуле, или гасить ночью или днём по будням.
но можно же сделать цифровой и замаскировать под ламповый, или УНЧ сделать ламповым, ВЧ части на однокристальном FM приемнике
уже делают вроде того))
http://radio-hobby.org/modules/newbb/viewtopic.php?topic_id=611&forum=11
а при чем тут 19 век
Ибо телефоны получили распространение в 19 веке и их концепт отлично впишется в мой функционал