Вывод информации на 4 разрядный 7сегментный индикатор при помощи двух 74hc595

CheBuraw
Offline
Зарегистрирован: 10.02.2015

Здравствуйте!
Для одного из проектов мне потребовались часы на 7 сегментном 4-х разрядном индикаторе и возможность подключить еще ряд внешних исполнительных устройств.
Вариант с LCD мне не подходит. То что находил в интернете не подходит, т.к. либо индикатором заняты все "ноги" Arduino, либо, при использовании 74hc595, регистр ставили на каждый разряд, что я считаю перерасходом микросхем.
В итоге решил делать на двух регистрах - один для генерации символов, другой для переключения разрядов.
После долгих часов оптимизации чужих скетчей у меня получился представленный ниже. В принципе код рабочий, но напрягает то что "засвечиваются" соседние разряды. В принципе жить с этим можно, но охота чтобы все разряды показывали четко те символы какие мне необходимы.
В данный момент вместо часов я подключил переменный резистор, для наглядности, а так же может кому и такое решение подойдет.

Вопрос у меня в следующем - Подскажите, пожалуйста что нужно переделать или добавить для корректного отображения символов.

Схема подключения:


Скетч:

001/*
002********************************************************************
003  Name    : Arduino, 4-разрядный 7-сегментный индикатор и 74HC595 сдвиговый регистр
004  Author  : CheBuraw
005  Date    : 10 Feb, 2015
006  Modified:
007  Version : 0.9
008 
009Это вариативная смесь уроков:
010 1. Tutorial: 74HC595 Shift Bit Register using a 7 Segment Display, ...
012shiftOutDisplay
014shiftOutAnalogueDisplay
016ShiftOut Reference:
018ShiftOut Tutorial:
021 
022 2. Digital Clock with 7-segments LED and RTC (Realtime Clock)
024********************************************************************
025 
026       4-разрядный 7-сегментный индикатор
027                1  A  F 2  3  B
028 _______________|__|__|__|__|__|_____________
029|         |         |    |         |         |
030|    A    |    A    |    |    A    |    A    |
031| F     B | F     B | dp | F     B | F     B |
032|    G    |    G    |    |    G    |    G    |
033| E     C | E     C | dp | E     C | E     C |
034|    D    |    D    |    |    D    |    D    |
035|_________|_________|____|_________|_________|
036                |  |  |  |  |  |
037                E  D dp  C  G  4
038 
039Соответствие отображаемого знака данным порта
040общий анод
041__________________________________________________
042     |   двоичный вид по сегментам   |            |
043Цифра|dp | G | F | E | D | C | B | A | Десятичный |
044-----|---|---|---|---|---|---|---|---|------------|
045  0  | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |    192     |
046  1  | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 |    249     |
047  2  | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 |    164     |
048  3  | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |    176     |
049  4  | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 |    153     |
050  5  | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |    146     |
051  6  | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |    130     |
052  7  | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |    248     |
053  8  | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |    128     |
054  9  | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |    144     |
055 dp  | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |    127     |
056-----*---*---*---*---*---*---*---*---*------------*
057 
05874HC595 Map:
059     _______
060Q1  |1 *  16|  Vcc                  PINS 1-7, 15   Q0 - Q7   Output Pins
061Q2  |2    15|  Q0                   PIN 8      GND       Ground, Vss
062Q3  |3    14|  DS                   PIN 9      Q7"       Serial Out
063Q4  |4    13|  OE                   PIN 10     MR        Master Reclear, active low
064Q5  |5    12|  ST_CP                PIN 11     SH_CP     Shift register clock pin
065Q6  |6    11|  SH_CP                PIN 12     ST_CP     Storage register clock pin (latch pin)
066Q7  |7    10|  MR                   PIN 13     OE        Output enable, active low
067GND |8_____9|  Q7"                  PIN 14     DS        Serial data input
068                                    PIN 16     Vcc       Positive supply voltage
069           _______
070   LED B -|1 *  16|-5V
071   LED C -|2    15|-LED A
072   LED D -|3    14|-PIN 11
073   LED E -|4    13|-GND
074   LED F -|5    12|-PIN 8
075   LED G -|6    11|-PIN 12 ; 1uF TO GND
076   LED dp-|7    10|-5V
077      GND-|8_____9|-NILL
078       
079*/
080 
081int latchPin = 8;     //Пин "защелки" первого регистра подключен к ST_CP входу первого регистра отвечающего за сегменты
082int latchPin2 = 9;    //Пин "защелки" второго регистра подключен к ST_CP входу первого регистра отвечающего за разряды
083int clockPin = 12;    //Пин подключен к SH_CP входу 74HC595
084int dataPin = 11;     //Пин подключен к DS входу 74HC595
085 
086int TimeLight = 5;  //время для разогрева сегментов
087int sensorPin=A0;
088 
089byte SegDisplay; // переменная для вывода символов на индикаторе
090byte RazrDisplay; // переменная для включения разрядов
091 
092// Настройка комбинации для отображения каждого номера на дисплее.
093// Комбинация выбрана на основе таблицы отображаемого знака данным порта
094// Соответственно { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , dp, - }
095byte g_digits[12]={192,249,164,176,153,146,130,248,128,144,127,255}; //массив цифр, генерирующий из сегментов цифры
096byte g_registerArray[4]={1,2,4,8}; //массив цифр, указывающий разряды
097 
098 
099void setup() {
100// обозначаем все пины как выходы
101  pinMode(latchPin, OUTPUT);
102   pinMode(latchPin2, OUTPUT);
103  pinMode(clockPin, OUTPUT);
104  pinMode(dataPin, OUTPUT);
105}
106 
107void loop() {
108  int disp = 0; //создаем переменную для вывода на экран
109 
110  int analogueValue = analogRead(sensorPin);  // читаем аналоговый пин A0
111  analogueValue = map(analogueValue, 0, 1023, 0, 8888); //преобразуем диапазон с А0 (0-1023) в нужный нам (0-8888)
112 
113  disp = analogueValue; // записываем получившуюся после преобразования цифру в переменну для вывода на экран
114   
115 // Разбиваем цифру по разрядам индикатора
116  if (disp < 10) // если наша цифра меньше 10, то
117  {
118    Razryad(3); Segment(11); // пишем в первый разряд прочерк
119    Razryad(0); Segment(11); // пишем во второй разряд прочерк
120    Razryad(1); Segment(11); // пишем в третий разряд прочерк
121    Razryad(2); Segment(disp); // пишем в четвертый разряд нашу цифру
122  }
123  else if (disp < 100) // если наша цифра меньше 100, то
124  {
125    Razryad(3); Segment(11); // пишем в первый разряд прочерк
126    Razryad(0); Segment(11); // пишем во второй разряд прочерк
127    Razryad(1); Segment(disp / 10); // пишем в третий разряд - цифру делёную на 10
128    Razryad(2); Segment(disp % 10); // пишем в четвертый разряд цифру оставшуюся от деления на 10
129/*
130 Допустим наша цифра 25.
131  Если мы ее поделим на 10, то у нас получится 2,5. Цифры после запятой, в данном случае,
132 у нас не остаются. Таким образом мы имеем в третем разряде цифру 2.
133  В чевертый разряд мы, как раз и записываем цифру-остаток полученную в результате деления.
134В нашем случае это и есть та самая 5.
135Аналогичным образом разбивается наша цифра и далее.
136*/
137  }
138  else if (disp < 1000)
139  {
140    Razryad(3); Segment(11);
141    Razryad(0); Segment(disp / 100);
142    Razryad(1); Segment((disp % 100) / 10);
143    Razryad(2); Segment(disp % 10);
144  }
145  else
146  {
147    Razryad(3); Segment(disp / 1000);
148    Razryad(0); Segment((disp % 1000) / 100);
149    Razryad(1); Segment((disp % 100) / 10);
150    Razryad(2); Segment(disp % 10);
151  }
152 }
153 
154 
155void Segment(int x) //функция для записи в 1 регистр информации для генерации символов
156{
157    digitalWrite(latchPin, LOW); // устанавливаем синхронизацию "защелки" на LOW
158SegDisplay=g_digits[x]; // получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре.
159      shiftOut(dataPin, clockPin, MSBFIRST, SegDisplay);  // Записываем информацию в регистр
160  digitalWrite(latchPin, HIGH); //"защелкиваем" регистр, тем самым устанавливая значения на выходах
161}
162 
163void Razryad(int r) //функция для записи во 2 регистр номера разряда индикатора
164{
165    digitalWrite(latchPin2, LOW); // устанавливаем синхронизацию "защелки" на LOW
166RazrDisplay=g_registerArray[r];  // получаем цифру и выводим номер регистра, из массива цифр, соответствующий этой цифре.
167      shiftOut(dataPin, clockPin, MSBFIRST, RazrDisplay); // Записываем информацию в регистр
168  digitalWrite(latchPin2, HIGH); //"защелкиваем" регистр, тем самым устанавливая значения на выходах
169 delay(TimeLight); // пауза, чтобы сегменты "разгорелись"
170}
Datak
Offline
Зарегистрирован: 09.10.2014

