два 8-ми сегментных индикаторов

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

vk007 пишет:

Тогда подумайте о том, чтобы используемые пины назначать не явно (2, 3, 4...), а через #define. Например,

#define A_SEG 2
#define B_SEG 3  // и т.д.

Будете разводить плату, поймете почему.


Ну это а понятно, спасибо

vk007
Offline
Зарегистрирован: 16.06.2015

Если действительно понятно, то это хорошо.

Правда, тут есть небольшой минус, связанный с вашей хотелкой увязать управление на один порт и за одну команду записывать нужную комбинацию. Впрочем, у вас и так это не очень получится, учитывая не желательность использования пинов с rx и tx.

Также, учитывая, что у вас Nano, не рассчитывайте на пины A6 и A7 - они работают только на вход.

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

vk007 пишет:

Если действительно понятно, то это хорошо.

Правда, тут есть небольшой минус, связанный с вашей хотелкой увязать управление на один порт и за одну команду записывать нужную комбинацию. Впрочем, у вас и так это не очень получится, учитывая не желательность использования пинов с rx и tx.

Также, учитывая, что у вас Nano, не рассчитывайте на пины A6 и A7 - они работают только на вход.


Rx-tx у меня не будут использоваться, а0-а7 и так только как входы используются

vk007
Offline
Зарегистрирован: 16.06.2015

d13lider пишет:
а0-а7 и так только как входы используются

:) не говорите гоп... вы все-таки видимо не до конца все поняли

Я все это упомянул только потому, что при разводке платы (особенно односторонней) часто бывает намного проще протянуть дорожку к другому (совсем рядом расположенному) пину, чем пытаться тянуть ее в обход, между выводов, с перемычками и прочими радостями к тому, который мы назначили в программе. Вот тогда нам пригодится и #define, и пины А0, А1, А2...

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

vk007 пишет:

d13lider пишет:
а0-а7 и так только как входы используются

:) не говорите гоп... вы все-таки видимо не до конца все поняли

Я все это упомянул только потому, что при разводке платы (особенно односторонней) часто бывает намного проще протянуть дорожку к другому (совсем рядом расположенному) пину, чем пытаться тянуть ее в обход, между выводов, с перемычками и прочими радостями к тому, который мы назначили в программе. Вот тогда нам пригодится и #define, и пины А0, А1, А2...

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

но все равно большое спасибо за уточнение)

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

ЕвгенийП пишет:

d13lider пишет:

вот почему? потому что надо как-то объявить пины выходом? если да то как их группой объявить?

Про группы, давайте вернёмся, кргда всё заработает. Несложно, но вот когда всё будет работать - сделаем группами.

d13lider пишет:

и переделал схему, на эмитор подал плюс вместо минуса. все заработало, загорелась одна цифра

Как хотите, можно и так. Я бы переделал программу, а не схему. Смотрите в чём разница.

Сейчас для того, чтобы зажечь цифру, Вам надо подать на пин базы тразнизстора LOW. А чтобы погасить - HIGH При включении МК (пока Ваша программа не успела туда ничего подать) там быдет LOW, и и цифра может мигнуть/дёрнуться.

А если Вы сделаете, как было раньше, то чтобы зажечь, подавать надо HIGH, а погасить - LOW. Поэспериментируйте и определитесь как Вы будете делать.

Как только убедитесь, что Вы можете уверено зажечь и погасить нужную цифру, перейдём с ледующему шагу - универсальной функции для любой цифры.

 

