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

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

Вы что ему таймер ломаете? Если нормально при одинаковых цифрах, то похоже ...

В общем, хотите разговора, а не флуда, подробности об индикаторе, схему подклюучения и скетч в студию.

uragan
Offline
Зарегистрирован: 23.02.2015

Почему ломаю? Схема один в один как у ТС, только катоды через ULN. Секундомер на двух регистрах работает на любых из трех. Изменение таймера с двух на три проходит, а дальше затык. Программа последняя, приведенная в топике, один в один, не работает с теми же симптомами. Буду дальше разбираться.

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

Программа с велосипедом работает.

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

uragan пишет:

Программа с велосипедом работает.

О-О////

uragan
Offline
Зарегистрирован: 23.02.2015

Не очень понял почему такой щенячий восторг. Число 666 пишется нормально, но если попробовать записать другое число, с разными цифрами, то все - засвечивается абракадабра. Посмотрел еще раз внимательно на велосипед. Центральная ось рисуется не на центральном регистре, а на крайних.

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

uragan пишет:

Не очень понял почему такой щенячий восторг. Число 666 пишется нормально, но если попробовать записать другое число, с разными цифрами, то все - засвечивается абракадабра. Посмотрел еще раз внимательно на велосипед. Центральная ось рисуется не на центральном регистре, а на крайних.

ты скетч опубликуешь или будешь продолжать мосг ебать?

uragan
Offline
Зарегистрирован: 23.02.2015

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

Для двух разрядного все работают, для трех ни один.

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

uragan пишет:

Центральная ось рисуется не на центральном регистре, а на крайних.

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

uragan
Offline
Зарегистрирован: 23.02.2015

И в центровом регистре тоже педали крутятся без оси. Но больше всего смущает цифра 666.

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

#define PIN_DIG0  15
#define PIN_DIG1  16
#define PIN_DIG2  14

//
//	Определение масок для сегментов
//
#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);
}
 volatile unsigned numberToShow =68;
// #define	PRESACLER	(1 << CS11)	//	Соответствует делителю частоты 8
//#define	TICKS		((uint16_t)(65536ul - 20000ul))	// Оставляет 20000 тиков до переполнения
#define  PRESACLER (1<<CS11)|(1<<CS10) //  Соответствует делителю частоты 64
#define TICKS   ((uint16_t)(65536ul - 1666ul)) // Оставляет 1666 тиков до переполнения ( 64*1666/16000 == 6,664 миллисекунды)



//
// Инициализация таймера. делается один раз
//
void setupTimer2(void) {
	PRR &= ~(1 << PRTIM1);	// Убедимся, что таймер 1 не отключен
	TCCR1A = 0;					// Установим Normal режим
	TCCR1B = PRESACLER;		// Установим делитель частоты 
	TCNT1 = TICKS;				// Установим счётчик
	TIMSK1 |= (1 << TOIE1);	// Разрешим прерывание по переполнению
	TIFR1 = 1;					//	Очистим Очистим флаг прерывания (если он взведён)
}

//
// Обработка прерывания по переполнению
//
ISR(TIMER1_OVF_vect) {
	TCNT1 = TICKS;				// Установим счётчик для следующего прерывания
	//
	//	Покажем очередную цифру, как мы это делали раньше
	//
static uint8_t currentDigit = 0;

	const uint8_t digitToShow = (currentDigit) ? numberToShow / 10 : numberToShow % 10;
	showDigit(digitToShow, currentDigit);
	currentDigit = (currentDigit + 1) % 2;	// В следующий раз показываем другую цифру


}

//
//	Всё, что выше  - это своя жизнь. От основной программы требуется только 
//	положить число для показа в numberToShow и оно будет показываться.
//	Больше основная программа ни о чём не заботится
//
///////////////////////////////////////////////////////////////////////////////////

void setup() {
	setupTimer2();
  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(14, OUTPUT);
  pinMode(15, OUTPUT);
  pinMode(16, OUTPUT);
}


//
// Здесь реализован простейший секундомер
//
void loop() {
	static int8_t counter = 0;
	numberToShow = counter;	//	теперь это число будет показываться
	counter = (counter + 1) % 100;
	delay(1000);
}
 
 

 