CheBuraw пишет:

напрягает то что "засвечиваются" соседние разряды

Ну, а почему засвечиваются, выяснили?

Предлагаю, например, сэкономить ардуиноноги, и оставить только один выход Latch, на обе 595-е.
Заодно и засвечивание пропадёт, мне кажется.

CheBuraw
Offline
Зарегистрирован: 10.02.2015

Datak пишет:

CheBuraw пишет:

напрягает то что "засвечиваются" соседние разряды

Ну, а почему засвечиваются, выяснили?

Предлагаю, например, сэкономить ардуиноноги, и оставить только один выход Latch, на обе 595-е.
Заодно и засвечивание пропадёт, мне кажется.

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

Паралельное расположение сдвиговых регистров я оставил умышленно, т.к. мне показалось, что так код проще получается. Возможно заблуждаюсь. Идея в том чтобы в перспективе, при необходимости, можно было расширить еще на 4 разряда. Такая реализация мне проще показалась, да и так всего 4 ноги у Arduino занял.

Не знаю как сюда видео работы устройства выложить, поэтому залил на яндекс

https://yadi.sk/i/DYnnWiuTeb4jD

Datak
Offline
Зарегистрирован: 09.10.2014

Да я же подсказал, осталось попробовать. :)

Проблема в том, что цифра на индикаторе меняется в один момент времени - в функции  Segment(int x),
а номер разряда в другой момент - в функции  Razryad(int r).

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

Можно попробовать изменить программу, чтобы строчки  digitalWrite(latchPin, HIGH);  и  digitalWrite(latchPin2, HIGH);  выполнялись подряд, и пауза между ними была как можно меньше.

Но в идеале, всё-таки советую оставить один  latchPin,  для достижения полной синхронности.
А увеличению разрядности это никак не помешает.

Datak
Offline
Зарегистрирован: 09.10.2014

CheBuraw пишет:

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

Я, кстати, параллельное расположение менять не предлагаю. Оно ничем не мешает - пусть остаётся, если удобно.

Нужно только объединить у 595-ых сдвиговые входы, и подключить к одному выходу ардуины.

-------

Upd: Не сдвиговые конечно, а входы защёлкивания. Ошибся, извините - ночью советовал. :)

2009Shef
Offline
Зарегистрирован: 23.10.2014

Стало интересно сколько и какие внешние устройства предполагается подключить помимо семисегментника.

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

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

 

axill
Offline
Зарегистрирован: 05.09.2011

2009Shef пишет:

Стало интересно сколько и какие внешние устройства предполагается подключить помимо семисегментника.

согласен, логичнее именно другую переферию подключить на сдвиговые регистры (если применимо), потому как врядли другую переферию нужно так часто переключать как выводы для семисегментника при динамической индикации

в данном варианте вместо PCF8574 целесообразней поставить драйвер семисегментников типа max7219

2009Shef
Offline
Зарегистрирован: 23.10.2014

Для семисегиентников есть прекрасный драйвер stled316. 

CheBuraw
Offline
Зарегистрирован: 10.02.2015

axill пишет:

в данном варианте вместо PCF8574 целесообразней поставить драйвер семисегментников типа max7219

   О применении max7219 я думал, но не стал использовать по ряду причин:
1. Работают только с индикаторами с общим катодом, а у меня общий анод на всех имеющихся индикаторах :(
2. У нас в городе max7219 не купить, а заказывать с китая только партиями не менее 10 штук. Ради 3-4 проектов заказывать 10 микросхем не охота.
3. Для своих нужд посчитал кощунством использовать max7219. Если уж их грузить, то по полной :)
4. max7219 в 3 раза дороже 74hc595. 300 рублей (за 10 штук), конечно, не великие деньги, но тем не менее.
5. 74hc595 считаю более распространенным.
...хотя, касательно цены! В данной схеме используются две 74hc595, а значит разница уже не в 3 раза, а с учетом удобства работы с библиотекой для max7219, может оно и действительно вариант правильнее и проще ;). Но не для меня. Если бы не причина №1, то думаю сделалбы на max7219.

   Драйвер stled316 и PCF8574 не стал использовать по тем же причинам - недоступность у нас в городе (думаю не только у меня) да и цена куда выше 74hc595.
   Еще, просто хотелось понять как работать с 74hc595 :)

2009Shef пишет:

Стало интересно сколько и какие внешние устройства предполагается подключить помимо семисегментника.

   На данный момент хочу повесить релюшки. Согласен, ими куда проще управлять через 74hc595, но я думал сделать некую универсальную схему, чтобы любой другой мог взять данный код и подключить другие устройства, необходимые именно ему.

Datak пишет:

Но в идеале, всё-таки советую оставить один  latchPin,  для достижения полной синхронности.
А увеличению разрядности это никак не помешает.

   Datak, большое Вам спасибо! Подключил как Вы советовали. Немного модифицировал код и УРА - все работает четко, без засветов :).
Я до этого пренебрегал данным вариантом в силу незнания как разделить данные отправляемые в разные регистры. Думал что это как-то сложно. Но после Вашей рекомендации, решил таки более детально изучить данный вариант. Как оказалось что это не сложнее моего варианта ранее. Просто данные необходима передавать, так сказать, наоборот - с начала для последнего регистра, затем для предпоследнего и т.д.

Скорректированная схема:

Итоговый код:

