Правда, тут есть небольшой минус, связанный с вашей хотелкой увязать управление на один порт и за одну команду записывать нужную комбинацию. Впрочем, у вас и так это не очень получится, учитывая не желательность использования пинов с rx и tx.
Также, учитывая, что у вас Nano, не рассчитывайте на пины A6 и A7 - они работают только на вход.
Правда, тут есть небольшой минус, связанный с вашей хотелкой увязать управление на один порт и за одну команду записывать нужную комбинацию. Впрочем, у вас и так это не очень получится, учитывая не желательность использования пинов с rx и tx.
Также, учитывая, что у вас Nano, не рассчитывайте на пины A6 и A7 - они работают только на вход.
Rx-tx у меня не будут использоваться, а0-а7 и так только как входы используются
:) не говорите гоп... вы все-таки видимо не до конца все поняли
Я все это упомянул только потому, что при разводке платы (особенно односторонней) часто бывает намного проще протянуть дорожку к другому (совсем рядом расположенному) пину, чем пытаться тянуть ее в обход, между выводов, с перемычками и прочими радостями к тому, который мы назначили в программе. Вот тогда нам пригодится и #define, и пины А0, А1, А2...
:) не говорите гоп... вы все-таки видимо не до конца все поняли
Я все это упомянул только потому, что при разводке платы (особенно односторонней) часто бывает намного проще протянуть дорожку к другому (совсем рядом расположенному) пину, чем пытаться тянуть ее в обход, между выводов, с перемычками и прочими радостями к тому, который мы назначили в программе. Вот тогда нам пригодится и #define, и пины А0, А1, А2...
ну нет))) в define я полюбому буду пины пихать. но аналоговые входы как выходы точно использовать не буду. разводка платы не составляет большого труда. тем более особых, запутывающих схему, элементов там не будет.
вот почему? потому что надо как-то объявить пины выходом? если да то как их группой объявить?
Про группы, давайте вернёмся, кргда всё заработает. Несложно, но вот когда всё будет работать - сделаем группами.
d13lider пишет:
и переделал схему, на эмитор подал плюс вместо минуса. все заработало, загорелась одна цифра
Как хотите, можно и так. Я бы переделал программу, а не схему. Смотрите в чём разница.
Сейчас для того, чтобы зажечь цифру, Вам надо подать на пин базы тразнизстора LOW. А чтобы погасить - HIGH При включении МК (пока Ваша программа не успела туда ничего подать) там быдет LOW, и и цифра может мигнуть/дёрнуться.
А если Вы сделаете, как было раньше, то чтобы зажечь, подавать надо HIGH, а погасить - LOW. Поэспериментируйте и определитесь как Вы будете делать.
Как только убедитесь, что Вы можете уверено зажечь и погасить нужную цифру, перейдём с ледующему шагу - универсальной функции для любой цифры.
я могу уже погасить и зажеч любую цифру. на примере сделал цифру "56" скетч но с delay(30) что бы протеус мог выдавать мерцаниями эти цифры. если сделать 10, он уже не справляется(((
А вот на счет аналоговых пинов, я бы не был так категоричен. Не бойтесь их, они не кусаются )))
Совсем недавно почти закончил проект, в котором тоже используется семисегментник - суточный таймер. Там тоже элементов раз-два и обчелся. От вашей схемы отличается только наличием +2 транзисторов (сборка на 4 цифры) и RTC. И знаете что? Несмотря на то, что я разводил двустороннюю плату, а А0-А2 все-равно использовал на управление индикатором. А все потому, что так было удобней.
А вот на счет аналоговых пинов, я бы не был так категоричен. Не бойтесь их, они не кусаются )))
Совсем недавно почти закончил проект, в котором тоже используется семисегментник - суточный таймер. Там тоже элементов раз-два и обчелся. От вашей схемы отличается только наличием +2 транзисторов (сборка на 4 цифры) и RTC. И знаете что? Несмотря на то, что я разводил двустороннюю плату, а А0-А2 все-равно использовал на управление индикатором. А все потому, что так было удобней.
не хочу их трогать не потому что боюсь. а потому что в будущем планирую еще кнопки присабачить. для других функций. допустим когда определюсь какой импульс нужен будет. могу их на кнопки вывести и уже нажав на кнопку будет пару сохраненных длительностей импульса.
не хочу их трогать ... потому что в будущем планирую еще кнопки присабачить
Не совсем разумно тратить по одному пину на каждую кнопку. Почитайте, например, вот эту тему. Там, среди прочего, есть и как подцепить несколько кнопок к всего-лишь одному аналоговому пину.
не хочу их трогать ... потому что в будущем планирую еще кнопки присабачить
Не совсем разумно тратить по одному пину на каждую кнопку. Почитайте, например, вот эту тему. Там, среди прочего, есть и как подцепить несколько кнопок к всего-лишь одному аналоговому пину.
не читая, логически подумать через резисторы?))) идея)))
Так, ну, всё-таки, Вы уверенно зажигаете и гасите любую цифру и готовы идти дальше?
Попробуйте запустить вот это скетч. Только учтите следующее
1. У меня сейчас нет возможности проверить, так что проверьте сами особенно определени цифр из сегментов, я мог где-то ошибиться.
2. Проставьте свои намера пинов, я поставил просто подряд.
3. Допишите в setup все необходимые pinMode
4. По идее этот скетч должен показывать цифры от 0 до 9 сменяя их каждые полсекунды, причём чётне показыватся в позиции цифры DIG0, а нечетные в позиции DIG1.
5. Убедитесь что всё понятно или задавайте вопросы.
ЕвгенийПчто то молчит((( ну ладно может дела у человека, еще и бездарей таких учить))) но учитель он отличный))) пропадая - дает время подумать, все осмыслить)))
не читая, логически подумать через резисторы?))) идея)))
Это очень просто если не нужно отлавдивать одновременное нажатие нескольких кнопок. Если нужно - там очеь тонко надо подбирать резисторы и и думать над схемой.
ЕвгенийПчто то молчит((( ну ладно может дела у человека, еще и бездарей таких учить))) но учитель он отличный))) пропадая - дает время подумать, все осмыслить)))
Кстати, не знаю как там симулирует протеус, если вдруг закобенится, поставьте явные HIGH/LOW во все digitalWrite. Для этого в строкак 53-60 надо сделать такую замену
Функция - это кусочек программы. который можно вызывать много раз из разных место для выполнения одних и тех же действий.
При описании функции в простейшем случае указывается тип возвращаемого значения (или void - ели возвращать ничего не нужно, имя функции и её параметры.
Давйте на маленьких примерах:
1. функция сладывает два числа (это её параметры) и возвращает результат:
// Функция принимает два параметра a и b типа const int
03
// Возвращает их сумму
04
//
05
intsum2(constinta, constintb) {
06
returna + b; // слово return означает "вернуть значение"
07
}
08
09
voidsetup() {
10
Serial.begin(115200);
11
intd = 13;
12
intc = 23;
13
Serial.println(sum2(1,2)); // должно напечататься 3
14
Serial.println(sum2(d,15)); // должно напечататься 28
15
Serial.println(sum2(d,c)); // должно напечататься 36
16
}
17
18
voidloop() {}
Теперь пример функции, которая ничего не возвращает. Тогда тип функции нужно указывать как void. Данные функции получают два параметра - первый пин и последний пин. Что они делают, написано в комментариях.
// Функция принимает два параметра startPin и endPin типа const int
13
// Устанавливает HIGH для всех пинов со startPin по endPin включительно
14
//
15
voidhighAll(constintstartPin, constintendPin) {
16
for(inti = startPin; i <= endPin; i++) {
17
digitalWrite(i, HIGH);
18
}
19
}
20
21
voidsetup() {
22
modeOutputAll(3, 10); // Поставим пины с 3 по 10 в OUTPUT
23
highAll(5, 7); // Выведем HIGH на пины 5, 6 и 7
24
}
25
26
voidloop() {}
Слово const в описании типа параметра означает. что я не собираюсь его менять. Это подсказка компилятору, чтобы ему легче было оптимизировать код. В принципе его можно опустить.
Стао понятнее? Нес стесняйтесь спрашивать. Прежде, чем мы пойдём дальше, надо снять все вопросы.
я так понял мы уже занимаемся на уровне "С" языка)))) и грубо говоря чуть ли не логику построение программы на уровне "понимания" процессором составляем 0100010101000100010101010011010010101010001010101001010010101010100101001010010, всмысле компелятору почти трудиться не придется)))
еще почитал про "&" "побитовое И" но не понял для чего он нужен. ну как не понял( догадки есть) как я думаю это что бы сложить 2 числа
допустим имея 10010011 и 11010110 получаем 10010010? это вы делаете я так понял для того что бы задать HIGH или LOW? грубо говоря
Ддя начала при побитовой операции & в результате единицами будут только те биты, которые были единицами в ОБОИХ операндах.
Далее, заметьте, что все наши маски сегментов (строки 24-31) содержат ровно по одному единичному биту. В каждой из восьми масок один бит 1. а все остальные 0.
Теперь давайте посмотрим на функцию setRawSegments(const int8_t mask). Её параметр mask - маска готовой цифры (т.е. в её параметре столько удиничных битов, сколько сенментов должно светиться). Внутри функции мы для каждого сегмента выполнеям & маски этого сегмента с параметром mask. Резальтатом этой операции & будет 0, если в mask этот сегмент отсутсвует (нулевой - его зажилать не надо) и НЕ_НОЛЬ если в mask бит этого сегмента единичный. 0 - соответсвет LOW, а любой не 0 - соответствует HIGH.
Например, я хочу нарисовать на индикаторе латинскую букву C - это сегменты a, d, e и f. Вот так я это делаю:
Ну, это простая строка. У функции showDigit два параметра - первый число, которое нужно показать. Второй - позиция в которой его нужно показывать.
Показываем мы наш счётчик cnt.
Позицию мы вычисляет побитовой операцией & - т.е. мы выделяем самый младший бит счётчика. Если младший бит равен нулю (cnt чётное), то "cnt & 1" - будет равно 0. Если младший бит cnt равен 1 (т.е. cnt - нечётное), то "cnt & 1" - будет равно 1.
Кстати, коль уж пошла такая пьянка, в следующей строке используется операция "отстаок от деления".
Т.е. мы прибавляем 1 к счётчику и берём остаток от деления результата на 10. Таки образома счётчки будет расти от 0 до 9. ПОтом снова станет 0 (т.к. отстаок от деления (9+1) на 10 равен нулю) и снова будет расти до 9, потом снова станет 0 и так до посинения.
Ну, это простая строка. У функции showDigit два параметра - первый число, которое нужно показать. Второй - позиция в которой его нужно показывать.
Показываем мы наш счётчик cnt.
Позицию мы вычисляет побитовой операцией & - т.е. мы выделяем самый младший бит счётчика. Если младший бит равен нулю (cnt чётное), то "cnt & 1" - будет равно 0. Если младший бит cnt равен 1 (т.е. cnt - нечётное), то "cnt & 1" - будет равно 1.
Кстати, коль уж пошла такая пьянка, в следующей строке используется операция "отстаок от деления".
Т.е. мы прибавляем 1 к счётчику и берём остаток от деления результата на 10. Таки образома счётчки будет расти от 0 до 9. ПОтом снова станет 0 (т.к. отстаок от деления (9+1) на 10 равен нулю) и снова будет расти до 9, потом снова станет 0 и так до посинения.
ничего бы не изменилось абсолютно. У чётных чисел остаток от деления на 2 равен нулю, а у нечётных - 1.
спасибо, я так и думал, но были сомнения, вы их развеяли. еще не попробовал нарисовать. т.е. я понял что бы нарисовать H ее надо определить в маску т.е. дописать
я так понял мы делаем это все для того что бы программа была как можно меньше, а следовательно что бы стабильнее работала? ведь можно было ее написать визуально проще используя только if и else if, но тогда она будет большая и время прохождения всех if будет тормозить весь процесс.
спасибо, я так и думал, но были сомнения, вы их развеяли. еще не попробовал нарисовать. т.е. я понял что бы нарисовать H ее надо определить в маску т.е. дописать
и программа будет уже выдавать 0-1-2-3-4-5-6-7-8-9-H
Не совсем. Первая из Ваших строк нужна, а вот во второй ничего менять не нужно, т.к. функция в которой эта строка живёт всё равно предназначена только для цифр.
Вы можете сделать так. В define опредеоить все символы, каке Вам хочется, например (я скопировал пример из своего проекта, а там у меня названия не типа MASK_A как я Вам написал, а типа A_MASK - переделайте уж сами):
я так понял мы делаем это все для того что бы программа была как можно меньше, а следовательно что бы стабильнее работала? ведь можно было ее написать визуально проще используя только if и else if, но тогда она будет большая и время прохождения всех if будет тормозить весь процесс.
Мы это делаем, чтобы отделить показ от собственно программы. Программа у нас будет просто записывать нужное для показа число в нужное место и совершенно не париться о показе. Показом будет заниматься программа обработки переполнения таймера сама по себе. Т.е. дело программы просто в нужное место положить число, а показ - он должен своей жизнью жить.
еще можно записать так, но так больше код. и почему то не могу понять, когда выскакивает последняя буква "H" и переходит все к "0" то ноль загорается на том же разряде(цифре) что и "H"
почему то не могу понять, когда выскакивает последняя буква "H" и переходит все к "0" то ноль загорается на том же разряде(цифре) что и "H"
Это правильно. 9 - нечётное число - показывается в 1 разряде. Н (типа 10) - чётное и показывается в нулевом разряде. 0 - тоже чётное и потому показывается тоже в нулевом разряде.
Это правильно. 9 - нечётное число - показывается в 1 разряде. Н (типа 10) - чётное и показывается в нулевом разряде. 0 - тоже чётное и потому показывается тоже в нулевом разряде.
все понял кроме последнего поста, на счет перебора цифр. понял что буквы лучше отдельно создать, так визуально лучше выглядит
Поехали дальше.
Теперь попробуем показать нормальное двузначное число.
Для начала заведём переменную для этого числа - пусть она будет, скажем однобайтовой беззнаковой, т.е. uint8_t (если знак нужен, то можно просто int8_t, но пока будем показывать без знака.
Мы пока не будем париться с таймером, это у нас следующий шаг, но давайте сразу объявим эту переменную волатильной (это означает, что она может быть неожиданно для основной программы изменена. Сейчас нам это не надо, но когда будем переходить на таймер - пригодится.
В эту переменную положим число для показа. Пока просто положим и не будем никогда менять - дай Бог нам его так показать.
Как известно, в любой конкретный момент времени мы можем показывать только одну цифру, а не две вместе. Для того, чтобы человеку казалось, что все цмфры горят одновременно, они должны загораться по очереди так, чтобы полный цикл (все цифры посветились) происходил не реже, чем 50 раз в секунду. Т.е. полный цикл (все цифры посветились) должен длиться не более, чем 1000/50 = 20 миллисекунд. Это называется "динамическая индикация".
Давайте посчитаем длительность свечения одной цифры. В общем случае, если у нас N цифр, а длительность полного цикла 20мс, длительность свечения одно цифры равна 20/N мс. В нашем случае N=2 и длительность свечения одной цифры получается 10мс.
Т.е. нам надо.
1. Установим ТЕКУЩАЯ_ЦИФРА = 0
2. Зажечь цифру в позиции ТЕКУЩАЯ_ЦИФРА 3. Выждатть 10мс
4. Погасить цифру в позиции ТЕКУЩАЯ_ЦИФРА
5. Установить ТЕКУЩАЯ_ЦИФРА = (ТЕКУЩАЯ_ЦИФРА + 1) % КОЛЧИЧЕСТВО_ЦИФР
(у нас КОЛЧИЧЕСТВО_ЦИФР == 2) (при этом после нулевой идёт 1, а потом снова 0 и т.д.)
6. перейти к шагу 2
Если мы будем работать по такому алгоритму, то у нас получится, что цифры по очереди горят по 10мс, а на глаз это будет как будто бы они обе горят постоянно.
Кстати, точно также делается для 3, 4, 5, 6 цифр, только задержка будет уже не 10мс, а 6, 5, 3 и 3 соответсвенно.
Давайте попробуем изобразить это в виде скетча. Я не буду усложнять всё миилисами и отказом от делэя, чтобы не усложнять и не запудривать мозги - всё равно будем на таймер переходить. так что делаем в лоб с делэями.
Теперь попробуем показать нормальное двузначное число.
Для начала заведём переменную для этого числа - пусть она будет, скажем однобайтовой беззнаковой, т.е. uint8_t (если знак нужен, то можно просто int8_t, но пока будем показывать без знака.
Мы пока не будем париться с таймером, это у нас следующий шаг, но давайте сразу объявим эту переменную волатильной (это означает, что она может быть неожиданно для основной программы изменена. Сейчас нам это не надо, но когда будем переходить на таймер - пригодится.
В эту переменную положим число для показа. Пока просто положим и не будем никогда менять - дай Бог нам его так показать.
volatile uint8_t numberToShow = 57;
Теперь смотрите, что мы делаем.
Как известно, в любой конкретный момент времени мы можем показывать только одну цифру, а не две вместе. Для того, чтобы человеку казалось, что все цмфры горят одновременно, они должны загораться по очереди так, чтобы полный цикл (все цифры посветились) происходил не реже, чем 50 раз в секунду. Т.е. полный цикл (все цифры посветились) должен длиться не более, чем 1000/50 = 20 миллисекунд. Это называется "динамическая индикация".
Давайте посчитаем длительность свечения одной цифры. В общем случае, если у нас N цифр, а длительность полного цикла 20мс, длительность свечения одно цифры равна 20/N мс. В нашем случае N=2 и длительность свечения одной цифры получается 10мс.
Т.е. нам надо.
1. Установим ТЕКУЩАЯ_ЦИФРА = 0
2. Зажечь цифру в позиции ТЕКУЩАЯ_ЦИФРА
3. Выждатть 10мс
4. Погасить цифру в позиции ТЕКУЩАЯ_ЦИФРА
5. Установить ТЕКУЩАЯ_ЦИФРА = (ТЕКУЩАЯ_ЦИФРА + 1) % КОЛЧИЧЕСТВО_ЦИФР
(у нас КОЛЧИЧЕСТВО_ЦИФР == 2)
(при этом после нулевой идёт 1, а потом снова 0 и т.д.)
6. перейти к шагу 2
Если мы будем работать по такому алгоритму, то у нас получится, что цифры по очереди горят по 10мс, а на глаз это будет как будто бы они обе горят постоянно.
Кстати, точно также делается для 3, 4, 5, 6 цифр, только задержка будет уже не 10мс, а 6, 5, 3 и 3 соответсвенно.
Давайте попробуем изобразить это в виде скетча. Я не буду усложнять всё миилисами и отказом от делэя, чтобы не усложнять и не запудривать мозги - всё равно будем на таймер переходить. так что делаем в лоб с делэями.
//
// я считаю, что нулевая цмфра слева (единицы), а первая справа (десятки)
// если у Вас по-другому - поменяйте.
//
void loop() {
static currentDigit = 0;
//
// следующая строка означает буквально следующее:
// ЕСЛИ (currentDigit НЕ_РАВНО 0) ТО digitToShow присвоить количество десятков в numberToShow
// ИНАЧЕ digitToShow присвоить количество единиц в numberToShow
//
const uint8_t digitToShow = (currentDigit) ? numberToShow / 10 : numberToShow % 10;
showDigit(digitToShow, currentDigit);
delay(10);
currentDigit = (currentDigit + 1) % 2;
}
Вот собственно к тому, что было добавьте объявление переменной и вот такой loop() и Вы должны увидеть на экране 57.
Если есть вопросы, задавайте.
Нам осталось только перейти к таймеру (ну и если хотите поговорить о виртуальных экранах).
немного подправил скетч. переменная currentDigit не была объявлена добавил uint8_t
Насчет токоограничительных резисторов. Не надо гадать и где-то читать, кому и что подходит - лучше самому рассчитать. Если сложно самому, то в интернете есть куча онлайн калькуляторов для их расчетов. Например, вот.
Даже если не нашли даташит на индикатор и не знаете ток и падение напряжения, то можно просто выбрать наиболее подходящий из списка.
Итак, заполняем: питание 5В; выбираем по цвету свечения, например, красный светодиод (для него прямое напряжение 1.9В и ток 20 мА); к-во 1 и получаем сопротивление 160 Ом (там же смотрим его мощность). Но учитывая, что наши светодиоды будут работать в импульсном режиме, то для компенсации яркости допустимо сопротивление немного уменьшить.
Коллега Вам правильно сказал, что нужно расчитать, но тут есть нюанс.
У ардуины заявлено, что HIGH = 5В, на практике же мы часто видим сьльно меньше (4,7 и даже 4.5) это нормально, в даташите контроллера сказано, что HIGH от 0,7 VCC, т.е. ото 3.5 вольт. Поэтому, я бы взял резистор где-то 150, поставил и померял бы ток. Если ток сильно меньше 20мА, взял бы резистор поменьше (если ток больше - то резистор побольше) и подобрал бы такой. чтобы ток был как можно ближе к 20мА (но не больше). Т.е. просто подобрал бы на конкретном железе.
Кроме того, напряжение просядет ещё на 0,6 - 0,7 вольта за счёт падени на транзисторе (на переходе коллектор-эмиттер).
Здесь это важно, т.к. светодиоды в динамических индикаторах светятся не всё время, поэтому чем ярче, тем лучше.
Тогда подумайте о том, чтобы используемые пины назначать не явно (2, 3, 4...), а через #define. Например,
1
#define A_SEG 2
2
#define B_SEG 3 // и т.д.
Будете разводить плату, поймете почему.
Ну это а понятно, спасибо
Если действительно понятно, то это хорошо.
Правда, тут есть небольшой минус, связанный с вашей хотелкой увязать управление на один порт и за одну команду записывать нужную комбинацию. Впрочем, у вас и так это не очень получится, учитывая не желательность использования пинов с rx и tx.
Также, учитывая, что у вас Nano, не рассчитывайте на пины A6 и A7 - они работают только на вход.
Если действительно понятно, то это хорошо.
Правда, тут есть небольшой минус, связанный с вашей хотелкой увязать управление на один порт и за одну команду записывать нужную комбинацию. Впрочем, у вас и так это не очень получится, учитывая не желательность использования пинов с rx и tx.
Также, учитывая, что у вас Nano, не рассчитывайте на пины A6 и A7 - они работают только на вход.
Rx-tx у меня не будут использоваться, а0-а7 и так только как входы используются
:) не говорите гоп... вы все-таки видимо не до конца все поняли
Я все это упомянул только потому, что при разводке платы (особенно односторонней) часто бывает намного проще протянуть дорожку к другому (совсем рядом расположенному) пину, чем пытаться тянуть ее в обход, между выводов, с перемычками и прочими радостями к тому, который мы назначили в программе. Вот тогда нам пригодится и #define, и пины А0, А1, А2...
:) не говорите гоп... вы все-таки видимо не до конца все поняли
Я все это упомянул только потому, что при разводке платы (особенно односторонней) часто бывает намного проще протянуть дорожку к другому (совсем рядом расположенному) пину, чем пытаться тянуть ее в обход, между выводов, с перемычками и прочими радостями к тому, который мы назначили в программе. Вот тогда нам пригодится и #define, и пины А0, А1, А2...
ну нет))) в define я полюбому буду пины пихать. но аналоговые входы как выходы точно использовать не буду. разводка платы не составляет большого труда. тем более особых, запутывающих схему, элементов там не будет.
но все равно большое спасибо за уточнение)
вот почему? потому что надо как-то объявить пины выходом? если да то как их группой объявить?
Про группы, давайте вернёмся, кргда всё заработает. Несложно, но вот когда всё будет работать - сделаем группами.
и переделал схему, на эмитор подал плюс вместо минуса. все заработало, загорелась одна цифра
Как хотите, можно и так. Я бы переделал программу, а не схему. Смотрите в чём разница.
Сейчас для того, чтобы зажечь цифру, Вам надо подать на пин базы тразнизстора LOW. А чтобы погасить - HIGH При включении МК (пока Ваша программа не успела туда ничего подать) там быдет LOW, и и цифра может мигнуть/дёрнуться.
А если Вы сделаете, как было раньше, то чтобы зажечь, подавать надо HIGH, а погасить - LOW. Поэспериментируйте и определитесь как Вы будете делать.
Как только убедитесь, что Вы можете уверено зажечь и погасить нужную цифру, перейдём с ледующему шагу - универсальной функции для любой цифры.
я могу уже погасить и зажеч любую цифру. на примере сделал цифру "56" скетч но с delay(30) что бы протеус мог выдавать мерцаниями эти цифры. если сделать 10, он уже не справляется(((
01
void
setup
() {
02
// put your setup code here, to run once:
03
pinMode(2, OUTPUT);
04
pinMode(3, OUTPUT);
05
pinMode(4, OUTPUT);
06
pinMode(5, OUTPUT);
07
pinMode(6, OUTPUT);
08
pinMode(7, OUTPUT);
09
pinMode(8, OUTPUT);
10
pinMode(9, OUTPUT);
11
pinMode(10, OUTPUT);
12
pinMode(11, OUTPUT);
13
14
15
}
16
17
void
loop
() {
18
// put your main code here, to run repeatedly:
19
cifra5();
20
delay(30);
21
off();
22
cifra6();
23
delay(30);
24
off();
25
}
26
void
cifra6()
27
{
28
digitalWrite(2, LOW);
29
digitalWrite(3, HIGH);
30
digitalWrite(4, HIGH);
31
digitalWrite(5, HIGH);
32
digitalWrite(6, HIGH);
33
digitalWrite(7, HIGH);
34
digitalWrite(8, LOW);
35
digitalWrite(9, HIGH);
36
digitalWrite(10, HIGH);
37
digitalWrite(11, LOW);
38
}
39
void
cifra5()
40
{
41
digitalWrite(2, LOW);
42
digitalWrite(3, HIGH);
43
digitalWrite(4, HIGH);
44
digitalWrite(5, LOW);
45
digitalWrite(6, HIGH);
46
digitalWrite(7, HIGH);
47
digitalWrite(8, LOW);
48
digitalWrite(9, HIGH);
49
digitalWrite(10, LOW);
50
digitalWrite(11, HIGH);
51
}
52
void
off()
53
{
54
digitalWrite(2, LOW);
55
digitalWrite(3, LOW);
56
digitalWrite(4, LOW);
57
digitalWrite(5, LOW);
58
digitalWrite(6, LOW);
59
digitalWrite(7, LOW);
60
digitalWrite(8, LOW);
61
digitalWrite(9, LOW);
62
digitalWrite(10, LOW);
63
digitalWrite(11, LOW);
64
}
Не за что. Не вам, так кому-то еще пригодится.
А вот на счет аналоговых пинов, я бы не был так категоричен. Не бойтесь их, они не кусаются )))
Совсем недавно почти закончил проект, в котором тоже используется семисегментник - суточный таймер. Там тоже элементов раз-два и обчелся. От вашей схемы отличается только наличием +2 транзисторов (сборка на 4 цифры) и RTC. И знаете что? Несмотря на то, что я разводил двустороннюю плату, а А0-А2 все-равно использовал на управление индикатором. А все потому, что так было удобней.
Не за что. Не вам, так кому-то еще пригодится.
А вот на счет аналоговых пинов, я бы не был так категоричен. Не бойтесь их, они не кусаются )))
Совсем недавно почти закончил проект, в котором тоже используется семисегментник - суточный таймер. Там тоже элементов раз-два и обчелся. От вашей схемы отличается только наличием +2 транзисторов (сборка на 4 цифры) и RTC. И знаете что? Несмотря на то, что я разводил двустороннюю плату, а А0-А2 все-равно использовал на управление индикатором. А все потому, что так было удобней.
не хочу их трогать не потому что боюсь. а потому что в будущем планирую еще кнопки присабачить. для других функций. допустим когда определюсь какой импульс нужен будет. могу их на кнопки вывести и уже нажав на кнопку будет пару сохраненных длительностей импульса.
не хочу их трогать ... потому что в будущем планирую еще кнопки присабачить
Не совсем разумно тратить по одному пину на каждую кнопку. Почитайте, например, вот эту тему. Там, среди прочего, есть и как подцепить несколько кнопок к всего-лишь одному аналоговому пину.
не хочу их трогать ... потому что в будущем планирую еще кнопки присабачить
Не совсем разумно тратить по одному пину на каждую кнопку. Почитайте, например, вот эту тему. Там, среди прочего, есть и как подцепить несколько кнопок к всего-лишь одному аналоговому пину.
не читая, логически подумать через резисторы?))) идея)))
Конечно, через резисторы, но лучше почитать )))
Так, ну, всё-таки, Вы уверенно зажигаете и гасите любую цифру и готовы идти дальше?
Попробуйте запустить вот это скетч. Только учтите следующее
1. У меня сейчас нет возможности проверить, так что проверьте сами особенно определени цифр из сегментов, я мог где-то ошибиться.
2. Проставьте свои намера пинов, я поставил просто подряд.
3. Допишите в setup все необходимые pinMode
4. По идее этот скетч должен показывать цифры от 0 до 9 сменяя их каждые полсекунды, причём чётне показыватся в позиции цифры DIG0, а нечетные в позиции DIG1.
5. Убедитесь что всё понятно или задавайте вопросы.
01
//
02
// Определение пинов для сегментов
03
// (поставьте Ваши пины, у меня мелкий экран и плохо видно какие там у Вас)
04
//
05
#define PIN_A 2
06
#define PIN_B 3
07
#define PIN_C 4
08
#define PIN_D 5
09
#define PIN_E 6
10
#define PIN_F 7
11
#define PIN_G 8
12
#define PIN_DP 9
13
14
//
15
// Определение пинов для цифр
16
// (поставьте Ваши пины, у меня мелкий экран и плохо видно какие там у Вас)
17
//
18
#define PIN_DIG0 10
19
#define PIN_DIG1 11
20
21
//
22
// Определение масок для сегментов
23
//
24
#define MASK_A (1 << 0)
25
#define MASK_B (1 << 1)
26
#define MASK_C (1 << 2)
27
#define MASK_D (1 << 3)
28
#define MASK_E (1 << 4)
29
#define MASK_F (1 << 5)
30
#define MASK_G (1 << 6)
31
#define MASK_DP (1 << 7)
32
33
//
34
// Определение цифр через маски сегментов
35
//
36
#define D0 (MASK_A | MASK_B | MASK_C | MASK_D | MASK_E | MASK_F)
37
#define D1 (MASK_B | MASK_C)
38
#define D2 (MASK_A | MASK_B | MASK_G | MASK_D | MASK_E)
39
#define D3 (MASK_A | MASK_B | MASK_C | MASK_D | MASK_G)
40
#define D4 (MASK_B | MASK_C | MASK_G | MASK_F)
41
#define D5 (MASK_A | MASK_C | MASK_D | MASK_F | MASK_G)
42
#define D6 (MASK_A | MASK_C | MASK_D | MASK_E | MASK_F | MASK_G)
43
#define D7 (MASK_A | (MASK_B | MASK_C))
44
#define D8 (MASK_A | MASK_B | MASK_C | MASK_D | MASK_E | MASK_F | MASK_G)
45
#define D9 (MASK_A | MASK_B | MASK_C | MASK_D | MASK_F | MASK_G)
46
47
48
49
//
50
// Функция устанавливает по маске - параметру (HIGH-горит, LOW-не горит)
51
//
52
void
setRawSegments(
const
int8_t mask) {
53
digitalWrite(PIN_A, mask & MASK_A);
54
digitalWrite(PIN_B, mask & MASK_B);
55
digitalWrite(PIN_C, mask & MASK_C);
56
digitalWrite(PIN_D, mask & MASK_D);
57
digitalWrite(PIN_E, mask & MASK_E);
58
digitalWrite(PIN_F, mask & MASK_F);
59
digitalWrite(PIN_G, mask & MASK_G);
60
digitalWrite(PIN_DP, mask & MASK_DP);
61
}
62
63
//
64
// Функция устанавливает все сегменты для цифры-параметра (HIGH-горит, LOW-не горит)
65
//
66
void
setSegments(
const
int8_t digit) {
67
static
const
uint8_t all_digits[] = { D0, D1, D2, D3, D4, D5, D6, D7, D8, D9 };
68
setRawSegments(all_digits[digit]);
69
}
70
71
//
72
// Функция зажигает цифру d в позиции pos
73
// При этом ставит пин соответсвующий позиции pos в LOW
74
//
75
void
showDigit(
const
uint8_t d,
const
uint8_t pos) {
76
static
const
uint8_t all_postions[] = { PIN_DIG0, PIN_DIG1 };
77
for
(register uint8_t i = 0; i <
sizeof
(all_postions) /
sizeof
(all_postions[0]); i++) {
78
digitalWrite(all_postions[i], pos != i);
79
}
80
setSegments(d);
81
}
82
83
84
void
setup
() {
85
// ... задайте все pinMode как раньше
86
}
87
88
void
loop
() {
89
static
uint8_t cnt = 0;
90
showDigit(cnt, cnt & 1);
91
cnt = (cnt + 1) % 10;
92
delay(500);
93
}
ЕвгенийП что то молчит((( ну ладно может дела у человека, еще и бездарей таких учить))) но учитель он отличный))) пропадая - дает время подумать, все осмыслить)))
не читая, логически подумать через резисторы?))) идея)))
Это очень просто если не нужно отлавдивать одновременное нажатие нескольких кнопок. Если нужно - там очеь тонко надо подбирать резисторы и и думать над схемой.
ЕвгенийП что то молчит((( ну ладно может дела у человека, еще и бездарей таких учить))) но учитель он отличный))) пропадая - дает время подумать, все осмыслить)))
Уже не молчу :)
да, иногда пропадаю - рабочее время :(
Кстати, не знаю как там симулирует протеус, если вдруг закобенится, поставьте явные HIGH/LOW во все digitalWrite. Для этого в строкак 53-60 надо сделать такую замену
1
// вместо
2
digitalWrite(PIN_A, mask & MASK_A);
3
4
// пишем
5
digitalWrite(PIN_A, (mask & MASK_A) ? HIGH : LOW);
И точно также в строке 78
1
// вместо
2
digitalWrite(all_postions[i], pos != i);
3
4
// пишем
5
digitalWrite(all_postions[i], (pos != i) ? HIGH : LOW);
протеус не кабенится, проставил pinMode, проставил пины в define. но я очень мало знаю о командах ардуино и после строки кода
1
#define D9 (MASK_A | MASK_B | MASK_C | MASK_D | MASK_F | MASK_G)
2
3
4
5
//
6
// Функция устанавливает по маске - параметру (HIGH-горит, LOW-не горит)
7
//
все перестает быть понятным
01
void
setRawSegments(
const
int8_t mask) {
// я так понимаю void начало функции, setRawSegments это название
02
// функции а вот в скобках не понимаю, предположения: const int8_t это значит что тип данных может быть только
03
//8 чего-то. а mask это новая переменная. но так же непонятная(((
04
digitalWrite(PIN_A, mask & MASK_A);
05
digitalWrite(PIN_B, mask & MASK_B);
06
digitalWrite(PIN_C, mask & MASK_C);
07
digitalWrite(PIN_D, mask & MASK_D);
08
digitalWrite(PIN_E, mask & MASK_E);
09
digitalWrite(PIN_F, mask & MASK_F);
10
digitalWrite(PIN_G, mask & MASK_G);
11
digitalWrite(PIN_DP, mask & MASK_DP);
12
}
Так оно заработало?
Если "нет", то говорите как себя ведёт. Если "да", то давайте снинмать вопросы прежде, чем двигаться дальше.
все перестает быть понятным
1
void
setRawSegments(
const
int8_t mask) {
// я так понимаю void начало функции, setRawSegments это название
2
// функции а вот в скобках не понимаю, предположения: const int8_t это значит что тип данных может быть только
3
//8 чего-то. а mask это новая переменная. но так же непонятная(((
4
5
<span style=
"line-height:1.5em;font-family:Verdana, Geneva, Arial, sans-serif;font-size:12px;"
></span>
Функция - это кусочек программы. который можно вызывать много раз из разных место для выполнения одних и тех же действий.
При описании функции в простейшем случае указывается тип возвращаемого значения (или void - ели возвращать ничего не нужно, имя функции и её параметры.
Давйте на маленьких примерах:
1. функция сладывает два числа (это её параметры) и возвращает результат:
01
//
02
// Функция принимает два параметра a и b типа const int
03
// Возвращает их сумму
04
//
05
int
sum2(
const
int
a,
const
int
b) {
06
return
a + b;
// слово return означает "вернуть значение"
07
}
08
09
void
setup
() {
10
Serial
.begin(115200);
11
int
d = 13;
12
int
c = 23;
13
Serial
.println(sum2(1,2));
// должно напечататься 3
14
Serial
.println(sum2(d,15));
// должно напечататься 28
15
Serial
.println(sum2(d,c));
// должно напечататься 36
16
}
17
18
void
loop
() {}
Теперь пример функции, которая ничего не возвращает. Тогда тип функции нужно указывать как void. Данные функции получают два параметра - первый пин и последний пин. Что они делают, написано в комментариях.
01
//
02
// Функция принимает два параметра startPin и endPin типа const int
03
// Устанавливает режим OUTPUT для всех пинов со startPin по endPin включительно
04
//
05
void
modeOutputAll(
const
int
startPin,
const
int
endPin) {
06
for
(
int
i = startPin; i <= endPin; i++) {
07
pinMode(i, OUTPUT);
08
}
09
}
10
11
//
12
// Функция принимает два параметра startPin и endPin типа const int
13
// Устанавливает HIGH для всех пинов со startPin по endPin включительно
14
//
15
void
highAll(
const
int
startPin,
const
int
endPin) {
16
for
(
int
i = startPin; i <= endPin; i++) {
17
digitalWrite(i, HIGH);
18
}
19
}
20
21
void
setup
() {
22
modeOutputAll(3, 10);
// Поставим пины с 3 по 10 в OUTPUT
23
highAll(5, 7);
// Выведем HIGH на пины 5, 6 и 7
24
}
25
26
void
loop
() {}
Слово const в описании типа параметра означает. что я не собираюсь его менять. Это подсказка компилятору, чтобы ему легче было оптимизировать код. В принципе его можно опустить.
Стао понятнее? Нес стесняйтесь спрашивать. Прежде, чем мы пойдём дальше, надо снять все вопросы.
с функциями понял, спасибо. понял логику программы. но не понятно почему после int ставиться 8_t
а потом еще и прибавляется u int8_t
с функциями понял, спасибо. понял логику программы. но не понятно почему после int ставиться 8_t
а потом еще и прибавляется u int8_t
8_t в данном случае означает, что int не двухбайтовы, а однобайтовый (нафига расходовать лишний байт, если и этого хватает?)
u в начале означает, что число беззнаковое и отрицательным не бывает.
Вы всё поняли и готовы "ехать дальше"?
еще почитал про "&" "побитовое И" но не понял для чего он нужен. ну как не понял( догадки есть) как я думаю это что бы сложить 2 числа
допустим имея 10010011 и 11010110 получаем 10010010? это вы делаете я так понял для того что бы задать HIGH или LOW? грубо говоря
я так понял мы уже занимаемся на уровне "С" языка)))) и грубо говоря чуть ли не логику построение программы на уровне "понимания" процессором составляем 0100010101000100010101010011010010101010001010101001010010101010100101001010010, всмысле компелятору почти трудиться не придется)))
а да, прошу прощения, все заработало в proteus
еще почитал про "&" "побитовое И" но не понял для чего он нужен. ну как не понял( догадки есть) как я думаю это что бы сложить 2 числа
допустим имея 10010011 и 11010110 получаем 10010010? это вы делаете я так понял для того что бы задать HIGH или LOW? грубо говоря
Ддя начала при побитовой операции & в результате единицами будут только те биты, которые были единицами в ОБОИХ операндах.
Далее, заметьте, что все наши маски сегментов (строки 24-31) содержат ровно по одному единичному биту. В каждой из восьми масок один бит 1. а все остальные 0.
Теперь давайте посмотрим на функцию setRawSegments(const int8_t mask). Её параметр mask - маска готовой цифры (т.е. в её параметре столько удиничных битов, сколько сенментов должно светиться). Внутри функции мы для каждого сегмента выполнеям & маски этого сегмента с параметром mask. Резальтатом этой операции & будет 0, если в mask этот сегмент отсутсвует (нулевой - его зажилать не надо) и НЕ_НОЛЬ если в mask бит этого сегмента единичный. 0 - соответсвет LOW, а любой не 0 - соответствует HIGH.
Например, я хочу нарисовать на индикаторе латинскую букву C - это сегменты a, d, e и f. Вот так я это делаю:
1
setRawSegments (MASK_A | MASK_D | MASK_E | MASK_F);
Давайте просто пальцем вести по тексту функции setRawSegments и думать что она делает.
01
setRawSegments (MASK_A | MASK_D | MASK_E | MASK_F);
02
03
...
04
05
void
setRawSegments(
const
int8_t mask) {
06
// передано MASK_A | MASK_D | MASK_E | MASK_F
07
// значит mask равно MASK_A | MASK_D | MASK_E | MASK_F
08
09
digitalWrite(PIN_A, mask & MASK_A);
// операция & даст НЕ_0 (он же HIGH), т.к. MASK_А присутствует в mask - зажигаем
10
digitalWrite(PIN_B, mask & MASK_B);
// операция & даст 0 (он же LOW), т.к. MASK_B не присутствует в mask - гасим
11
digitalWrite(PIN_C, mask & MASK_C);
// операция & даст 0 (он же LOW), т.к. MASK_C не присутствует в mask - гасим
12
digitalWrite(PIN_D, mask & MASK_D);
// операция & даст НЕ_0 (он же HIGH), т.к. MASK_В присутствует в mask - зажигаем
13
digitalWrite(PIN_E, mask & MASK_E);
// и т.д.
14
digitalWrite(PIN_F, mask & MASK_F);
15
digitalWrite(PIN_G, mask & MASK_G);
16
digitalWrite(PIN_DP, mask & MASK_DP);
17
}
Попробуйте сами нарисовать хоть букву H - или там ещё чего и так же рассуждайте.
Нам осталось совсем немного.
1. сделать чтобы показывалось честное двузначное число пока на delay'ях
2. перейти от delay'ев к таймеру.
Если хотите, на закуску, можем о виртуальных экранах поговорить.
Как будете готовы продолжать, скажите.
Нам осталось совсем немного.
1. сделать чтобы показывалось честное двузначное число пока на delay'ях
2. перейти от delay'ев к таймеру.
Если хотите, на закуску, можем о виртуальных экранах поговорить.
Как будете готовы продолжать, скажите.
хорошо, пока я все перевариваю. пытаюсь понять когда какая цифра приходит и что с ней становится в последствии начиная со строки
1
106 showDigit(cnt, cnt & 1);
106 showDigit(cnt, cnt & 1);
Ну, это простая строка. У функции showDigit два параметра - первый число, которое нужно показать. Второй - позиция в которой его нужно показывать.
Показываем мы наш счётчик cnt.
Позицию мы вычисляет побитовой операцией & - т.е. мы выделяем самый младший бит счётчика. Если младший бит равен нулю (cnt чётное), то "cnt & 1" - будет равно 0. Если младший бит cnt равен 1 (т.е. cnt - нечётное), то "cnt & 1" - будет равно 1.
Кстати, коль уж пошла такая пьянка, в следующей строке используется операция "отстаок от деления".
1
cnt = (cnt + 1) % 10;
Т.е. мы прибавляем 1 к счётчику и берём остаток от деления результата на 10. Таки образома счётчки будет расти от 0 до 9. ПОтом снова станет 0 (т.к. отстаок от деления (9+1) на 10 равен нулю) и снова будет расти до 9, потом снова станет 0 и так до посинения.
Обратите внимене, что в строке
1
showDigit(cnt, cnt & 1);
Можно было вместо & использовать остаток от деления на 2 и написать
1
showDigit(cnt, cnt % 2);
ничего бы не изменилось абсолютно. У чётных чисел остаток от деления на 2 равен нулю, а у нечётных - 1.
Ну, это простая строка. У функции showDigit два параметра - первый число, которое нужно показать. Второй - позиция в которой его нужно показывать.
Показываем мы наш счётчик cnt.
Позицию мы вычисляет побитовой операцией & - т.е. мы выделяем самый младший бит счётчика. Если младший бит равен нулю (cnt чётное), то "cnt & 1" - будет равно 0. Если младший бит cnt равен 1 (т.е. cnt - нечётное), то "cnt & 1" - будет равно 1.
Кстати, коль уж пошла такая пьянка, в следующей строке используется операция "отстаок от деления".
1
cnt = (cnt + 1) % 10;
Т.е. мы прибавляем 1 к счётчику и берём остаток от деления результата на 10. Таки образома счётчки будет расти от 0 до 9. ПОтом снова станет 0 (т.к. отстаок от деления (9+1) на 10 равен нулю) и снова будет расти до 9, потом снова станет 0 и так до посинения.
Обратите внимене, что в строке
1
showDigit(cnt, cnt & 1);
Можно было вместо & использовать остаток от деления на 2 и написать
1
showDigit(cnt, cnt % 2);
ничего бы не изменилось абсолютно. У чётных чисел остаток от деления на 2 равен нулю, а у нечётных - 1.
спасибо, я так и думал, но были сомнения, вы их развеяли. еще не попробовал нарисовать. т.е. я понял что бы нарисовать H ее надо определить в маску т.е. дописать
1
#define D10 ( MASK_B | MASK_C | MASK_E | MASK_F | MASK_G)
2
// потом в строчке
3
static
const
uint8_t all_digits[] = { D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10 };
4
// дописываем D10
и программа будет уже выдавать 0-1-2-3-4-5-6-7-8-9-H
я так понял мы делаем это все для того что бы программа была как можно меньше, а следовательно что бы стабильнее работала? ведь можно было ее написать визуально проще используя только if и else if, но тогда она будет большая и время прохождения всех if будет тормозить весь процесс.
да кстати еще одну строчку надо заменить.
1
cnt = (cnt + 1) % 11;
спасибо, я так и думал, но были сомнения, вы их развеяли. еще не попробовал нарисовать. т.е. я понял что бы нарисовать H ее надо определить в маску т.е. дописать
1
#define D10 ( MASK_B | MASK_C | MASK_E | MASK_F | MASK_G)
2
// потом в строчке
3
static
const
uint8_t all_digits[] = { D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10 };
4
// дописываем D10
и программа будет уже выдавать 0-1-2-3-4-5-6-7-8-9-H
Не совсем. Первая из Ваших строк нужна, а вот во второй ничего менять не нужно, т.к. функция в которой эта строка живёт всё равно предназначена только для цифр.
Вы можете сделать так. В define опредеоить все символы, каке Вам хочется, например (я скопировал пример из своего проекта, а там у меня названия не типа MASK_A как я Вам написал, а типа A_MASK - переделайте уж сами):
01
#define SYMBOL_MINUS (G_MASK)
02
03
#define SYMBOL_A (A_MASK | B_MASK | C_MASK | E_MASK | F_MASK | G_MASK)
04
#define SYMBOL_F (A_MASK | D_MASK | E_MASK | F_MASK | G_MASK)
05
#define SYMBOL_C (A_MASK | E_MASK | F_MASK | D_MASK)
06
#define SYMBOL_E (A_MASK | D_MASK | E_MASK | F_MASK | G_MASK)
07
#define SYMBOL_H (B_MASK | C_MASK | E_MASK | F_MASK | G_MASK)
08
#define SYMBOL_P (A_MASK | B_MASK | E_MASK | F_MASK | G_MASK)
09
#define SYMBOL_G (A_MASK | E_MASK | F_MASK)
10
#define SYMBOL_L (D_MASK | E_MASK | F_MASK)
11
#define SYMBOL_F (A_MASK | E_MASK | F_MASK | G_MASK)
12
#define SYMBOL_d (B_MASK | C_MASK | D_MASK | E_MASK | G_MASK)
13
#define SYMBOL_b (C_MASK | D_MASK | E_MASK | F_MASK | G_MASK)
а использовать ихх прямо так, смотрите:
1
setRawSegments(SYMBOL_A);
// Рисуем букву А
2
setRawSegments(SYMBOL_E);
// Рисуем букву E
Ничего другого менять не нужно.
да кстати еще одну строчку надо заменить.
1
cnt = (cnt + 1) % 11;
Ну, это только если Вы хотите, чтобы они подряд показывались. Но смысла в этом нет. НЕ_ЦИФРЫ лучше показывать отдельно, как я описал в прошлом посте.
я так понял мы делаем это все для того что бы программа была как можно меньше, а следовательно что бы стабильнее работала? ведь можно было ее написать визуально проще используя только if и else if, но тогда она будет большая и время прохождения всех if будет тормозить весь процесс.
Мы это делаем, чтобы отделить показ от собственно программы. Программа у нас будет просто записывать нужное для показа число в нужное место и совершенно не париться о показе. Показом будет заниматься программа обработки переполнения таймера сама по себе. Т.е. дело программы просто в нужное место положить число, а показ - он должен своей жизнью жить.
01
void
loop
() {
02
static
uint8_t cnt = 0;
03
showDigit(cnt, cnt & 1);
04
cnt = (cnt + 1);
05
if
(cnt == 11)
06
{
07
cnt = 0;
08
}
09
delay(500);
10
}
все понял кроме последнего поста, на счет перебора цифр. понял что буквы лучше отдельно создать, так визуально лучше выглядит
ЕвгенийП а вы в каком городе живете? по соотношении с Московским временем какая разница в часах?
Это правильно. 9 - нечётное число - показывается в 1 разряде. Н (типа 10) - чётное и показывается в нулевом разряде. 0 - тоже чётное и потому показывается тоже в нулевом разряде.
ЕвгенийП а вы в каком городе живете? по соотношении с Московским временем какая разница в часах?
Нет, никакой. Переславль-Залесский, это 130 вёрст от Москвы по ярославской дороге.
Это правильно. 9 - нечётное число - показывается в 1 разряде. Н (типа 10) - чётное и показывается в нулевом разряде. 0 - тоже чётное и потому показывается тоже в нулевом разряде.
так и думал, спасибо
продолжим или до завтра отложим?
Работаем. Я здесь просто большой пост пишу
все понял кроме последнего поста, на счет перебора цифр. понял что буквы лучше отдельно создать, так визуально лучше выглядит
Поехали дальше.
Теперь попробуем показать нормальное двузначное число.
Для начала заведём переменную для этого числа - пусть она будет, скажем однобайтовой беззнаковой, т.е. uint8_t (если знак нужен, то можно просто int8_t, но пока будем показывать без знака.
Мы пока не будем париться с таймером, это у нас следующий шаг, но давайте сразу объявим эту переменную волатильной (это означает, что она может быть неожиданно для основной программы изменена. Сейчас нам это не надо, но когда будем переходить на таймер - пригодится.
В эту переменную положим число для показа. Пока просто положим и не будем никогда менять - дай Бог нам его так показать.
1
volatile uint8_t numberToShow = 57;
Теперь смотрите, что мы делаем.
Как известно, в любой конкретный момент времени мы можем показывать только одну цифру, а не две вместе. Для того, чтобы человеку казалось, что все цмфры горят одновременно, они должны загораться по очереди так, чтобы полный цикл (все цифры посветились) происходил не реже, чем 50 раз в секунду. Т.е. полный цикл (все цифры посветились) должен длиться не более, чем 1000/50 = 20 миллисекунд. Это называется "динамическая индикация".
Давайте посчитаем длительность свечения одной цифры. В общем случае, если у нас N цифр, а длительность полного цикла 20мс, длительность свечения одно цифры равна 20/N мс. В нашем случае N=2 и длительность свечения одной цифры получается 10мс.
Т.е. нам надо.
1. Установим ТЕКУЩАЯ_ЦИФРА = 0
2. Зажечь цифру в позиции ТЕКУЩАЯ_ЦИФРА
3. Выждатть 10мс
4. Погасить цифру в позиции ТЕКУЩАЯ_ЦИФРА
5. Установить ТЕКУЩАЯ_ЦИФРА = (ТЕКУЩАЯ_ЦИФРА + 1) % КОЛЧИЧЕСТВО_ЦИФР
(у нас КОЛЧИЧЕСТВО_ЦИФР == 2)
(при этом после нулевой идёт 1, а потом снова 0 и т.д.)
6. перейти к шагу 2
Если мы будем работать по такому алгоритму, то у нас получится, что цифры по очереди горят по 10мс, а на глаз это будет как будто бы они обе горят постоянно.
Кстати, точно также делается для 3, 4, 5, 6 цифр, только задержка будет уже не 10мс, а 6, 5, 3 и 3 соответсвенно.
Давайте попробуем изобразить это в виде скетча. Я не буду усложнять всё миилисами и отказом от делэя, чтобы не усложнять и не запудривать мозги - всё равно будем на таймер переходить. так что делаем в лоб с делэями.
01
//
02
// я считаю, что нулевая цмфра слева (единицы), а первая справа (десятки)
03
// если у Вас по-другому - поменяйте.
04
//
05
void
loop
() {
06
static
currentDigit = 0;
07
//
08
// следующая строка означает буквально следующее:
09
// ЕСЛИ (currentDigit НЕ_РАВНО 0) ТО digitToShow присвоить количество десятков в numberToShow
10
// ИНАЧЕ digitToShow присвоить количество единиц в numberToShow
11
//
12
const
uint8_t digitToShow = (currentDigit) ? numberToShow / 10 : numberToShow % 10;
13
showDigit(digitToShow, currentDigit);
14
delay(10);
15
currentDigit = (currentDigit + 1) % 2;
16
}
Вот собственно к тому, что было добавьте объявление переменной и вот такой loop() и Вы должны увидеть на экране 57.
Если есть вопросы, задавайте.
Нам осталось только перейти к таймеру (ну и если хотите поговорить о виртуальных экранах).
Поехали дальше.
Теперь попробуем показать нормальное двузначное число.
Для начала заведём переменную для этого числа - пусть она будет, скажем однобайтовой беззнаковой, т.е. uint8_t (если знак нужен, то можно просто int8_t, но пока будем показывать без знака.
Мы пока не будем париться с таймером, это у нас следующий шаг, но давайте сразу объявим эту переменную волатильной (это означает, что она может быть неожиданно для основной программы изменена. Сейчас нам это не надо, но когда будем переходить на таймер - пригодится.
В эту переменную положим число для показа. Пока просто положим и не будем никогда менять - дай Бог нам его так показать.
volatile uint8_t numberToShow = 57;
Теперь смотрите, что мы делаем.
Как известно, в любой конкретный момент времени мы можем показывать только одну цифру, а не две вместе. Для того, чтобы человеку казалось, что все цмфры горят одновременно, они должны загораться по очереди так, чтобы полный цикл (все цифры посветились) происходил не реже, чем 50 раз в секунду. Т.е. полный цикл (все цифры посветились) должен длиться не более, чем 1000/50 = 20 миллисекунд. Это называется "динамическая индикация".
Давайте посчитаем длительность свечения одной цифры. В общем случае, если у нас N цифр, а длительность полного цикла 20мс, длительность свечения одно цифры равна 20/N мс. В нашем случае N=2 и длительность свечения одной цифры получается 10мс.
Т.е. нам надо.
1. Установим ТЕКУЩАЯ_ЦИФРА = 0
2. Зажечь цифру в позиции ТЕКУЩАЯ_ЦИФРА
3. Выждатть 10мс
4. Погасить цифру в позиции ТЕКУЩАЯ_ЦИФРА
5. Установить ТЕКУЩАЯ_ЦИФРА = (ТЕКУЩАЯ_ЦИФРА + 1) % КОЛЧИЧЕСТВО_ЦИФР
(у нас КОЛЧИЧЕСТВО_ЦИФР == 2)
(при этом после нулевой идёт 1, а потом снова 0 и т.д.)
6. перейти к шагу 2
Если мы будем работать по такому алгоритму, то у нас получится, что цифры по очереди горят по 10мс, а на глаз это будет как будто бы они обе горят постоянно.
Кстати, точно также делается для 3, 4, 5, 6 цифр, только задержка будет уже не 10мс, а 6, 5, 3 и 3 соответсвенно.
Давайте попробуем изобразить это в виде скетча. Я не буду усложнять всё миилисами и отказом от делэя, чтобы не усложнять и не запудривать мозги - всё равно будем на таймер переходить. так что делаем в лоб с делэями.
//
// я считаю, что нулевая цмфра слева (единицы), а первая справа (десятки)
// если у Вас по-другому - поменяйте.
//
void loop() {
static currentDigit = 0;
//
// следующая строка означает буквально следующее:
// ЕСЛИ (currentDigit НЕ_РАВНО 0) ТО digitToShow присвоить количество десятков в numberToShow
// ИНАЧЕ digitToShow присвоить количество единиц в numberToShow
//
const uint8_t digitToShow = (currentDigit) ? numberToShow / 10 : numberToShow % 10;
showDigit(digitToShow, currentDigit);
delay(10);
currentDigit = (currentDigit + 1) % 2;
}
Вот собственно к тому, что было добавьте объявление переменной и вот такой loop() и Вы должны увидеть на экране 57.
Если есть вопросы, задавайте.
Нам осталось только перейти к таймеру (ну и если хотите поговорить о виртуальных экранах).
немного подправил скетч. переменная currentDigit не была объявлена добавил uint8_t
и поменял цифры местами все заработало
что такое виртуальные экраны? хочу знать)
P.S. купил индикатор , где то в интернете прочитал что резисторы по 100ом для них идут для подключения к МК. взял и их еще.
Насчет токоограничительных резисторов. Не надо гадать и где-то читать, кому и что подходит - лучше самому рассчитать. Если сложно самому, то в интернете есть куча онлайн калькуляторов для их расчетов. Например, вот.
Даже если не нашли даташит на индикатор и не знаете ток и падение напряжения, то можно просто выбрать наиболее подходящий из списка.
Итак, заполняем: питание 5В; выбираем по цвету свечения, например, красный светодиод (для него прямое напряжение 1.9В и ток 20 мА); к-во 1 и получаем сопротивление 160 Ом (там же смотрим его мощность). Но учитывая, что наши светодиоды будут работать в импульсном режиме, то для компенсации яркости допустимо сопротивление немного уменьшить.
зеленый светодиод
Там в списке зеленый тоже имеется :)
Так может вы знаете марку индикатора? Тогда лучше даташит на него найти и там посмотреть параметры.
10 ом мне кажется маловато.
Коллега Вам правильно сказал, что нужно расчитать, но тут есть нюанс.
У ардуины заявлено, что HIGH = 5В, на практике же мы часто видим сьльно меньше (4,7 и даже 4.5) это нормально, в даташите контроллера сказано, что HIGH от 0,7 VCC, т.е. ото 3.5 вольт. Поэтому, я бы взял резистор где-то 150, поставил и померял бы ток. Если ток сильно меньше 20мА, взял бы резистор поменьше (если ток больше - то резистор побольше) и подобрал бы такой. чтобы ток был как можно ближе к 20мА (но не больше). Т.е. просто подобрал бы на конкретном железе.
Кроме того, напряжение просядет ещё на 0,6 - 0,7 вольта за счёт падени на транзисторе (на переходе коллектор-эмиттер).
Здесь это важно, т.к. светодиоды в динамических индикаторах светятся не всё время, поэтому чем ярче, тем лучше.
да,рассчитал надо для 5В 140Ом ближайший 150. так что зря 5 рублей за 10 резисторов потратил((( эх... ладно поднакаплю в следующем месяце и куплю)))
даташит не нашел, 3 первые страницы гугла. только схема подключения. а про токи ничего(