uragan
Offline
Зарегистрирован: 23.02.2015

#define PIN_A 7
#define PIN_B 9
#define PIN_C 5
#define PIN_D 3
#define PIN_E 2
#define PIN_F 8
#define PIN_G 6
#define PIN_DP  4

#define PIN_DIG0  14
#define PIN_DIG1  15
#define PIN_DIG2  16
//
//  Определение пинов для сегментов
//  (поставьте Ваши пины, у меня мелкий экран и плохо видно какие там у Вас)

//
#define  PRESACLER (1<<CS11)|(1<<CS10) //  Соответствует делителю частоты 8
#define TICKS   ((uint16_t)(65536ul - 1666ul)) // Оставляет 20000 тиков до переполнения



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

//
//  Определение масок для сегментов
//
#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)

volatile unsigned numberToShow = 0;

//
//  Функция устанавливает по маске - параметру (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, PIN_DIG2 }; 
  for (register uint8_t i = 0; i < sizeof(all_postions) / sizeof(all_postions[0]); i++) {
    digitalWrite(all_postions[i], pos != i);
  }
  setSegments(d);
}

//
// Инициализация таймера. делается один раз
//
void setupTimer2(void) {
  PRR &= ~(1 << PRTIM1);  // Убедимся, что таймер 1 не отключен
  TCCR1A = 0;         // Установим Normal режим
  TCCR1B = PRESACLER;   // Установим делитель частоты 
  TCNT1 = TICKS;        // Установим счётчик
  TIMSK1 |= (1 << TOIE1); // Разрешим прерывание по переполнению
  TIFR1 = 1;          //  Очистим Очистим флаг прерывания (если он взведён)
}
//
// Обработка прерывания по переполнению
//
ISR(TIMER1_OVF_vect) {
  TCNT1 = TICKS;        // Установим счётчик для следующего прерывания
  //
  //  Покажем очередную цифру, как мы это делали раньше
  //
static uint8_t currentDigit ;
uint8_t digitToShow ;
  if (currentDigit == 0) digitToShow = numberToShow / 100;
else if (currentDigit == 1) digitToShow = (numberToShow % 100) / 10;
else digitToShow = numberToShow % 10;
  showDigit(digitToShow, currentDigit);
  currentDigit = (currentDigit + 1)%3;   // В следующий раз показываем другую цифру

}

//
//  Всё, что выше  - это своя жизнь. От основной программы требуется только 
//  положить число для показа в numberToShow и оно будет показываться.
//  Больше основная программа ни о чём не заботится
//
///////////////////////////////////////////////////////////////////////////////////


void setup() {
  setupTimer2();
    // ... задайте все pinMode как раньше
    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(14, OUTPUT);
  pinMode(15, OUTPUT);
  pinMode(16, OUTPUT); 


                            
}

//  
//  я считаю, что нулевая цмфра слева (единицы), а первая справа (десятки)
//  если у Вас по-другому - поменяйте.
//
void loop() {
 

numberToShow = 123;

}//
//

 

uragan
Offline
Зарегистрирован: 23.02.2015

Первый код с секундомером работает на любых двух регистрах.  Второй если цифры одинаковые, показывает нормально, если разные - нет.

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

Ну, Вас просили ещё подробности об индикаторе и схему подключения. И кстати, я не понял фразы "работает на любых двух регистрах", поясните. Также не пноял "не показывает нормально". - а как показывает?

uragan
Offline
Зарегистрирован: 23.02.2015

На любых - программно менял номера пинов. Таким образом проверял что все подключено правильно.

Почти все сегменты светятся, но с разной яркостью.

В велосипеде , вроде бы, сегменты высвечиваются наооборот. 

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

uragan
Offline
Зарегистрирован: 23.02.2015

Разобрался. Общий катод, поэтому в соответствующем месте надо ставить 1, а не 0.

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

Спасибо ЕвгенийП за науку.

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

Не за что, только заметьте, я дважды (здесь и здесь) просил Вас дать мне подробности об индикаторе (например ссылку на товар у продавца или модель) и схему. Вы игнорировали. дали, давно б разобрались. Хотя и лучше, что Вы сами всё раскопали. Это полезнее, чем если бы я за Вас это сделал.