01********************************************************************
02  Name    : Arduino, 4-разрядный 7-сегментный индикатор, 74HC595 сдвиговый регистр, переменный резистор
03  Author  : CheBuraw
04  Date    : 11 Feb, 2015
05  Version : 0.9
06********************************************************************
07int latchPin = 8;     //Пин "защелки" первого регистра подключен к ST_CP входу первого регистра отвечающего за сегменты
08int clockPin = 12;    //Пин подключен к SH_CP входу 74HC595
09int dataPin = 11;     //Пин подключен к DS входу 74HC595
10 
11int TimeLight = 5;  //время для разогрева сегментов
12int sensorPin=A0;
13 
14byte SegDisplay; // переменная для вывода символов на индикаторе
15byte RazrDisplay; // переменная для включения разрядов
16 
17// Настройка комбинации для отображения каждого номера на дисплее.
18// Комбинация выбрана на основе таблицы отображаемого знака данным порта
19// Соответственно { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , dp, - }
20byte g_digits[12]={192,249,164,176,153,146,130,248,128,144,127,255}; //массив цифр, генерирующий из сегментов цифры
21byte g_registerArray[4]={1,2,4,8}; //массив цифр, указывающий разряды
22 
23 
24void setup() {
25// обозначаем все пины как выходы
26  pinMode(latchPin, OUTPUT);
27  pinMode(clockPin, OUTPUT);
28  pinMode(dataPin, OUTPUT);
29}
30 
31void loop() {
32  int disp = 0; //создаем переменную для вывода на экран
33 
34  int analogueValue = analogRead(sensorPin);  // читаем аналоговый пин A0
35  analogueValue = map(analogueValue, 0, 1023, 0, 8888); //преобразуем диапазон с А0 (0-1023) в нужный нам (0-8888)
36 
37  disp = analogueValue; // записываем получившуюся после преобразования цифру в переменну для вывода на экран
38   
39 // Разбиваем цифру по разрядам индикатора
40  if (disp < 10) // если наша цифра меньше 10, то
41  {
42    Indicate(0, 11); // пишем в первый разряд пусто
43    Indicate(1, 11); // пишем во второй разряд пусто
44    Indicate(2, 11); // пишем в третий разряд пусто
45    Indicate(3, disp); // пишем в четвертый разряд нашу цифру
46  }
47  else if (disp < 100) // если наша цифра меньше 100, то
48  {
49    Indicate(0, 11); // пишем в первый разряд пусто
50    Indicate(1, 11); // пишем во второй разряд пусто
51    Indicate(2, disp / 10); // пишем в третий разряд - цифру делёную на 10
52    Indicate(3, disp % 10); // пишем в четвертый разряд цифру оставшуюся от деления на 10
53/*
54 Допустим наша цифра 25.
55  Если мы ее поделим на 10, то у нас получится 2,5. Цифры после запятой, в данном случае,
56 у нас не остаются. Таким образом мы имеем в третем разряде цифру 2.
57  В чевертый разряд мы, как раз и записываем цифру-остаток полученную в результате деления.
58В нашем случае это и есть та самая 5.
59Аналогичным образом разбивается наша цифра и далее.
60*/
61  }
62  else if (disp < 1000)
63  {
64    Indicate(0, 11);
65    Indicate(1, disp / 100);   
66    Indicate(2, (disp % 100) / 10);
67    Indicate(3, disp % 10);
68  }
69  else
70  {
71    Indicate(0, disp / 1000);
72    Indicate(1, (disp % 1000) / 100);   
73    Indicate(2, (disp % 100) / 10);
74    Indicate(3, disp % 10);
75  }
76 }
77 
78void Indicate(int r,int x)
79{
80SegDisplay=g_digits[x]; // получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре.
81RazrDisplay=g_registerArray[r];  // получаем цифру и выводим номер регистра, из массива цифр, соответствующий этой цифре.
82  digitalWrite(latchPin, LOW);  // устанавливаем синхронизацию "защелки" на LOW
83      shiftOut(dataPin, clockPin, MSBFIRST, RazrDisplay); // Записываем информацию для второго регистра (Номер разряда)
84      shiftOut(dataPin, clockPin, MSBFIRST, SegDisplay);  // Записываем информацию для первого регистра (Номер символа)
85  digitalWrite(latchPin, HIGH);  //"защелкиваем" регистр, тем самым устанавливая значения на выходах
86 
87   delay(TimeLight); // пауза, чтобы сегменты "разгорелись"
88}

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

Datak
Offline
Зарегистрирован: 09.10.2014

CheBuraw, рад что всё получилось.
Схема размытая, не видно, то ли там, о чём я писал, но судя по программе - да, кажется всё так.
Только лишний latchPin2 там почистить бы, чтобы с толку не сбивал. :)

А строки с 41 по 77 можно попробовать заменить на такие:

1for( int i = 0; i < 4; i++ )
2{
3   if( i == 0 || disp != 0 )
4      Indicate( i, disp % 10 );
5   else
6      Indicate( i, 11 );
7 
8   disp /= 10;
9}

Должно работать, если я нигде не ошибся.

CheBuraw
Offline
Зарегистрирован: 10.02.2015

Datak, код почистил, latchPin2 убрал :) .

По поводу предложенного Вами кода. В моем исходнике фигурируют "Indicate(1, (disp % 1000) / 100);" в Вашем коде я не понял как реализуются такие моменты. Может я просто плохо понял, я еще новичек в програмировании.

Я тут собрал на основе данного скетча Вариант использования.
Arduino, 4-разрядный 7-сегментный индикатор, 74HC595 сдвиговый регистр, DS1307 RTC

001/*
002********************************************************************
003  Name    : Arduino, 4-разрядный 7-сегментный индикатор, 74HC595 сдвиговый регистр, DS1307 RTC
004  Author  : CheBuraw
005  Date    : 11 Feb, 2015
006  Modified:
007  Version : 1.0
008********************************************************************
009 
0104-разрядный 7-сегментный индикатор. общий анод
011                1  A  F 2  3  B
012 _______________|__|__|__|__|__|_____________
013|         |         |    |         |         |
014|    A    |    A    |    |    A    |    A    |
015| F     B | F     B | dp | F     B | F     B |
016|    G    |    G    |    |    G    |    G    |
017| E     C | E     C | dp | E     C | E     C |
018|    D    |    D    |    |    D    |    D    |
019|_________|_________|____|_________|_________|
020                |  |  |  |  |  |
021                E  D dp  C  G  4
022 
02374HC595 Map:
024     _______
025Q1  |1 *  16|  Vcc                  PINS 1-7, 15   Q0 - Q7   Output Pins
026Q2  |2    15|  Q0                   PIN 8      GND       Ground, Vss
027Q3  |3    14|  DS                   PIN 9      Q7"       Serial Out
028Q4  |4    13|  OE                   PIN 10     MR        Master Reclear, active low
029Q5  |5    12|  ST_CP                PIN 11     SH_CP     Shift register clock pin
030Q6  |6    11|  SH_CP                PIN 12     ST_CP     Storage register clock pin (latch pin)
031Q7  |7    10|  MR                   PIN 13     OE        Output enable, active low
032GND |8_____9|  Q7"                  PIN 14     DS        Serial data input
033                                    PIN 16     Vcc       Positive supply voltage
034           _______
035   LED B -|1 *  16|-5V
036   LED C -|2    15|-LED A
037   LED D -|3    14|-PIN 11
038   LED E -|4    13|-GND
039   LED F -|5    12|-PIN 8
040   LED G -|6    11|-PIN 12 ; 1uF TO GND
041   LED dp-|7    10|-5V
042      GND-|8_____9|-NILL
043       
044*/
045#include <Wire.h>
046#include "RTClib.h"
047RTC_DS1307 RTC;
048 
049int latchPin = 8;     //Пин "защелки" первого регистра подключен к ST_CP входу первого регистра отвечающего за сегменты
050int clockPin = 12;    //Пин подключен к SH_CP входу 74HC595
051int dataPin = 11;     //Пин подключен к DS входу 74HC595
052 
053int TimeLight = 5;  //время для разогрева сегментов
054 
055byte SegDisplay; // переменная для вывода символов на индикаторе
056byte RazrDisplay; // переменная для включения разрядов
057 
058// Настройка комбинации для отображения каждого номера на дисплее.
059byte g_digits[12]={
060 B01000000, B01111001,    // 0 1
061 B00100100, B00110000,    // 2 3
062 B00011001, B00010010,    // 4 5
063 B00000010, B01111000,    // 6 7
064 B00000000, B00010000,    // 8 9
065 B11111111, };        // все сегменты выключены
066 
067byte g_registerArray[4]={1,2,4,8}; //массив цифр, указывающий разряды
068 
069 
070void setup() {
071  Wire.begin();
072  RTC.begin();
073   
074// обозначаем все пины как выходы
075  pinMode(latchPin, OUTPUT);
076  pinMode(clockPin, OUTPUT);
077  pinMode(dataPin, OUTPUT);
078}
079 
080void loop() {
081  int hour,minute,sec,disp = 0;
082 
083  DateTime now = RTC.now();
084 
085  hour = now.hour();
086  minute = now.minute();
087  sec = now.second();
088   
089  disp = (hour * 100) + minute;
090 // Разбиваем цифру по разрядам индикатора
091  if (disp < 10) // если наша цифра меньше 10, то
092  {
093    Indicate(0, 11); // пишем в первый разряд пусто
094    Indicate(1, 11); // пишем во второй разряд пусто
095    Indicate(2, 11); // пишем в третий разряд пусто
096    Indicate(3, disp); // пишем в четвертый разряд нашу цифру
097  }
098  else if (disp < 100) // если наша цифра меньше 100, то
099  {
100    Indicate(0, 11); // пишем в первый разряд пусто
101    Indicate(1, 11); // пишем во второй разряд пусто
102    Indicate(2, disp / 10); // пишем в третий разряд - цифру делёную на 10
103    Indicate(3, disp % 10); // пишем в четвертый разряд цифру оставшуюся от деления на 10
104/*
105 Допустим наша цифра 25.
106  Если мы ее поделим на 10, то у нас получится 2,5. Цифры после запятой, в данном случае,
107 у нас не остаются. Таким образом мы имеем в третем разряде цифру 2.
108  В чевертый разряд мы, как раз и записываем цифру-остаток полученную в результате деления.
109В нашем случае это и есть та самая 5.
110Аналогичным образом разбивается наша цифра и далее.
111*/
112  }
113  else if (disp < 1000)
114  {
115    Indicate(0, 11);
116    Indicate(1, disp / 100);   
117    Indicate(2, (disp % 100) / 10);
118    Indicate(3, disp % 10);
119  }
120  else
121  {
122    Indicate(0, disp / 1000);
123    Indicate(1, (disp % 1000) / 100);
124    Indicate(2, (disp % 100) / 10);
125    Indicate(3, disp % 10);
126  }
127 
128 }
129 
130void Indicate(int r,int x)
131{
132SegDisplay=g_digits[x]; // получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре.
133RazrDisplay=g_registerArray[r];  // получаем цифру и выводим номер регистра, из массива цифр, соответствующий этой цифре.
134  digitalWrite(latchPin, LOW);  // устанавливаем синхронизацию "защелки" на LOW
135      shiftOut(dataPin, clockPin, MSBFIRST, RazrDisplay); // Записываем информацию для второго регистра (Номер разряда)
136      shiftOut(dataPin, clockPin, MSBFIRST, SegDisplay);  // Записываем информацию для первого регистра (Номер символа)
137  digitalWrite(latchPin, HIGH);  //"защелкиваем" регистр, тем самым устанавливая значения на выходах
138 
139   delay(TimeLight); // пауза, чтобы сегменты "разгорелись"
140}

 