я могу уже погасить и зажеч любую цифру. на примере сделал цифру "56" скетч но с delay(30) что бы протеус мог выдавать мерцаниями эти цифры. если сделать 10, он уже не справляется((( 

void setup() {
  // put your setup code here, to run once:
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);


}

void loop() {
  // put your main code here, to run repeatedly:
cifra5();
delay(30);
off();
cifra6();
delay(30);
off();
}
void cifra6()
{
  digitalWrite(2, LOW);
digitalWrite(3, HIGH);
digitalWrite(4, HIGH);
digitalWrite(5, HIGH);
digitalWrite(6, HIGH);
digitalWrite(7, HIGH);
digitalWrite(8, LOW);
digitalWrite(9, HIGH);
digitalWrite(10, HIGH);
digitalWrite(11, LOW);
}
void cifra5()
{
  digitalWrite(2, LOW);
digitalWrite(3, HIGH);
digitalWrite(4, HIGH);
digitalWrite(5, LOW);
digitalWrite(6, HIGH);
digitalWrite(7, HIGH);
digitalWrite(8, LOW);
digitalWrite(9, HIGH);
digitalWrite(10, LOW);
digitalWrite(11, HIGH);
}
void off()
{
  digitalWrite(2, LOW);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
digitalWrite(5, LOW);
digitalWrite(6, LOW);
digitalWrite(7, LOW);
digitalWrite(8, LOW);
digitalWrite(9, LOW);
digitalWrite(10, LOW);
digitalWrite(11, LOW);
}

 

vk007
Offline
Зарегистрирован: 16.06.2015

Не за что. Не вам, так кому-то еще пригодится.

А вот на счет аналоговых пинов, я бы не был так категоричен. Не бойтесь их, они не кусаются )))

Совсем недавно почти закончил проект, в котором тоже используется семисегментник - суточный таймер. Там тоже элементов раз-два и обчелся. От вашей схемы отличается только наличием +2 транзисторов (сборка на 4 цифры) и RTC. И знаете что? Несмотря на то, что я разводил двустороннюю плату, а А0-А2 все-равно использовал на управление индикатором. А все потому, что так было удобней.

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

vk007 пишет:

Не за что. Не вам, так кому-то еще пригодится.

А вот на счет аналоговых пинов, я бы не был так категоричен. Не бойтесь их, они не кусаются )))

Совсем недавно почти закончил проект, в котором тоже используется семисегментник - суточный таймер. Там тоже элементов раз-два и обчелся. От вашей схемы отличается только наличием +2 транзисторов (сборка на 4 цифры) и RTC. И знаете что? Несмотря на то, что я разводил двустороннюю плату, а А0-А2 все-равно использовал на управление индикатором. А все потому, что так было удобней.

не хочу их трогать не потому что боюсь. а потому что в будущем планирую еще кнопки присабачить. для других функций. допустим когда определюсь какой импульс нужен будет. могу их на кнопки вывести и уже нажав на кнопку будет пару сохраненных длительностей импульса.

vk007
Offline
Зарегистрирован: 16.06.2015

d13lider пишет:

не хочу их трогать ... потому что в будущем планирую еще кнопки присабачить

Не совсем разумно тратить по одному пину на каждую кнопку. Почитайте, например, вот эту тему. Там, среди прочего, есть и как подцепить несколько кнопок к всего-лишь одному аналоговому пину.

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

vk007 пишет:

d13lider пишет:

не хочу их трогать ... потому что в будущем планирую еще кнопки присабачить

Не совсем разумно тратить по одному пину на каждую кнопку. Почитайте, например, вот эту тему. Там, среди прочего, есть и как подцепить несколько кнопок к всего-лишь одному аналоговому пину.

не читая, логически подумать через резисторы?))) идея))) 

vk007
Offline
Зарегистрирован: 16.06.2015

Конечно, через резисторы, но лучше почитать )))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Так, ну, всё-таки, Вы уверенно зажигаете и гасите любую цифру и готовы идти дальше?

Попробуйте запустить вот это скетч. Только учтите следующее

1. У меня сейчас нет возможности проверить, так что проверьте сами особенно определени цифр из сегментов, я мог где-то ошибиться.

2. Проставьте свои намера пинов, я поставил просто подряд.

3. Допишите в setup все необходимые pinMode