uragan
Offline
Зарегистрирован: 23.02.2015

И это тоже заметил. Работающий секундомер заставлял в этом сомневаться.

BOOM
BOOM аватар
Онлайн
Зарегистрирован: 14.11.2018

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

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

Гораздо проще скзать, что к одному физическому экрану у меня привязано N виртуальных. На каждую функцию свой собственный виртуальный экран. Тогда допустим, часы ничего не проверяют, а тупо выводят время на свой собственный экран всегда. Тоже самое термометр ничего не проверяет, а просто всегда выводит температуру на свой собственный экран. То есть всё упростилось. Всё выглядит так, как будто у них в вправду собственные экраны. Они (часы или термометр) вообще-то понятия не имеют и знать не хотят, что именно сейчас показывается на реальном экране - они выводят свои данные на виртуальный экран и не парятся ни о чём.

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

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

Концепция понятна? 

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

Ну, мы до этого ещё доберёмся если интересно. 

Мне интересна реализация в примере, если можно. 

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

ну это ж тривиально, не?

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

несколько структур 

{

char Line1[16];

char Line2[16];

}

и актуальный указатель для вывода одной из них.   Сам не догадаешь? 

BOOM
BOOM аватар
Онлайн
Зарегистрирован: 14.11.2018

То есть так банально? Потом на реальном дисплее просто печатать обе эти линии, при необходимости?

Я думал что то по мудрее....

BOOM
BOOM аватар
Онлайн
Зарегистрирован: 14.11.2018

Ещё вопрос о функции вывода на печать на реальный дисплей.
Получается, что при таком подходе приходится полностью весь дисплей обновлять (перерисовывать/перепечатывать) на каждом такте/раз в N-тактов? Или как быть? У меня сейчас в проекте данные обновляются на дисплее только если они изменились. При подходе с виртуальными дисплеями такое реализуемо?

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

DetSimen пишет:

несколько структур 

А в случае семисегментника, так и несколько чисел :)

astwo
Offline
Зарегистрирован: 10.07.2019

Не хотелось мудрсвовать но ладно. Есть код прикладной. Ну тот когда надо поменять контент программы сообщения, место и порядок надписей. А есть все остальное. Остальное тоже не однородно. Работа с виртуальными экранами это уровень обработки данных. Что то похожее на String. Может в большой упаковке, а может в виде рассыпи отдельных функций и структуры приведённой вышн. А есть канальный уровень. Это код который эти данные забрасывать уже на чип дисплея.

BOOM
BOOM аватар
Онлайн
Зарегистрирован: 14.11.2018

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

Как я это вижу? Флаг - «Что то изменилось, надо бы перерисовать дисплей». Его же можно и в примере с меняющимися часами и температурой использовать для смены «кадра». Не?

astwo
Offline
Зарегистрирован: 10.07.2019

Ну вспомни библиотеку для лсд1602 и2с. Там гибрид. Что туда напечатано. То на экран и отправлено. Но если сделать промежуточный объект. И туда печатать. Конечно на экране ничего нет. Что бы было надо создавать ещё объект который будет настраивать канал и2с и чип дисплея. А когда надо показать то даётся команда отправить этот виртуальный дисплей на отображение реального.

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

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

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

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

BOOM
BOOM аватар
Онлайн
Зарегистрирован: 14.11.2018

Я iic не использую, мне и так пинов хватает. 
Собственно заинтересовала идея виртуальных дисплеев, но не хочется на каждом такте дисплей перерисовывать. А так как в программировании я ещё как котёнок, хотелось бы у более опытных участников форума узнать по максимуму. 

astwo
Offline
Зарегистрирован: 10.07.2019

Информация с датчиков приходит асинхроно. Да и датчиков море. Вот и приходится хранить все данные. Вдруг вот как раз их надо показать на экране. А так напечатал на экране значение и забыл. Нужный экран всегда готов к показу. Код упрощается. Да и по памяти перерасход не большой.

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

Данные хранить надо в любом случае. Как их можно забывать?