Да простят меня читатели, но это реплика на реплику. А началось всё с интересной статьи, где автор познакомил нас со своей разработкой на базе ATMega8. Понятно, камень этот избыточен для той задачи, которая была на нем реализована, на что и обратил внимание оппонент.
Но теперь уже у меня засвербило… гм, в ладонях, и я не мог не попытаться вставить свои пять копеек. Я понимаю, настоящая моя заметка для комментария великовата, а на полноценную статью не тянет, но все же попробую.
Пересказывать содержание предыдущих серий смысла нет, кому интересно — я привел ссылки. Перейдем сразу к сути.
Схема на реле, предложенная уважаемым автором, вызвала у меня некое подобие зубной боли. Возможно потому, что в юности довелось иметь дело с декадно-шаговыми и координатными АТС, после чего я на всю жизнь возненавидел реле. Да, релейные схемы — это просто, да, работать они будут даже в условиях ядерного взрыва, но…
Первое но — надежность
Как вы думаете, какие самые ненадежные компоненты электронных схем? Возможно я и ошибаюсь, но по моему опыту это механические контакты и электролитические конденсаторы. Контакты подгорают, окисляются, конденсаторы сохнут. А тут вся схема состоит из контактов и конденсаторов. К тому же в этой схеме полярные конденсаторы включены параллельно обмоткам реле, и в результате при разрыве цепи ЭДС самоиндукции замыкается через что? — правильно — через конденсатор, который в этом случае поработает таким плохоньким диодом. Причем тот оказывается подключенным в обратной полярности. Не думаю, что это пойдет на пользу и так не слишком надежному компоненту.
Второе но — стоимость
Сколько стоит одно реле? Поискав на «Али», ничего приличного дешевле одного американского доллара не нашел. Ладно, пусть я не умею искать, возьмем цену 50 центов. Четыре реле (ведь в оригинальной схеме четыре канала) — уже два бакса. Получается только одни реле будут стоить больше, чем вся комплектуха варианта на микроконтроллере, включая сам микроконтроллер. А если в той схеме еще повыбрасывать лишние детали…
Третье но — расширяемость
А вот скажите мне: что мы будем делать с этой схемой, если понадобится ввести в изделие дополнительную функциональность? Нет, я не прошу играть военные марши, а хотя бы и пискнуть зуммером после истечения времени, которое дается игроку на ответ?
Воооот…
Ладно, это была присказка. А теперь к делу. Смотрите схему. Процитирую: «спаять было быстрее чем рисовать».
Одна условно-бесплатная микросхема, три резистора, три конденсатора. Пьезопищалка. И все, практически. Питать это хозяйство можно от трех элементов AA. Без всяких стабилизаторов. В покое потребляет меньше микроампера (power down mode) — можно отказаться от выключателя — еще один ненавистный контакт.
Контроллер AVR AT90S1200 не потому, что он чем-то хорош, просто у меня после одного из древних проектов их осталось с полведра, а так как он давно снят с производства — сейчас уже никуда его не приткнешь. Только в какую-нибудь самоделку. Поэтому и условно-бесплатный. Но, как верно заметил автор первой статьи, здесь подойдет любой.
Теперь про программу. Так как в этом контроллере ОЗУ нет (от слова вообще), а стек аппаратный и всего лишь трёхуровневый, ни о каких языках высокого уровня речь не идет. Только Ассемблер, только хардкор…
Посадить кнопки на прерывания тоже не получится. Внешнее прерывание только одно, а знатоков за столом шесть. Что ж, будем опрашивать в цикле. Причем опрашивать все одновременно, дабы не было преимущества ни у одного игрока. Время цикла опроса при частоте тактового генератора 1МГц — 6мкс, то есть мы вылавливаем разницу между нажатиями в 6мкс. Если два игрока нажмут кнопку одновременно, ну вдруг, мало ли — будут засвечены два светодиода. Все честно. Хотя, думаю, вероятность такого события будет очень низка. Но все же, если точность определения лидера в 6мкс недостаточна — можно подключить кварц, прошить фьюз и запустить контроллер на частоте 12МГц. В этом случае частота опроса повысится в 12 раз. Ваш К.О.
Дребезг контактов ни на что не влияет, так как мы реагируем на первый же замеченный спад уровня. После этого следует обработка нажатия, и что уже там творится на кнопке — нас не волнует.
Согласен, разные кнопки с разным временем и характером дребезга могут дать кому-то преимущество в микросекунду-другую, но, по-моему, это уже вылавливание блох.
;---------------------------------------------------------------------------- ;¦ Title : Своя игра. Пример реализации ;¦ Version : 0.0 ;¦ ;¦ Last updated : 16.01.16 ;¦ Target : AT90S1200 1MHz (внутренний RC-генератор) ;+--------------------------------------------------------------------------- .include "1200def.inc" ;¦ Определение регистровых переменных ;+--------------------------------------------------------------------------- .def acc = r20 ; временная переменная .def temp1 = r21 ; просто локальная переменная .def temp2 = r22 ; просто локальная переменная .def temp3 = r23 ; просто локальная переменная .def temp4 = r24 ; просто локальная переменная .def temp5 = r25 ; просто локальная переменная .def temp6 = r26 ; просто локальная переменная .def temp7 = r27 ; просто локальная переменная ;¦ Определение сигналов в портах ;+--------------------------------------------------------------------------- .equ ini_b = 0b00111111 ; начальные значения PORTB .equ dir_b = 0b11111111 ; маска направлений 1-out 0-in ; ¦¦¦¦¦¦¦¦ .equ led01 = 0 ;¦¦¦¦¦¦¦+-12(out) .equ led02 = 1 ;¦¦¦¦¦¦+--13(out) .equ led03 = 2 ;¦¦¦¦¦+---14(out) .equ led04 = 3 ;¦¦¦¦+----15(out) .equ led05 = 4 ;¦¦¦+-----16(out) .equ led06 = 5 ;¦¦+------17(out) (MOSI) .equ buzzer1 = 6 ;¦+-------18(out) (MISO) .equ buzzer2 = 7 ;+--------19(out) (SCK) .equ ini_d = 0b00111111 ; начальные значения PORTD .equ dir_d = 0b01000000 ; маска направлений 1-out 0-in ; ¦¦¦¦¦¦¦ .equ key01 = 0 ; ¦¦¦¦¦¦+--2 (in) .equ key02 = 1 ; ¦¦¦¦¦+---3 (in) .equ key03 = 2 ; ¦¦¦¦+----6 (in) (INT0) .equ key04 = 3 ; ¦¦¦+-----7 (in) .equ key05 = 4 ; ¦¦+------8 (in) .equ key06 = 5 ; ¦+-------9 (in) .equ pin11 = 6 ; +--------11(out) не исп. ;¦ Макросы ;¦ ;+--------------------------------------------------------------------------- .include "mymacros.inc" .macro init_ports ldi acc,dir_b out DDRB,acc ; настроили порт B на ввод/вывод ldi acc,ini_b out PORTB,acc ; вывели в порт ldi acc,dir_d out DDRD,acc ; настроили порт D на ввод/вывод ldi acc,ini_d out PORTD,acc ; вывели в порт .endmacro .macro init_wd wdr ; reset watchdog timer ldi acc,0b00001111 ; watchdog разрешен, коэф. деления - 2048 out WDTCR,acc .endmacro .macro init_irq ; портит acc ldi acc,(1<<se)+(1<<sm)+(0<<isc01)+(0<<isc00) ; ¦ ¦ ¦ ¦ ; ¦ ¦ +----------+-- прерывания: "00" - по низкому уровню ; ¦ +--------------------- 0-idle mode 1-power down ; +----------------------------- 1-sleep разрешен out MCUCR,acc ; ldi acc,(1<<int0) ; out GIMSK,acc ; разрешили внешние прерывания от INT0 clr acc out GIMSK,acc ; запретили внешние прерывания от INT0 .endmacro .macro comparator_off ; портит acc ldi acc,(1<<ACD) out ACSR,acc ; выключили компаратор для экономии энергии .endmacro .macro speaker_up sbi PORTB,buzzer1 cbi PORTB,buzzer2 .endmacro .macro speaker_dn sbi PORTB,buzzer2 cbi PORTB,buzzer1 .endmacro ;---------------------------------------------------------------------------- ;¦ ;¦ Точка входа ;¦ ;+--------------------------------------------------------------------------- .CSEG .org 0 rjmp start ; на начало программы ;---------------------------------------------------------------------------- ;¦ ;¦ Подпрограммы ;¦ ;+--------------------------------------------------------------------------- ;¦ Задержки ;¦ ;¦ Портит temp5,6,7 ;+--------------------------------------------------------------------------- .equ const10ms = 2500-2 .macro wait_ms ; задержка от 10 до 2550мс, кратная десяти ldi temp5,@0/10 rcall delay10N .endmacro .macro wait_s ; задержка от 1 до 255с ldi temp4,@0 lb1: ldi temp5,100 rcall delay10N dec temp4 brne PC-3 .endmacro delay10N: ; wdr ; 1 ldi temp6,low(const10ms) ; 1 ldi temp7,high(const10ms) ; 1 d10ms1: ; один цикл - 4 такта, 4мкс subi temp6,1 ; 1 sbci temp7,0 ; 1 brne d10ms1 ; 2 djnz temp5,delay10N ; ret ;¦ Звуковой сигнал 2.5кГц (два полупериода по 200мкс) ;¦ ;¦ Портит temp6,7 ;+--------------------------------------------------------------------------- .equ const200us = 49 .macro beep rcall snd .endmacro snd: ldi temp6,0 ; 256 периодов меандра snd1: speaker_up rcall delay200us speaker_dn rcall delay200us djnz temp6,snd1 ret delay200us: ; 3 (вызов) ldi temp7,const200us ; 1 del200: nop ; 1 djnz temp7,del200 ; 1+2 ret ; 4-1 ;---------------------------------------------------------------------------- ;¦ ;¦ Начало программы ;¦ ;+--------------------------------------------------------------------------- start: init_ports init_irq ; только чтобы разрешить sleep comparator_off waitloop: ; wdr in acc,PIND ori acc,0b11000000 ; забиваем два старших разряда. Они не используются cpi acc,0xff breq waitloop ; ждем пока хоть одна кнопка не будет нажата out PORTB,acc ; зажгли светодиод, соответствующий нажатой кнопке beep ; звуковой сигнал ; даем время на ответ wait_s 10 ; ждем N секунд ; время истекло - тройной звуковой сигнал beep wait_ms 100 ; ждем N миллисекунд beep wait_ms 100 beep ldi acc,0xff out PORTB,acc ; погасили все светодиоды sleep rjmp 0 ; этот джамп не нужен. Из слипа выходим только по сбросу .exit ;полный конец обеда -------------------------------------------------
Спасибо за внимание. Если что не так — пишите в личку, исправлю.
ссылка на оригинал статьи http://geektimes.ru/post/269332/
Добавить комментарий