Ненормативная схемотехника: ATmega8 – кто сказал, что выше головы не прыгнешь?

    Вот уж несколько лет, как я увлёкся микроконтроллерами, а именно семейством AVR. Ещё на этапе освоения Ардуино (в этот момент часть аудитории поплевались и ушли читать другие статьи) я пытался выдавить из неё больше, чем задумано. Меня всегда больше интересовали нестандартные решения обычных задач. Сейчас я знаю об AVR намного больше, чем ещё пару лет назад, и всё больше убеждаюсь, что знаю очень мало.



    С чего начинает среднестатистический начинающий электронщик? Правильно, с часов! Как только научился пользоваться голыми контроллерами, а не платами Ардуино, захотел сделать часы на Атмеге, голой Атмеге без кучи ключей и буферных микросхем. И обязательно со статической индикацией, а не с динамической (ну не люблю я её). Собственно, статическая индикация программно гораздо проще, а ведь мы простых путей не ищем. Но зато возникают другие проблемы, которые несколько раз меня останавливали в самом начале пути. Понятно, что если взять Атмегу пожирней, задействовать в ней половину ножек и полпроцента памяти, задача упрощается донельзя, собственно, такие настольные часы на ATmega128 работают у меня на столе пару лет.



    Но это не наш метод. Я с самого начала хотел именно ATmega8, как самую доступную и самую дешёвую (в том числе в дип-корпусе). Всё то же самое можно и на ATmega48, но её попробуй ещё найди, разве что у Вас в ящике стола валяется их много с незапамятных времён.
    Посмотрим на картинку, известную всем, кто недавно интересуется AVR.



    Глядя на неё, легко посчитать, что мы можем задействовать на часовой индикатор 20 ножек, ещё на двух у нас будет кварц (куда от него денешься, внутреннее тактирование не прокатит, нам ведь от часов нужна точность какая-никакая). Ну и сброс. На четыре семисегментных индикатора нужно 28 ног, ну даже 27, ведь десятки часов можно отображать цифрами 1 и 2, а ноль не отображать. Ещё когда идея только зарождалась, я это количество сократил до 22 ножек, ведь для отображения десятков часов можно обойтись цифрой 1, и оба её сегмента зажигать от одной ноги контроллера. Но как ни крути, пары ног мне всё же не хватало, даже при том что я давно знал о возможности использования как ввода-вывода ножки Reset, но так ещё ни разу и не попробовал (если не считать ATtiny13, её не так жалко было), ведь параллельного программатора у меня нет, а любая отладка – это минимум несколько итераций прошивки, вряд ли всё идеально выйдет с первого раза. Так и лежал этот замысел в закромах мозга, и ждал своего времени, пока как-то мне не пришла в голову ещё одна интересная идея.
    Посмотрел я однажды на светодиодную ленту (120 светодиодов на метр) и понял, что можно легко и просто сделать электронные часы любого размера с её использованием. Просто нарезаем сегменты желаемой длины и наклеиваем их на подходящее основание, для больших размеров сегмент может складываться из двух и более лент по ширине. В моём случае отрезаем сегменты по шесть светиков, таким образом длина сегмента составляет 50 мм, высота цифры 100, для моей задумки офисных часов вполне достаточно.



    Но вот незадача, напряжение питания ленты 12 вольт, а AVR хочет не больше 5 вольт (люди утверждают, что и 8 вольт выдерживают, но я проверять пока не буду, да и не поможет). То есть нужно ставить 22 ключа для включения всех сегментов. Если применить драйвер ULN2003, хватит (почти) трёх штук, это копейки, но, как я писал выше, это не наш метод, хотя этот вариант можно приберечь для часов побольше. Ну никак это не вписывается в концепцию «голая Атмега».

    И вот тут-то начинается самое интересное. Напряжение питания ленты 12 вольт, первые признаки жизни белые светодиоды (три штуки последовательно) начинают подавать при более чем 7.5 вольт, и, что очень важно, до этого напряжения ток через ленту практически равен нулю (можете проверить). На ножке контроллера, работающей в режиме выхода, может быть уровень 0 вольт или 5 вольт (третий вариант рассмотрим позже), и если подключить сегмент анодом к +12 вольт, а катодом к выходу контроллера, напряжение на сегменте будет равняться соответственно 12 вольт (светит) или 7 вольт (не светит). Даже если бы через погасший сегмент протекал мизерный ток, он ушёл бы к плюсу питания контроллера через защитный диод, которые в AVR гораздо более выносливые, чем нас пугали в обучающих статьях. Третий вариант – ножка в режиме входа, напряжение на сегменте 7 вольт благодаря защитному диоду, стало быть сегмент не светит. Конечно, как только я обдумал всё это в теории, сразу же проверил на практике, залив в контроллер простой «блинк» для одной из ног.



    А так как сейчас в силу некоторых обстоятельств мои возможности для экспериментов слегка ограничены, напряжение питания для сегмента случайно оказалось более 18 вольт, и сегмент гас не полностью, так что я успел разочаровано подумать, что подпалил выход. Когда уменьшил напряжение (на тот момент даже нечем было померить), всё стало на свои места, так что, благодаря нелепой случайности, теперь я точно знаю, что для схемы не смертельно небольшое повышение напряжения выше 12 вольт. С напряжением определились, а что с током? На моей ленте (и скорей всего на вашей тоже) стоят резисторы по 150 ом, ток через сегмент не более 20 мА, только сегмент в данном случае – это три светика, а каждый сегмент моих часов состоят из двух сегментов ленты, так что 40 мА. Вроде даже вписываемся в даташит, но на 20 выходов это уже 800 мА, что намного выше дозволенных 200 мА на корпус. Ток через ленту очень зависит от напряжения на ней, и нелинейно падает даже при небольшом снижении, что является большим минусом при обычном использовании ленты, и плюсом в данном случае, ведь реальное напряжение на сегментах равно 12 вольт минус падение на ключе (около 0.6 вольт), а ещё при желании можно снизить напряжение питания, понизив тем самым яркость часов. Так что страшные 800 мА несложно снизить раза в два. В любом случае, я был уверен, что это не станет проблемой, да и приобретённый опыт ценнее, чем возможность потери одной Атмеги. Вот так просто ATmega8 коммутирует индикатор с напряжением в два с лишним раза выше, чем её собственное напряжение питания. Именно это я имел ввиду в заголовке статьи. Хотя способ совсем не нов, по такому же принципу работает советская микросхема К155ИД1 – высоковольтный дешифратор управления газоразрядными индикаторами, где сравнительно низковольтные выходы (до 60 вольт) коммутировали индикаторы с напряжением зажигания 150 вольт и выше.



    Дальнейшие эксперименты я продолжил с обычным четырёхсимвольным семисегментным индикатором с общими анодами и раздельными катодами, как раз припасён был для такого случая.



    Аноды к +5 вольт через один на всех резистор, для отладки прошивки этого за глаза. Первоначально я остановился на варианте использования в качестве двух недостающих ног пинов подключения кварца (итого 22 выхода), а тактировать контроллер от внешнего генератора минутных импульсов через (внимание!)…



    … вход сброса. Это ещё один занимательный лайфхак, который описан здесь Как сохранять переменные arduino, при reset.

    Можете попробовать залить в Ардуино простой код и посмотреть результат работы в «Мониторе порта», периодически сбрасывая её кнопкой или с клавиатуры:

    пробник
    #define NO_INIT __attribute__((section(".noinit")))
    void setup() {
        static unsigned NO_INIT nonInitCounter;
        nonInitCounter=nonInitCounter+2048;
        Serial.begin(9600);
        Serial.print("Setup counter: ");
        Serial.println(nonInitCounter);
    }
    void loop(){}


    Не буду приводить свой код, дабы не подвергаться критике лишний раз (я не самый лучший
    программист), но если в двух словах, можно создать глобальную переменную, которая сохраняется при перезагрузке контроллера. Раз в минуту под воздействием внешнего импульса сброса Атмега перезагружается, и начинает заново отрабатывать прошивку: считывает переменную, преобразует её в показания часов и минут, выводит на индикатор, увеличивает переменную на одну минуту. Дальше опять сброс, и всё по новой. Пришлось порыться в интернете и опробовать два вида программного сброса, ведь внешнего генератора у меня пока не было, а жмакать сброс всё время вручную не сильно удобно.

    пример функции
    void softReset() {
      //программный сброс //http://kazus.ru/forums/showthread.php?t=13540&page=3#
      asm volatile ("rjmp 0x0000");//Sketch uses 2 412 bytes
      //программный сброс //https://www.cyberforum.ru/post11307314.html
      //((void(*)(void))0)();//Sketch uses 2 416 bytes
    }

    Что интересно, эта переменная может сохраняться даже после отключения питания (не всегда). И это не EEPROM, если кто подумал. По мере отладки я пришёл к использованию нескольких таких переменных.

    Кто-то скажет: какой внешний генератор, а как же концепция голой Атмеги? На момент опытов я был уверен, что в качестве генератора выступит некая козявка размером с рисинку и ценой в пару копеек. Но когда всё заработало в теории и пришло время с козявкой определиться, меня ждал облом. Единственное, что меня могло бы устроить, это старая добрая К176ИЕ12, кто бы мог подумать! На дворе двадцать первый век, а в природе нет простого доступного аппаратного генератора минутных импульсов.

    Не беда, подумал я. Можно и раз в секунду. Немного переписал код, проверил работу, отлично. Но опять же, для внешнего генератора я нашёл только DS1307 (и её аналоги). Да, стоит копейки, для обвязки достаточно кварца (и ещё несколько необязательных элементов). Вот только чтобы она генерировала секундные импульсы, ей нужно подать команду по шине I2C. Чем подать? И какую? (Теперь я уже знаю, но на тот момент не было с чем пробовать). Короче, не подходит. Ладно, последняя надежда. Некоторые западные часы 90-х тактировались частотой сети 50 гц. Возможно, сейчас у нас частота стабильней, чем была 30 лет назад. Попробовал сымитировать – работает. Если бы воплотил в жизнь, было бы оригинально – контроллер, перезагружающийся 100 раз в секунду. Но я пока отмёл этот вариант и стал искать другие.

    Итак, я мог использовать 22 выхода (что мне достаточно) и пин сброса в качестве входа. Но не срослось… Вернёмся к варианту с кварцем. Минус две ноги на кварц – получаем 20, даже если ножку сброса сделать портом ввода-вывода, получим 21, всё равно не хватает одного, хоть ты тресни! Но недавно я нашёл способ, о котором задумывался ещё два года назад, что-то не получилось тогда. У нас есть пин AREF для опорного напряжения, относительно которого происходят аналоговые измерения. И на этот пин мы можем программно подать напряжение питания в качестве опорного или встроенное опорное напряжение 2.56 (для ATmega8). Проверил, измерил, действительно можно получить на ножке AREF напряжение 0 вольт, 2.56 вольт, или 5 вольт.

    превращаем AREF в ещё один выход
    // превращаем AREF в ещё один выход
    void setup() {
    }
    void loop() {
      ADMUX = 7 + 64; // уровень 1 (5 вольт) // 7-номер аналогового входа
    //почему 7 аналоговый вход? А потому что физически у Атмеги входы от 0 до 5,
    //и назначение аналоговым входом входа 7 не помешает работе остальных в качестве выходов
      delay(3000);
      ADMUX = 7 + 64 + 128; // уровень 2.56 вольт // 7-номер аналогового входа
      delay(3000);
      ADMUX = 7; // уровень 0
      delay(3000);
    }


    Нюанс: это если замерять относительно общего провода. Если мерить относительно +5 вольт, во всех трёх случаях получаем ноль. То есть нагрузку можно подключить между AREF и общим. Экспериментально установил, что можно получить ток до 20 мА при 2.56 вольт на ноге и до 40 мА при 5 вольт на ноге, этого вполне достаточно, чтоб зажечь светодиод, к примеру. Вот он, заветный двадцать второй выход! Конечно, напрямую управлять двенадцативольтовым сегментом не получится, нужен транзистор. Под руку попался легендарный КТ315, сколько лет я к нему не прикасался, как по мне, это одно из лучших произведений советской электроники, наряду с микрухой К155ЛА3. Когда-то я КТ315 и КТ361 даже в качестве ключей импульсного трансформатора питания применял, при напряжении порядка 60 вольт, и неоднократно. Здесь же нагрузка для него плёвая, и я принципиально даже резистор в базу не поставлю (20 мА вполне себе допустимый ток базы).

    Ну что ж, думал я, 22 выхода есть, отлажу код с 21 выходом, а 22-й на ножке сброса оставлю напоследок, когда всё остальное уже заработало. Ещё ведь и кнопки установки времени нужно куда-то приткнуть, а ног не осталось вовсе. Если б Атмега была в SMD-корпусе, можно было бы воспользоваться входами А6 и А7, выходами они всё равно не умеют. Но у меня корпус DIP, так что такой роскоши позволить себе не могу. Зато ведь можно выходы сделать входами, правда, в это время придётся погасить индикацию, но для опроса кнопок достаточно нескольких миллисекунд, никто и не заметит (как я ошибался!). Значит, перевожу ножки кнопок в режим входов, подтягиваем программно к питанию, и ждём пару миллисекунд. Если в это время какая-то из кнопок замкнута на минус, ждём ещё 20 миллисекунд, убеждаемся, что кнопка всё ещё нажата, и производим соответствующее действие в программе. Кнопки: «минуты плюс», «минуты минус», «часы плюс», «коррекция плюс». Коррекция – подстройка значения секунд раз в сутки в зависимости от суточного ухода показаний. Всё заработало почти с первого раза. Нюанс: при замкнутой кнопке сегмент, подключенный к той же ножке, оказывается включён, такой вот побочный эффект, что поделать. Поэтому кнопки изменения минут подключаю к выводам контроллера, которые управляют сегментами единиц часов, а кнопки изменения часов подключаю к выводам контроллера, которые управляют сегментами единиц минут. Выставляя минуты, совсем не обращаешь внимания, что с показаниями часов что-то не так, и наоборот.
    Ну вот всё и получилось в макете с семисегментными индикаторами. Но параллельно я пытался накопать информации по поводу применения ноги сброса в качестве порта ввода-вывода. А там всё довольно туманно и неопределённо. Основное, что об этом пишут: 1 – выход с открытым коллектором (не точно), 2 – выход чрезвычайно слаботочный (тоже не наверняка). Даже если использовать внешний транзистор, нужно точно знать, открытый коллектор (сток) или нет, ведь тогда состояние выхода нужно инвертировать. А перепрошить я уже не смогу. В общем, опять двадцать пять! Вернее, двадцать один. Двадцать один гарантированный выход вместо 22. Опять одного не хватает. Опять я мечусь в поисках решения.

    Возвращаюсь к AREF. Я могу получить три разных уровня на нём. Значит можно зажечь один сегмент, или два одновременно, или ни одного. Я обратился к своей же прошлой публикации (как давно это было!):Ненормативная схемотехника: семисегментный индикатор на ATtiny13.

    Чтобы попробовать использовать решение с совместным включением двух сегментов. Перебирая возможные пары сегментов, и осознавая, что подобное усложнение портит всю картину, я внезапно додумался, что для цифры десятков минут поле поиска значительно сужается – цифра ведь может быть только от 0 до 5. И тут пришло озарение:



    во всех этих цифрах сегменты А и D или вместе светятся, или вместе погашены! Не нужно никаких трёх состояний, достаточно просто соединить сегменты А и D вместе и подключить к одному выходу. И теперь 21 выхода хватит всем. Довожу код, проверяю на макетке с семисегментным индикатором, бинго!

    Всё, пора делать финальный вариант. Нарезаю светодиодную ленту, наклеиваю сегменты на подходящее основание, которым оказался кусок пластиковой вагонки (примерно 150х350 для цифр высотой 100). К каждому сегменту нужно подвести +12 вольт и проводник от соответствующего выхода контроллера.



    В качестве монтажного провода применил для +12 тонкую проволочку без изоляции, вынутую из обычного гибкого провода, подпаиваю к плюсу каждого сегмента, продеваю через проколотое отверстие на другую сторону основания и спаиваю их все вместе, а для остальных проводников обмоточный провод в лаковой изоляции, продеваю их через те же отверстия и подпаиваю к панельке контроллера. На каждую цифру получилось по три отверстия в местах, где сходятся сегменты, в одно отверстие выходит один провод на +12, и два или три провода в изоляции. Также к контроллеру подведены четыре провода от кнопок, кнопки замыкаются на минус, подтяжка внутренняя. Я при проверке обходился без кнопок, просто касался провода проводом.



    Сегменты цифр разведены по контроллеру именно в таком порядке для упрощения кода.
    Первая цифра (единица, напоминаю) состоит из цельного куска ленты длиной 10 см. Подключаю 5 вольт питания контроллера и 12 вольт питания индикации, включаю. Вот он, торжественный момент, всё красиво светится, часики работают. Кстати, на КДПВ в начале статьи в качестве светофильтра на индикаторах лежит лист обычной бумаги для принтера, яркости хватает с избытком.

    Мне не очень нравится американская система отображения времени, когда часы дважды в сутки считают до двенадцати. Я применил свою: с нуля часов до 19, и затем 8, 9, 10, 11. А с учётом того, что часы офисные, в 8 вечера их редко кто увидит.



    В такие моменты ощущаешь некоторое разочарование, что прям вот так сразу заработало, даже как-то неинтересно. Поначалу я упорно не хотел замечать некое мерцание индикаторов, пока мне на него не указали коллеги. В макете этого мерцания не было видно совсем, а тут прям бросается в глаза. Выше я писал, что при опросе кнопок после перевода ножек в режим ввода сделана пауза в пару миллисекунд, без этой паузы остаточный потенциал на ножке воспринимался как нажатие. Так вот этих двух миллисекунд, в течение которых индикаторы потушены, оказалось достаточно для мерцания индикации. И это при том, что опрос происходит два раза в секунду. То есть глаз замечает двухмиллисекундную паузу дважды в секунду, чего я никак не ожидал. Было подозрение, что вследствие переходных процессов контроллер каждый раз перепроверяет, действительно ли нажаты кнопки (а это по 20 мсек на каждую). Я внёс некоторые изменения в код, временно отключив все лишние функции, но подозрения не подтвердились. В результате помогли следующие изменения: для опроса кнопок перевожу те выходы, которые задействованы под кнопки, в высокий уровень, тем самым погасив соответствующие сегменты, только после этого перевожу те же ножки в режим входа. Таким образом от паузы в 2 мсек можно избавиться совсем, но я оставил на всякий случай 300 микросекунд, проблема исчезла полностью.

    Что мы имеем в итоге? Ножка сброса контроллера работает по прямому назначению и используется только при заливке прошивки, ножки кварца подключены к кварцу, как и положено. Двадцать ног работают как порты ввода-вывода, и нога AREF управляет ключевым транзистором, как раз на него и навешена цифра десятков часов (1). Ещё четыре ножки питания, никто не отлынивает, все ноги задействованы. По поводу кварца: я всерьёз рассматривал вариант применения часового кварцевого резонатора на 32768 Гц (считал его более точным), но отказался от идеи, побороздив интернет. Оказывается, запустить Атмегу с часовым кварцем не так-то просто и нет никаких гарантий работоспособности, а плюсов от применения не особо. Экономичность нас не интересует в данном случае, основное потребление – индикация. С точностью тоже всё неопределённо. А суточный уход вполне компенсируется программно. Зато большим плюсом является простота подключения, кварц на 8 или 16 МГц без проблем работает даже без конденсаторов. В результате вся схема состоит (если не считать индикаторы и питание) из Атмеги, кварцевого резонатора, и транзистора, припаянных прямо к панельке. Питание контроллера обеспечивается малогабаритным стабилизатором из серии 7805, ток через него мизерный, но на всякий случай я припаял его теплоотводом к кусочку оцинковки примерно 30х30 мм. В целом же часы питаются от внешнего блока питания на 12 вольт, который, по сути, дороже всех комплектующих. Фактический ток потребления часов 560 мА при показаниях часов 18-08 (это максимальное количество сегментов, которые можно засветить одновременно), получается около 28 мА на сегмент. Это при напряжении питания часов 11.7 вольт, ещё 0.3 вольта падает на диоде, включенном для защиты от неправильного подключения и чтоб немного снизить напряжение и ток соответственно. Падение на выходных ключах Атмеги около 0.56 вольт. Все токовые режимы превышены, но Атмега справляется, честь и хвала творцам! Запаса яркости избыточно, напряжение питания можно ещё снижать. Если тактировать Атмегу от внутреннего генератора, то можно ножки кварца отдать индикатору, а время считывать по I2C с DS1307. Опять же будут заняты все ноги, но зато питание часов можно будет отключать хоть на неделю, а время продолжит тикать. Хотя точность DS1307 совсем не радует, и по моему опыту, и по отзывам в интернете. Зато на ней есть дополнительный выход с открытым коллектором, которому можно дать команду мигать с частотой 1 Гц, и навесить на него разделительную точку. В моих часах разделительных точек пока нет, можно разрезать ту же ленту на отдельные светодиоды и подключить постоянно к напряжению питания. Мигать не будет, но я думаю над этим. Может, кто подскажет, как выжать ещё каплю из Атмеги?

    И, напоследок, код для тех, кто захочет повторить. Компилировал и прошивал в ArduinoIDE. Я не программер, так что примите как есть, если кто предложит лучше, с удовольствием выложу.

    Особо чувствительным не смотреть
    Я предупреждал
    
    bool Flag;
    uint8_t TimS;
    uint16_t TimH = 12; // время при включении 12-34
    uint16_t TimH_;
    uint16_t TimM = 34;
    uint16_t TimH0;
    uint16_t TimH1;
    uint16_t TimM0;
    uint16_t TimM1;
    uint16_t TimKorr = 7; // коррекия по умолчанию 7 - это 0 секунд, если 0 - это -28 сек, если 14 - это +28 сек
    
    // массив для цифр
    int semisegm_[10] = {B01011111, B00000110, B01101011, B01100111, B00110110, B01110101, B01111101, B00000111, B01111111, B01110111};
    
    void setup() {                                                         //
      PORTB = 0;
      PORTC = 0;
      PORTD = 0;
      // инициализация Timer1
      cli();  // отключить глобальные прерывания
      TCCR1A = 0;   // установить регистр в 0
      TCCR1B = 0;   // установить регистр в 0
      // Таймер переполняeтся каждые 65535 отсчетов при коэффициенте деления 1024 или за 4,194с
      OCR1A = 62499; // установка регистра совпадения (4 секунд)
      TCCR1B |= (1 << WGM12);  // включить CTC режим > сброс таймера по совпадению
      TCCR1B |= (1 << CS10);   // Установить биты CS10 CS12 на коэффициент деления 1024
      TCCR1B |= (1 << CS12);
      TIMSK |= (1 << OCIE1A);  // для ATMEGA8
      sei(); // включить глобальные прерывания
    }   
    
    void loop() {
      if (TimM > 59) {
        TimM = 0;
        TimH++;
        Flag = 0;
      }
      if (TimH > 23)TimH = 0;
      if (TimM < 0) {
        TimM = 59;
      }
      if (TimH == 0) {
        if (TimM == 0) {
          if (TimS == 7) {
            if (Flag == 0) {
              TimS = TimKorr;
              Flag = 1;
            }
          }
        }
      }
      TimH_ = TimH;
      if (TimH > 19)TimH_ = TimH - 12;
      TimH0 = TimH_ / 10;
      TimH1 = TimH_ % 10;
      TimM0 = TimM / 10;
      TimM1 = TimM % 10;
      Led(TimH0, TimH1, TimM0, TimM1);
      Key();
    }
    
    // функция индикации
    void Led(uint16_t TimH0, uint16_t TimH1, uint16_t TimM0, uint16_t TimM1) {
      DDRB = semisegm_[TimM1];
      DDRC = semisegm_[TimM0];
      DDRD = semisegm_[TimH1];
      bitWrite(DDRD, 7, bitRead(semisegm_[TimM1], 6));
      ADMUX = 199 * TimH0; // уровень 2.56 на AREF
      PORTB = 0;
      PORTC = 0;
      PORTD = 0;
      delay(500); // полсекунды просто отображаем время
    }
    
    // функция опроса кнопок
    void Key() {
      bitWrite(PORTB, 2, 1);
      bitWrite(PORTD, 2, 1);
      bitWrite(PORTD, 1, 1);
      bitWrite(PORTD, 0, 1);
      bitWrite(DDRB, 2, 0);
      bitWrite(DDRD, 2, 0);
      bitWrite(DDRD, 1, 0);
      bitWrite(DDRD, 0, 0);
      delayMicroseconds(300); 
      if (bit_is_clear(PINB, 2)) {  
        delay(20);
        if (bit_is_clear(PINB, 2)) {
          TimH++;
        }
      }
      if (bit_is_clear(PIND, 1)) {
        delay(20);
        if (bit_is_clear(PIND, 1)) {
          TimM++;
        }
      }
      if (bit_is_clear(PIND, 0)) {
        delay(20);
        if (bit_is_clear(PIND, 0)) {
          TimM--;
        }
      }
      if (bit_is_clear(PIND, 2)) {
        delay(20);
        if (bit_is_clear(PIND, 2)) {
          TimKorr++;
          if (TimKorr > 14)TimKorr = 0;
          Led(0, 8, TimKorr / 10, TimKorr % 10);
          delay(500);
        }
      }
    }
    
    ISR(TIMER1_COMPA_vect) // Выполняем 1 раз в 4 секунды.
    {
      TimS++;
      if (TimS > 14) {
        TimM++;
        TimS = 0;
      }
    }
    


    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

    Ваше мнение по поводу решений в статье

    • 14,0%Ничего нового, всё это есть в даташитах.12
    • 58,1%Оригинально, но я бы так никогда не сделал.50
    • 17,4%Возможно, воспользуюсь одним из решений.15
    • 1,2%Прям в ближайшее время себе заделаю такие-же.1
    • 9,3%Другой вариант ответа8
    Реклама
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее

    Комментарии 49

      +3
      Я так понимаю, включать надо ровно в 12:34?
        0
        Вы же обычные электронные часы в 0-00 не включаете? Начальные показания любые зашить можно. Установка времени есть.
        +6
        Можно было взять адресную ленту, там одного вывода хватило бы
          0
          Если бы речь шла только о количестве выводов контроллера, я бы взял 3 штуки 74HC595, обошлось бы раз в сто дешевле. Кроме того, адресной ленты 120 шт/м не нахожу даже цену посмотреть.
            0
            а положить две ленты рядом 60 шт/м со сдвигом в шахматном порядке?
            или я не понял, и была цель максимально задействовать все без исключения выводы контроллера?
          +6
          Не понял, какая проблема запустить атмегу с часовым кварцем? Сам чип пусть тактируется от внутреннего генератора, а внешний часовой кварц тактирует таймер 2.
            0
            Прошу прощения за поздний ответ — в тот день почему-то не отправилось, заметил сейчас.

            какая проблема
            возможно, у людей проблема прочитать даташит, узнать требования к ёмкости кварца и токам утечки, и отмыть плату от полу-активного флюса. В результате — генератор может тупо не стартовать. Наблюдал со стороны, как такое происходило с платами на silabs c8051f350 и на STM8L
            +4
            я не понял другое — вы написали, что не любите динамическую индикацию, но у вас все равно есть перерывы (по факту, даже мерцания). Почему же динамическая на частоте 100 кГц не нравится (хотя там как раз никаких мерцаний не увидишь ничем), а статическая с мерцанием — годится?
              +3
              Потому что банальная вкусовщина со стороны автора, логическое обоснование тут искать бессмысленно.
                0
                Если действительно 100 кГц, я не против. Но почему-то не делают. Везде, где я видел, на два-три порядка меньше, если скользнуть взглядом, остаётся шлейф из сегментов. Ну и для динамики при 12 вольтах питания нужно добавить больше десятка деталей.
                  0
                  Но почему-то не делают.

                  Потому что просто так на 100 кГц мосфеты с вывода контроллера не заведутся :) Надо ставить или городить из рассыпухи драйвер, а это усложнение и удорожание :)
                    –1
                    Взять вместо мосфетов интегральный буфер — и дело в шляпе! У меня на частоте 2МГц данные в светодиодную панель бегают!!! (см. мой ЖЖ)
                      +1
                      Вы бы дали конкретную ссылку :)
                        +1
                        Вот.
                        // вообще, я крайне редко отвечаю на комментарии, т.к. больше одного комментария в сутки не могу оставлять. Такой вот идиотизм на быдлохабре творится.

                        А вот ниже еще про светодиоды коммент. Отвечу и на него.
                        Понятно, что, учитывая инерционность нашего зрения, никакого смысла ШИМить светодиоды частотой свыше сотни-другой герц, нет. А на еще более высоких частотах попрут вовсю нелинейные свойства p-n переходов. В общем, светодиод — это вам не вентилятор или мотор! Его можно и нужно ШИМить на низких частотах в сотню герц. А вот мотору уже нужно минимум 30кГц, чтобы не слышно было противного писка.

                        Если бы эти панели были несколько подороже, то не было бы необходимости постоянно обновлять картинку: закинул в 2048×3 ячеек сдвиговых регистров данные, подержал 10мс, потом следующий кадр закинул — и так обновлять по 100 фреймов в секунду. Ничего не мерцало бы. Но т.к. в панелях этих сильно сэкономили на сдвиговых регистрах, приходится по сути в 16 проходов только 1 кадр формировать! Реализовать с таким подходом на панели 32×64 хотя бы по 4 бита цвета в каждый канал будет проблематично, а уж 8 бит на цвет — просто невозможно. С моей RGB-панелью в ходе экспериментов выяснилось, что быстрей 2МГц данные передавать нельзя: начинаются глюки в виде лишних или недостающих пикселей. А на осциллограмме даже на 2МГц жесть, что творится! Понятно, что неплохие шумы вносятся еще из-за того, что мой велосипед распаян на макетке кучей длинных проводочков, но вряд ли даже при грамотной трассировке многослойной печатной платы получится хотя бы до 10МГц догнать скорость передачи данных. Но «тетрис» и «змейка» у меня завелись. Сейчас понемногу по вечерам «арканоид» пилю.
                          +1
                          закинул в 2048×3 ячеек сдвиговых регистров данные, подержал 10мс, потом следующий кадр закинул — и так обновлять по 100 фреймов в секунду.

                          Да и крепеж панели не будет нужен — спокойно будут стоять на проводах питания, по которым в них заливается до 60 ампер для диодов (по 10 мА на каждый цвет каждого диода) :)
                        +1
                        У меня на частоте 2МГц данные в светодиодную панель бегают
                        Данные можно и на большей частоте передавать (я передавал на частоте 8 МГц), а вот светодиодам даже 100 кГц может не понравиться. Надо попробовать.
                  +1
                  К155ИД1 – высоковольтный дешифратор управления газоразрядными индикаторами, где сравнительно низковольтные выходы (до 60 вольт) коммутировали индикаторы с напряжением зажигания 150 вольт и выше.

                  Все немножко хитрее. А именно — общий катодный резистор.
                  Когда хотя-бы один сегмент включен, то напряжение на катоде становится равным напряжению падения на горящей лампе, что значительно снижает напряжение на закрытых транзисторах остальных каналов.
                  Правда там это вынужденная мера, из-за очень большой разницы напряжениий горения тлеющего разряда и его первоначального зажигания. Со светодиодами все значительно проще и ваша схема вполне рабочая.
                    +1
                    Общий анодный резистор, вообще-то. Напряжение на аноде около 150В.
                    60В на погашенных катодах — это -90В относительно анода, что гарантированно меньше напряжения поддержания разряда.
                      0

                      Да, что-то я дал маху...

                      0
                      В газоразрядных индикаторах нет сегментов, которые могут включаться одновременно, кстати.
                      0
                      а как же 8 вечера? ну точнее 20 часов… у вас нет am/pm индикатора и первая цифра жестко 1.
                      не аккуратненько. порой проснулся смотришь на часы и понятия не имеешь это уже 6 вечера и темно или еще 6 утра и не рассвело пока что. зимой в питере с утра идешь на работу — еще темно. выходишь с работы — уже темно. так что я сторонник точного указания времени, без догадок какое время дня сейчас.
                        0
                        Проснувшись в 8 вечера на работе (офисные часы), можно действительно начать работать, не разобравшись. К стрелочным часам никто претензий не предъявляет.
                        Но пару весёлых историй типа «прилёг вздремнуть после работы, проснулся в шесть вечера и прибежал опять на работу» я слышал.
                          0

                          Стрелочные часы бывают и с 24-часовым циферблатом, пусть и сравнительно редко.

                        +1

                        Как разминка для серых клеточек — норм. В продакт — категорически нет.

                          0
                          А вот так — слабо?
                          Вообще, восьмибитки нынче — отмирающий вид. Они очень дороги по сравнению с 32-битными МК, а учитывая крайне скудную периферию, для восьмибиток остается очень узкая область применения. Скажем, использовать 8-ногий 15-рублевый микроконтроллер для генерирования разных импульсов вместо 555. Ну или влажность почвы измерять и мастеру по радиоканалу отправлять данные… В общем, там, где нужно выполнять всего одну задачу, не требующую большой нагрузки.
                          P.S. Светодиодные ленты потребляют достаточно приличный ток. Даже если пускать по 10мА через каждый сегмент, в случае, когда они все загорятся, суммарное потребление портами МК будет значительно превышать предельное значение из документации. В общем, если оно и будет работать какое-то время, то только вопреки здравому смыслу.
                            0
                            использовать 8-ногий 15-рублевый
                            Какой, например? У нас минимум вдвое дороже.
                            там, где нужно выполнять всего одну задачу, не требующую большой нагрузки
                            Как раз тот случай- 16% флеша, хотя можно и меньше. Зачем здесь что-то мощнее?
                              +1
                              Зато их в макетную плату для первичного тестирования вставить можно. И паять паяльником. И панельку использовать. И eeprom даже на очень «дохлых» кристаллах есть. И жрут они меньше.
                              +1
                              Знаете, почему микроконтроллер не помер от подключения к его ноге 12 вольт через сегмент светодиодной ленты? Причина банальная. Если взглянуть на схему, то можно увидеть, что сегмент состоит из трех последовательно включенных светодиодов и токоотграничивающего резистора. Обычно, в распространенных светодиодах падение напряжения на кристалле достигает ± 2,5 вольт. Так как их три, то в сумме получается 7,5 вольт. Итого, из 12 вольт 7,5 падает на светодиодах и ноге остается 4,5 вольта, что как бы в пределах нормы для микроконтроллера AVR. Я даже не учел падение напряжения на резисторе. Если мне память не изменяет, то напряжение пробоя защитного диода на AVRках составляет 6 вольт или около того. Так что тут чистая физика и никакой магии.
                                +1
                                то напряжение пробоя защитного диода на AVRках составляет 6 вольт
                                Напряжение открытия защитных диодов составляет 0,5 В, только их два, и подключены они к обоим шинам питания.
                                Но я бы конечно не рекомендовал делать так, как делает автор. Это очень, очень грязное решение.
                                  0
                                  только их два
                                  На каждой ноге.
                                  Но суть не в этом. Диод открывается, когда есть ток. А ток равен нулю, как я уже писал.
                                    0

                                    Диод открывается не током, а напряжением. Вам просто повезло, что 12 — 5 = 7, и 7< 7.5.

                                      0
                                      Диод открывается не током, а напряжением
                                      Согласен, неправильно выразился.
                                      Вам просто повезло, что 12 — 5 = 7, и 7< 7.5
                                      Повезло- это если б я не знал об этом. А так расчёт, о чём я и написал.
                                    0
                                    А, точно. Они сработают, если напряжение на ноге превысит напряжение питания на полвольта. Я уже и забыл. Спасибо, что напомнили.
                                      0
                                      На самом деле даже не полвольта, а практически от нуля (это можно увидеть на вольтамперной характеристике), но ток при низком напряжении на диоде тоже близок к нулю, я столкнулся с этим на практике много лет назад, экспериментируя с очень малыми токами. В этом легко убедиться, измерив постоянное напряжение простым мультиметром, и затем измерить его же через диод, напряжение покажет то же самое, то есть падение напряжения на диоде около нуля. Так что не стоит особо рассчитывать на полвольта, это только при токах, близких к паспортным для диода.
                                  0

                                  ATMega8? Чувак! AT90S2313 — вот тема была. Или на ATtiny85 запили тоже самое (хотя, это не о часах). Прошивка только на его ассемблере, никаких сишечек! А то у всех ардуины, да атмеги, ещё и STM32 прикрутят...

                                    0

                                    Так то для часов есть специальные микросхемы. Достаточно подключить кварц, индикатор и питание. И пару резисторов-конденсаторов в обвязку. Но это скучно ;)

                                      0
                                      Не знаю такой для светодиодной индикации. Если она и есть (подскажите), то наверняка намного дороже, чем Атмега. Кроме того, Атмега у меня уже есть.
                                        0

                                        Для светодиодов и я не знаю. Для вакуумных — 100500 их. 145ИК1901 за $4 продают, например. Кстати, вакуумные индикаторы красивше :)

                                          0
                                          145ИК1901- мои первые, конструктор, примерно 1987 год. Потом несколько доработок. Вакуумные индикаторы у меня служили мало, года по три, потом повышал напряжение накала, но хватало не надолго. Тогда мне тоже казались красивше, сейчас по=другому смотрю.
                                            0
                                            Тогда мне тоже казались красивше, сейчас по=другому смотрю.

                                            Nixie Clock сейчас модно ;) Вкусовщина, конечно.
                                              0
                                              Тоже давно сделать хочу, индикаторов нет пока. Хотя за модой никогда не гнался.
                                                0

                                                FTGJ, Nixie — газоразрядные (неонки). С накалом — вакуумно-флуоресцентные ("магический глаз" в "теплых ламповых" приёмниках или VFD).

                                        0

                                        Зачем использовать ds1307, когда есть ds3231?

                                          0
                                          Зачем Жигули, если есть Ауди? Цена ds1307+кварц в десять раз меньше, чем ds3231.
                                            0

                                            Для одноразового хобби проекта +- 2$ это ниачом. Разве что сам себе поставил задачу сделать именно из этих палочек ;)

                                          +1
                                          двух миллисекунд, в течение которых индикаторы потушены, оказалось достаточно для мерцания индикации.
                                          Интересный опыт, спасибо что поделились.

                                          Все токовые режимы превышены, но Атмега справляется
                                          Надеюсь, Вы понимаете, что надежность и повторяемость схемы — так себе.
                                            +2
                                            Понравилось использование ноги Aref)
                                              0
                                              Я поражаюсь, скольких людей авторы Arduino сбили с толка своим loop(). Зачем гонять по кругу, если а) внутри контроллера состояние не меняется б) изменение состояния выходов происходит только как результат прерывания?
                                                0
                                                Как раз в данном случае в loop() крутится индикация и опрос кнопок. Но могу подтвердить: действительно некоторые моменты пришлось переучивать после Ардуино, причём оказалось ещё и проще.

                                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                              Самое читаемое