4. По идее этот скетч должен показывать цифры от 0 до 9 сменяя их каждые полсекунды, причём чётне показыватся в позиции цифры DIG0, а нечетные в позиции DIG1.

5. Убедитесь что всё понятно или задавайте вопросы.

//
//	Определение пинов для сегментов
//	(поставьте Ваши пины, у меня мелкий экран и плохо видно какие там у Вас)
//
#define PIN_A	2
#define PIN_B	3
#define PIN_C	4
#define PIN_D	5
#define PIN_E	6
#define PIN_F	7
#define PIN_G	8
#define PIN_DP	9

//
//	Определение пинов для цифр
//	(поставьте Ваши пины, у меня мелкий экран и плохо видно какие там у Вас)
//
#define PIN_DIG0	10
#define PIN_DIG1	11

//
//	Определение масок для сегментов
//
#define MASK_A	(1 << 0)
#define MASK_B	(1 << 1)
#define MASK_C	(1 << 2)
#define MASK_D	(1 << 3)
#define MASK_E	(1 << 4)
#define MASK_F	(1 << 5)
#define MASK_G	(1 << 6)
#define MASK_DP		(1 << 7)

//
//	Определение цифр через маски сегментов
//
#define	D0	(MASK_A | MASK_B | MASK_C | MASK_D | MASK_E | MASK_F)
#define	D1	(MASK_B | MASK_C)
#define	D2	(MASK_A | MASK_B | MASK_G | MASK_D | MASK_E)
#define	D3	(MASK_A | MASK_B | MASK_C | MASK_D | MASK_G)
#define	D4	(MASK_B | MASK_C | MASK_G | MASK_F)
#define	D5	(MASK_A | MASK_C | MASK_D | MASK_F | MASK_G)
#define	D6	(MASK_A | MASK_C | MASK_D | MASK_E | MASK_F | MASK_G)
#define	D7	(MASK_A | (MASK_B | MASK_C))
#define	D8	(MASK_A | MASK_B | MASK_C | MASK_D | MASK_E | MASK_F | MASK_G)
#define	D9	(MASK_A | MASK_B | MASK_C | MASK_D | MASK_F | MASK_G)



//
//	Функция устанавливает по маске - параметру (HIGH-горит, LOW-не горит)
//
void setRawSegments(const int8_t mask) {
	digitalWrite(PIN_A, mask & MASK_A);
	digitalWrite(PIN_B, mask & MASK_B);
	digitalWrite(PIN_C, mask & MASK_C);
	digitalWrite(PIN_D, mask & MASK_D);
	digitalWrite(PIN_E, mask & MASK_E);
	digitalWrite(PIN_F, mask & MASK_F);
	digitalWrite(PIN_G, mask & MASK_G);
	digitalWrite(PIN_DP, mask & MASK_DP);
}

//
//	Функция устанавливает все сегменты для цифры-параметра (HIGH-горит, LOW-не горит)
//
void setSegments(const int8_t digit) {
	static const uint8_t all_digits[] = { D0, D1, D2, D3, D4, D5, D6, D7, D8, D9 }; 
	setRawSegments(all_digits[digit]);
}

//
//	Функция зажигает цифру d в позиции pos
//	При этом ставит пин соответсвующий позиции pos в LOW
//
void showDigit(const uint8_t d, const uint8_t pos) {
	static const uint8_t all_postions[] = { PIN_DIG0, PIN_DIG1 }; 
	for (register uint8_t i = 0; i < sizeof(all_postions) / sizeof(all_postions[0]); i++) {
		digitalWrite(all_postions[i], pos != i);
	}
	setSegments(d);
}


void setup() {
	// ... задайте все pinMode как раньше 
}

void loop() {
	static uint8_t cnt = 0;
	showDigit(cnt, cnt & 1);
	cnt = (cnt + 1) % 10;
	delay(500);
}

 

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

