два 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
001//
002//
003//  Определение пинов для сегментов
004//  (поставьте Ваши пины, у меня мелкий экран и плохо видно какие там у Вас)
005#define PIN_A 7
006#define PIN_B 9
007#define PIN_C 5
008#define PIN_D 3
009#define PIN_E 2
010#define PIN_F 8
011#define PIN_G 6
012#define PIN_DP  4
013 
014#define PIN_DIG0  15
015#define PIN_DIG1  16
016#define PIN_DIG2  14
017 
018//
019//  Определение масок для сегментов
020//
021#define MASK_A  (1 << 0)
022#define MASK_B  (1 << 1)
023#define MASK_C  (1 << 2)
024#define MASK_D  (1 << 3)
025#define MASK_E  (1 << 4)
026#define MASK_F  (1 << 5)
027#define MASK_G  (1 << 6)
028#define MASK_DP     (1 << 7)
029 
030//
031//  Определение цифр через маски сегментов
032//
033#define D0  (MASK_A | MASK_B | MASK_C | MASK_D | MASK_E | MASK_F)
034#define D1  (MASK_B | MASK_C)
035#define D2  (MASK_A | MASK_B | MASK_G | MASK_D | MASK_E)
036#define D3  (MASK_A | MASK_B | MASK_C | MASK_D | MASK_G)
037#define D4  (MASK_B | MASK_C | MASK_G | MASK_F)
038#define D5  (MASK_A | MASK_C | MASK_D | MASK_F | MASK_G)
039#define D6  (MASK_A | MASK_C | MASK_D | MASK_E | MASK_F | MASK_G)
040#define D7  (MASK_A | (MASK_B | MASK_C))
041#define D8  (MASK_A | MASK_B | MASK_C | MASK_D | MASK_E | MASK_F | MASK_G)
042#define D9  (MASK_A | MASK_B | MASK_C | MASK_D | MASK_F | MASK_G)
043 
044 
045 
046//
047//  Функция устанавливает по маске - параметру (HIGH-горит, LOW-не горит)
048//
049void setRawSegments(const int8_t mask) {
050    digitalWrite(PIN_A, mask & MASK_A);
051    digitalWrite(PIN_B, mask & MASK_B);
052    digitalWrite(PIN_C, mask & MASK_C);
053    digitalWrite(PIN_D, mask & MASK_D);
054    digitalWrite(PIN_E, mask & MASK_E);
055    digitalWrite(PIN_F, mask & MASK_F);
056    digitalWrite(PIN_G, mask & MASK_G);
057    digitalWrite(PIN_DP, mask & MASK_DP);
058}
059 
060//
061//  Функция устанавливает все сегменты для цифры-параметра (HIGH-горит, LOW-не горит)
062//
063void setSegments(const int8_t digit) {
064    static const uint8_t all_digits[] = { D0, D1, D2, D3, D4, D5, D6, D7, D8, D9 };
065    setRawSegments(all_digits[digit]);
066}
067 
068//
069//  Функция зажигает цифру d в позиции pos
070//  При этом ставит пин соответсвующий позиции pos в LOW
071//
072void showDigit(const uint8_t d, const uint8_t pos) {
073    static const uint8_t all_postions[] = { PIN_DIG0, PIN_DIG1};
074    for (register uint8_t i = 0; i < sizeof(all_postions) / sizeof(all_postions[0]); i++) {
075        digitalWrite(all_postions[i], pos != i);
076    }
077    setSegments(d);
078}
079 volatile unsigned numberToShow =68;
080// #define  PRESACLER   (1 << CS11)   //  Соответствует делителю частоты 8
081//#define   TICKS       ((uint16_t)(65536ul - 20000ul)) // Оставляет 20000 тиков до переполнения
082#define  PRESACLER (1<<CS11)|(1<<CS10) //  Соответствует делителю частоты 64
083#define TICKS   ((uint16_t)(65536ul - 1666ul)) // Оставляет 1666 тиков до переполнения ( 64*1666/16000 == 6,664 миллисекунды)
084 
085 
086 
087//
088// Инициализация таймера. делается один раз
089//
090void setupTimer2(void) {
091    PRR &= ~(1 << PRTIM1);    // Убедимся, что таймер 1 не отключен
092    TCCR1A = 0;                 // Установим Normal режим
093    TCCR1B = PRESACLER;     // Установим делитель частоты
094    TCNT1 = TICKS;              // Установим счётчик
095    TIMSK1 |= (1 << TOIE1);   // Разрешим прерывание по переполнению
096    TIFR1 = 1;                  //  Очистим Очистим флаг прерывания (если он взведён)
097}
098 
099//
100// Обработка прерывания по переполнению
101//
102ISR(TIMER1_OVF_vect) {
103    TCNT1 = TICKS;              // Установим счётчик для следующего прерывания
104    //
105    //  Покажем очередную цифру, как мы это делали раньше
106    //
107static uint8_t currentDigit = 0;
108 
109    const uint8_t digitToShow = (currentDigit) ? numberToShow / 10 : numberToShow % 10;
110    showDigit(digitToShow, currentDigit);
111    currentDigit = (currentDigit + 1) % 2;  // В следующий раз показываем другую цифру
112 
113 
114}
115 
116//
117//  Всё, что выше  - это своя жизнь. От основной программы требуется только
118//  положить число для показа в numberToShow и оно будет показываться.
119//  Больше основная программа ни о чём не заботится
120//
121///////////////////////////////////////////////////////////////////////////////////
122 
123void setup() {
124    setupTimer2();
125  pinMode(2, OUTPUT);
126  pinMode(3, OUTPUT);
127  pinMode(4, OUTPUT);
128  pinMode(5, OUTPUT);
129  pinMode(6, OUTPUT);
130  pinMode(7, OUTPUT);
131  pinMode(8, OUTPUT);
132  pinMode(9, OUTPUT);
133  pinMode(14, OUTPUT);
134  pinMode(15, OUTPUT);
135  pinMode(16, OUTPUT);
136}
137 
138 
139//
140// Здесь реализован простейший секундомер
141//
142void loop() {
143    static int8_t counter = 0;
144    numberToShow = counter; //  теперь это число будет показываться
145    counter = (counter + 1) % 100;
146    delay(1000);
147}

 