Datak
Offline
Зарегистрирован: 09.10.2014

CheBuraw пишет:

я не понял как реализуются такие моменты

Реализуются до обидного просто.

Сначала выводится младший разряд числа -  disp % 10,
а потом число делится на десять - disp /= 10 - и значит, младшим становится следующий разряд.
Индикатор 4-х разрядный, поэтому весь этот фокус повторяется в цикле 4 раза.

Дополнительная проверка, if в цикле, нужна для того чтобы не выводить нули перед старшим значащим разрядом. Вот тут я как раз немного сомневаюсь, но надеюсь что не ошибся. :)
 

CheBuraw
Offline
Зарегистрирован: 10.02.2015

Datak пишет:

Реализуются до обидного просто.

Сначала выводится младший разряд числа -  disp % 10,
а потом число делится на десять - disp /= 10 - и значит, младшим становится следующий разряд.
Индикатор 4-х разрядный, поэтому весь этот фокус повторяется в цикле 4 раза.

Дополнительная проверка, if в цикле, нужна для того чтобы не выводить нули перед старшим значащим разрядом. Вот тут я как раз немного сомневаюсь, но надеюсь что не ошибся. :)

На индикаторе все показывается :). Круть!
..но есть один нюанс - разряды отображаются зеркально. Например сейчас 21:27, а показывается 72:12.

В принципе это не смертельно и можно поправить тут:
byte g_registerArray[4]={8,4,2,1}; //массив цифр, указывающий разряды

Крутил, вертел Ваш код, менял значения в цикле, но ничего толкового из этого так и не вышло :(

...но может Вы поправите это в Вашем варианте? (извините за наглость)

Datak пишет:

Индикатор 4-х разрядный, поэтому весь этот фокус повторяется в цикле 4 раза.

Правильно ли я понял, что если я задействую 8 разрядов, то мне необходимо будет заменить 4 на 8 в строке
 

1for( int i = 0; i < 4; i++ )

?

Datak
Offline
Зарегистрирован: 09.10.2014

CheBuraw пишет:

..но есть один нюанс - разряды отображаются зеркально. Например сейчас 21:27, а показывается 72:12.

Ну, бывает, да, когда вслепую программы пишешь, без проверки. :)

CheBuraw пишет:

В принципе это не смертельно и можно поправить тут:
byte g_registerArray[4]={8,4,2,1}; //массив цифр, указывающий разряды

Крутил, вертел Ваш код, менял значения в цикле, но ничего толкового из этого так и не вышло :(

...но может Вы поправите это в Вашем варианте? (извините за наглость)

Да кажется должно помочь, если  g_registerArray  написать в обратном порядке. Что, действительно не работает? Так сразу не соображу что-то.
Поправить наверно не трудно, но без проверки боюсь опять обману. Попробуйте лучше там, на месте починить. В конце концов, провода идущие на разряды можно перевоткнуть.

Если уж никак не получится - пишите, придумаем что-нибудь.

CheBuraw пишет:

Правильно ли я понял, что если я задействую 8 разрядов, то мне необходимо будет заменить 4 на 8 в строке
 

1for( int i = 0; i < 4; i++ )

?

Абсолютно правильно, задумано именно так. Только размер переменной  disp  придётся взять побольше - unsigned long - т.к. 8 разрядов в  int  не уместятся. И таблицу  g_registerArray  удлиннить, разумеется.

Ну и потом ещё отладить всё, если я опять где-то ошибся. :)

CheBuraw
Offline
Зарегистрирован: 10.02.2015

Нашел у себя ошибку в Arduino, 4-разрядный 7-сегментный индикатор, 74HC595 сдвиговый регистр, DS1307 RTC
 

090// Разбиваем цифру по разрядам индикатора
091  if (disp < 10) // если наша цифра меньше 10, то
092  {
093    Indicate(0, 11); // пишем в первый разряд пусто
094    Indicate(1, 11); // пишем во второй разряд пусто
095    Indicate(2, 11); // пишем в третий разряд пусто
096    Indicate(3, disp); // пишем в четвертый разряд нашу цифру
097  }
098  else if (disp < 100) // если наша цифра меньше 100, то
099  {
100    Indicate(0, 11); // пишем в первый разряд пусто
101    Indicate(1, 11); // пишем во второй разряд пусто
102    Indicate(2, disp / 10); // пишем в третий разряд - цифру делёную на 10
103    Indicate(3, disp % 10); // пишем в четвертый разряд цифру оставшуюся от деления на 10
104/*
105 Допустим наша цифра 25.
106  Если мы ее поделим на 10, то у нас получится 2,5. Цифры после запятой, в данном случае,
107 у нас не остаются. Таким образом мы имеем в третем разряде цифру 2.
108  В чевертый разряд мы, как раз и записываем цифру-остаток полученную в результате деления.
109В нашем случае это и есть та самая 5.
110Аналогичным образом разбивается наша цифра и далее.
111*/
112  }
113  else if (disp < 1000)
114  {
115    Indicate(0, 11);
116    Indicate(1, disp / 100);   
117    Indicate(2, (disp % 100) / 10);
118    Indicate(3, disp % 10);
119  }