ЕвгенийП  что то молчит((( ну ладно может дела у человека, еще и бездарей таких учить))) но учитель он отличный))) пропадая - дает время подумать, все осмыслить))) 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

d13lider пишет:

не читая, логически подумать через резисторы?))) идея))) 

Это очень просто если не нужно отлавдивать одновременное нажатие нескольких кнопок. Если нужно - там очеь тонко надо подбирать резисторы и и думать над схемой.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

d13lider пишет:

ЕвгенийП  что то молчит((( ну ладно может дела у человека, еще и бездарей таких учить))) но учитель он отличный))) пропадая - дает время подумать, все осмыслить))) 

 

Уже не молчу :)

да, иногда пропадаю - рабочее время :(

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Кстати, не знаю как там симулирует протеус, если вдруг закобенится, поставьте явные HIGH/LOW во все digitalWrite. Для этого в строкак 53-60 надо сделать такую замену

// вместо
digitalWrite(PIN_A, mask & MASK_A);

// пишем
digitalWrite(PIN_A, (mask & MASK_A) ? HIGH : LOW);

И точно также в строке 78

// вместо
digitalWrite(all_postions[i], pos != i);

// пишем
digitalWrite(all_postions[i], (pos != i) ? HIGH : LOW);

 

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

протеус не кабенится, проставил pinMode, проставил пины в define. но я очень мало знаю о командах ардуино и после строки кода  

#define D9  (MASK_A | MASK_B | MASK_C | MASK_D | MASK_F | MASK_G)



//
//  Функция устанавливает по маске - параметру (HIGH-горит, LOW-не горит)
//

 все перестает быть понятным

void setRawSegments(const int8_t mask) { // я так понимаю void начало функции, setRawSegments это название
// функции а вот в скобках не понимаю, предположения: const int8_t это значит что тип данных может быть только 
//8 чего-то. а mask это новая переменная. но так же непонятная((( 
  digitalWrite(PIN_A, mask & MASK_A);
  digitalWrite(PIN_B, mask & MASK_B);
  digitalWrite(PIN_C, mask & MASK_C);
  digitalWrite(PIN_D, mask & MASK_D);
  digitalWrite(PIN_E, mask & MASK_E);
  digitalWrite(PIN_F, mask & MASK_F);
  digitalWrite(PIN_G, mask & MASK_G);
  digitalWrite(PIN_DP, mask & MASK_DP);
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Так оно заработало?

Если "нет", то говорите как себя ведёт. Если "да", то давайте снинмать вопросы прежде, чем двигаться дальше.

d13lider пишет:

 все перестает быть понятным

void setRawSegments(const int8_t mask) { // я так понимаю void начало функции, setRawSegments это название
// функции а вот в скобках не понимаю, предположения: const int8_t это значит что тип данных может быть только 
//8 чего-то. а mask это новая переменная. но так же непонятная((( 
 

Функция - это кусочек программы. который можно вызывать много раз из разных место для выполнения одних и тех же действий.

При описании функции в простейшем случае указывается тип возвращаемого значения (или void - ели возвращать ничего не нужно, имя функции и её параметры.

Давйте на маленьких примерах:

1. функция сладывает два числа (это её параметры) и возвращает результат:


//	
//	Функция принимает два параметра a и b типа const int 
//	Возвращает их сумму
//
int sum2(const int a, const int b) {
	return a + b; // слово return означает "вернуть значение"
}

void setup() {
	Serial.begin(115200);
	int d = 13;
	int c = 23;
	Serial.println(sum2(1,2)); //	должно напечататься 3
	Serial.println(sum2(d,15)); //	должно напечататься 28
	Serial.println(sum2(d,c)); //	должно напечататься 36
}

void loop() {}

Теперь пример функции, которая ничего не возвращает. Тогда тип функции нужно указывать как void. Данные функции получают два параметра - первый пин и последний пин. Что они делают, написано в комментариях.

//	
//	Функция принимает два параметра startPin и endPin типа const int 
//	Устанавливает режим OUTPUT для всех пинов со startPin по endPin включительно
//
void modeOutputAll(const int startPin, const int endPin) {
	for (int i = startPin; i <= endPin; i++) {
		pinMode(i, OUTPUT);
	}
}

//	
//	Функция принимает два параметра startPin и endPin типа const int 
//	Устанавливает HIGH для всех пинов со startPin по endPin включительно
//
void highAll(const int startPin, const int endPin) {
	for (int i = startPin; i <= endPin; i++) {
		digitalWrite(i, HIGH);
	}
}

void setup() {
	modeOutputAll(3, 10); //	Поставим пины с 3 по 10 в OUTPUT
	highAll(5, 7);	// Выведем HIGH на пины 5, 6 и 7
}

void loop() {}

Слово const в описании типа параметра означает. что я не собираюсь его менять. Это подсказка компилятору, чтобы ему легче было оптимизировать код. В принципе его можно опустить.

Стао понятнее? Нес стесняйтесь спрашивать. Прежде, чем мы пойдём дальше, надо снять все вопросы.

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

с функциями понял, спасибо. понял логику программы. но не понятно почему после int ставиться 8_t

а потом еще и прибавляется u int8_t

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

d13lider пишет:

с функциями понял, спасибо. понял логику программы. но не понятно почему после int ставиться 8_t

а потом еще и прибавляется u int8_t

8_t в данном случае означает, что int не двухбайтовы, а однобайтовый (нафига расходовать лишний байт, если и этого хватает?)

u в начале означает, что число беззнаковое и отрицательным не бывает.

Вы всё поняли и готовы "ехать дальше"?

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

еще почитал про "&" "побитовое И" но не понял для чего он нужен. ну как не понял( догадки есть) как я думаю это что бы сложить 2 числа 

допустим имея 10010011 и 11010110 получаем  10010010? это вы делаете я так понял для того что бы задать HIGH или LOW? грубо говоря

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

я так понял мы уже занимаемся на уровне "С" языка)))) и грубо говоря чуть ли не логику построение программы на уровне "понимания" процессором составляем 0100010101000100010101010011010010101010001010101001010010101010100101001010010, всмысле компелятору почти трудиться не придется)))

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