uragan
Offline
Зарегистрирован: 23.02.2015
001#define PIN_A 7
002#define PIN_B 9
003#define PIN_C 5
004#define PIN_D 3
005#define PIN_E 2
006#define PIN_F 8
007#define PIN_G 6
008#define PIN_DP  4
009 
010#define PIN_DIG0  14
011#define PIN_DIG1  15
012#define PIN_DIG2  16
013//
014//  Определение пинов для сегментов
015//  (поставьте Ваши пины, у меня мелкий экран и плохо видно какие там у Вас)
016 
017//
018#define  PRESACLER (1<<CS11)|(1<<CS10) //  Соответствует делителю частоты 8
019#define TICKS   ((uint16_t)(65536ul - 1666ul)) // Оставляет 20000 тиков до переполнения
020 
021 
022 
023//
024//  Определение пинов для цифр
025//  (поставьте Ваши пины, у меня мелкий экран и плохо видно какие там у Вас)
026//
027 
028//
029//  Определение масок для сегментов
030//
031#define MASK_A  (1 << 0)
032#define MASK_B  (1 << 1)
033#define MASK_C  (1 << 2)
034#define MASK_D  (1 << 3)
035#define MASK_E  (1 << 4)
036#define MASK_F  (1 << 5)
037#define MASK_G  (1 << 6)
038#define MASK_DP   (1 << 7)
039 
040//
041//  Определение цифр через маски сегментов
042//
043#define D0  (MASK_A | MASK_B | MASK_C | MASK_D | MASK_E | MASK_F)
044#define D1  (MASK_B | MASK_C)
045#define D2  (MASK_A | MASK_B | MASK_G | MASK_D | MASK_E)
046#define D3  (MASK_A | MASK_B | MASK_C | MASK_D | MASK_G)
047#define D4  (MASK_B | MASK_C | MASK_G | MASK_F)
048#define D5  (MASK_A | MASK_C | MASK_D | MASK_F | MASK_G)
049#define D6  (MASK_A | MASK_C | MASK_D | MASK_E | MASK_F | MASK_G)
050#define D7  (MASK_A | (MASK_B | MASK_C))
051#define D8  (MASK_A | MASK_B | MASK_C | MASK_D | MASK_E | MASK_F | MASK_G)
052#define D9  (MASK_A | MASK_B | MASK_C | MASK_D | MASK_F | MASK_G)
053 
054volatile unsigned numberToShow = 0;
055 
056//
057//  Функция устанавливает по маске - параметру (HIGH-горит, LOW-не горит)
058//
059void setRawSegments(const int8_t mask) {
060  digitalWrite(PIN_A, mask & MASK_A);
061  digitalWrite(PIN_B, mask & MASK_B);
062  digitalWrite(PIN_C, mask & MASK_C);
063  digitalWrite(PIN_D, mask & MASK_D);
064  digitalWrite(PIN_E, mask & MASK_E);
065  digitalWrite(PIN_F, mask & MASK_F);
066  digitalWrite(PIN_G, mask & MASK_G);
067  digitalWrite(PIN_DP, mask & MASK_DP);
068}
069 
070//
071//  Функция устанавливает все сегменты для цифры-параметра (HIGH-горит, LOW-не горит)
072//
073void setSegments(const int8_t digit) {
074  static const uint8_t all_digits[] = { D0, D1, D2, D3, D4, D5, D6, D7, D8, D9};
075  setRawSegments(all_digits[digit]);
076}
077 
078//
079//  Функция зажигает цифру d в позиции pos
080//  При этом ставит пин соответсвующий позиции pos в LOW
081//
082void showDigit(const uint8_t d, const uint8_t pos) {
083  static const uint8_t all_postions[] = { PIN_DIG0, PIN_DIG1, PIN_DIG2 };
084  for (register uint8_t i = 0; i < sizeof(all_postions) / sizeof(all_postions[0]); i++) {
085    digitalWrite(all_postions[i], pos != i);
086  }
087  setSegments(d);
088}
089 
090//
091// Инициализация таймера. делается один раз
092//
093void setupTimer2(void) {
094  PRR &= ~(1 << PRTIM1);  // Убедимся, что таймер 1 не отключен
095  TCCR1A = 0;         // Установим Normal режим
096  TCCR1B = PRESACLER;   // Установим делитель частоты
097  TCNT1 = TICKS;        // Установим счётчик
098  TIMSK1 |= (1 << TOIE1); // Разрешим прерывание по переполнению
099  TIFR1 = 1;          //  Очистим Очистим флаг прерывания (если он взведён)
100}
101//
102// Обработка прерывания по переполнению
103//
104ISR(TIMER1_OVF_vect) {
105  TCNT1 = TICKS;        // Установим счётчик для следующего прерывания
106  //
107  //  Покажем очередную цифру, как мы это делали раньше
108  //
109static uint8_t currentDigit ;
110uint8_t digitToShow ;
111  if (currentDigit == 0) digitToShow = numberToShow / 100;
112else if (currentDigit == 1) digitToShow = (numberToShow % 100) / 10;
113else digitToShow = numberToShow % 10;
114  showDigit(digitToShow, currentDigit);
115  currentDigit = (currentDigit + 1)%3;   // В следующий раз показываем другую цифру
116 
117}
118 
119//
120//  Всё, что выше  - это своя жизнь. От основной программы требуется только
121//  положить число для показа в numberToShow и оно будет показываться.
122//  Больше основная программа ни о чём не заботится
123//
124///////////////////////////////////////////////////////////////////////////////////
125 
126 
127void setup() {
128  setupTimer2();
129    // ... задайте все pinMode как раньше
130    pinMode(2, OUTPUT);
131  pinMode(3, OUTPUT);
132  pinMode(4, OUTPUT);
133  pinMode(5, OUTPUT);
134  pinMode(6, OUTPUT);
135  pinMode(7, OUTPUT);
136  pinMode(8, OUTPUT);
137  pinMode(9, OUTPUT);
138  pinMode(14, OUTPUT);
139  pinMode(15, OUTPUT);
140  pinMode(16, OUTPUT);
141 
142 
143                             
144}
145 
146// 
147//  я считаю, что нулевая цмфра слева (единицы), а первая справа (десятки)
148//  если у Вас по-другому - поменяйте.
149//
150void loop() {
151  
152 
153numberToShow = 123;
154 
155}//
156//

 

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 аватар
Offline
Зарегистрирован: 14.11.2018

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

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

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

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

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

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

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

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

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

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

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

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

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

{

char Line1[16];

char Line2[16];

}

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

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

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

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

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

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

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

DetSimen пишет:

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

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

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

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

BOOM
BOOM аватар
Offline
Зарегистрирован: 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 аватар
Offline
Зарегистрирован: 14.11.2018

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

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

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

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

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