Почему ломаю? Схема один в один как у ТС, только катоды через ULN. Секундомер на двух регистрах работает на любых из трех. Изменение таймера с двух на три проходит, а дальше затык. Программа последняя, приведенная в топике, один в один, не работает с теми же симптомами. Буду дальше разбираться.
Сильно помогло бы, если в программе велосипед в лупе привели бы образец как цифру выводить.
Не очень понял почему такой щенячий восторг. Число 666 пишется нормально, но если попробовать записать другое число, с разными цифрами, то все - засвечивается абракадабра. Посмотрел еще раз внимательно на велосипед. Центральная ось рисуется не на центральном регистре, а на крайних.
Не очень понял почему такой щенячий восторг. Число 666 пишется нормально, но если попробовать записать другое число, с разными цифрами, то все - засвечивается абракадабра. Посмотрел еще раз внимательно на велосипед. Центральная ось рисуется не на центральном регистре, а на крайних.
ты скетч опубликуешь или будешь продолжать мосг ебать?
Ну, Вас просили ещё подробности об индикаторе и схему подключения. И кстати, я не понял фразы "работает на любых двух регистрах", поясните. Также не пноял "не показывает нормально". - а как показывает?
Не за что, только заметьте, я дважды (здесь и здесь) просил Вас дать мне подробности об индикаторе (например ссылку на товар у продавца или модель) и схему. Вы игнорировали. дали, давно б разобрались. Хотя и лучше, что Вы сами всё раскопали. Это полезнее, чем если бы я за Вас это сделал.
Виртуальные экраны это вот что такое. Вот представьте ради-часы или автомагнитолу - у этих устройств частенько один и тот ;е экран используется для разных целей. То показывает время, то частоту радиостанции, то настройки громкости и баланса и т.п. в зависимости от нажатия каких-то кнопок.
Гораздо проще скзать, что к одному физическому экрану у меня привязано N виртуальных. На каждую функцию свой собственный виртуальный экран. Тогда допустим, часы ничего не проверяют, а тупо выводят время на свой собственный экран всегда. Тоже самое термометр ничего не проверяет, а просто всегда выводит температуру на свой собственный экран. То есть всё упростилось. Всё выглядит так, как будто у них в вправду собственные экраны. Они (часы или термометр) вообще-то понятия не имеют и знать не хотят, что именно сейчас показывается на реальном экране - они выводят свои данные на виртуальный экран и не парятся ни о чём.
Ну и есть функция, которая по каким-то нажатиям кнопок или ещё по каким командам, просто переключает физический экран с одного виртуального на другой.
Вот допустим, Вы посмотрели температуру. Затем экран переключился на время. Но термометр каждую минуту исправно пишет новую температуру на свой виртуальный экранчик, которого никто видит. Затем Вы нажимаете кнопку, физически экран переходит с виртуального экрана часов на виртуальных экран термометра и Вы видите новую, текущую температуру (он же её в виртуальном экране регулярно обновлял). При этом ни часы, ни термометр не знают о том, что Вы переключали физический экран с одного виртуального на другой - они вообще про физический экран ничего не знают - они пишут в свои виртуальные и спят спокойно.
Концепция понятна?
реализуется это гораздо проще и короче, чем объясняется. Виртуальный экран - это просто переменная типа нашей numberToShow - своя для каждой функции. А переключатель - это программа из трёх строк, которая определяет какую из этих "numberToShow" отображать на физическом экране. Вот и вся реализация.
Ещё вопрос о функции вывода на печать на реальный дисплей.
Получается, что при таком подходе приходится полностью весь дисплей обновлять (перерисовывать/перепечатывать) на каждом такте/раз в N-тактов? Или как быть? У меня сейчас в проекте данные обновляются на дисплее только если они изменились. При подходе с виртуальными дисплеями такое реализуемо?
Не хотелось мудрсвовать но ладно. Есть код прикладной. Ну тот когда надо поменять контент программы сообщения, место и порядок надписей. А есть все остальное. Остальное тоже не однородно. Работа с виртуальными экранами это уровень обработки данных. Что то похожее на String. Может в большой упаковке, а может в виде рассыпи отдельных функций и структуры приведённой вышн. А есть канальный уровень. Это код который эти данные забрасывать уже на чип дисплея.
Не хочу показаться камнем без острых углов, но я все же не совсем понял как канальный уровень поймёт, что на прикладном уровне произошли изменения в отображаемой информации и надо дисплей перерисовать?
Как я это вижу? Флаг - «Что то изменилось, надо бы перерисовать дисплей». Его же можно и в примере с меняющимися часами и температурой использовать для смены «кадра». Не?
Ну вспомни библиотеку для лсд1602 и2с. Там гибрид. Что туда напечатано. То на экран и отправлено. Но если сделать промежуточный объект. И туда печатать. Конечно на экране ничего нет. Что бы было надо создавать ещё объект который будет настраивать канал и2с и чип дисплея. А когда надо показать то даётся команда отправить этот виртуальный дисплей на отображение реального.
Все зависит от задачи, я предпочитаю сохранять данные от разных функций в памяти, а уже отдельная часть логики решает что и когда выводить.
PS. Мало с дисплеями работал, а меню вообще страдание, все таки железка которая сама решает как жить программируется проще. Впрочем дело вкуса.
Я iic не использую, мне и так пинов хватает.
Собственно заинтересовала идея виртуальных дисплеев, но не хочется на каждом такте дисплей перерисовывать. А так как в программировании я ещё как котёнок, хотелось бы у более опытных участников форума узнать по максимуму.
Информация с датчиков приходит асинхроно. Да и датчиков море. Вот и приходится хранить все данные. Вдруг вот как раз их надо показать на экране. А так напечатал на экране значение и забыл. Нужный экран всегда готов к показу. Код упрощается. Да и по памяти перерасход не большой.
Вы что ему таймер ломаете? Если нормально при одинаковых цифрах, то похоже ...
В общем, хотите разговора, а не флуда, подробности об индикаторе, схему подклюучения и скетч в студию.
Почему ломаю? Схема один в один как у ТС, только катоды через ULN. Секундомер на двух регистрах работает на любых из трех. Изменение таймера с двух на три проходит, а дальше затык. Программа последняя, приведенная в топике, один в один, не работает с теми же симптомами. Буду дальше разбираться.
Сильно помогло бы, если в программе велосипед в лупе привели бы образец как цифру выводить.
Программа с велосипедом работает.
Программа с велосипедом работает.
О-О////
Не очень понял почему такой щенячий восторг. Число 666 пишется нормально, но если попробовать записать другое число, с разными цифрами, то все - засвечивается абракадабра. Посмотрел еще раз внимательно на велосипед. Центральная ось рисуется не на центральном регистре, а на крайних.
Не очень понял почему такой щенячий восторг. Число 666 пишется нормально, но если попробовать записать другое число, с разными цифрами, то все - засвечивается абракадабра. Посмотрел еще раз внимательно на велосипед. Центральная ось рисуется не на центральном регистре, а на крайних.
ты скетч опубликуешь или будешь продолжать мосг ебать?
В смысле сделать копию любого скетча для трехрегистрового индикатора из этой темы? Могу даже пины воткнуть в те же адреса. Тоже мысль.
Для двух разрядного все работают, для трех ни один.
Центральная ось рисуется не на центральном регистре, а на крайних.
Интересно девки пляшут. У велосипеда должна быть центральная ось в центре, а по краям педали крутятся в противофазе.
И в центровом регистре тоже педали крутятся без оси. Но больше всего смущает цифра 666.
// // // Определение пинов для сегментов // (поставьте Ваши пины, у меня мелкий экран и плохо видно какие там у Вас) #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); }#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; }// //Первый код с секундомером работает на любых двух регистрах. Второй если цифры одинаковые, показывает нормально, если разные - нет.
Ну, Вас просили ещё подробности об индикаторе и схему подключения. И кстати, я не понял фразы "работает на любых двух регистрах", поясните. Также не пноял "не показывает нормально". - а как показывает?
На любых - программно менял номера пинов. Таким образом проверял что все подключено правильно.
Почти все сегменты светятся, но с разной яркостью.
В велосипеде , вроде бы, сегменты высвечиваются наооборот.
Из того что пробовал. Если принудительно в функции, которую обрабатывает таймер, написать цифру в каком-нибудь сегменте - исправно пишет.
Разобрался. Общий катод, поэтому в соответствующем месте надо ставить 1, а не 0.
Перетащил из обработчика в лоор , поставил большой делай, сразу увидел.
Спасибо ЕвгенийП за науку.
Не за что, только заметьте, я дважды (здесь и здесь) просил Вас дать мне подробности об индикаторе (например ссылку на товар у продавца или модель) и схему. Вы игнорировали. дали, давно б разобрались. Хотя и лучше, что Вы сами всё раскопали. Это полезнее, чем если бы я за Вас это сделал.
И это тоже заметил. Работающий секундомер заставлял в этом сомневаться.
Виртуальные экраны это вот что такое. Вот представьте ради-часы или автомагнитолу - у этих устройств частенько один и тот ;е экран используется для разных целей. То показывает время, то частоту радиостанции, то настройки громкости и баланса и т.п. в зависимости от нажатия каких-то кнопок.
Гораздо проще скзать, что к одному физическому экрану у меня привязано N виртуальных. На каждую функцию свой собственный виртуальный экран. Тогда допустим, часы ничего не проверяют, а тупо выводят время на свой собственный экран всегда. Тоже самое термометр ничего не проверяет, а просто всегда выводит температуру на свой собственный экран. То есть всё упростилось. Всё выглядит так, как будто у них в вправду собственные экраны. Они (часы или термометр) вообще-то понятия не имеют и знать не хотят, что именно сейчас показывается на реальном экране - они выводят свои данные на виртуальный экран и не парятся ни о чём.
Ну и есть функция, которая по каким-то нажатиям кнопок или ещё по каким командам, просто переключает физический экран с одного виртуального на другой.
Вот допустим, Вы посмотрели температуру. Затем экран переключился на время. Но термометр каждую минуту исправно пишет новую температуру на свой виртуальный экранчик, которого никто видит. Затем Вы нажимаете кнопку, физически экран переходит с виртуального экрана часов на виртуальных экран термометра и Вы видите новую, текущую температуру (он же её в виртуальном экране регулярно обновлял). При этом ни часы, ни термометр не знают о том, что Вы переключали физический экран с одного виртуального на другой - они вообще про физический экран ничего не знают - они пишут в свои виртуальные и спят спокойно.
Концепция понятна?
реализуется это гораздо проще и короче, чем объясняется. Виртуальный экран - это просто переменная типа нашей numberToShow - своя для каждой функции. А переключатель - это программа из трёх строк, которая определяет какую из этих "numberToShow" отображать на физическом экране. Вот и вся реализация.
Ну, мы до этого ещё доберёмся если интересно.
Мне интересна реализация в примере, если можно.
ну это ж тривиально, не?
несколько структур
{
char Line1[16];
char Line2[16];
}
и актуальный указатель для вывода одной из них. Сам не догадаешь?
То есть так банально? Потом на реальном дисплее просто печатать обе эти линии, при необходимости?
Я думал что то по мудрее....
Ещё вопрос о функции вывода на печать на реальный дисплей.
Получается, что при таком подходе приходится полностью весь дисплей обновлять (перерисовывать/перепечатывать) на каждом такте/раз в N-тактов? Или как быть? У меня сейчас в проекте данные обновляются на дисплее только если они изменились. При подходе с виртуальными дисплеями такое реализуемо?
несколько структур
А в случае семисегментника, так и несколько чисел :)
Не хотелось мудрсвовать но ладно. Есть код прикладной. Ну тот когда надо поменять контент программы сообщения, место и порядок надписей. А есть все остальное. Остальное тоже не однородно. Работа с виртуальными экранами это уровень обработки данных. Что то похожее на String. Может в большой упаковке, а может в виде рассыпи отдельных функций и структуры приведённой вышн. А есть канальный уровень. Это код который эти данные забрасывать уже на чип дисплея.
Не хочу показаться камнем без острых углов, но я все же не совсем понял как канальный уровень поймёт, что на прикладном уровне произошли изменения в отображаемой информации и надо дисплей перерисовать?
Как я это вижу? Флаг - «Что то изменилось, надо бы перерисовать дисплей». Его же можно и в примере с меняющимися часами и температурой использовать для смены «кадра». Не?
Ну вспомни библиотеку для лсд1602 и2с. Там гибрид. Что туда напечатано. То на экран и отправлено. Но если сделать промежуточный объект. И туда печатать. Конечно на экране ничего нет. Что бы было надо создавать ещё объект который будет настраивать канал и2с и чип дисплея. А когда надо показать то даётся команда отправить этот виртуальный дисплей на отображение реального.
BOOM, никак - это просто разные вещи. Канальному уровню вообще пофиг чего там отображается - его дело данные гнать.
Все зависит от задачи, я предпочитаю сохранять данные от разных функций в памяти, а уже отдельная часть логики решает что и когда выводить.
PS. Мало с дисплеями работал, а меню вообще страдание, все таки железка которая сама решает как жить программируется проще. Впрочем дело вкуса.
Я iic не использую, мне и так пинов хватает.
Собственно заинтересовала идея виртуальных дисплеев, но не хочется на каждом такте дисплей перерисовывать. А так как в программировании я ещё как котёнок, хотелось бы у более опытных участников форума узнать по максимуму.
Информация с датчиков приходит асинхроно. Да и датчиков море. Вот и приходится хранить все данные. Вдруг вот как раз их надо показать на экране. А так напечатал на экране значение и забыл. Нужный экран всегда готов к показу. Код упрощается. Да и по памяти перерасход не большой.
Данные хранить надо в любом случае. Как их можно забывать?