а да, прошу прощения, все заработало в proteus

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

d13lider пишет:

еще почитал про "&" "побитовое И" но не понял для чего он нужен. ну как не понял( догадки есть) как я думаю это что бы сложить 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. Вот так я это делаю:

setRawSegments (MASK_A | MASK_D | MASK_E | MASK_F);

Давайте просто пальцем вести по тексту функции setRawSegments и думать что она делает. 

setRawSegments (MASK_A | MASK_D | MASK_E | MASK_F);

...

void setRawSegments(const int8_t mask) {
// передано MASK_A | MASK_D | MASK_E | MASK_F
//	значит mask равно MASK_A | MASK_D | MASK_E | MASK_F

	digitalWrite(PIN_A, mask & MASK_A);   //  операция & даст НЕ_0 (он же HIGH), т.к. MASK_А присутствует в mask - зажигаем
	digitalWrite(PIN_B, mask & MASK_B);   //  операция & даст 0 (он же LOW), т.к. MASK_B не присутствует в mask - гасим
	digitalWrite(PIN_C, mask & MASK_C);   //  операция & даст 0 (он же LOW), т.к. MASK_C не присутствует в mask - гасим
	digitalWrite(PIN_D, mask & MASK_D);   //  операция & даст НЕ_0 (он же HIGH), т.к. MASK_В присутствует в mask - зажигаем
	digitalWrite(PIN_E, mask & MASK_E);   //  и т.д.
	digitalWrite(PIN_F, mask & MASK_F);
	digitalWrite(PIN_G, mask & MASK_G);
	digitalWrite(PIN_DP, mask & MASK_DP);
}

