Работаю я в одном коллективе, в котором в обеденный перерыв завелась традиция играть в шахматы, но в обычные играть быстро надоело (да и коллектив большой), поэтому пробовали разные варианты и остановились пока на шахматах для четверых. Хорошая традиция, приятное времяпровождение на обеде, но была одна беда — обед короткий, а некоторые товарищи ой как любят долго думать. Решение в шахматах для таких «тугодумов» давно известно — шахматные часы, но тут ведь играют четверо! Чем не повод для творчества? Вполне себе повод!
Аппаратная часть
Сами часы построены на базе ATMega8 (вначале делал на ATTiny 2313, но не хватило оперативное памяти для всех функций), 4-х строчном дисплее WinStar WH1604A одном бузере и 4-х кнопках:
Дисплей WH1604A подключен по схеме с 4-битной шиной данных (не только для экономии ножек микроконтроллера, но и потому что использовалась стандартная бибилиотека CodeVision AVR для работы с такими дисплеями, а она предполагает именно такое подключение). Из интересного — контрастность дисплея не регулируется и собрана на стабилитроне IN 4731A рассчитанном на падение напряжения 4.3В, но при токе в 6 мА который нужен подсветке дисплея на нем падает около 4.0В, а это как раз падение напряжения дающее оптимальную контрастность дисплея (напряжение на входе Vee должно быть именно Vcc — 4В, а не GND + 1В — это важно при питании дисплея повышенным или пониженным напряжением). Такая схема применена потому, что часы по плану должны работать в широком диапазоне входных напряжений (от 6.7В в случае питания 4-мя новыми батарейками АА, до около 4-х вольт при питании -3мя старыми батарейками АА или 4-мя подсевшими аккумуляторами АА, каждый из которых может выдавать в подсевшем состоянии уже по 1В). Контрастность на стабилитроне прекрасно себя показала и сохраняется постоянной при напряжениях питания от 4.0В до почти 6.9В.
Подсветка на схеме выведена на порт PB1 микроконтроллера и включается программно (реально включается только если играть в сумерках на улице, потому что в комнате и так видно а аккумуляторы подсветка садит сильно, т.к. максимальный ток потребления подсвети до 200 мА).
Кнопки зашунтированы конденсаторами 0.1 мкФ, но кроме того приняты программные меры для предотвращения дребезга контактов и двойных срабатываний.
Так же на плате разведен разъем для программатора (потому что прошивка многократно доделывалась и обновлялась), но его ставить не обязательно. Управление бузером выведено на порт PB0.
Предусмотрены два варианта питания — от блока на 4 батарейки/аккумулятора формата АА или от внешнего блока питания через L7805. Источник питания переключается ползунковым переключателем.
Все это собрано на печатной следующей плате:
Плата односторонняя, присутствуют перемычки, дисплей ставится «поверх» платы в разъем (однорядный SIL-16). Постарался сделать плату максимально компактной (на самом деле она чуть больше самого дисплея и то только потому что нужно было сверху разместить ряд кнопок):
Поверх платы с обратной стороны располагается блок для батареек АА:
Программная часть
Программа написана в среде CodeVision AVR. Поскльку в Atmega8 для шахматных часов более чем достаточно памяти, решено оставшуюся часть flash использовать для «секундомера» и «таймера обратного отсчета». Внешний кварц не использовался, ровно как и какая-либо внешняя микросхема времени, потому что как настоящие «часы», работающие сутками в задачи которых входит отображение относительно точного времени, перед шахматными часами на стоит, а погрешность даже в несколько секунд за время часовой партии значения не имеет (тем более что для всех игроков эта погрешность будет одинаковая).
Кнопки, смотря на них слева на право, имеют значения «LEFT», «SET», «RIGHT», «STEP». «LEFT», «RIGHT» и «SET» используются для перемещения по меню и изменения настроек, а «STEP» для начала игры и индикации хода (эта кнопка сделана гораздо больше остальных чтобы ее удобно было нажимать).
Код постарался разбить на модули, объединенные в общий проект, каждый модуль в своем файле и отвечает за одну из функций устройства (главное меню, режим шахматных часов, режим таймера, режим секундомера, глобальные вспомогательные функции и глобальные константы). Но конечно код эталоном быть не может («лапшеображного» кода и не очень оптимальных решений в нем хватает).
Из интересного — функции опроса кнопок с предотвращение дребезга контактов и надежным определением «отпускания» кнопки:
#define DEBOUNCE_TIME 25 /* время ожидания для предотвращения «дребезга контактов» (по-умолчанию: 25) */
#define LOCK_INPUT_TIME 250 /* время ожидания после того, как кнопка нажата (по-умолчанию: 250) */
/* Проверка состояния кнопки по биту порта PINC */
char checkButtonPressed(char PINC_bit) {
return (PINC & (0x01<<PINC_bit)) == 0;
}
/* Проверяет, нажата ли кнопка */
char buttonIsPressed(char PINC_bit) {
if (checkButtonPressed(PINC_bit)) {
delay_ms(DEBOUNCE_TIME);
if (checkButtonPressed(PINC_bit)) return 1;
}
return 0;
}
/* Проверяет, отпущена ли кнопка */
char buttonIsReleased(char PINC_bit) {
if (!checkButtonPressed(PINC_bit)) {
delay_ms(DEBOUNCE_TIME);
if (!checkButtonPressed(PINC_bit)) return 1;
}
return 0;
}
void waitButtonReleased(char PINC_bit) {
buzzer_beep(BUZZER_BEEP_MILLIS);
while(!buttonIsReleased(PINC_bit));
}
Изменение значений таймера и времени игры/времени на ход сделано так, что если нажать и удерживать кнопку, то чем дольше удерживаешь кнопку, тем быстрее меняются значения (подсмотрел как сделано управление на духовке всего 3-мя кнопками, в то же время достаточно удобно). Для этого используется функция с 4-мя «скоростями» изменения показаний времени за цикл обработки:
#define SCROLL_SPEED2_ITERATIONS 10
#define SCROLL_SPEED2_DELAY_MS 80
#define SCROLL_SPEED3_ITERATIONS 10*4
#define SCROLL_SPEED3_DELAY_MS 80/4
#define SCROLL_SPEED4_ITERATIONS 10*4*4
#define SCROLL_SPEED4_DELAY_MS 0
void inputAdjustableDelay(unsigned int iterations) {
if(iterations > SCROLL_SPEED4_ITERATIONS)
delay_ms(SCROLL_SPEED4_DELAY_MS);
else if(iterations > SCROLL_SPEED3_ITERATIONS)
delay_ms(SCROLL_SPEED3_DELAY_MS);
else if(iterations > SCROLL_SPEED2_ITERATIONS)
delay_ms(SCROLL_SPEED2_DELAY_MS);
else
delay_ms(LOCK_INPUT_TIME);
}
Т.е. первые 10 значений после нажатия кнопки меняются медленно, следующие 40 значений уже меняются быстрее, следующие 160 еще быстрее и если кнопка и дальше не отпускается, что значения меняются с максимальной скоростью. Соответственно чуть промахнулся — отпустил кнопку, нажал еще раз и уже на самой медленной скорости «подправил» значения — удобно. Такой вариант позволяет достаточно быстро менять значения в больших диапазонах (в сутках 86400 секунд, так что это большой диапазон для изменения значений одной кнопкой, например).
В программе реализован контроль напряжения питания и если оно падает ниже 4В, то отключается подсветка. В других случаях интенсивность подсветки можно выбрать в главном меню (причем при значении 0 — не проходит ни одного импульса в ШИМ, т.е. потребление тока подсветкой отсутствует полностью).
Все действия реализованы на двух таймерах — Таймер 1 используется для отсчета времени в 1/100 долях секунды и выполнения всех операций основанных на времени, а Таймер 2 отвечает только за подсветку экрана. Сам код функций таймеров максимально «легковесный» (только изменения значений переменных — весь код по обработке значений вынесен в главный цикл программы).
Еще из интересного — есть две языковые версии прошивки (русская и английская). Выбор версии прошивки осуществляется подключением соответствующего файла локализации (language_rus.c или language_eng.c). Для корректного отображения русского языка из исходника набранного в среде CodeVision AVR используется специальная русифицированная библиотека для работы в дисплеем (сам дисплей русифицирован, но коды букв в ROM дисплея не соответствуют раскладке Windows и чтобы не писать русский текст в исходнике «спецсимволами» используется локализованная библиотека — файлы прилагаются).
В интерфейсе можно выбирать количество игроков (от 2 до 4), время на партию и «прибавку» времени за каждый сделанный ход. Если игрок случайно забыл нажать на кнопку или нажал на кнопку дважды — можно переключить время текущего игрока клавишами «LEFT» и «RIGHT». Можно поставить игру на паузу кнопкой «SET». Переход хода осуществляется кнопкой «STEP».
В режиме таймера можно выставить время кнопками «LEFT» и «RIGHT», старт таймера кнопкой «STEP», ей же можно поставить его на паузу или остановить, кнопкой «SET» можно перезапустить таймер сначала (удобно когда делаешь какие-то упражнения и нужно много раз отмерять одинаковые промежутки времени).
В режиме секундомера вообще все просто — старт и остановка кнопкой «STEP».
В главном меню всегда отображается напряжение питания и в последнем пункте можно выставить яркость подсветки кнопками «LEFT» и «RIGHT».
Все изменения и настройки сохраняются в EEPROM автоматически.
Корпус
Корпус разрабатывал в SolidWorks 2012 с целью дальнейшей печати на 3D-принтере. Опт показал, что лучше всего начинать моделирования корпуса со схематичной модели самой платы, компонентов на ней и крепежных отверстий:
Дальше, уже отталкиваясь от макета платы и главных ее элементов (создавая привязки к ним) создается корпус, состоящий из двух половинок, предназначенных для скручивания болтиками M4, крышка для отсека с батарейками и кнопки:
В собранном виде получается примерно вот так:
Все отверстия для переключателя, кнопок и разъема питания сделаны на стыке верхней и нижней половины корпуса в виде «выемок».
Корпус печатал в http://3d-lab.com.ua/ — вот что получилось:
В собранном виде:
Ну и на игровом месте в варианте шахмат для четверых:
В варианте шахмат для троих:
И в варианте гексагональных шахмат для двоих:
Вариант питания 3-мя батарейками (+ сделанный из болтика 5*50 токопроводящий муляж батарейки вместо 4-й батарейки в отсеке):
Вот и все.
PS: Обычные шахматы у нас тоже есть (вы не поверите, сейчас уже — 35 коробок на офис из 14 сотрудников!), но в них у нас никто не играет. Такие мы «коты» 😉