Ничего не зря. Учитывая все выше изложенное, 100 Ом вполне могут подойти. ЕвгенийП немного опередил меня насчет того, что еще немного напряжения откусит транзистор.
Не нашли вы, поищем мы - марку индикатора в студию.
переменная currentDigit не была объявлена добавил uint8_t и поменял цифры местами все заработало что такое виртуальные экраны? хочу знать)
Отлично! Правильно сделал. Работает и хорошо. Сейчас продолжим в сторону таймера таймер.
Виртуальные экраны это вот что такое. Вот представьте ради-часы или автомагнитолу - у этих устройств частенько один и тот ;е экран используется для разных целей. То показывает время, то частоту радиостанции, то настройки громкости и баланса и т.п. в зависимости от нажатия каких-то кнопок. так ведь?
Вот давайте представим себе часы-термометр - устройство, которое показывает время, а по нажатии какой-то кнопки начинает показывать температуру, а через 30 секунд само переключается обратно на время. Представили?
А теперь представьте как бы Вы это программировали.
Если "в лоб", то получается очень геморойно. Допустим, сменилась минута. Надо бы отобразить, но программа должна сначала проверить, а что в данный момент показывается на экране. Если время, то отображаем, а если температура, то ничего не делаем. Или наоборот, температурный датчик получил новую температуру (он может это раз в минуту делать). И что ему делать? Кидаться показывать? Нет! Сначала нужно проверить? что в данный момент должно быть на экране. Если температура, то да - показывать, а если время, то не надо.
Так вот, когда режимов показа много, то программа становится слишком запутанной из-за многочисленных проверок. Обязательно что-нибудь забудешь или где-нибудь запутаешься.
Гораздо проще скзать, что к одному физическому экрану у меня привязано N виртуальных. На каждую функцию свой собственный виртуальный экран. Тогда допустим, часы ничего не проверяют, а тупо выводят время на свой собственный экран всегда. Тоже самое термометр ничего не проверяет, а просто всегда выводит температуру на свой собственный экран. То есть всё упростилось. Всё выглядит так, как будто у них в вправду собственные экраны. Они (часы или термометр) вообще-то понятия не имеют и знать не хотят, что именно сейчас показывается на реальном экране - они выводят свои данные на виртуальный экран и не парятся ни о чём.
Ну и есть функция, которая по каким-то нажатиям кнопок или ещё по каким командам, просто переключает физический экран с одного виртуального на другой.
Вот допустим, Вы посмотрели температуру. Затем экран переключился на время. Но термометр каждую минуту исправно пишет новую температуру на свой виртуальный экранчик, которого никто видит. Затем Вы нажимаете кнопку, физически экран переходит с виртуального экрана часов на виртуальных экран термометра и Вы видите новую, текущую температуру (он же её в виртуальном экране регулярно обновлял). При этом ни часы, ни термометр не знают о том, что Вы переключали физический экран с одного виртуального на другой - они вообще про физический экран ничего не знают - они пишут в свои виртуальные и спят спокойно.
Концепция понятна?
реализуется это гораздо проще и короче, чем объясняется. Виртуальный экран - это просто переменная типа нашей numberToShow - своя для каждой функции. А переключатель - это программа из трёх строк, которая определяет какую из этих "numberToShow" отображать на физическом экране. Вот и вся реализация.
Ну, мы до этого ещё доберёмся если интересно. ЕСйчас давайте про таймер. Сейчас напишу отдельынй пост.
Ничего не зря. Учитывая все выше изложенное, 100 Ом вполне могут подойти. ЕвгенийП немного опередил меня насчет того, что еще немного напряжения откусит транзистор.
Не нашли вы, поищем мы - марку индикатора в студию.
все понял. ну я думаю такая функция мне не нужна, но если придумаю зачем, то идея отличная. 5-6 экранов создать, но это думаю для компьютера в машину или на мотоцикл более полезно. а в данном проекте максимум можно 2 экрана. и то для токового ограничения споттера, тоже режима 3-4. но у меня споттер не очень сильный поэтому его вссегда на максимум использовать буду. и в следствии эта функция тоже отпадает
О таймерах. Я буду говорить о т.н. нормально режиме работы таймера (Normal Mode). Есть и другие режимы.
Это такая штука, которая будучи включённой (их иногда выключают для экономии энергии) постоянно тикает и увеличивает свой счётчик от нуля до максимального значения. Когда счётчик достигает максимального значения, он сбрасывается в ноль и продолжает тикать дальше. И так бесконечно.
В тот момент, когда счётчик сбрасывается в 0, происходит прерывание по переполнению таймера, его можно обработать (что-то сделать программно).
Каково максимальное значение? Для 8-битового таймера это 256, для 16-битового – 65536.
Всего в ATmega328 три таймера. 0-ой, 1-ый и 2-ой. Нулевой и второй – восьмибитовые, первый – 16-тибитовый.
Нулевой таймер в Ардуино занят. На нём сидят millis, delay и прочие вещи, связанные со временем. Так что его лучше не трогать. А то всё это добро сломается.
Что касается остальных двух, они тоже не совсем свободны, но это уже предмет «торга» - что нам нужнее.
Итак, что мы потеряем если начнём крутить какой-то таймер.
Таймер 1: обслуживает ШИМ на пинах 9 и 10.
Таймер 2: обслуживает ШИМ на пинах 3 и 11
Кроме того на таймеры завязана функуция tone.
Наконец, разные библиотеки используют тот или иной таймер, а такая библиотека как TLC5940 умудряется занять их ВСЕ и ничего нам не оставить.
Каким таймером пользоваться нам? Это зависит от того. какие у нас ещё есть библиотеки (надо смотреть чем они пользуются, чтобы с ними не «подраться») и от того ШИМом на каких ногах мы готовы пожертвовать.
В моём примере я буду использовать таймер 1. Если Вам реально нужен таймер 2, то Вам нужно сделать ровно те же самые вещи, только немного с другими названиями. Откроете даташит микросхемы ATmega328 на стр. 141 там всё написано.
Итак, поехали.
Вы уже поняли, что таймер тупо увеличивает свой счётчик от 0 до Максимального значения (для нашего таймера 1 это 65536, т.к. он шестнадцатибитовый), затем генерирует прерывание по переполнению, сбрасывает счётчик в 0 и всё повторяется.
Как часто он тикает?
Тикает таймер через каждые P тактов процессора, где P (prescaler) – делитель частоты. Делитель частоты устанавливается для каждого таймера независимо. Таймер №1, с которым мы работаем, имеет следующие делители частоты: 1 (тикает на каждом тикает процессора), 8, 64, 128, 1024.
Сколько тиков процессора умещается в 10мс? При частоте 16МГц, 16 тиков это микросекунда, стало быть 16000 тиков – 1 миллисекунда. Ну, а 10 мс, очевидно 160000 тиков. Столько мы отсчитать на таймере не можем (переполнимся нахрен), на помощь приходит делитель частоты. Например, возьмём делитель 8. Один тик таймера будет равен восьми тикам процессора. Значит в 10 миллисекундах будет 160 000 / 8 = 20 000 тысяч тиков таймера. Столько мы можем себе позволить.
Алгоритм работы с таймером такой.
1. Настроить режим и делитель частоты.
2. Записать в счётчик таймера число 45536 ( = 65536 – 20000).
Всё, через 20000 тиков таймера (т.е. через 10 миллисекунд) наступит переполнение. Мы должны обработать прерывание, а именно сделать следующее:
1. Переключить нашу цифру
3. Записать Записать в счётчик таймера число 45536 ( = 65536 – 20000).
Всё.
Опять через 20000 тиков таймера (т.е. через 10 миллисекунд) наступит переполнение. Мы должны снова обработать прерывание, а именно снова сделать тоже самое!
При таком подходе у нас цифры будут переключаться каждые 10мс без нашего участия и никак нас не напрягая! Наш loop будет пустым. Мы может там делать что угодно – хоть ставить delay(100500) – таймеру плевать на наши делэи, он будет делать своё дело.
Ну, вот такова теория. Изучите пока, если что непонятно, поройтесь в сети.
Завтра с утра напишу пример, который будет реально работать. Сейчас ардуины под рукой нет, потому не могу написать и проверить.
про таймеры читаю уже 3-й день) до 12 до часу ночи))) вопросы при изучении материала остались только какими командами задавать точку отсчета. и какая команда будет этот тик "нулевой" показывать. и как же это все совместить))) по теории понял, спасибо огромное. буду ждать завтра.
вот еще чего не понял, почему именно 8, 64, 128, 1024. когда мы 160000 можем разделить на 100 допустим. тогда получиться 1600. и когда от точки 1600 будет доходить до "нуля" записываем "1" потом снова до нуля "2" и т.д. до 100 когда будет 100-й цикл то значит пора выполнять команду. или я что-то не понял?
Так, ну смотрите. Берёте последний работающий пример. В нём все оставляете на месте, только очищаете loop() (всё из него выбрасываете).
В начало добавляете всё добро из нынешнего кода по 38 строку.Только заметьте. что строка 4 у Вас там уже есть. Дублировать не надо.
В setup() добавляете строчку «setupTimer2();» как здесь.
Наконец, в данном примере в loop() живёт простейший секундомер. Когда запустите – на экране будут меняться числа раз в секунду.
Надеюсь, Вы понимаете, код секундомера не имеет никакого отношения к показу числа на экране. Всё, что требуется – это присвоить переменной numberToShow значение и это значение и будет показываться. Сам секундомер написан исключительно для примера.
Отпишитесь как заработает / нет. Но, вроде, должно. То, что мы не ошиблись в подсчётах времени, я проверил на осциллографе - точно 10мс.
Если потребуется совет по переделке на три разряда, выложите полный текст работающего скетча на два. Так будет удобнее разговаривать (номера строк там, то, сё). Ну. я думаю, Вы справитесь.
Отпишитесь как заработает / нет. Но, вроде, должно. То, что мы не ошиблись в подсчётах времени, я проверил на осциллографе - точно 10мс.
Если потребуется совет по переделке на три разряда, выложите полный текст работающего скетча на два. Так будет удобнее разговаривать (номера строк там, то, сё). Ну. я думаю, Вы справитесь.
Отпишитесь как заработает / нет. Но, вроде, должно. То, что мы не ошиблись в подсчётах времени, я проверил на осциллографе - точно 10мс.
Если потребуется совет по переделке на три разряда, выложите полный текст работающего скетча на два. Так будет удобнее разговаривать (номера строк там, то, сё). Ну. я думаю, Вы справитесь.
все заработало, но не могу понять как переделать на 3 цифры. добавил 3 знак на пин 12 и добавил его в строку
Тип uint8_t однобайтовый. Максимальное число, которое в него влазит - 256. А раз у Вас три цифры, Вам надо. чтобы влазило до 999. Заменяем тип uint8_t на unsigned
Буквально это значит ЕСЛИ (currentDigit == 0) ТО digitToShow получет значение ( numberToShow / 10) - это количество десятков ИНАЧЕ digitToShow получет значение ( numberToShow % 10) - это количество единиц
Теперь Вам надо сделать чуть сложнее, а именно
ЕСЛИ (currentDigit == 0) ТО digitToShow получет значение ( numberToShow / 100) - это количество сотен
ИНАЧЕ ЕСЛИ (currentDigit == 1) digitToShow получет значение ( numberToShow % 100) / 10 - это количество десятков
ИНАЧЕ digitToShow получет значение ( numberToShow % 10) - это количество единиц
Ну, как-то так и надо написать. например, вместо этой строки такую конструкцию.
означает что к currentDigit надо прибавить 1 и взять остаток от деления на 2. Т.е. он будет принимать значения 0, 1, 0, 1, 0, ... А Вам теперь надо, чтобы он принимал значения 0, 1, 2, 0, 1, 2, 0, ... Т.е. надо брать остаток от деления на 3. Стало быть в этой строке двойку заменяем на тройку.
Кажется, всё. Ну, если чего забыл, потом подправим. Проверьте.
// я считаю, что нулевая цмфра слева (единицы), а первая справа (десятки)
150
// если у Вас по-другому - поменяйте.
151
//
152
voidloop() {
153
154
155
numberToShow = 987;
156
157
}
такой код получился, все работает, я такю же логику делал. но у меня не работало, оказывается протеус кабенился. и все должно было работать. значит я понял суть программы.
единственное что я не правильно делал. в строке uint8_t digitToShow; было const. и у меня ругался компилятор. я не понял почему а теперь разобрался. константа не сожет меняться же.а я ее пытался поменять. понял
Сейчас я тут чуто занят, через пару часов вернусь. Но в принципе суть оптимизации вот в чём.
Вот смотрите, допустим Вы вывели число и оно там минуту показывается не меняясь.
Но при этом каждые 10мс мы исполняем строки 113-115, т.е. делаем кучу операций деления для разделения числа на сотни, десятки и единицы. Нафига столько раз его делить? Нужно делить его один раз при занесении, а потом только показывать готовые разряды.
Через пару часов освобожуь и если не увиже здест Вышего решения, то покажу как это просто и легко сделать.
идея супер, прошу дать мне до завтра подумать. сегодня у меня семейные дела. я подумаю как это сделать . и если придумаю, завтра в обед напишу как реализовал.
думаю надо создать переменную для каждого разряда, и сделать условие, если измениллось число в loop. посмотреть какой разряд сменился и вычеслить его. может так?
В основной программе я бы это число для показаза не присваивал прямо, а вызывал бы функцию "показать число".
Она бы всё разделяла на сотни, единицы и десятки и складывала бы в массив из трёх байтов. Причём складывала бы не сами числа, а уже готовые маски. Это был бы масси масок
А обработчик прерывания тупо показывал бы готовые разряды из массива масок.
Это дало бы дополнительный плюс. Можно было бы при надобности, ничего не меняе, показывать заодно и не только числа, а всякие C, H и прочие символы, т.к. их маски можно было бы прямо складывать в этот массив масок.
В основной программе я бы это число для показаза не присваивал прямо, а вызывал бы функцию "показать число".
Она бы всё разделяла на сотни, единицы и десятки и складывала бы в массив из трёх байтов. Причём складывала бы не сами числа, а уже готовые маски. Это был бы масси масок
А обработчик прерывания тупо показывал бы готовые разряды из массива масок.
Это дало бы дополнительный плюс. Можно было бы при надобности, ничего не меняе, показывать заодно и не только числа, а всякие C, H и прочие символы, т.к. их маски можно было бы прямо складывать в этот массив масок.
что то "сделал проще" я вообще не понимаю)))) можно по подробнее?
Я выставил делитель частоты и потом нужное количество секунд разделил на этот делитель, и от максимального количества "тиков" отнял число которое рассчитал
Ладно, как бы Вы это число не считали, оно посчитано неправильно. Давайте ещё раз разберём, как оно считается.
Исходными данными будет:
Find – частота обновления индикатора в герцах. Эта величина связана с особенностями зрения и равна 50Гц. Если взять меньше, то изображение будет заметно «мерцать». Fcpu – частота процессора в герцах N – количество разрядов индикатора Pre – делитель частоты таймера
Будем искать количество тиков таймера, в течение которых должна светиться цифра.
А потом в программе мы будем зажигать цифру, выжидать рассчитанное колиество тиков, затем включать следующую цифру.
Теперь давайте рассуждать.
Период обновления индикатора, очевидно обратная величина частоты:
Длительность свечения одной цифры, очевидно равна периоду обновления, делённому на количество цифр:
Длительность одного такта процессора, очевидно обратная величина тактовой частоты,
Длительность одного тика таймера, очевидно равна длительности такта процессора, умноженной на делитель частоты:
Наконец, количество тиков таймера, в течение которых должна светиться цифра равно длительности свечения одной цифры, поделённой на длительность одного тика таймера:
Вот и весь расчёт. Если вспомнить 5-6 класс средней школы, то всё вышесказанное можно привести к одной формуле:
Давайте подставим сюда Fcpu = 16 000 000, Find=50, N=3 и Pre=64.
Результат:1 666,(6).
Округлять надо всегда вниз – пусть лучше частота обновления будет чуть больше, чем чуть меньше.
Сейчас займусь собственно скетчем. Делов-то там на копейку, но писать пояснения занимает в разы больше времени, чем собственно делать - так что это может занять время.
Ну, вот, смотрите, у меня нет возможности проверить, так что если где чего ляпнул - отлаживать вместе будем.
Здесь в основной программе, вместо присваивания мы передаём число некой функции, которая сразу же раздирает его на сотни, десятки и единицы и складывает уже готовые маски для показа в массив масок.
Пример сдлеан так: сначала показывается число 666, а через три секунды начинается "велосипед".
Прошу прощения, все выходные был занят ремонтом блока зажигания на катер. и вообще мозги в эту сторону не соображали. поэтому смотрел по возможности.
ЕвгенийП пишет:
Сколько тиков процессора умещается в 10мс? При частоте 16МГц, 16 тиков это микросекунда, стало быть 16000 тиков – 1 миллисекунда. Ну, а 10 мс, очевидно 160000 тиков. Столько мы отсчитать на таймере не можем (переполнимся нахрен), на помощь приходит делитель частоты. Например, возьмём делитель 8. Один тик таймера будет равен восьми тикам процессора. Значит в 10 миллисекундах будет 160 000 / 8 = 20 000 тысяч тиков таймера. Столько мы можем себе позволить.
вот исходя из этого я понял как считать. вы сказали 10мс это 160 000 тиков. значит 50 мс(почему 50? потому что протеус не может быстрее генерировать, и на реальном железе я конечно буду выставлять такую скорость, при которой у меня не будут мерцать цифры) 50мс это 160000х5 = 800 000 и потом разделил на делитель частоты 64, и получил число 12 500. и Записал в счётчик таймера число 53036 ( = 65536 – 12500). но за полную формулу рассчета спасибо)
ЕвгенийП пишет:
Ну, вот, смотрите, у меня нет возможности проверить, так что если где чего ляпнул - отлаживать вместе будем.
Здесь в основной программе, вместо присваивания мы передаём число некой функции, которая сразу же раздирает его на сотни, десятки и единицы и складывает уже готовые маски для показа в массив масок.
Пример сдлеан так: сначала показывается число 666, а через три секунды начинается "велосипед".
все заработало, и 666, и велосипед. все есть. не понимаю правда половину, ну как не понимаю, понимаю какая строчка за что отвечает, а вот за что отвечает div_t и div, и вообще что это такое? я наверно достал такими вопросами. и может у вас есть какой нибудь источник, где можно посмотреть все такие команды, просто нет на сайте ардуины этого)))
вот исходя из этого я понял как считать. вы сказали 10мс это 160 000 тиков. значит 50 мс(почему 50?
Вот здесь "перепутка". Не 50 мс, а 50 герц частота - обновления экрана. Это не из-за протеуса, а из-за физиологии зрения. С такой частотй мерцать не будет, можете смело использовать.
Надеюсь, подробный разбор в посте №135 понятен и больше на эту тему вопросов нет?
d13lider пишет:
а вот за что отвечает div_t и div, и вообще что это такое?
Это вовсе не ардуиновская фишка - это "обще-Сишное", т.е. стнандартная библиотека языка С.
дело в том, что если при операции деления Вам нужен и остаток и частное, то на честном С деление нужно быполнять дважды, т.к. что-то одно обязательно теряется. Функция div закрывает эту пролему, т.к. она выполняет деление один раз и возвращает структуру div_t в которой есть и частное (quot) и остаток (rem). Вот я и пользуюсь ею, чтобы два раза не делить.
вот исходя из этого я понял как считать. вы сказали 10мс это 160 000 тиков. значит 50 мс(почему 50?
Вот здесь "перепутка". Не 50 мс, а 50 герц частота - обновления экрана. Это не из-за протеуса, а из-за физиологии зрения. С такой частотй мерцать не будет, можете смело использовать.
Надеюсь, подробный разбор в посте №135 понятен и больше на эту тему вопросов нет?
это я понял, но говорю протеус не может правильно отобразить индикатор, и если ставишь быстрее скорость обновления, просто пропадает цифра. и все, 50мс я ставил для тестов. что бы видить какие цифры будут отображаться. а на реальном железе будет совсем по другому. и то, что моргать они будут это я понял. но тогда я поставлю частоту обновления выше. ну т.е. как вы и сказали 50гц.
ЕвгенийП пишет:
Это вовсе не ардуиновская фишка - это "обще-Сишное", т.е. стнандартная библиотека языка С.
дело в том, что если при операции деления Вам нужен и остаток и частное, то на честном С деление нужно быполнять дважды, т.к. что-то одно обязательно теряется. Функция div закрывает эту пролему, т.к. она выполняет деление один раз и возвращает структуру div_t в которой есть и частное (quot) и остаток (rem). Вот я и пользуюсь ею, чтобы два раза не делить.
спасибо большое буду глубже изучать. в общем выложу прибор который получился через пару дней, и еще вопрос, по схеме силовой части сможете подсказать? в общем хочу управление нагрузкой 220v сделать через симистор, либо 2 тиристора, что можете посоветовать, нагрузка около 30-35А
спасибо большое буду глубже изучать. в общем выложу прибор который получился через пару дней, и еще вопрос, по схеме силовой части сможете подсказать? в общем хочу управление нагрузкой 220v сделать через симистор, либо 2 тиристора, что можете посоветовать, нагрузка около 30-35А
Подсказать-то могу, но лучше не стоит. Дело в том, что в программированнии я профессионал, а в электронике - любитель-самоучка. Так что такие подсказки - лучше не надо.
Подсказать-то могу, но лучше не стоит. Дело в том, что в программированнии я профессионал, а в электронике - любитель-самоучка. Так что такие подсказки - лучше не надо.
подскажите, в области электроники я смотрю у вас "любитель" получается лучше чем некоторые "проффесионалы"
Подсказать-то могу, но лучше не стоит. Дело в том, что в программированнии я профессионал, а в электронике - любитель-самоучка. Так что такие подсказки - лучше не надо.
подскажите, в области электроники я смотрю у вас "любитель" получается лучше чем некоторые "проффесионалы"
ладно я думаю с этой темой мы разобрались, я наверное свой вопрос перенесу в " Аппаратные вопросы"
Думаю, да. Симисторы на пользовал на таких токах, но вот полевой транзистор IRFZ44N (по даташиту - 49А) в таком же точно корпусе у меня работает и до 42 ампер отлично держит, только радиатор хороший нужен.
Ничего не зря. Учитывая все выше изложенное, 100 Ом вполне могут подойти. ЕвгенийП немного опередил меня насчет того, что еще немного напряжения откусит транзистор.
Не нашли вы, поищем мы - марку индикатора в студию.
Отлично! Правильно сделал. Работает и хорошо. Сейчас продолжим в сторону таймера таймер.
Виртуальные экраны это вот что такое. Вот представьте ради-часы или автомагнитолу - у этих устройств частенько один и тот ;е экран используется для разных целей. То показывает время, то частоту радиостанции, то настройки громкости и баланса и т.п. в зависимости от нажатия каких-то кнопок. так ведь?
Вот давайте представим себе часы-термометр - устройство, которое показывает время, а по нажатии какой-то кнопки начинает показывать температуру, а через 30 секунд само переключается обратно на время. Представили?
А теперь представьте как бы Вы это программировали.
Если "в лоб", то получается очень геморойно. Допустим, сменилась минута. Надо бы отобразить, но программа должна сначала проверить, а что в данный момент показывается на экране. Если время, то отображаем, а если температура, то ничего не делаем. Или наоборот, температурный датчик получил новую температуру (он может это раз в минуту делать). И что ему делать? Кидаться показывать? Нет! Сначала нужно проверить? что в данный момент должно быть на экране. Если температура, то да - показывать, а если время, то не надо.
Так вот, когда режимов показа много, то программа становится слишком запутанной из-за многочисленных проверок. Обязательно что-нибудь забудешь или где-нибудь запутаешься.
Гораздо проще скзать, что к одному физическому экрану у меня привязано N виртуальных. На каждую функцию свой собственный виртуальный экран. Тогда допустим, часы ничего не проверяют, а тупо выводят время на свой собственный экран всегда. Тоже самое термометр ничего не проверяет, а просто всегда выводит температуру на свой собственный экран. То есть всё упростилось. Всё выглядит так, как будто у них в вправду собственные экраны. Они (часы или термометр) вообще-то понятия не имеют и знать не хотят, что именно сейчас показывается на реальном экране - они выводят свои данные на виртуальный экран и не парятся ни о чём.
Ну и есть функция, которая по каким-то нажатиям кнопок или ещё по каким командам, просто переключает физический экран с одного виртуального на другой.
Вот допустим, Вы посмотрели температуру. Затем экран переключился на время. Но термометр каждую минуту исправно пишет новую температуру на свой виртуальный экранчик, которого никто видит. Затем Вы нажимаете кнопку, физически экран переходит с виртуального экрана часов на виртуальных экран термометра и Вы видите новую, текущую температуру (он же её в виртуальном экране регулярно обновлял). При этом ни часы, ни термометр не знают о том, что Вы переключали физический экран с одного виртуального на другой - они вообще про физический экран ничего не знают - они пишут в свои виртуальные и спят спокойно.
Концепция понятна?
реализуется это гораздо проще и короче, чем объясняется. Виртуальный экран - это просто переменная типа нашей numberToShow - своя для каждой функции. А переключатель - это программа из трёх строк, которая определяет какую из этих "numberToShow" отображать на физическом экране. Вот и вся реализация.
Ну, мы до этого ещё доберёмся если интересно. ЕСйчас давайте про таймер. Сейчас напишу отдельынй пост.
Ничего не зря. Учитывая все выше изложенное, 100 Ом вполне могут подойти. ЕвгенийП немного опередил меня насчет того, что еще немного напряжения откусит транзистор.
Не нашли вы, поищем мы - марку индикатора в студию.
KEM-5361AG
Виртуальные экраны
все понял. ну я думаю такая функция мне не нужна, но если придумаю зачем, то идея отличная. 5-6 экранов создать, но это думаю для компьютера в машину или на мотоцикл более полезно. а в данном проекте максимум можно 2 экрана. и то для токового ограничения споттера, тоже режима 3-4. но у меня споттер не очень сильный поэтому его вссегда на максимум использовать буду. и в следствии эта функция тоже отпадает
О таймерах. Я буду говорить о т.н. нормально режиме работы таймера (Normal Mode). Есть и другие режимы.
Это такая штука, которая будучи включённой (их иногда выключают для экономии энергии) постоянно тикает и увеличивает свой счётчик от нуля до максимального значения. Когда счётчик достигает максимального значения, он сбрасывается в ноль и продолжает тикать дальше. И так бесконечно.
В тот момент, когда счётчик сбрасывается в 0, происходит прерывание по переполнению таймера, его можно обработать (что-то сделать программно).
Каково максимальное значение? Для 8-битового таймера это 256, для 16-битового – 65536.
Всего в ATmega328 три таймера. 0-ой, 1-ый и 2-ой. Нулевой и второй – восьмибитовые, первый – 16-тибитовый.
Нулевой таймер в Ардуино занят. На нём сидят millis, delay и прочие вещи, связанные со временем. Так что его лучше не трогать. А то всё это добро сломается.
Что касается остальных двух, они тоже не совсем свободны, но это уже предмет «торга» - что нам нужнее.
Итак, что мы потеряем если начнём крутить какой-то таймер.
Таймер 1: обслуживает ШИМ на пинах 9 и 10.
Таймер 2: обслуживает ШИМ на пинах 3 и 11
Кроме того на таймеры завязана функуция tone.
Наконец, разные библиотеки используют тот или иной таймер, а такая библиотека как TLC5940 умудряется занять их ВСЕ и ничего нам не оставить.
Каким таймером пользоваться нам? Это зависит от того. какие у нас ещё есть библиотеки (надо смотреть чем они пользуются, чтобы с ними не «подраться») и от того ШИМом на каких ногах мы готовы пожертвовать.
В моём примере я буду использовать таймер 1. Если Вам реально нужен таймер 2, то Вам нужно сделать ровно те же самые вещи, только немного с другими названиями. Откроете даташит микросхемы ATmega328 на стр. 141 там всё написано.
Итак, поехали.
Вы уже поняли, что таймер тупо увеличивает свой счётчик от 0 до Максимального значения (для нашего таймера 1 это 65536, т.к. он шестнадцатибитовый), затем генерирует прерывание по переполнению, сбрасывает счётчик в 0 и всё повторяется.
Как часто он тикает?
Тикает таймер через каждые P тактов процессора, где P (prescaler) – делитель частоты. Делитель частоты устанавливается для каждого таймера независимо. Таймер №1, с которым мы работаем, имеет следующие делители частоты: 1 (тикает на каждом тикает процессора), 8, 64, 128, 1024.
Сколько тиков процессора умещается в 10мс? При частоте 16МГц, 16 тиков это микросекунда, стало быть 16000 тиков – 1 миллисекунда. Ну, а 10 мс, очевидно 160000 тиков. Столько мы отсчитать на таймере не можем (переполнимся нахрен), на помощь приходит делитель частоты. Например, возьмём делитель 8. Один тик таймера будет равен восьми тикам процессора. Значит в 10 миллисекундах будет 160 000 / 8 = 20 000 тысяч тиков таймера. Столько мы можем себе позволить.
Алгоритм работы с таймером такой.
1. Настроить режим и делитель частоты.
2. Записать в счётчик таймера число 45536 ( = 65536 – 20000).
Всё, через 20000 тиков таймера (т.е. через 10 миллисекунд) наступит переполнение. Мы должны обработать прерывание, а именно сделать следующее:
1. Переключить нашу цифру
3. Записать Записать в счётчик таймера число 45536 ( = 65536 – 20000).
Всё.
Опять через 20000 тиков таймера (т.е. через 10 миллисекунд) наступит переполнение. Мы должны снова обработать прерывание, а именно снова сделать тоже самое!
При таком подходе у нас цифры будут переключаться каждые 10мс без нашего участия и никак нас не напрягая! Наш loop будет пустым. Мы может там делать что угодно – хоть ставить delay(100500) – таймеру плевать на наши делэи, он будет делать своё дело.
Ну, вот такова теория. Изучите пока, если что непонятно, поройтесь в сети.
Завтра с утра напишу пример, который будет реально работать. Сейчас ардуины под рукой нет, потому не могу написать и проверить.
про таймеры читаю уже 3-й день) до 12 до часу ночи))) вопросы при изучении материала остались только какими командами задавать точку отсчета. и какая команда будет этот тик "нулевой" показывать. и как же это все совместить))) по теории понял, спасибо огромное. буду ждать завтра.
вот еще чего не понял, почему именно 8, 64, 128, 1024. когда мы 160000 можем разделить на 100 допустим. тогда получиться 1600. и когда от точки 1600 будет доходить до "нуля" записываем "1" потом снова до нуля "2" и т.д. до 100 когда будет 100-й цикл то значит пора выполнять команду. или я что-то не понял?
вот еще чего не понял, почему именно 8, 64, 128, 1024.
Делители частоты аппаратно реализованы в микроконтроллере. Уж какие есть. Других нету.
ну т.е. это даже понимать не надо, просто запомнить. понял. видимо когда будем настраивать длеатель частоты пойму больше.
Так, ну смотрите. Берёте последний работающий пример. В нём все оставляете на месте, только очищаете loop() (всё из него выбрасываете).
В начало добавляете всё добро из нынешнего кода по 38 строку.Только заметьте. что строка 4 у Вас там уже есть. Дублировать не надо.
В setup() добавляете строчку «setupTimer2();» как здесь.
Наконец, в данном примере в loop() живёт простейший секундомер. Когда запустите – на экране будут меняться числа раз в секунду.
Надеюсь, Вы понимаете, код секундомера не имеет никакого отношения к показу числа на экране. Всё, что требуется – это присвоить переменной numberToShow значение и это значение и будет показываться. Сам секундомер написан исключительно для примера.
01
#define PRESACLER (1 << CS11) // Соответствует делителю частоты 8
02
#define TICKS ((uint16_t)(65536ul - 20000ul)) // Оставляет 20000 тиков до переполнения
03
04
volatile uint8_t numberToShow = 0;
// число для показа
05
06
//
07
// Инициализация таймера. делается один раз
08
//
09
void
setupTimer2(
void
) {
10
PRR &= ~(1 << PRTIM1);
// Убедимся, что таймер 1 не отключен
11
TCCR1A = 0;
// Установим Normal режим
12
TCCR1B = PRESACLER;
// Установим делитель частоты
13
TCNT1 = TICKS;
// Установим счётчик
14
TIMSK1 |= (1 << TOIE1);
// Разрешим прерывание по переполнению
15
TIFR1 = 1;
// Очистим Очистим флаг прерывания (если он взведён)
16
}
17
18
//
19
// Обработка прерывания по переполнению
20
//
21
ISR(TIMER1_OVF_vect) {
22
TCNT1 = TICKS;
// Установим счётчик для следующего прерывания
23
//
24
// Покажем очередную цифру, как мы это делали раньше
25
//
26
static
uint8_t currentDigit = 0;
27
const
uint8_t digitToShow = (currentDigit) ? numberToShow / 10 : numberToShow % 10;
28
showDigit(digitToShow, currentDigit);
29
currentDigit = (currentDigit + 1) % 2;
// В следующий раз показываем другую цифру
30
}
31
32
//
33
// Всё, что выше - это своя жизнь. От основной программы требуется только
34
// положить число для показа в numberToShow и оно будет показываться.
35
// Больше основная программа ни о чём не заботится
36
//
37
///////////////////////////////////////////////////////////////////////////////////
38
39
void
setup
() {
40
setupTimer2();
41
}
42
43
44
//
45
// Здесь реализован простейший секундомер
46
//
47
void
loop
() {
48
static
int8_t counter = 0;
49
numberToShow = counter;
// теперь это число будет показываться
50
counter = (counter + 1) % 100;
51
delay(1000);
52
}
Разбирайтесь.
Надеюсь, на три цифры Вы теперь и сами сможете переделать.
Разбирайтесь.
Надеюсь, на три цифры Вы теперь и сами сможете переделать.
спасибо большое! будем тестировать, и понимать. вы случайно не преподаете в каком нибудь МГУ?)
В разное время я преподавал в разных местах (и даже странах), в том числе и читал лекции в МГУ. Сейчас - нет.
Отпишитесь как заработает / нет. Но, вроде, должно. То, что мы не ошиблись в подсчётах времени, я проверил на осциллографе - точно 10мс.
Если потребуется совет по переделке на три разряда, выложите полный текст работающего скетча на два. Так будет удобнее разговаривать (номера строк там, то, сё). Ну. я думаю, Вы справитесь.
Отпишитесь как заработает / нет. Но, вроде, должно. То, что мы не ошиблись в подсчётах времени, я проверил на осциллографе - точно 10мс.
Если потребуется совет по переделке на три разряда, выложите полный текст работающего скетча на два. Так будет удобнее разговаривать (номера строк там, то, сё). Ну. я думаю, Вы справитесь.
хорошо, спасибо!
а как сделать делитель частоты 64? какая строка отвечает я понял, там просто написанно 1 << CS11, а что это значит я не понимаю(
просто хочу задать 50мс а для этого надо делитель выставить на 64 а составить тиков 12500
просто хочу задать 50мс а для этого надо делитель выставить на 64 а составить тиков 12500
нашел, разобрался.
1
#define PRESACLER (0<<CS12)|(1<<CS11)|(1<<CS10)
2
#define TICKS ((uint16_t)(65536ul - 12500ul))
но
(0<<CS12)
можно опустить, т.к. в дефолте и так стоит в нуле
Отпишитесь как заработает / нет. Но, вроде, должно. То, что мы не ошиблись в подсчётах времени, я проверил на осциллографе - точно 10мс.
Если потребуется совет по переделке на три разряда, выложите полный текст работающего скетча на два. Так будет удобнее разговаривать (номера строк там, то, сё). Ну. я думаю, Вы справитесь.
все заработало, но не могу понять как переделать на 3 цифры. добавил 3 знак на пин 12 и добавил его в строку
1
void
showDigit(
const
uint8_t d,
const
uint8_t pos) {
2
static
const
uint8_t all_postions[] = { PIN_DIG0, PIN_DIG1, PIN_DIG2 };
весь код который получился
001
//
002
// Определение пинов для сегментов
003
// (поставьте Ваши пины, у меня мелкий экран и плохо видно какие там у Вас)
004
//
005
#define PIN_A 9
006
#define PIN_B 8
007
#define PIN_C 7
008
#define PIN_D 6
009
#define PIN_E 5
010
#define PIN_F 4
011
#define PIN_G 3
012
#define PIN_DP 2
013
014
//
015
//
016
//
017
#define PRESACLER (1<<CS11)|(1<<CS10) // Соответствует делителю частоты 8
018
#define TICKS ((uint16_t)(65536ul - 12500ul)) // Оставляет 20000 тиков до переполнения
019
020
021
022
//
023
// Определение пинов для цифр
024
// (поставьте Ваши пины, у меня мелкий экран и плохо видно какие там у Вас)
025
//
026
#define PIN_DIG0 10
027
#define PIN_DIG1 11
028
#define PIN_DIG2 12
029
030
//
031
// Определение масок для сегментов
032
//
033
#define MASK_A (1 << 0)
034
#define MASK_B (1 << 1)
035
#define MASK_C (1 << 2)
036
#define MASK_D (1 << 3)
037
#define MASK_E (1 << 4)
038
#define MASK_F (1 << 5)
039
#define MASK_G (1 << 6)
040
#define MASK_DP (1 << 7)
041
042
//
043
// Определение цифр через маски сегментов
044
//
045
#define D0 (MASK_A | MASK_B | MASK_C | MASK_D | MASK_E | MASK_F)
046
#define D1 (MASK_B | MASK_C)
047
#define D2 (MASK_A | MASK_B | MASK_G | MASK_D | MASK_E)
048
#define D3 (MASK_A | MASK_B | MASK_C | MASK_D | MASK_G)
049
#define D4 (MASK_B | MASK_C | MASK_G | MASK_F)
050
#define D5 (MASK_A | MASK_C | MASK_D | MASK_F | MASK_G)
051
#define D6 (MASK_A | MASK_C | MASK_D | MASK_E | MASK_F | MASK_G)
052
#define D7 (MASK_A | (MASK_B | MASK_C))
053
#define D8 (MASK_A | MASK_B | MASK_C | MASK_D | MASK_E | MASK_F | MASK_G)
054
#define D9 (MASK_A | MASK_B | MASK_C | MASK_D | MASK_F | MASK_G)
055
056
volatile uint8_t numberToShow = 00;
057
058
//
059
// Функция устанавливает по маске - параметру (HIGH-горит, LOW-не горит)
060
//
061
void
setRawSegments(
const
int8_t mask) {
062
digitalWrite(PIN_A, mask & MASK_A);
063
digitalWrite(PIN_B, mask & MASK_B);
064
digitalWrite(PIN_C, mask & MASK_C);
065
digitalWrite(PIN_D, mask & MASK_D);
066
digitalWrite(PIN_E, mask & MASK_E);
067
digitalWrite(PIN_F, mask & MASK_F);
068
digitalWrite(PIN_G, mask & MASK_G);
069
digitalWrite(PIN_DP, mask & MASK_DP);
070
}
071
072
//
073
// Функция устанавливает все сегменты для цифры-параметра (HIGH-горит, LOW-не горит)
074
//
075
void
setSegments(
const
int8_t digit) {
076
static
const
uint8_t all_digits[] = { D0, D1, D2, D3, D4, D5, D6, D7, D8, D9,};
077
setRawSegments(all_digits[digit]);
078
}
079
080
//
081
// Функция зажигает цифру d в позиции pos
082
// При этом ставит пин соответсвующий позиции pos в LOW
083
//
084
void
showDigit(
const
uint8_t d,
const
uint8_t pos) {
085
static
const
uint8_t all_postions[] = { PIN_DIG0, PIN_DIG1, PIN_DIG2 };
086
for
(register uint8_t i = 0; i <
sizeof
(all_postions) /
sizeof
(all_postions[0]); i++) {
087
digitalWrite(all_postions[i], pos != i);
088
}
089
setSegments(d);
090
}
091
092
//
093
// Инициализация таймера. делается один раз
094
//
095
void
setupTimer2(
void
) {
096
PRR &= ~(1 << PRTIM1);
// Убедимся, что таймер 1 не отключен
097
TCCR1A = 0;
// Установим Normal режим
098
TCCR1B = PRESACLER;
// Установим делитель частоты
099
TCNT1 = TICKS;
// Установим счётчик
100
TIMSK1 |= (1 << TOIE1);
// Разрешим прерывание по переполнению
101
TIFR1 = 1;
// Очистим Очистим флаг прерывания (если он взведён)
102
}
103
//
104
// Обработка прерывания по переполнению
105
//
106
ISR(TIMER1_OVF_vect) {
107
TCNT1 = TICKS;
// Установим счётчик для следующего прерывания
108
//
109
// Покажем очередную цифру, как мы это делали раньше
110
//
111
static
uint8_t currentDigit = 0;
112
const
uint8_t digitToShow = (currentDigit) ? numberToShow % 10 : numberToShow / 10;
113
showDigit(digitToShow, currentDigit);
114
currentDigit = (currentDigit + 1) % 2;
// В следующий раз показываем другую цифру
115
}
116
117
//
118
// Всё, что выше - это своя жизнь. От основной программы требуется только
119
// положить число для показа в numberToShow и оно будет показываться.
120
// Больше основная программа ни о чём не заботится
121
//
122
///////////////////////////////////////////////////////////////////////////////////
123
124
125
void
setup
() {
126
setupTimer2();
127
// ... задайте все pinMode как раньше
128
pinMode(2, OUTPUT);
129
pinMode(3, OUTPUT);
130
pinMode(4, OUTPUT);
131
pinMode(5, OUTPUT);
132
pinMode(6, OUTPUT);
133
pinMode(7, OUTPUT);
134
pinMode(8, OUTPUT);
135
pinMode(9, OUTPUT);
136
pinMode(10, OUTPUT);
137
pinMode(11, OUTPUT);
138
pinMode(12, OUTPUT);
139
pinMode(13, OUTPUT);
140
141
142
}
143
144
//
145
// я считаю, что нулевая цмфра слева (единицы), а первая справа (десятки)
146
// если у Вас по-другому - поменяйте.
147
//
148
void
loop
() {
149
150
static
int8_t counter = 0;
151
static
int8_t storona = 0;
152
// теперь это число будет показываться
153
if
(counter == 1000)
154
{
155
storona =1;
156
}
157
else
if
(counter == 0)
158
{
159
storona = 0;
160
}
161
if
(storona == 0)
162
{
163
counter = counter +1;
164
}
165
else
166
counter = counter -1;
167
168
169
numberToShow = counter;
170
delay (250);
171
}
правда изменил счетчик от 0 до 1000 и потом в обратном направлении
я так понял в этой строчке что то заменить надо. но вот побитывые выражения не понимаю.
1
currentDigit = (currentDigit + 1) % 2;
а как сделать делитель частоты 64? какая строка отвечает я понял, там просто написанно 1 << CS11, а что это значит я не понимаю(
Давайте. я Вм лучше "удочку дам".
Скачайте даташит клонтроллера ATmega328p и на стр. 134 найдёте таблицу всех делителей для таймера 1 (у других другие).
В частности для 64 там указано CS11 и CS10. Записывается это так:
(1 << CS11) | (1 << CS10)
если потребуются другие делители, то по аналогии.
но
(0<<CS12)
можно опустить, т.к. в дефолте и так стоит в нуле
Более того, это вообще бессмысленная записть - она всегда равна 0
я так понял в этой строчке что то заменить надо. но вот побитывые выражения не понимаю.
1
currentDigit = (currentDigit + 1) % 2;
Ну, двойку-то здесь надо на тройку менять - это же остаток от деления.
Но это не всё.
Сейчас посмотрю и отпишусь.
но
(0<<CS12)
можно опустить, т.к. в дефолте и так стоит в нуле
Более того, это вообще бессмысленная записть - она всегда равна 0
ну я тоже самое сказал) дефолт это же "изначальное состояние" т
Итак. меняем на три цифры.
1. Строка 56.
Тип uint8_t однобайтовый. Максимальное число, которое в него влазит - 256. А раз у Вас три цифры, Вам надо. чтобы влазило до 999. Заменяем тип uint8_t на unsigned
2. строка 112.
Это разделение на десятки и 1. Смотрите
digitToShow = (currentDigit) ? numberToShow % 10 : numberToShow / 10;
Буквально это значит ЕСЛИ (currentDigit == 0) ТО digitToShow получет значение ( numberToShow / 10) - это количество десятков
ИНАЧЕ digitToShow получет значение ( numberToShow % 10) - это количество единиц
Теперь Вам надо сделать чуть сложнее, а именно
ЕСЛИ (currentDigit == 0) ТО digitToShow получет значение ( numberToShow / 100) - это количество сотен
ИНАЧЕ ЕСЛИ (currentDigit == 1) digitToShow получет значение ( numberToShow % 100) / 10 - это количество десятков
ИНАЧЕ digitToShow получет значение ( numberToShow % 10) - это количество единиц
Ну, как-то так и надо написать. например, вместо этой строки такую конструкцию.
1
uint8_t digitToShow;
2
if
(currentDigit == 0) digitToShow = numberToShow / 100;
3
else
if
(currentDigit == 1) digitToShow = (numberToShow % 100) / 10;
4
else
digitToShow = numberToShow % 10;
currentDigit = (currentDigit + 1) % 2;
означает что к currentDigit надо прибавить 1 и взять остаток от деления на 2. Т.е. он будет принимать значения 0, 1, 0, 1, 0, ... А Вам теперь надо, чтобы он принимал значения 0, 1, 2, 0, 1, 2, 0, ... Т.е. надо брать остаток от деления на 3. Стало быть в этой строке двойку заменяем на тройку.
Кажется, всё. Ну, если чего забыл, потом подправим. Проверьте.
Проверьте как работает и надо будет финишную полировку сделать: небольшую оптимизацию и возможность показывать другие знаки (не числа).
001
//
002
// Определение пинов для сегментов
003
// (поставьте Ваши пины, у меня мелкий экран и плохо видно какие там у Вас)
004
//
005
#define PIN_A 9
006
#define PIN_B 8
007
#define PIN_C 7
008
#define PIN_D 6
009
#define PIN_E 5
010
#define PIN_F 4
011
#define PIN_G 3
012
#define PIN_DP 2
013
014
//
015
//
016
//
017
#define PRESACLER (1<<CS11)|(1<<CS10) // Соответствует делителю частоты 8
018
#define TICKS ((uint16_t)(65536ul - 12500ul)) // Оставляет 20000 тиков до переполнения
019
020
021
022
//
023
// Определение пинов для цифр
024
// (поставьте Ваши пины, у меня мелкий экран и плохо видно какие там у Вас)
025
//
026
#define PIN_DIG0 10
027
#define PIN_DIG1 11
028
#define PIN_DIG2 12
029
030
//
031
// Определение масок для сегментов
032
//
033
#define MASK_A (1 << 0)
034
#define MASK_B (1 << 1)
035
#define MASK_C (1 << 2)
036
#define MASK_D (1 << 3)
037
#define MASK_E (1 << 4)
038
#define MASK_F (1 << 5)
039
#define MASK_G (1 << 6)
040
#define MASK_DP (1 << 7)
041
042
//
043
// Определение цифр через маски сегментов
044
//
045
#define D0 (MASK_A | MASK_B | MASK_C | MASK_D | MASK_E | MASK_F)
046
#define D1 (MASK_B | MASK_C)
047
#define D2 (MASK_A | MASK_B | MASK_G | MASK_D | MASK_E)
048
#define D3 (MASK_A | MASK_B | MASK_C | MASK_D | MASK_G)
049
#define D4 (MASK_B | MASK_C | MASK_G | MASK_F)
050
#define D5 (MASK_A | MASK_C | MASK_D | MASK_F | MASK_G)
051
#define D6 (MASK_A | MASK_C | MASK_D | MASK_E | MASK_F | MASK_G)
052
#define D7 (MASK_A | (MASK_B | MASK_C))
053
#define D8 (MASK_A | MASK_B | MASK_C | MASK_D | MASK_E | MASK_F | MASK_G)
054
#define D9 (MASK_A | MASK_B | MASK_C | MASK_D | MASK_F | MASK_G)
055
056
volatile unsigned numberToShow = 0;
057
058
//
059
// Функция устанавливает по маске - параметру (HIGH-горит, LOW-не горит)
060
//
061
void
setRawSegments(
const
int8_t mask) {
062
digitalWrite(PIN_A, mask & MASK_A);
063
digitalWrite(PIN_B, mask & MASK_B);
064
digitalWrite(PIN_C, mask & MASK_C);
065
digitalWrite(PIN_D, mask & MASK_D);
066
digitalWrite(PIN_E, mask & MASK_E);
067
digitalWrite(PIN_F, mask & MASK_F);
068
digitalWrite(PIN_G, mask & MASK_G);
069
digitalWrite(PIN_DP, mask & MASK_DP);
070
}
071
072
//
073
// Функция устанавливает все сегменты для цифры-параметра (HIGH-горит, LOW-не горит)
074
//
075
void
setSegments(
const
int8_t digit) {
076
static
const
uint8_t all_digits[] = { D0, D1, D2, D3, D4, D5, D6, D7, D8, D9};
077
setRawSegments(all_digits[digit]);
078
}
079
080
//
081
// Функция зажигает цифру d в позиции pos
082
// При этом ставит пин соответсвующий позиции pos в LOW
083
//
084
void
showDigit(
const
uint8_t d,
const
uint8_t pos) {
085
static
const
uint8_t all_postions[] = { PIN_DIG0, PIN_DIG1, PIN_DIG2 };
086
for
(register uint8_t i = 0; i <
sizeof
(all_postions) /
sizeof
(all_postions[0]); i++) {
087
digitalWrite(all_postions[i], pos != i);
088
}
089
setSegments(d);
090
}
091
092
//
093
// Инициализация таймера. делается один раз
094
//
095
void
setupTimer2(
void
) {
096
PRR &= ~(1 << PRTIM1);
// Убедимся, что таймер 1 не отключен
097
TCCR1A = 0;
// Установим Normal режим
098
TCCR1B = PRESACLER;
// Установим делитель частоты
099
TCNT1 = TICKS;
// Установим счётчик
100
TIMSK1 |= (1 << TOIE1);
// Разрешим прерывание по переполнению
101
TIFR1 = 1;
// Очистим Очистим флаг прерывания (если он взведён)
102
}
103
//
104
// Обработка прерывания по переполнению
105
//
106
ISR(TIMER1_OVF_vect) {
107
TCNT1 = TICKS;
// Установим счётчик для следующего прерывания
108
//
109
// Покажем очередную цифру, как мы это делали раньше
110
//
111
static
uint8_t currentDigit = 0;
112
uint8_t digitToShow ;
113
if
(currentDigit == 0) digitToShow = numberToShow / 100;
114
else
if
(currentDigit == 1) digitToShow = (numberToShow % 100) / 10;
115
else
digitToShow = numberToShow % 10;
116
showDigit(digitToShow, currentDigit);
117
currentDigit = (currentDigit + 1)%3;
// В следующий раз показываем другую цифру
118
119
}
120
121
//
122
// Всё, что выше - это своя жизнь. От основной программы требуется только
123
// положить число для показа в numberToShow и оно будет показываться.
124
// Больше основная программа ни о чём не заботится
125
//
126
///////////////////////////////////////////////////////////////////////////////////
127
128
129
void
setup
() {
130
setupTimer2();
131
// ... задайте все pinMode как раньше
132
pinMode(2, OUTPUT);
133
pinMode(3, OUTPUT);
134
pinMode(4, OUTPUT);
135
pinMode(5, OUTPUT);
136
pinMode(6, OUTPUT);
137
pinMode(7, OUTPUT);
138
pinMode(8, OUTPUT);
139
pinMode(9, OUTPUT);
140
pinMode(10, OUTPUT);
141
pinMode(11, OUTPUT);
142
pinMode(12, OUTPUT);
143
pinMode(13, OUTPUT);
144
145
146
}
147
148
//
149
// я считаю, что нулевая цмфра слева (единицы), а первая справа (десятки)
150
// если у Вас по-другому - поменяйте.
151
//
152
void
loop
() {
153
154
155
numberToShow = 987;
156
157
}
такой код получился, все работает, я такю же логику делал. но у меня не работало, оказывается протеус кабенился. и все должно было работать. значит я понял суть программы.
единственное что я не правильно делал. в строке uint8_t digitToShow; было const. и у меня ругался компилятор. я не понял почему а теперь разобрался. константа не сожет меняться же.а я ее пытался поменять. понял
в общем все работает, как оптимизировать?
Сейчас я тут чуто занят, через пару часов вернусь. Но в принципе суть оптимизации вот в чём.
Вот смотрите, допустим Вы вывели число и оно там минуту показывается не меняясь.
Но при этом каждые 10мс мы исполняем строки 113-115, т.е. делаем кучу операций деления для разделения числа на сотни, десятки и единицы. Нафига столько раз его делить? Нужно делить его один раз при занесении, а потом только показывать готовые разряды.
Через пару часов освобожуь и если не увиже здест Вышего решения, то покажу как это просто и легко сделать.
идея супер, прошу дать мне до завтра подумать. сегодня у меня семейные дела. я подумаю как это сделать . и если придумаю, завтра в обед напишу как реализовал.
Хорошо, тогда не буду подсказывать пока. Удачи!
думаю надо создать переменную для каждого разряда, и сделать условие, если измениллось число в loop. посмотреть какой разряд сменился и вычеслить его. может так?
Ну, я бы проще сделал.
В основной программе я бы это число для показаза не присваивал прямо, а вызывал бы функцию "показать число".
Она бы всё разделяла на сотни, единицы и десятки и складывала бы в массив из трёх байтов. Причём складывала бы не сами числа, а уже готовые маски. Это был бы масси масок
А обработчик прерывания тупо показывал бы готовые разряды из массива масок.
Это дало бы дополнительный плюс. Можно было бы при надобности, ничего не меняе, показывать заодно и не только числа, а всякие C, H и прочие символы, т.к. их маски можно было бы прямо складывать в этот массив масок.
Ну, я бы проще сделал.
В основной программе я бы это число для показаза не присваивал прямо, а вызывал бы функцию "показать число".
Она бы всё разделяла на сотни, единицы и десятки и складывала бы в массив из трёх байтов. Причём складывала бы не сами числа, а уже готовые маски. Это был бы масси масок
А обработчик прерывания тупо показывал бы готовые разряды из массива масок.
Это дало бы дополнительный плюс. Можно было бы при надобности, ничего не меняе, показывать заодно и не только числа, а всякие C, H и прочие символы, т.к. их маски можно было бы прямо складывать в этот массив масок.
что то "сделал проще" я вообще не понимаю)))) можно по подробнее?
Ну, давайте начнём полировку.
для начала.
Отуда Вы взяли число в строке 19. Как Вы его считали? Можете описать?
Я выставил делитель частоты и потом нужное количество секунд разделил на этот делитель, и от максимального количества "тиков" отнял число которое рассчитал
Ладно, как бы Вы это число не считали, оно посчитано неправильно. Давайте ещё раз разберём, как оно считается.
Исходными данными будет:
Find – частота обновления индикатора в герцах. Эта величина связана с особенностями зрения и равна 50Гц. Если взять меньше, то изображение будет заметно «мерцать».
Fcpu – частота процессора в герцах
N – количество разрядов индикатора
Pre – делитель частоты таймера
Будем искать количество тиков таймера, в течение которых должна светиться цифра.
А потом в программе мы будем зажигать цифру, выжидать рассчитанное колиество тиков, затем включать следующую цифру.
Теперь давайте рассуждать.
Вот и весь расчёт. Если вспомнить 5-6 класс средней школы, то всё вышесказанное можно привести к одной формуле:
Давайте подставим сюда Fcpu = 16 000 000, Find=50, N=3 и Pre=64.
Результат:1 666,(6).
Округлять надо всегда вниз – пусть лучше частота обновления будет чуть больше, чем чуть меньше.
Потому, окончательный результат: 1 666.
Сейчас займусь собственно скетчем. Делов-то там на копейку, но писать пояснения занимает в разы больше времени, чем собственно делать - так что это может занять время.
Ну, вот, смотрите, у меня нет возможности проверить, так что если где чего ляпнул - отлаживать вместе будем.
Здесь в основной программе, вместо присваивания мы передаём число некой функции, которая сразу же раздирает его на сотни, десятки и единицы и складывает уже готовые маски для показа в массив масок.
Пример сдлеан так: сначала показывается число 666, а через три секунды начинается "велосипед".
001
//
002
// Определение пинов для сегментов
003
// (поставьте Ваши пины, у меня мелкий экран и плохо видно какие там у Вас)
004
//
005
#define PIN_A 9
006
#define PIN_B 8
007
#define PIN_C 7
008
#define PIN_D 6
009
#define PIN_E 5
010
#define PIN_F 4
011
#define PIN_G 3
012
#define PIN_DP 2
013
014
//
015
//
016
//
017
#define PRESACLER (1<<CS11)|(1<<CS10) // Соответствует делителю частоты 64
018
#define TICKS ((uint16_t)(65536ul - 1666ul)) // Оставляет 1666 тиков до переполнения ( 64*1666/16000 == 6,664 миллисекунды)
019
020
021
//
022
// Определение пинов для цифр
023
// (поставьте Ваши пины, у меня мелкий экран и плохо видно какие там у Вас)
024
//
025
#define PIN_DIG0 10
026
#define PIN_DIG1 11
027
#define PIN_DIG2 12
028
029
//
030
// Определение масок для сегментов
031
//
032
#define MASK_A (1 << 0)
033
#define MASK_B (1 << 1)
034
#define MASK_C (1 << 2)
035
#define MASK_D (1 << 3)
036
#define MASK_E (1 << 4)
037
#define MASK_F (1 << 5)
038
#define MASK_G (1 << 6)
039
#define MASK_DP (1 << 7)
040
041
//
042
// Определение цифр через маски сегментов
043
//
044
#define D0 (MASK_A | MASK_B | MASK_C | MASK_D | MASK_E | MASK_F)
045
#define D1 (MASK_B | MASK_C)
046
#define D2 (MASK_A | MASK_B | MASK_G | MASK_D | MASK_E)
047
#define D3 (MASK_A | MASK_B | MASK_C | MASK_D | MASK_G)
048
#define D4 (MASK_B | MASK_C | MASK_G | MASK_F)
049
#define D5 (MASK_A | MASK_C | MASK_D | MASK_F | MASK_G)
050
#define D6 (MASK_A | MASK_C | MASK_D | MASK_E | MASK_F | MASK_G)
051
#define D7 (MASK_A | (MASK_B | MASK_C))
052
#define D8 (MASK_A | MASK_B | MASK_C | MASK_D | MASK_E | MASK_F | MASK_G)
053
#define D9 (MASK_A | MASK_B | MASK_C | MASK_D | MASK_F | MASK_G)
054
055
#define TOTAL_DIGITS 3
056
057
volatile uint8_t maskArray[TOTAL_DIGITS] = { MASK_G, MASK_G, MASK_G };
058
059
//
060
// Функция складывает готовую маску в массив масок
061
//
062
inline
void
putMask(
const
uint8_t mask,
const
uint8_t pos) {
063
if
(pos < TOTAL_DIGITS) maskArray[pos] = mask;
064
}
065
066
//
067
// Функция разделяет число на сотни, десятки и единицы и складывает в массив масок
068
// сотни в позицию 2
069
// десятки в позицию 1
070
// единицы в позицию 0
071
//
072
void
putNumber(
const
unsigned number) {
073
static
const
uint8_t allDigits[] = { D0, D1, D2, D3, D4, D5, D6, D7, D8, D9 };
074
div_t divRes = div(number, 100);
075
putMask(allDigits[divRes.quot], 2);
076
divRes = div(divRes.rem, 10);
077
putMask(allDigits[divRes.quot], 1);
078
putMask(allDigits[divRes.rem], 0);
079
}
080
081
//
082
// Функция устанавливает по маске - параметру (HIGH-горит, LOW-не горит)
083
//
084
void
setRawSegments(
const
int8_t mask) {
085
digitalWrite(PIN_A, mask & MASK_A);
086
digitalWrite(PIN_B, mask & MASK_B);
087
digitalWrite(PIN_C, mask & MASK_C);
088
digitalWrite(PIN_D, mask & MASK_D);
089
digitalWrite(PIN_E, mask & MASK_E);
090
digitalWrite(PIN_F, mask & MASK_F);
091
digitalWrite(PIN_G, mask & MASK_G);
092
digitalWrite(PIN_DP, mask & MASK_DP);
093
}
094
095
//
096
// Инициализация таймера. делается один раз
097
//
098
void
setupTimer2(
void
) {
099
PRR &= ~(1 << PRTIM1);
// Убедимся, что таймер 1 не отключен
100
TCCR1A = 0;
// Установим Normal режим
101
TCCR1B = PRESACLER;
// Установим делитель частоты
102
TCNT1 = TICKS;
// Установим счётчик
103
TIMSK1 |= (1 << TOIE1);
// Разрешим прерывание по переполнению
104
TIFR1 = 1;
// Очистим Очистим флаг прерывания (если он взведён)
105
}
106
//
107
// Обработка прерывания по переполнению
108
//
109
ISR(TIMER1_OVF_vect) {
110
TCNT1 = TICKS;
// Установим счётчик для следующего прерывания
111
//
112
// Покажем очередную цифру, как мы это делали раньше
113
//
114
static
uint8_t currentDigit = 0;
115
static
const
uint8_t all_postions[] = { PIN_DIG0, PIN_DIG1, PIN_DIG2 };
116
for
(register uint8_t i = 0; i < TOTAL_DIGITS; i++) {
117
digitalWrite(all_postions[i], currentDigit != i);
118
}
119
setRawSegments(maskArray[currentDigit]);
120
currentDigit = (currentDigit + 1) % TOTAL_DIGITS;
// В следующий раз показываем другую цифру
121
}
122
123
//
124
// Всё, что выше - это своя жизнь. От основной программы требуется только
125
// положить число для показа в numberToShow и оно будет показываться.
126
// Больше основная программа ни о чём не заботится
127
//
128
///////////////////////////////////////////////////////////////////////////////////
129
130
131
void
setup
() {
132
setupTimer2();
133
// ... задайте все pinMode как раньше
134
pinMode(2, OUTPUT);
135
pinMode(3, OUTPUT);
136
pinMode(4, OUTPUT);
137
pinMode(5, OUTPUT);
138
pinMode(6, OUTPUT);
139
pinMode(7, OUTPUT);
140
pinMode(8, OUTPUT);
141
pinMode(9, OUTPUT);
142
pinMode(10, OUTPUT);
143
pinMode(11, OUTPUT);
144
pinMode(12, OUTPUT);
145
pinMode(13, OUTPUT);
146
putNumber(666);
147
delay(2000);
148
putMask(MASK_G, 1);
// это нужно для велосипеда - рисует центральную ось
149
}
150
151
//
152
// велосипед
153
//
154
void
loop
() {
155
static
unsigned
long
millis0 = millis() - 120;
156
unsigned
long
curMillis = millis();
157
static
uint8_t maskIndex = 0;
158
const
static
uint16_t masks [] = { MASK_A, MASK_G, MASK_D };
159
if
(curMillis - millis0 >= 120) {
160
millis0 = curMillis;
161
putMask(masks[maskIndex], 0);
162
putMask(masks[2 - maskIndex], 2);
163
maskIndex = (maskIndex + 1) % (
sizeof
(masks) /
sizeof
(masks[0]));
164
}
165
}
Прошу прощения, все выходные был занят ремонтом блока зажигания на катер. и вообще мозги в эту сторону не соображали. поэтому смотрел по возможности.
Сколько тиков процессора умещается в 10мс? При частоте 16МГц, 16 тиков это микросекунда, стало быть 16000 тиков – 1 миллисекунда. Ну, а 10 мс, очевидно 160000 тиков. Столько мы отсчитать на таймере не можем (переполнимся нахрен), на помощь приходит делитель частоты. Например, возьмём делитель 8. Один тик таймера будет равен восьми тикам процессора. Значит в 10 миллисекундах будет 160 000 / 8 = 20 000 тысяч тиков таймера. Столько мы можем себе позволить.
вот исходя из этого я понял как считать. вы сказали 10мс это 160 000 тиков. значит 50 мс(почему 50? потому что протеус не может быстрее генерировать, и на реальном железе я конечно буду выставлять такую скорость, при которой у меня не будут мерцать цифры) 50мс это 160000х5 = 800 000 и потом разделил на делитель частоты 64, и получил число 12 500. и Записал в счётчик таймера число 53036 ( = 65536 – 12500). но за полную формулу рассчета спасибо)
Ну, вот, смотрите, у меня нет возможности проверить, так что если где чего ляпнул - отлаживать вместе будем.
Здесь в основной программе, вместо присваивания мы передаём число некой функции, которая сразу же раздирает его на сотни, десятки и единицы и складывает уже готовые маски для показа в массив масок.
Пример сдлеан так: сначала показывается число 666, а через три секунды начинается "велосипед".
все заработало, и 666, и велосипед. все есть. не понимаю правда половину, ну как не понимаю, понимаю какая строчка за что отвечает, а вот за что отвечает div_t и div, и вообще что это такое? я наверно достал такими вопросами. и может у вас есть какой нибудь источник, где можно посмотреть все такие команды, просто нет на сайте ардуины этого)))
P.s.
изменил строки, т.к. рисовал цифры не правильно, допустим число 254 рисовал как 452
072
void
putNumber(
const
unsigned number) {
073
static
const
uint8_t allDigits[] = { D0, D1, D2, D3, D4, D5, D6, D7, D8, D9 };
074
div_t divRes = div(number, 100);
075
putMask(allDigits[divRes.quot], 2);
076
divRes = div(divRes.rem, 10);
077
putMask(allDigits[divRes.quot], 1);
078
putMask(allDigits[divRes.rem], 0);
079
}
изменил на
072
void
putNumber(
const
unsigned number) {
073
static
const
uint8_t allDigits[] = { D0, D1, D2, D3, D4, D5, D6, D7, D8, D9 };
074
div_t divRes = div(number, 100);
075
putMask(allDigits[divRes.quot], 0);
076
divRes = div(divRes.rem, 10);
077
putMask(allDigits[divRes.quot], 1);
078
putMask(allDigits[divRes.rem], 2);
079
}
вот исходя из этого я понял как считать. вы сказали 10мс это 160 000 тиков. значит 50 мс(почему 50?
Вот здесь "перепутка". Не 50 мс, а 50 герц частота - обновления экрана. Это не из-за протеуса, а из-за физиологии зрения. С такой частотй мерцать не будет, можете смело использовать.
Надеюсь, подробный разбор в посте №135 понятен и больше на эту тему вопросов нет?
Это вовсе не ардуиновская фишка - это "обще-Сишное", т.е. стнандартная библиотека языка С.
дело в том, что если при операции деления Вам нужен и остаток и частное, то на честном С деление нужно быполнять дважды, т.к. что-то одно обязательно теряется. Функция div закрывает эту пролему, т.к. она выполняет деление один раз и возвращает структуру div_t в которой есть и частное (quot) и остаток (rem). Вот я и пользуюсь ею, чтобы два раза не делить.
А полный список функций, которые есть в данной версии С-шной библиотеки можно посмотреть на сайте Atmel. В частности, вот про функцию div, а вот про структуру div_t.
Ну, отлично, так и надо.
вот исходя из этого я понял как считать. вы сказали 10мс это 160 000 тиков. значит 50 мс(почему 50?
Вот здесь "перепутка". Не 50 мс, а 50 герц частота - обновления экрана. Это не из-за протеуса, а из-за физиологии зрения. С такой частотй мерцать не будет, можете смело использовать.
Надеюсь, подробный разбор в посте №135 понятен и больше на эту тему вопросов нет?
это я понял, но говорю протеус не может правильно отобразить индикатор, и если ставишь быстрее скорость обновления, просто пропадает цифра. и все, 50мс я ставил для тестов. что бы видить какие цифры будут отображаться. а на реальном железе будет совсем по другому. и то, что моргать они будут это я понял. но тогда я поставлю частоту обновления выше. ну т.е. как вы и сказали 50гц.
Это вовсе не ардуиновская фишка - это "обще-Сишное", т.е. стнандартная библиотека языка С.
дело в том, что если при операции деления Вам нужен и остаток и частное, то на честном С деление нужно быполнять дважды, т.к. что-то одно обязательно теряется. Функция div закрывает эту пролему, т.к. она выполняет деление один раз и возвращает структуру div_t в которой есть и частное (quot) и остаток (rem). Вот я и пользуюсь ею, чтобы два раза не делить.
А полный список функций, которые есть в данной версии С-шной библиотеки можно посмотреть на сайте Atmel. В частности, вот про функцию div, а вот про структуру div_t.
спасибо большое буду глубже изучать. в общем выложу прибор который получился через пару дней, и еще вопрос, по схеме силовой части сможете подсказать? в общем хочу управление нагрузкой 220v сделать через симистор, либо 2 тиристора, что можете посоветовать, нагрузка около 30-35А
Подсказать-то могу, но лучше не стоит. Дело в том, что в программированнии я профессионал, а в электронике - любитель-самоучка. Так что такие подсказки - лучше не надо.
Подсказать-то могу, но лучше не стоит. Дело в том, что в программированнии я профессионал, а в электронике - любитель-самоучка. Так что такие подсказки - лучше не надо.
подскажите, в области электроники я смотрю у вас "любитель" получается лучше чем некоторые "проффесионалы"
Подсказать-то могу, но лучше не стоит. Дело в том, что в программированнии я профессионал, а в электронике - любитель-самоучка. Так что такие подсказки - лучше не надо.
подскажите, в области электроники я смотрю у вас "любитель" получается лучше чем некоторые "проффесионалы"
ладно я думаю с этой темой мы разобрались, я наверное свой вопрос перенесу в " Аппаратные вопросы"
подскажите, в области электроники я смотрю у вас "любитель" получается лучше чем некоторые "проффесионалы"
Я бы сделал вот так, только с учётом замечания коллеги в посте №18 там же.
одного такого симистора я не найду. а возможно запаралелить их? или это уже 2 обвязки для каждого симистора делать?
Почему не найдёте? На 30-35А? Ну, вот, например - http://www.chipdip.ru/product/bta41-700b/
Они доставляют в Евросеть - очень быстро.
Почему не найдёте? На 30-35А? Ну, вот, например - http://www.chipdip.ru/product/bta41-700b/
Они доставляют в Евросеть - очень быстро.
я просто не уверен что там ток 30-35А. а если 50? что бы запасик был) по рассчетам 30-35А
и они реально на таких тонких ножках смогут секунд 5-6 держать 40А?
Думаю, да. Симисторы на пользовал на таких токах, но вот полевой транзистор IRFZ44N (по даташиту - 49А) в таком же точно корпусе у меня работает и до 42 ампер отлично держит, только радиатор хороший нужен.