Попробуйте сами нарисовать хоть букву H - или там ещё чего и так же рассуждайте.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Нам осталось совсем немного.

1. сделать чтобы показывалось честное двузначное число пока на delay'ях

2. перейти от delay'ев к таймеру.

Если хотите, на закуску, можем о виртуальных экранах поговорить.

Как будете готовы продолжать, скажите.

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

ЕвгенийП пишет:

Нам осталось совсем немного.

1. сделать чтобы показывалось честное двузначное число пока на delay'ях

2. перейти от delay'ев к таймеру.

Если хотите, на закуску, можем о виртуальных экранах поговорить.

Как будете готовы продолжать, скажите.

хорошо, пока я все перевариваю. пытаюсь понять когда какая цифра приходит и что с ней становится в последствии начиная со строки 

 106 showDigit(cnt, cnt & 1);

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

d13lider пишет:

 106 showDigit(cnt, cnt & 1);

Ну, это простая строка. У функции showDigit два параметра - первый число, которое нужно показать. Второй - позиция в которой его нужно показывать.

Показываем мы наш счётчик cnt.

Позицию мы вычисляет побитовой операцией & - т.е. мы выделяем самый младший бит счётчика. Если младший бит равен нулю (cnt чётное), то "cnt & 1" - будет равно 0. Если младший бит cnt равен 1 (т.е. cnt - нечётное), то "cnt & 1" - будет равно 1.

Кстати, коль уж пошла такая пьянка, в следующей строке используется операция "отстаок от деления".

cnt = (cnt + 1) % 10;

Т.е. мы прибавляем 1 к счётчику и берём остаток от деления результата на 10. Таки образома счётчки будет расти от 0 до 9. ПОтом снова станет 0 (т.к. отстаок от деления (9+1) на 10 равен нулю) и снова будет расти до 9, потом снова станет 0 и так до посинения.

Обратите внимене, что в строке

showDigit(cnt, cnt & 1);

Можно было вместо & использовать остаток от деления на 2 и написать

showDigit(cnt, cnt % 2);

ничего бы не изменилось абсолютно. У чётных чисел остаток от деления на 2 равен нулю, а у нечётных - 1.

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

ЕвгенийП пишет:

 

Ну, это простая строка. У функции showDigit два параметра - первый число, которое нужно показать. Второй - позиция в которой его нужно показывать.

Показываем мы наш счётчик cnt.

Позицию мы вычисляет побитовой операцией & - т.е. мы выделяем самый младший бит счётчика. Если младший бит равен нулю (cnt чётное), то "cnt & 1" - будет равно 0. Если младший бит cnt равен 1 (т.е. cnt - нечётное), то "cnt & 1" - будет равно 1.

Кстати, коль уж пошла такая пьянка, в следующей строке используется операция "отстаок от деления".

cnt = (cnt + 1) % 10;

Т.е. мы прибавляем 1 к счётчику и берём остаток от деления результата на 10. Таки образома счётчки будет расти от 0 до 9. ПОтом снова станет 0 (т.к. отстаок от деления (9+1) на 10 равен нулю) и снова будет расти до 9, потом снова станет 0 и так до посинения.

Обратите внимене, что в строке

showDigit(cnt, cnt & 1);

Можно было вместо & использовать остаток от деления на 2 и написать

showDigit(cnt, cnt % 2);

ничего бы не изменилось абсолютно. У чётных чисел остаток от деления на 2 равен нулю, а у нечётных - 1.

спасибо, я так и думал, но были сомнения, вы их развеяли. еще не попробовал нарисовать. т.е. я понял что бы нарисовать H ее надо определить в маску т.е. дописать 

#define D10  ( MASK_B | MASK_C | MASK_E | MASK_F | MASK_G)
// потом в строчке 
static const uint8_t all_digits[] = { D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10 }; 
// дописываем D10