Indicate(0, 11); ссылается на 12 символ (учитывая, что адрес первого символа - 0, а последнего - 11) в массиве данных, а там его нет :( поэтому отображаются все сегменты, а надо чтобы ничего не отображалось :).
Что бы всё отображалось надо поправить на Indicate(0, 10);

Исправленная, оптимизированная Datak`ом и проверенная версия  кода:
Arduino, 4-разрядный 7-сегментный индикатор, 74HC595 сдвиговый регистр, DS1307 RTC

...но и тут есть небольшая недоработочка -  в 0 часов будут показываться только минуты :).
Корректируется исправлением нашего пресловутого Indicate(0, 10); на Indicate(0, 0); и в этом случае до 10 утра часы будут отображаться в формате 00, 01, 02, ..., 09. Если не напрягает, то скетч готов к использованию. Ну а если кому надо будет, то, думаю, допилят. ...а может и сам как-нибудь попозже доделаю.

Datak
Offline
Зарегистрирован: 09.10.2014

CheBuraw пишет:

Корректируется исправлением нашего пресловутого Indicate(0, 10); на Indicate(0, 0); и в этом случае до 10 утра часы будут отображаться в формате 00, 01, 02, ..., 09.

Не, исправляется это тем, что условие  if -- else  в цикле вообще убирается, оставляется просто

1Indicate( i, disp % 10 );

Результат должен получиться тот же.

А если всё же хочется чтобы часы показывались без лишних нулей, можно условие поменять на такое:

1if( i < 3 || disp != 0 )

 

CheBuraw
Offline
Зарегистрирован: 10.02.2015

Да! На сколько все просто, как оказывается, решается :).
А я уж пробовал внуть Вашего кода еще один if запихать, но ничего путёвого из этого не получилось.

Sirox
Offline
Зарегистрирован: 24.02.2015

Добрый день, спасибо за код!

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

Щас нет возможности проверить, но если инвертировать эти значения то поможет ?

1B01000000, B01111001,    // 0 1
2B00100100, B00110000,    // 2 3
3B00011001, B00010010,    // 4 5
4B00000010, B01111000,    // 6 7
5B00000000, B00010000,    // 8 9
6B11111111, };        // все сегменты выключены

 

CheBuraw
Offline
Зарегистрирован: 10.02.2015

Sirox, грубо говоря, Вам необходимо все нули поменять на единички, а единички на нули.
Поясню смысл указанного Вами фрагмента кода.
Символ "B" говорит что представленное число в бинарном формате.
Далее следуют команды для зажигания сегментов индикатора - "dpGFEDCBA". Для отображения цифры 5 нам необходимо подать питание или "единички" (для индикаторов с общим катодом) на сегменты A,F,G,C,D или если написать их в алфавитном порядке A,C,D,F,G. Остальные сегменты мы оставляем "обесточенными" то есть пишем в них "нули".

Таким образом заполняем наш шаблон:
B - Говорим что число бинарное
dp - Зажигаем точку, значит ставим 1
G - Зажигаем этот сегмент, значит ставим 1
F - Зажигаем этот сегмент, значит ставим 1
E - Этот сегмент не должен гореть, значит ставим 0
D - Зажигаем этот сегмент, значит ставим 1
C - Зажигаем этот сегмент, значит ставим 1
B - Этот сегмент не должен гореть, значит ставим 0
A - Зажигаем этот сегмент, значит ставим 1
В итоге имеем следующий код для цифры 5 - B11101101 (для индикаторов с общим катодом)
 _________
|         |
|    A    |
| F     B |
|    G    |
| E     C |
|    D    |
|_________|

Остальные цифры давайте сами ;) !

Если не получиться, то пишите.

Sirox
Offline
Зарегистрирован: 24.02.2015

Не выходит, и так и пробовал и эдак, даташит моего индикатора http://zip-2002.ru/z_pdf/kem-5461agr-1.pdf / Предпологаю что порядок сегментов у меня другой, поэтому такая абра кадабра выводится.

 

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

а если просто инвертировать значение? для сегментов и для общего анода или катода

а лучше добавить переменную типа boolean которой задаешь общий катор иди анод

 

Sirox
Offline
Зарегистрирован: 24.02.2015
Получилось только выводить одинаковые числа 1111 или 2222 и т.д. При этом тускло светит первая цифра. Если хоть одна цифра другая то абра кадабра. 
Подставляю для проверки в
hour = 99; // Считываем значение часов minute = 99; // Считываем значение минут
 
01#include <Wire.h>
02 
03int latchPin = 2;     //Пин "защелки" первого регистра подключен к ST_CP входу первого регистра отвечающего за сегменты
04int clockPin = 3;    //Пин подключен к SH_CP входу 74HC595
05int dataPin = 4;     //Пин подключен к DS входу 74HC595
06 
07int TimeLight = 5;  //время для разогрева сегментов
08 
09byte SegDisplay; // переменная для вывода символов на индикаторе
10byte RazrDisplay; // переменная для включения разрядов
11 
12// Настройка комбинации для отображения каждого номера на дисплее.
13 
14byte g_digits[11]={
15B00111111, B00000110,    // 0 1
16B01011011, B01001111,    // 2 3
17B01100110, B01101101,    // 4 5
18B01111101, B00000111,    // 6 7
19B01111111, B01101111,    // 8 9
20B00000000, };         // все сегменты выключены
21 
22byte g_registerArray[4]={8,4,2,1}; //массив цифр, указывающий разряды
23 
24void setup() {
25  Wire.begin();
26   
27// обозначаем все пины как выходы
28  pinMode(latchPin, OUTPUT);
29  pinMode(clockPin, OUTPUT);
30  pinMode(dataPin, OUTPUT);
31}
32 
33void loop() {
34  int hour,minute,disp = 0;
35 
36  hour = 99; // Считываем значение часов
37  minute = 89; // Считываем значение минут
38   
39  disp = (hour * 100) + minute; //"Собираем" значения часов и минут в одну цифру
40  
41 // Разбиваем цифру по разрядам индикатора
42for( int i = 0; i < 4; i++ )
43{
44   if( i == 0 || disp != 0 )
45      Indicate( i, disp % 10 );
46   else
47      Indicate( i, 10 );
48 
49   disp /= 10;
50}
51 
52 }
53 
54void Indicate(int r,int x)
55{
56SegDisplay=g_digits[x]; // получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре.
57RazrDisplay=g_registerArray[r];  // получаем цифру и выводим номер регистра, из массива цифр, соответствующий этой цифре.
58  digitalWrite(latchPin, LOW);  // устанавливаем синхронизацию "защелки" на LOW
59      shiftOut(dataPin, clockPin, MSBFIRST, RazrDisplay); // Записываем информацию для второго регистра (Номер разряда)
60      shiftOut(dataPin, clockPin, MSBFIRST, SegDisplay);  // Записываем информацию для первого регистра (Номер символа)
61  digitalWrite(latchPin, HIGH);  //"защелкиваем" регистр, тем самым устанавливая значения на выходах
62 
63   delay(TimeLight); // пауза, чтобы сегменты "разгорелись"
64}

 

 

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

что такое shiftOut. цикл от 0 до 8 (или наоборот) и перебор битов с дерганьем clock.

можно залезть в файлы, и найти что делает конктено shiftOut, переделать, добавить инверсию или доп. параметр boolean через & и радоваться жизни

да и незачем делать такое

1disp = (hour * 100) + minute;

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

а то получается собираем число сотни и тысячи + десятки и еденицы, а потом снова разделяем

CheBuraw
Offline
Зарегистрирован: 10.02.2015

Sirox, посмотрите повнимательнее, может где соединили не так. У меня такое было :). Долго мучался, потом нашел и все запустилось. Порой даже проще все провода повыдё1ргивать и заново подключить.
Ноги Вашего индикатора, судя по представленному даташиту, полностью совпадают с моим индикатором. Так что тут все должно быть нормально.
Пока еще не разобрал свою схему, залил Ваш скетч. Все нормально работает.

jeka_tm, из всех найденных мною вариантов, только этот мне показался понятным, поэтому я и сделал по этому принципу.
Буду Вам очень признателен, да думаю и не я один, если Вы покажете Ваше решение вывода цифр в заданном разряде. Если Ваш код будет короче и понятнее, то буду использовать его ;) !

Sirox
Offline
Зарегистрирован: 24.02.2015

Спасибо за отзывчивость ! Проверял уже раза 3, буду ковыряться дальше, приносит это дело удовольствие мне )

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013
1disp = (hour * 100) + minute;

я этот вариант предлагал так как ТС мог выводить число, но не умел похоже выводить отдельную цифру в нужном разряде

вот посмотри код. может наведет на мысли переделать

переменная anod кстати задает общий анод или катод подключен

01//==================================================================================
02//                                Зажигаем сегменты
03//==================================================================================
04void F_Seg(byte n, byte point){
05  byte m = Digit[n];
06  for(byte i=0;i<7;i++){
07    (Anod)? dWrite(Seg[i],!(m & Anod)) : dWrite(Seg[i],(m & !Anod));
08    m >>= 1;
09  }
10  (point)? dWrite(Seg[7], !Anod) : dWrite(Seg[7], Anod);

 

CheBuraw
Offline
Зарегистрирован: 10.02.2015

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

Я с него начинал :). Только тут надо еще переменный резистор подключить к A0, выше есть схема подключения. В скетче есть ссылка на ролик ютубовкий, он на английском, но, даже если Вы им и не владеете, то думаю в общих чертах поймете о чем речь идет.

CheBuraw
Offline
Зарегистрирован: 10.02.2015

jeka_tm, правильно ли я понимаю что предложенный Вами код это фрагмент какого-то большого кода? Вы его выкладывали куда-нибудь? Можно ли его целиком посмотреть? Просто судя по незакрытой скобке функции void F_Seg там должен быть еще код.
Если Вам не трудно, можете прокомментировать, для таких бестолковых как я, смысл каждой строки в представленном Вами фрагменте.

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

да весь смысла нет

01void F_Seg(byte n){
02  byte m = Digit[n]; //считываем из массива значение по адресу n,
03  //где n это число которое нужно вывести
04  for(byte i=0;i<7;i++){//цикл для перебора всех битов в байте
05    (Anod)? dWrite(Seg[i],!(m & Anod)) : dWrite(Seg[i],(m & !Anod));// тоже самое можно записать понятнее
06    /*
07    if(Anod==1){
08      dWrite(Seg[i],!(m & Anod));
09    }
10    else{
11     dWrite(Seg[i],(m & !Anod));
12    }
13     */
14    m >>= 1;//сдвигаем вправо на 1
15  }
16}

функция dWrite это урезанная digitalWrite и делает тоже самое, ну почти. шим не отрубает на выходе

CheBuraw
Offline
Зарегистрирован: 10.02.2015

jeka_tm, правильно ли я понял, что этот код некая альтернатива shiftOut? Или тут есть и средство разбиения цифр на разряды, т.е. записи каждой цифры в нужный разряд?

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

это не альтернатива. это код для управления индикатором без 74HC595. а точнее 1 цифрой просто ногодрыганьем

короче это долго. если работает оставь как есть

Datak
Offline
Зарегистрирован: 09.10.2014

Sirox, инвертировать нужно не только массив g_digits,  но и  g_registerArray тоже.

В остальном - всё так же, по-моему. Должно работать.

Sirox
Offline
Зарегистрирован: 24.02.2015
1byte g_registerArray[4]={8,4,2,1};

А каким образом? 1,2,4,8 делал, не получается. Может цифры другие должны быть?

Datak
Offline
Зарегистрирован: 09.10.2014
1byte g_registerArray[4]={~8,~4,~2,~1}; //массив цифр, указывающий разряды

 

Sirox
Offline
Зарегистрирован: 24.02.2015

Одна голова хорошо, а две лучше, спасибо все заработало!

Sirox
Offline
Зарегистрирован: 24.02.2015

Доброго дня, дисплей я планирую приспособить для авто по типу (без верхней шкалы)

Есть проблемы по выводу дробных и отрицательных чисел ,  а также по избавлению от delay

Вот код для вывода temp, цифры моргают, как правильно использовать millis или библиотеку которая это просто сделает?

 

 

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

 

01void ledDigitDisplay(float num, float time)
02{
03    unsigned long ltime = millis();
04     
05    // Настройки
06    // 6, 8, 9, 12 - GND
07    int pin[] = {6, 7, 8, 9, 10, 2, 11, 3, 4, 12, 13, 5}; // Пины
08    int settingsSegments[] = {pin[10], pin[6], pin[3], pin[1], pin[0], pin[9], pin[4], pin[2]}; // Порядок сегментов
09    int segments[] = {0b00111111, 0b00000110, 0b01011011, 0b01001111, 0b01100110, 0b01101101, 0b01111101, 0b00000111, 0b01111111, 0b01101111, 0b10000000, 0b01000000}; // 1, 2, 3, 4, 5, 6, 7, 8, 9, '.', '-'
10    for(int i = 0; i < 12; ++i) pinMode(pin[i], OUTPUT); // Определяем пины как выход
11 
12    int floatingPoint = 0, minus = 4;
13 
14    if(num > -1000 && num < 0) // Разбираемся с отрицательными числами
15    {
16        minus--;
17        if(num > -100) minus--;
18        if(num > -10) minus--;
19        num = -num;
20    }
21 
22    for(int i = 0; num < 1000 && minus == 4; ++i) // Разбираемся с дробными числами
23    {
24        if(int(num * 10) != int(num)*10)
25        {
26            floatingPoint++;
27            num *= 10;
28        }
29        else
30            break;
31    }
32     
33    for(int i = 0, temp; millis() - ltime <= time * 1000; i++)
34    {
35        if(i == 4) i = 0;
36 
37        temp = int(num / pow(10, i)) % 10; // Цифра которую передадим индикатору
38        if(num >= 10000 || num <= -10000 || minus == i) // Если минус или переполнение, передаем '-'
39            temp = 11;
40 
41        if(i == 3 && (num >= 1000 || floatingPoint == i || minus == i)) pinMode(pin[11], OUTPUT); else pinMode(pin[11], INPUT); // Работаем с 4 разрядом
42        if(i == 2 && (num >= 100 || floatingPoint == i || minus == i)) pinMode(pin[8], OUTPUT); else pinMode(pin[8], INPUT); // Работаем с 3 разрядом
43        if(i == 1 && (num >= 10 || floatingPoint == i || minus == i)) pinMode(pin[7], OUTPUT); else pinMode(pin[7], INPUT); // Работаем с 2 разрядом
44        if(i == 0) pinMode(pin[5], OUTPUT); else pinMode(pin[5], INPUT); // Работаем с 1 разрядом
45 
46        for(int j = 0; j < 8; j++) // Передаем число
47            if(segments[temp] & (1 << j))
48                digitalWrite(settingsSegments[j], HIGH);
49 
50        if(floatingPoint && floatingPoint == i) // Передаем точку
51            digitalWrite(settingsSegments[7], HIGH);
52 
53        delay(1); // Небольшая пауза, чтобы светодиоды разгорелись
54 
55        for(int j = 0; j < 8; j++) digitalWrite(settingsSegments[j], LOW); // Выключаем все светодиоды
56    }
57}
58 
59void setup()
60{
61 
62}
63 
64 
65 
66void loop()
67{
68    ledDigitDisplay(3.14, 2);
69    ledDigitDisplay(123, 2);
70    ledDigitDisplay(-5, 2);
71}

 

bwn
Offline
Зарегистрирован: 25.08.2014

по millis():

unsigned long a;    Объявили переменную

if (a<=millis()) {Выполнили; a=millis()+5000;} Проверили, произвели действия, обновили значение задержки (5 секунд)

Все.

CheBuraw
Offline
Зарегистрирован: 10.02.2015

Sirox, delay в обоих схемах используется для свечения сегментов. Сама по себе задержка минимальна и я думаю что она сильно не должна мешать. Как я понимаю delay не всегда плохо и порой без него сложно (но задействуя разные прерывания, можно) обойтись.  Ну это мое ламерское заключение :).

По поводу предложенного Вами кода. А можете его целиком и под спойлер выложить, или ссылочку на него дать? Думаю я смогу их "объединить", ну или по крайней мере попробую :). Самому интересно себя проверить.

 

Sirox
Offline
Зарегистрирован: 24.02.2015

Для свечения сегментов - нет претензий, у меня там есть еще один который дает задержку при опросе датчика. А код, это был весь, ссылка вот http://nextable.ru/144-4-razryadnyy-7-segmentnyy-indikator-i-arduino.html. было б замечательно если получится.

Sirox
Offline
Зарегистрирован: 24.02.2015

Спасибо! Бубду пробывать

Sirox
Offline
Зарегистрирован: 24.02.2015

CheBuraw, привет!

Есть какие нибудь успехи по числам  ?

CheBuraw
Offline
Зарегистрирован: 10.02.2015

Sirox, Извините, но пока порадовать не чем :(. Все попытки успехом не увенчались. Я, ведь тоже, програмист тот еще :) сам ардуиной и програмерством в целом где-то полгода занимаюсь. Буду продолжать попытки. Я думаю Datak бы Вам помог, он мне вон сколько конструктивных советов давал, да и Вам тоже помочь успел.

Datak
Offline
Зарегистрирован: 09.10.2014

Да я отвлёкся как-то, извините. К тому же, думаю, вдруг там у вас спортивный интерес, или азарт какой-нибудь - а тут я со своими советами. :)

Sirox пишет:
По дробным и отрицательным нашол код по преобразованию , но там напрямую без регистров подключено, как совместить?

Вывод цифр там происходит в строках 41...55. Для начала можно просто заменить их на вызов нашей Indicate( i, temp ), но придётся добавить дополнительные проверки для вывода точки и минуса, и незначащие нули у них гасятся немного по-другому... так что проще получится своё написать. :)

Для начала разбираемся с минусом:

01#define SPACE 10
02#define MINUS 11
03 
04int  disp;
05bool minus;
06 
07.......
08 
09disp = -123; // получаем какое-то значение, например с датчика
10 
11.......
12 
13minus = ( disp < 0 );
14 
15if( minus ) disp = -disp;
16 
17for( int i = 0; i < 4; i++ )
18{
19   byte Value;
20 
21   if( i == 0 || disp != 0 )
22   {
23      Value = disp % 10
24      disp /= 10;
25   }
26   else
27   if( minus )
28   {
29      Value = MINUS;
30      minus = FALSE;
31   }
32   else
33   {
34      Value = SPACE;
35   }
36 
37   Indicate( i, Value );
38}

В таблицу g_digits, разумеется, надо добавить ещё одно значение - для вывода знака "минус". Попробуйте, должно работать.

Останется добавить "точку" для дробных чисел, и ещё, желательно, проверку на переполнение. Но не сейчас, попозже, ладно?

 
Sirox
Offline
Зарегистрирован: 24.02.2015

Спасибо огромное! Вечером буду пробывать, да конечно подождем 

Nemo
Offline
Зарегистрирован: 07.03.2015

Подскажите пожалуйста, купил вот такой вот шилд. http://www.aliexpress.com/snapshot/6494994863.html?orderId=65798713751283

Не могу понять как правильно подключить на 8 11 и 12 входы андруино что куда.

QH; RCLK; SCLK - на шилде, и

DS; ST_CP; SH_CP - в данной теме.

Что куда чтобы ничего не спалить?

 

CheBuraw
Offline
Зарегистрирован: 10.02.2015

Nemo, я думаю спалить Вам там ничего не удастся, если правильно подключите GND и VCC. А вот остальные пины я бы советовал Вам прозвонить тестером, на какие ноги регистров они разведены. Нам нужны 11, 12 и 14 ножки регистров.

Описание у продавца данного шильдика крайне непонятное :). Если подключить получиться. то решение очень компактное. Мне же вон что нагородить пришлось :)

Вот нашел схему подключения Вашего шилда на каком-то китайском сайте, немного погуглив :).

Судя по ней на данном шилде с одной стороны выходы именуются SCLK, RCLK и DIO , что для нашего подключения значит SH_CP, ST_CP и DS соответственно. Я так думаю что именно на этих контактах и распаены контакты для подключения на данном шилде.

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

 

Nemo
Offline
Зарегистрирован: 07.03.2015

CheBuraw Большое спасибо. По коду сам допетрил.  Все подключил, индикация работает. Девайсик действительно компактный получился.

Правильный ответ на мой вопрос, который задан постом выше такой:

RCLK - это защелка (SS, STcp); SCLK - тактовый (CLK, SHcp); а QH - остается пин данных (SDI, DS)

(Люди на соседнем ресурсе подсказали.)

Теперь вот ломаю голову как отобразить числа с плавающей точкой. Например "-3.75"

Собираю термометр на ds18b20. По индикации с минусом - получилось. К стати, по поводу минуса: как переделать цыкл for на минус так и не допетрил. Пришлось идти более длинным путем. А если брать модуль числа и после вывода подставлять минус вперед, то мерцение всех цыфр получается не здоровое. Теперь у меня в коде по if проверяется число на минус, затем через if выводится минусовое значение, а ниже в случае положительного значения - выводится через for. Может кому сгодиться.

А вот с точкой - пока ваяю.

Nemo
Offline
Зарегистрирован: 07.03.2015

Ну как то так:

001int latchPin = 8;     // Пин "защелки" первого регистра подключен к RCLK (SS, ST_CP) входу
002int clockPin = 12;    // Пин "тактовый" подключен к SCLK (CLK, SH_CP) входу 74HC595
003int dataPin = 11;     // Пин "данных" подключен к QH (SDI, DS) входу 74HC595
004 
005int TimeLight = 5;    // Время для разогрева сегментов
006 
007byte SegDisplay;      // Переменная для вывода символов на индикаторе
008byte RazrDisplay;     // Переменная для включения разрядов
009 
010// Настройка комбинации для отображения каждого номера на индикаторе
011// Массив цифр, генерирующий на сегментах цифры в двоичной системе исчисления
012byte g_digits[25]={
013 B11000000, B11111001, B10100100, B10110000, B10011001,   // 0 1 2 3 4
014 B10010010, B10000010, B11111000, B10000000, B10010000,   // 5 6 7 8 9
015 B01000000, B01111001, B00100100, B00110000, B00011001,   // 0. 1. 2. 3. 4.
016 B00010010, B00000010, B01111000, B00000000, B00010000,   // 5. 6. 7. 8. 9.
017 B01111111, B10111111, B10011100, B11000110,   // точка, прочерк, градус, цельсия
018 B11111111, };                             // все сегменты выключены
019byte g_registerArray[4]={1,2,4,8}; //массив цифр, указывающий разряды
020 
021void setup()
022{ // обозначаем все пины как выходы
023  pinMode(latchPin, OUTPUT);
024  pinMode(clockPin, OUTPUT);
025  pinMode(dataPin, OUTPUT);
026}
027 
028void loop()
029{
030  float temperature = 1.23;  // Можете подставить любые значения. Следите чтобы стояла именно . (например 5.75 а не 5,75) иначе - ошибка компаиляции вам обеспечена
031  int disp;                  // Переменная для целых чисел температуры              
032  int disp_sot;              // Переменная для дробной части числа
033   
034  disp = int (temperature);                 // Избавляемся от десятых и сотых (оставляем челую часть числа)
035  temperature = (temperature - disp) * 100; // Переводим десятые и сотые в целую часть числа
036  disp_sot = int (abs(temperature));        // Обрубаем значения после запятой (оставляем целую часть числа) модуль - для избавления от минуса
037   
038  // Разбиваем цифру по разрядам индикатора
039  if (disp < 0) // Если значение минусовое, то выполняется следующее условие
040    {
041      disp = abs(disp); // используем модуль дабы избавиться от минуса. Его мы подставим в процессе
042        /* Допустим наша цифра 25.
043           Если мы ее поделим на 10, то у нас получится 2,5. Цифры после запятой, в данном случае,
044           у нас не остаются. Таким образом мы имеем в третем разряде цифру 2.
045           В чевертый разряд мы, как раз и записываем цифру-остаток полученную в результате деления.
046           В нашем случае это и есть та самая 5.
047           Аналогичным образом разбивается наша цифра и далее.
048        */
049      if (disp < 10) // если наша цифра меньше 10, то
050        {
051        Indicate(0, disp_sot % 10);      // пишем в первый разряд сотую долю цифры
052        Indicate(1, disp_sot / 10);      // пишем во второй разряд десятую долю цифры
053        Indicate(2, disp + 10);          // пишем в третий разряд нашу цифру с точкой
054        Indicate(3, 21);                 // пишем в четвертый разряд минус
055        }
056      else if (disp < 100) // если наша цифра меньше 100, то
057        {
058        Indicate(0, disp_sot / 10);      // пишем в первый разряд десятую долю цифры
059        Indicate(1, (disp % 10) + 10);   // пишем во второй разряд - цифру оставшуюся от деления на 10 с точкой
060        Indicate(2, disp / 10);          // пишем в третий разряд - цифру делёную на 10
061        Indicate(3, 21);                 // пишем в четвертый разряд минус
062        }
063      else
064        {
065        Indicate(0, 21);    // Думаю что температура ниже 99 градусов
066        Indicate(1, 21);    // вряд ли возможна, поэтому
067        Indicate(2, 21);    // выводим прочерки во всех регистрах
068        Indicate(3, 21);
069        }    
070    }
071  else if (disp == 0)    // Значение температуры ровно 0 градусов
072    {
073        Indicate(0, 23);      // пишем в первый разряд - символ цельсия "С"
074        Indicate(1, 22);      // пишем во второй разряд - символ градуса
075        Indicate(2, disp);    // пишем в третий разряд - цифру ноль
076        Indicate(3, 24);      // пишем в четвертый разряд пусто
077    }
078  else // Если значение положительное, то выполняется следующий цикл
079    {       
080      if (disp < 10) // если наша цифра меньше 10, то
081        {
082        Indicate(0, 22);                 // пишем в первый разряд символ градуса
083        Indicate(1, disp_sot % 10);      // пишем во второй разряд сотую долю цифры
084        Indicate(2, disp_sot / 10);      // пишем в третий разряд десятую долю цифры
085        Indicate(3, disp + 10);          // пишем в четвертый разряд нашу цифру с точкой
086        }
087      else if (disp < 100) // если наша цифра меньше 100, то
088        {
089        Indicate(0, disp_sot % 10);      // пишем в первый разряд - сотую долю цифры
090        Indicate(1, disp_sot / 10);      // пишем во второй разряд - десятую долю цифры
091        Indicate(2, (disp % 10) + 10);   // пишем в третий разряд - цифру оставшуюся от деления на 10 с точкой
092        Indicate(3, disp / 10);          // пишем в четвертый разряд - цифру делёную на 10
093        }
094      else if (disp < 1000) // если наша цифра меньше 1000, то
095        {
096        Indicate(0, disp_sot / 10);      // пишем в первый разряд - десятую долю цифры
097        Indicate(1, (disp % 10) + 10);   // пишем во второй разряд - последнюю целую цифру с точкой
098        Indicate(2, (disp % 100) / 10);  // пишем в третий разряд - цифру оставшуюся от деления на 100
099        Indicate(3, (disp / 100));       // пишем в четвертый разряд - цифру делёную на 100
100        }
101       else // перестраховаться, на случай если вы засунете свой термометр в доменную печь
102        {
103        Indicate(0, 21);    // Думаю что температура выше 999 градусов
104        Indicate(1, 21);    // вряд ли возможна, поэтому
105        Indicate(2, 21);    // выводим прочерки во всех регистрах
106        Indicate(3, 21);
107        }      
108 
109/*  Как реализовать короткий цыкл с плавающей точкой с десятыми и сотыми, пока не придумал
110    for( int i = 0; i < 4; i++ )
111      {
112      if( i == 0 || disp != 0 )
113          Indicate( i, disp % 10 );
114      else
115          Indicate( i, 24 );
116      disp /= 10;
117      }
118*/     
119    }
120}
121 
122void Indicate(int r,int x) // Функция собственно, отображения цыфр на индикаторе.
123  {
124    SegDisplay=g_digits[x]; // получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре.
125    RazrDisplay=g_registerArray[r];  // получаем цифру и выводим номер регистра, из массива цифр, соответствующий этой цифре.
126    digitalWrite(latchPin, LOW);   // устанавливаем синхронизацию "защелки" на LOW
127      shiftOut(dataPin, clockPin, MSBFIRST, SegDisplay);  // Записываем информацию для первого регистра (Номер символа)
128      shiftOut(dataPin, clockPin, MSBFIRST, RazrDisplay); // Записываем информацию для второго регистра (Номер разряда)
129    digitalWrite(latchPin, HIGH);  //"защелкиваем" регистр, тем самым устанавливая значения на выходах
130   
131    delay(TimeLight); // пауза, чтобы сегменты "разгорелись"
132  }

в строке №30 можно менять значение на любый цифры, и смотреть что получается на индикаторе. Обрабатывается диапазон значений от -99,99 до +999 градусов цельсия с сотыми долями.

Прикрутить реальный датчик температуры ds18b20 думаю сможете сами. Это уже дело техники.

Осталось все это великолепие записать как библиотеку, так как в дальнейшем планирую успользовать в одном проекте несколько датчиков и несколько индикаторов. (Улица, дом, телица, аквариум, и т.д.)  Не пропадать же выходам Arduino !

Sirox
Offline
Зарегистрирован: 24.02.2015

Отличная работа, благодарствую! У тебя с датчиком получилось? А то при опросе датчика задержка которая мешает (мерцают цифры)

Nemo
Offline
Зарегистрирован: 07.03.2015

Sirox пишет:

Отличная работа, благодарствую! У тебя с датчиком получилось? А то при опросе датчика задержка которая мешает (мерцают цифры)

Спсибо. Сейчас кумекаю как эту красоту в функцию запихнуть. У меня будет датчик не один. С датчиком поке не пробовал. Привинчу - отпишусь.

К стати: переменные TimeLight, SegDisplay, RazrDisplay можно объявлять непосредственно в самой функции Indicate. Я их туда перенес.

И еще: баг какой то. Если поставить температуру 36,6 - показывает 36,59 Где то арифметика с округлениями шалит наверное. Но погрешность в 1 сотую думаю не критично.

p/s/ а как код свернуть, чтобы страницу не раздувать?

Sirox
Offline
Зарегистрирован: 24.02.2015

4 дисплея сразу это сильно) Можно проще - выводить на одном по кнопке или по интервалу, чтобы различать датчики можно докупить одноразрядный индикатор и поставить рядом, на котом будет меняться символ или цифра обозначающая тот или иной датчик.