и программа будет уже выдавать 0-1-2-3-4-5-6-7-8-9-H

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

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

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

да кстати еще одну строчку надо заменить.

cnt = (cnt + 1) % 11;

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

d13lider пишет:

спасибо, я так и думал, но были сомнения, вы их развеяли. еще не попробовал нарисовать. т.е. я понял что бы нарисовать H ее надо определить в маску т.е. дописать 

#define D10  ( MASK_B | MASK_C | MASK_E | MASK_F | MASK_G)  
// потом в строчке 
static const uint8_t all_digits[] = { D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10 }; 
// дописываем D10

и программа будет уже выдавать 0-1-2-3-4-5-6-7-8-9-H

Не совсем. Первая из Ваших строк нужна, а вот во второй ничего менять не нужно, т.к. функция в которой эта строка живёт всё равно предназначена только для цифр.

Вы можете сделать так. В define опредеоить все символы, каке Вам хочется, например (я скопировал пример из своего проекта, а там у меня названия не типа MASK_A как я Вам написал, а типа A_MASK - переделайте уж сами):

#define SYMBOL_MINUS (G_MASK)

#define SYMBOL_A (A_MASK | B_MASK | C_MASK | E_MASK | F_MASK | G_MASK)
#define SYMBOL_F (A_MASK | D_MASK | E_MASK | F_MASK | G_MASK)
#define SYMBOL_C (A_MASK | E_MASK | F_MASK | D_MASK)
#define SYMBOL_E (A_MASK | D_MASK | E_MASK | F_MASK | G_MASK)
#define SYMBOL_H (B_MASK | C_MASK | E_MASK | F_MASK | G_MASK)
#define SYMBOL_P (A_MASK | B_MASK | E_MASK | F_MASK | G_MASK)
#define SYMBOL_G (A_MASK | E_MASK | F_MASK)
#define SYMBOL_L (D_MASK | E_MASK | F_MASK)
#define SYMBOL_F (A_MASK | E_MASK | F_MASK | G_MASK)
#define SYMBOL_d (B_MASK | C_MASK | D_MASK | E_MASK | G_MASK)
#define SYMBOL_b (C_MASK | D_MASK | E_MASK | F_MASK | G_MASK)

а использовать ихх прямо так, смотрите:

setRawSegments(SYMBOL_A); // Рисуем букву А
setRawSegments(SYMBOL_E); // Рисуем букву E

Ничего другого менять не нужно.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

d13lider пишет:

да кстати еще одну строчку надо заменить.

cnt = (cnt + 1) % 11;

Ну, это только если Вы хотите, чтобы они подряд показывались. Но смысла в этом нет. НЕ_ЦИФРЫ лучше показывать отдельно, как я описал в прошлом посте.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

d13lider пишет:

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

Мы это делаем, чтобы отделить показ от собственно программы. Программа у нас будет просто записывать нужное для показа число в нужное место и совершенно не париться о показе. Показом будет заниматься программа обработки переполнения таймера сама по себе. Т.е. дело программы просто в нужное место положить число, а показ - он должен своей жизнью жить.

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015
void loop() {
  static uint8_t cnt = 0;
  showDigit(cnt, cnt & 1);
  cnt = (cnt + 1);
  if (cnt == 11)
  {
    cnt = 0;
  }
  delay(500);
}

 

 еще можно записать так, но так больше код. и почему то не могу понять, когда выскакивает последняя буква "H" и переходит все к "0" то ноль загорается на том же разряде(цифре) что и "H"
d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

все понял кроме последнего поста, на счет перебора цифр. понял что буквы лучше отдельно создать, так визуально лучше выглядит

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

ЕвгенийП  а вы в каком городе живете? по соотношении с Московским временем какая разница в часах?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

d13lider пишет:
почему то не могу понять, когда выскакивает последняя буква "H" и переходит все к "0" то ноль загорается на том же разряде(цифре) что и "H"

Это правильно. 9 - нечётное число - показывается в 1 разряде. Н (типа 10) - чётное и показывается в нулевом разряде. 0 - тоже чётное и потому показывается тоже в нулевом разряде.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

d13lider пишет:

ЕвгенийП  а вы в каком городе живете? по соотношении с Московским временем какая разница в часах?

Нет, никакой. Переславль-Залесский, это 130 вёрст от Москвы по ярославской дороге.

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

ЕвгенийП пишет:

 

Это правильно. 9 - нечётное число - показывается в 1 разряде. Н (типа 10) - чётное и показывается в нулевом разряде. 0 - тоже чётное и потому показывается тоже в нулевом разряде.

так и думал, спасибо

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

продолжим или до завтра отложим?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Работаем. Я здесь просто большой пост пишу

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

d13lider пишет:

все понял кроме последнего поста, на счет перебора цифр. понял что буквы лучше отдельно создать, так визуально лучше выглядит

Поехали дальше.

Теперь попробуем показать нормальное двузначное число.

Для начала заведём переменную для этого числа - пусть она будет, скажем однобайтовой беззнаковой, т.е. 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.

Если есть вопросы, задавайте.

Нам осталось только перейти к таймеру (ну и если хотите поговорить о виртуальных экранах).
 

 

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

ЕвгенийП пишет:

Поехали дальше.

Теперь попробуем показать нормальное двузначное число.

Для начала заведём переменную для этого числа - пусть она будет, скажем однобайтовой беззнаковой, т.е. 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

и поменял цифры местами все заработало

что такое виртуальные экраны? хочу знать)

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

P.S. купил индикатор , где то в интернете прочитал что резисторы по 100ом для них идут для подключения к МК. взял и их еще. 

vk007
Offline
Зарегистрирован: 16.06.2015

Насчет токоограничительных резисторов. Не надо гадать и где-то читать, кому и что подходит - лучше самому рассчитать. Если сложно самому, то в интернете есть куча онлайн калькуляторов для их расчетов. Например, вот.

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

Итак, заполняем: питание 5В; выбираем по цвету свечения, например, красный светодиод (для него прямое напряжение 1.9В и ток 20 мА); к-во 1 и получаем сопротивление 160 Ом (там же смотрим его мощность). Но учитывая, что наши светодиоды будут работать в импульсном режиме, то для компенсации яркости допустимо сопротивление немного уменьшить.

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

зеленый светодиод

vk007
Offline
Зарегистрирован: 16.06.2015

Там в списке зеленый тоже имеется :)

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

10 ом мне кажется маловато.

Коллега Вам правильно сказал, что нужно расчитать, но тут есть нюанс.

У ардуины заявлено, что HIGH =  5В, на практике же мы часто видим сьльно меньше (4,7 и даже 4.5) это нормально, в даташите контроллера сказано, что HIGH от 0,7 VCC, т.е. ото 3.5 вольт. Поэтому, я бы взял резистор где-то 150, поставил и померял бы ток. Если ток сильно меньше 20мА, взял бы резистор поменьше (если ток больше - то резистор побольше) и подобрал бы такой. чтобы ток был как можно ближе к 20мА (но не больше). Т.е. просто подобрал бы на конкретном железе.

Кроме того, напряжение просядет ещё на 0,6 - 0,7 вольта за счёт падени на транзисторе (на переходе коллектор-эмиттер).

Здесь это важно, т.к. светодиоды в динамических индикаторах светятся не всё время, поэтому чем ярче, тем лучше.

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

да,рассчитал надо для 5В 140Ом ближайший 150. так что зря 5  рублей за 10 резисторов потратил((( эх... ладно поднакаплю в следующем месяце и куплю))) 

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

даташит не нашел, 3 первые страницы гугла. только схема подключения. а про токи ничего(