Вывод информации на 4 разрядный 7сегментный индикатор при помощи двух 74hc595
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- следующая ›
- последняя »
- Войдите на сайт для отправки комментариев
Здравствуйте!
Для одного из проектов мне потребовались часы на 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, ... |
011 | <a href="http://www.youtube.com/watch?v=shcumKPTcTk" title="http://www.youtube.com/watch?v=shcumKPTcTk" rel="nofollow">http://www.youtube.com/watch?v=shcumKPTcTk</a> |
012 | shiftOutDisplay |
013 | <a href="https://gist.github.com/benjjo/6559436" title="https://gist.github.com/benjjo/6559436" rel="nofollow">https://gist.github.com/benjjo/6559436</a> |
014 | shiftOutAnalogueDisplay |
015 | <a href="https://gist.github.com/benjjo/6559456" title="https://gist.github.com/benjjo/6559456" rel="nofollow">https://gist.github.com/benjjo/6559456</a> |
016 | ShiftOut Reference: |
017 | <a href="http://arduino.ru/Reference/ShiftOut" title="http://arduino.ru/Reference/ShiftOut" rel="nofollow">http://arduino.ru/Reference/ShiftOut</a> |
018 | ShiftOut Tutorial: |
019 | <a href="http://arduino.ru/Reference/ShiftOut" title="http://arduino.ru/Reference/ShiftOut" rel="nofollow">http://arduino.ru/Reference/ShiftOut</a> |
020 | <a href="http://arduino.ru/Tutorial/registr_74HC595" title="http://arduino.ru/Tutorial/registr_74HC595" rel="nofollow">http://arduino.ru/Tutorial/registr_74HC595</a> |
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 |
058 | 74HC595 Map: |
059 | _______ |
060 | Q1 |1 * 16| Vcc PINS 1-7, 15 Q0 - Q7 Output Pins |
061 | Q2 |2 15| Q0 PIN 8 GND Ground, Vss |
062 | Q3 |3 14| DS PIN 9 Q7" Serial Out |
063 | Q4 |4 13| OE PIN 10 MR Master Reclear, active low |
064 | Q5 |5 12| ST_CP PIN 11 SH_CP Shift register clock pin |
065 | Q6 |6 11| SH_CP PIN 12 ST_CP Storage register clock pin (latch pin) |
066 | Q7 |7 10| MR PIN 13 OE Output enable, active low |
067 | GND |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 |
081 | int latchPin = 8; //Пин "защелки" первого регистра подключен к ST_CP входу первого регистра отвечающего за сегменты |
082 | int latchPin2 = 9; //Пин "защелки" второго регистра подключен к ST_CP входу первого регистра отвечающего за разряды |
083 | int clockPin = 12; //Пин подключен к SH_CP входу 74HC595 |
084 | int dataPin = 11; //Пин подключен к DS входу 74HC595 |
085 |
086 | int TimeLight = 5; //время для разогрева сегментов |
087 | int sensorPin=A0; |
088 |
089 | byte SegDisplay; // переменная для вывода символов на индикаторе |
090 | byte RazrDisplay; // переменная для включения разрядов |
091 |
092 | // Настройка комбинации для отображения каждого номера на дисплее. |
093 | // Комбинация выбрана на основе таблицы отображаемого знака данным порта |
094 | // Соответственно { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , dp, - } |
095 | byte g_digits[12]={192,249,164,176,153,146,130,248,128,144,127,255}; //массив цифр, генерирующий из сегментов цифры |
096 | byte g_registerArray[4]={1,2,4,8}; //массив цифр, указывающий разряды |
097 |
098 |
099 | void setup () { |
100 | // обозначаем все пины как выходы |
101 | pinMode(latchPin, OUTPUT); |
102 | pinMode(latchPin2, OUTPUT); |
103 | pinMode(clockPin, OUTPUT); |
104 | pinMode(dataPin, OUTPUT); |
105 | } |
106 |
107 | void 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 |
155 | void Segment( int x) //функция для записи в 1 регистр информации для генерации символов |
156 | { |
157 | digitalWrite(latchPin, LOW); // устанавливаем синхронизацию "защелки" на LOW |
158 | SegDisplay=g_digits[x]; // получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре. |
159 | shiftOut(dataPin, clockPin, MSBFIRST, SegDisplay); // Записываем информацию в регистр |
160 | digitalWrite(latchPin, HIGH); //"защелкиваем" регистр, тем самым устанавливая значения на выходах |
161 | } |
162 |
163 | void Razryad( int r) //функция для записи во 2 регистр номера разряда индикатора |
164 | { |
165 | digitalWrite(latchPin2, LOW); // устанавливаем синхронизацию "защелки" на LOW |
166 | RazrDisplay=g_registerArray[r]; // получаем цифру и выводим номер регистра, из массива цифр, соответствующий этой цифре. |
167 | shiftOut(dataPin, clockPin, MSBFIRST, RazrDisplay); // Записываем информацию в регистр |
168 | digitalWrite(latchPin2, HIGH); //"защелкиваем" регистр, тем самым устанавливая значения на выходах |
169 | delay(TimeLight); // пауза, чтобы сегменты "разгорелись" |
170 | } |
напрягает то что "засвечиваются" соседние разряды
Ну, а почему засвечиваются, выяснили?
Предлагаю, например, сэкономить ардуиноноги, и оставить только один выход Latch, на обе 595-е.
Заодно и засвечивание пропадёт, мне кажется.
напрягает то что "засвечиваются" соседние разряды
Ну, а почему засвечиваются, выяснили?
Предлагаю, например, сэкономить ардуиноноги, и оставить только один выход Latch, на обе 595-е.
Заодно и засвечивание пропадёт, мне кажется.
Я так думаю, что причина в функции отображения. Как-то не очень мне нравиться как она работает. Видел проекты в которых всё четко отображается, но вот в коде их я так разобраться и не смог :(. Поэтому, собственно и сюда решил написать, может кто подскажет правильный вариант.
Паралельное расположение сдвиговых регистров я оставил умышленно, т.к. мне показалось, что так код проще получается. Возможно заблуждаюсь. Идея в том чтобы в перспективе, при необходимости, можно было расширить еще на 4 разряда. Такая реализация мне проще показалась, да и так всего 4 ноги у Arduino занял.
Не знаю как сюда видео работы устройства выложить, поэтому залил на яндекс
https://yadi.sk/i/DYnnWiuTeb4jD
Да я же подсказал, осталось попробовать. :)
Проблема в том, что цифра на индикаторе меняется в один момент времени - в функции Segment(int x),
а номер разряда в другой момент - в функции Razryad(int r).
Чем эти моменты дальше друг от друга, тем больше рассинхронизация разряда и цифры, и соответственно заметнее засветка.
Можно попробовать изменить программу, чтобы строчки digitalWrite(latchPin, HIGH); и digitalWrite(latchPin2, HIGH); выполнялись подряд, и пауза между ними была как можно меньше.
Но в идеале, всё-таки советую оставить один latchPin, для достижения полной синхронности.
А увеличению разрядности это никак не помешает.
Паралельное расположение сдвиговых регистров я оставил умышленно, т.к. мне показалось, что так код проще получается.
Я, кстати, параллельное расположение менять не предлагаю. Оно ничем не мешает - пусть остаётся, если удобно.
Нужно только объединить у 595-ых сдвиговые входы, и подключить к одному выходу ардуины.
-------
Upd: Не сдвиговые конечно, а входы защёлкивания. Ошибся, извините - ночью советовал. :)
Стало интересно сколько и какие внешние устройства предполагается подключить помимо семисегментника.
Может стоит именно эти устройства подключить через сдвиговые регистры или взят I2C расширитель портов например PCF8574 и не мучаться со сдвиговыми регистрами.
А вообще вот мой код для работы с семисегментным индикатором напрямую без сдвиговых регистров но его не сложно модифицировать под регистры.
001
#include <avr/io.h>
002
#include <avr/interrupt.h>
003
/*
004
!!! Все примеры и описания функций для 4-х разрядного индикатора !!!
005
Дисплей
006
Количество разрядов индикатора (NUM_DIGITS)
007
вычисляется из размера массива COM_PIN но можно задать и в явном виде
008
*/
009
#define NUM_DIGITS sizeof(COM_PIN)
010
#define commonAnode 1 //Тип дисплея 0=Общий катод, 1=Общий анод
011
const
byte
LED_PIN[8] = {0,1,2,3,4,5,6,7};
//Массив пинов сегментов (A - G, dp)
012
const
byte
COM_PIN[] = {8,9,10,11};
//Массив пинов разрядов
013
unsigned
char
buffer[NUM_DIGITS];
//массив символов для вывода (буфер)
014
volatile unsigned
char
currentDigit = 0;
//Номер разряда для отображения
015
// массив символов для вывода на дисплей
016
prog_uchar charMap[21] PROGMEM = {
017
// биты | 6 5 4 3 2 1 0 |
018
// сегменты | a b c d e f g |
019
// Биты raw
020
0b1111110,
//0 0x00
021
0b0110000,
//1 0x01
022
0b1101101,
//2 0x02
023
0b1111001,
//3 0x03
024
0b0110011,
//4 0x04
025
0b1011011,
//5 0x05
026
0b1011111,
//6 0x06
027
0b1110000,
//7 0x07
028
0b1111111,
//8 0x08
029
0b1111011,
//9 0x09
030
0b1110111,
//a 0x0A
031
0b0011111,
//b 0x0B
032
0b1001110,
//c 0x0C
033
0b0111101,
//d 0x0D
034
0b1101111,
//e 0x0E
035
0b1000111,
//f 0x0F
036
0b1100111,
//P 0x10
037
0b0001111,
//t 0x11
038
0b0011100,
//u 0x12
039
0b0000000,
// 0x13 пустой символ (пробел)
040
0b0000001
//- 0x14 знак минус
041
};
042
043
void
setup
() {
044
//Serial.begin(9600);
045
Display_setup();
046
//так можно выводить время
047
DisplayTime(12,30,1);
048
}
049
050
void
loop
() {
051
ClearDisplay();
052
DisplayNumeric(567, 10, 1, 3);
053
delay(1000);
054
DisplayNumeric(9876, 10, 0, 4);
055
delay(1000);
056
}
057
//Функции для работы с диспле
058
void
Display_setup(){
059
// Настройка всех пинов сегментов
060
for
(
int
i=0;i<8;++i) {
061
//int temp = pgm_read_word_near(LED_PIN + i);
062
pinMode(LED_PIN[i], OUTPUT);
063
digitalWrite(LED_PIN[i], !commonAnode);
064
}
065
// Настройка всех пинов разрядов
066
for
(
int
i=0;i<NUM_DIGITS;++i) {
067
//int t = pgm_read_word_near(COM_PIN + i);
068
pinMode(COM_PIN[i], OUTPUT);
069
digitalWrite(COM_PIN[i], commonAnode);
070
}
071
// Настройка таймера Т2 на прерывание по переполнению
072
noInterrupts();
// Запрещаем прерывания
073
//Частота переключения разрядов при 16 MHz ~488 Hz (при 8 MHz ~244 Hz)
074
//разделив на количество разрядов получим общую частоту обновления
075
TCCR2B = (1<<CS20)|(1<<CS22);
//Предделитель 128
076
TIMSK2 |= (1<<TOIE2);
// Разрешение прерывания по переполнению
077
interrupts();
// Разрешаем все прерывания
078
}
079
080
void
DisplayTime(
int
mm,
int
ss, boolean dpOn){
081
unsigned
int
num = mm*100+ss;
082
for
(
int
i = 3; i>=0; --i){
083
int
digit = num % 10;
084
buffer[i] = pgm_read_byte_near(charMap+digit);
085
if
(dpOn && i==1) {
086
buffer[1] |= 0x80;
//BIN 1000 0000
087
}
088
if
(commonAnode) {
089
buffer[i] = ~buffer[i];
090
}
091
num = num / 10;
092
}
093
}
094
//просто очищаем дисплей записывая в буфер 0
095
void
ClearDisplay(){
096
for
(
int
i=NUM_DIGITS-1; i>=0; --i){
097
buffer[i] = 0;
098
if
(commonAnode) {
099
buffer[i] = ~buffer[i];
100
}
101
}
102
}
103
104
/*просто вывод чисел
105
входные данные DisplayNumeric(value, base, start, places)
106
value - число можно ввести в базисе BIN B1111 = DEC 15 = HEX 0x0F
107
base - базис выводимого числа если (BIN -2, DEC - 10, HEX - 16)
108
Пример 1: value=0x0F, base=10 на дисплее будет 15
109
Пример 2: value=15, а base=16 на дисплее будет 0F
110
Пример 2: value=9876, а base=10 на дисплее будет 9876
111
start - первый разряд с которого будет выведенно число нумерация с 0
112
places - количество разрядов для числа
113
Пример 1: start=1 places=4 можно вывести 4 значное число
114
Пример 2: start=2 places=4 можно вывести 3 значное число вывод со 2 разряда*/
115
void
DisplayNumeric(unsigned
int
value, unsigned
int
base
,
byte
start,
byte
places){
116
for
(
int
i =places+start-1;i>=start;--i) {
117
int
digit = value %
base
;
118
buffer[i] = pgm_read_byte_near(charMap+digit);
119
value = value /
base
;
120
if
(commonAnode) {
121
buffer[i] = ~buffer[i];
122
}
123
}
124
}
125
/*
126
Функция задания символов в массиве buffer. Синтаксис:
127
setdisplayRaw(position, newValue, dpOn);
128
position: номер разряда нумерация с 0
129
newValue: номер символа в массиве charMap
130
dpOn: горит ли точка 0=не горит 1=горит
131
*/
132
void
setdisplayRaw(
byte
position,
byte
newValue, boolean dpOn) {
133
if
(position < NUM_DIGITS) {
134
buffer[position] = pgm_read_byte_near(charMap+newValue);
135
if
(dpOn) {
136
buffer[position] |= 0x80;
//BIN 1000 0000
137
}
138
if
(commonAnode) {
139
buffer[position] = ~buffer[position];
140
}
141
}
142
}
143
// Обработчик прерывания по переполнению Т2
144
ISR(TIMER2_OVF_vect) {
145
//Выключаем предыдущий разряд
146
if
(currentDigit >= (NUM_DIGITS)) {
147
digitalWrite(COM_PIN[currentDigit-1], !commonAnode);
148
currentDigit = 0;
149
}
150
else
{
151
digitalWrite(COM_PIN[currentDigit-1], !commonAnode);
152
}
153
//Зажигаем сегменты соответственно массиву buffer
154
for
(
int
i=0;i<7;i++) {
155
digitalWrite(LED_PIN[i], buffer[currentDigit] & (1<<(6-i)));
156
}
157
//Зажигаем точку
158
digitalWrite(LED_PIN[7], buffer[currentDigit] & 0x80);
159
//Включаем текущий разряд
160
digitalWrite(COM_PIN[currentDigit], commonAnode);
161
++currentDigit;
162
}
Стало интересно сколько и какие внешние устройства предполагается подключить помимо семисегментника.
согласен, логичнее именно другую переферию подключить на сдвиговые регистры (если применимо), потому как врядли другую переферию нужно так часто переключать как выводы для семисегментника при динамической индикации
в данном варианте вместо PCF8574 целесообразней поставить драйвер семисегментников типа max7219
Для семисегиентников есть прекрасный драйвер stled316.
в данном варианте вместо 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 :)
Стало интересно сколько и какие внешние устройства предполагается подключить помимо семисегментника.
На данный момент хочу повесить релюшки. Согласен, ими куда проще управлять через 74hc595, но я думал сделать некую универсальную схему, чтобы любой другой мог взять данный код и подключить другие устройства, необходимые именно ему.
Но в идеале, всё-таки советую оставить один latchPin, для достижения полной синхронности.
А увеличению разрядности это никак не помешает.
Datak, большое Вам спасибо! Подключил как Вы советовали. Немного модифицировал код и УРА - все работает четко, без засветов :).
Я до этого пренебрегал данным вариантом в силу незнания как разделить данные отправляемые в разные регистры. Думал что это как-то сложно. Но после Вашей рекомендации, решил таки более детально изучить данный вариант. Как оказалось что это не сложнее моего варианта ранее. Просто данные необходима передавать, так сказать, наоборот - с начала для последнего регистра, затем для предпоследнего и т.д.
Скорректированная схема:
Итоговый код:
01
********************************************************************
02
Name : Arduino, 4-разрядный 7-сегментный индикатор, 74HC595 сдвиговый регистр, переменный резистор
03
Author : CheBuraw
04
Date : 11 Feb, 2015
05
Version : 0.9
06
********************************************************************
07
int
latchPin = 8;
//Пин "защелки" первого регистра подключен к ST_CP входу первого регистра отвечающего за сегменты
08
int
clockPin = 12;
//Пин подключен к SH_CP входу 74HC595
09
int
dataPin = 11;
//Пин подключен к DS входу 74HC595
10
11
int
TimeLight = 5;
//время для разогрева сегментов
12
int
sensorPin=A0;
13
14
byte
SegDisplay;
// переменная для вывода символов на индикаторе
15
byte
RazrDisplay;
// переменная для включения разрядов
16
17
// Настройка комбинации для отображения каждого номера на дисплее.
18
// Комбинация выбрана на основе таблицы отображаемого знака данным порта
19
// Соответственно { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , dp, - }
20
byte
g_digits[12]={192,249,164,176,153,146,130,248,128,144,127,255};
//массив цифр, генерирующий из сегментов цифры
21
byte
g_registerArray[4]={1,2,4,8};
//массив цифр, указывающий разряды
22
23
24
void
setup
() {
25
// обозначаем все пины как выходы
26
pinMode(latchPin, OUTPUT);
27
pinMode(clockPin, OUTPUT);
28
pinMode(dataPin, OUTPUT);
29
}
30
31
void
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
78
void
Indicate(
int
r,
int
x)
79
{
80
SegDisplay=g_digits[x];
// получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре.
81
RazrDisplay=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
}
А еще буду очень благодарен, если мне подскажут как информацию в спойлер прятать.
CheBuraw, рад что всё получилось.
Схема размытая, не видно, то ли там, о чём я писал, но судя по программе - да, кажется всё так.
Только лишний latchPin2 там почистить бы, чтобы с толку не сбивал. :)
А строки с 41 по 77 можно попробовать заменить на такие:
1
for
(
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
}
Должно работать, если я нигде не ошибся.
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
010
4-разрядный 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
023
74HC595 Map:
024
_______
025
Q1 |1 * 16| Vcc PINS 1-7, 15 Q0 - Q7 Output Pins
026
Q2 |2 15| Q0 PIN 8 GND Ground, Vss
027
Q3 |3 14| DS PIN 9 Q7" Serial Out
028
Q4 |4 13| OE PIN 10 MR Master Reclear, active low
029
Q5 |5 12| ST_CP PIN 11 SH_CP Shift register clock pin
030
Q6 |6 11| SH_CP PIN 12 ST_CP Storage register clock pin (latch pin)
031
Q7 |7 10| MR PIN 13 OE Output enable, active low
032
GND |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"
047
RTC_DS1307 RTC;
048
049
int
latchPin = 8;
//Пин "защелки" первого регистра подключен к ST_CP входу первого регистра отвечающего за сегменты
050
int
clockPin = 12;
//Пин подключен к SH_CP входу 74HC595
051
int
dataPin = 11;
//Пин подключен к DS входу 74HC595
052
053
int
TimeLight = 5;
//время для разогрева сегментов
054
055
byte
SegDisplay;
// переменная для вывода символов на индикаторе
056
byte
RazrDisplay;
// переменная для включения разрядов
057
058
// Настройка комбинации для отображения каждого номера на дисплее.
059
byte
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
067
byte
g_registerArray[4]={1,2,4,8};
//массив цифр, указывающий разряды
068
069
070
void
setup
() {
071
Wire.begin();
072
RTC.begin();
073
074
// обозначаем все пины как выходы
075
pinMode(latchPin, OUTPUT);
076
pinMode(clockPin, OUTPUT);
077
pinMode(dataPin, OUTPUT);
078
}
079
080
void
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
130
void
Indicate(
int
r,
int
x)
131
{
132
SegDisplay=g_digits[x];
// получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре.
133
RazrDisplay=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
}
я не понял как реализуются такие моменты
Реализуются до обидного просто.
Сначала выводится младший разряд числа - disp % 10,
а потом число делится на десять - disp /= 10 - и значит, младшим становится следующий разряд.
Индикатор 4-х разрядный, поэтому весь этот фокус повторяется в цикле 4 раза.
Дополнительная проверка, if в цикле, нужна для того чтобы не выводить нули перед старшим значащим разрядом. Вот тут я как раз немного сомневаюсь, но надеюсь что не ошибся. :)
Реализуются до обидного просто.
Сначала выводится младший разряд числа - disp % 10,
а потом число делится на десять - disp /= 10 - и значит, младшим становится следующий разряд.
Индикатор 4-х разрядный, поэтому весь этот фокус повторяется в цикле 4 раза.
Дополнительная проверка, if в цикле, нужна для того чтобы не выводить нули перед старшим значащим разрядом. Вот тут я как раз немного сомневаюсь, но надеюсь что не ошибся. :)
На индикаторе все показывается :). Круть!
..но есть один нюанс - разряды отображаются зеркально. Например сейчас 21:27, а показывается 72:12.
В принципе это не смертельно и можно поправить тут:
byte g_registerArray[4]={8,4,2,1}; //массив цифр, указывающий разряды
Крутил, вертел Ваш код, менял значения в цикле, но ничего толкового из этого так и не вышло :(
...но может Вы поправите это в Вашем варианте? (извините за наглость)
Индикатор 4-х разрядный, поэтому весь этот фокус повторяется в цикле 4 раза.
Правильно ли я понял, что если я задействую 8 разрядов, то мне необходимо будет заменить 4 на 8 в строке
1
for
(
int
i = 0; i < 4; i++ )
?
..но есть один нюанс - разряды отображаются зеркально. Например сейчас 21:27, а показывается 72:12.
Ну, бывает, да, когда вслепую программы пишешь, без проверки. :)
В принципе это не смертельно и можно поправить тут:
byte g_registerArray[4]={8,4,2,1}; //массив цифр, указывающий разряды
Крутил, вертел Ваш код, менял значения в цикле, но ничего толкового из этого так и не вышло :(
...но может Вы поправите это в Вашем варианте? (извините за наглость)
Да кажется должно помочь, если g_registerArray написать в обратном порядке. Что, действительно не работает? Так сразу не соображу что-то.
Поправить наверно не трудно, но без проверки боюсь опять обману. Попробуйте лучше там, на месте починить. В конце концов, провода идущие на разряды можно перевоткнуть.
Если уж никак не получится - пишите, придумаем что-нибудь.
Правильно ли я понял, что если я задействую 8 разрядов, то мне необходимо будет заменить 4 на 8 в строке
1
for
(
int
i = 0; i < 4; i++ )
?
Абсолютно правильно, задумано именно так. Только размер переменной disp придётся взять побольше - unsigned long - т.к. 8 разрядов в int не уместятся. И таблицу g_registerArray удлиннить, разумеется.
Ну и потом ещё отладить всё, если я опять где-то ошибся. :)
Нашел у себя ошибку в 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
001
/*
002
********************************************************************
003
Name : Arduino, 4-разрядный 7-сегментный индикатор, 74HC595 сдвиговый регистр, DS1307 RTC
004
Author : CheBuraw
005
Date : 12 Feb, 2015
006
Optimiser: Datak
007
Version : 1.1
008
********************************************************************
009
010
4-разрядный 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
023
74HC595 Map:
024
_______
025
Q1 |1 * 16| Vcc PINS 1-7, 15 Q0 - Q7 Output Pins
026
Q2 |2 15| Q0 PIN 8 GND Ground, Vss
027
Q3 |3 14| DS PIN 9 Q7" Serial Out
028
Q4 |4 13| OE PIN 10 MR Master Reclear, active low
029
Q5 |5 12| ST_CP PIN 11 SH_CP Shift register clock pin
030
Q6 |6 11| SH_CP PIN 12 ST_CP Storage register clock pin (latch pin)
031
Q7 |7 10| MR PIN 13 OE Output enable, active low
032
GND |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"
047
RTC_DS1307 RTC;
048
049
int
latchPin = 8;
//Пин "защелки" первого регистра подключен к ST_CP входу первого регистра отвечающего за сегменты
050
int
clockPin = 12;
//Пин подключен к SH_CP входу 74HC595
051
int
dataPin = 11;
//Пин подключен к DS входу 74HC595
052
053
int
TimeLight = 5;
//время для разогрева сегментов
054
055
byte
SegDisplay;
// переменная для вывода символов на индикаторе
056
byte
RazrDisplay;
// переменная для включения разрядов
057
058
// Настройка комбинации для отображения каждого номера на дисплее.
059
060
byte
g_digits[11]={
061
B01000000, B01111001,
// 0 1
062
B00100100, B00110000,
// 2 3
063
B00011001, B00010010,
// 4 5
064
B00000010, B01111000,
// 6 7
065
B00000000, B00010000,
// 8 9
066
B11111111, };
// все сегменты выключены
067
068
byte
g_registerArray[4]={8,4,2,1};
//массив цифр, указывающий разряды
069
070
void
setup
() {
071
Wire.begin();
072
RTC.begin();
073
074
// обозначаем все пины как выходы
075
pinMode(latchPin, OUTPUT);
076
pinMode(clockPin, OUTPUT);
077
pinMode(dataPin, OUTPUT);
078
}
079
080
void
loop
() {
081
int
hour,minute,disp = 0;
082
083
DateTime now = RTC.now();
//Создаём переменную для вывода времени
084
085
hour = now.hour();
// Считываем значение часов
086
minute = now.minute();
// Считываем значение минут
087
088
disp = (hour * 100) + minute;
//"Собираем" значения часов и минут в одну цифру
089
090
// Разбиваем цифру по разрядам индикатора
091
for
(
int
i = 0; i < 4; i++ )
092
{
093
if
( i == 0 || disp != 0 )
094
Indicate( i, disp % 10 );
095
else
096
Indicate( i, 10 );
097
098
disp /= 10;
099
}
100
101
}
102
103
void
Indicate(
int
r,
int
x)
104
{
105
SegDisplay=g_digits[x];
// получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре.
106
RazrDisplay=g_registerArray[r];
// получаем цифру и выводим номер регистра, из массива цифр, соответствующий этой цифре.
107
digitalWrite(latchPin, LOW);
// устанавливаем синхронизацию "защелки" на LOW
108
shiftOut(dataPin, clockPin, MSBFIRST, RazrDisplay);
// Записываем информацию для второго регистра (Номер разряда)
109
shiftOut(dataPin, clockPin, MSBFIRST, SegDisplay);
// Записываем информацию для первого регистра (Номер символа)
110
digitalWrite(latchPin, HIGH);
//"защелкиваем" регистр, тем самым устанавливая значения на выходах
111
112
delay(TimeLight);
// пауза, чтобы сегменты "разгорелись"
113
}
...но и тут есть небольшая недоработочка - в 0 часов будут показываться только минуты :).
Корректируется исправлением нашего пресловутого Indicate(0, 10); на Indicate(0, 0); и в этом случае до 10 утра часы будут отображаться в формате 00, 01, 02, ..., 09. Если не напрягает, то скетч готов к использованию. Ну а если кому надо будет, то, думаю, допилят. ...а может и сам как-нибудь попозже доделаю.
Корректируется исправлением нашего пресловутого Indicate(0, 10); на Indicate(0, 0); и в этом случае до 10 утра часы будут отображаться в формате 00, 01, 02, ..., 09.
Не, исправляется это тем, что условие if -- else в цикле вообще убирается, оставляется просто
1
Indicate( i, disp % 10 );
Результат должен получиться тот же.
А если всё же хочется чтобы часы показывались без лишних нулей, можно условие поменять на такое:
1
if
( i < 3 || disp != 0 )
Да! На сколько все просто, как оказывается, решается :).
А я уж пробовал внуть Вашего кода еще один if запихать, но ничего путёвого из этого не получилось.
Добрый день, спасибо за код!
Все собрал, но как выяснилось у меня общий катод, подскажите новичку что нужно изменить в коде или в схеме подключения.
Щас нет возможности проверить, но если инвертировать эти значения то поможет ?
1
B01000000, B01111001,
// 0 1
2
B00100100, B00110000,
// 2 3
3
B00011001, B00010010,
// 4 5
4
B00000010, B01111000,
// 6 7
5
B00000000, B00010000,
// 8 9
6
B11111111, };
// все сегменты выключены
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 |
|_________|
Остальные цифры давайте сами ;) !
Если не получиться, то пишите.
Не выходит, и так и пробовал и эдак, даташит моего индикатора http://zip-2002.ru/z_pdf/kem-5461agr-1.pdf / Предпологаю что порядок сегментов у меня другой, поэтому такая абра кадабра выводится.
а если просто инвертировать значение? для сегментов и для общего анода или катода
а лучше добавить переменную типа boolean которой задаешь общий катор иди анод
01
#include <Wire.h>
02
03
int
latchPin = 2;
//Пин "защелки" первого регистра подключен к ST_CP входу первого регистра отвечающего за сегменты
04
int
clockPin = 3;
//Пин подключен к SH_CP входу 74HC595
05
int
dataPin = 4;
//Пин подключен к DS входу 74HC595
06
07
int
TimeLight = 5;
//время для разогрева сегментов
08
09
byte
SegDisplay;
// переменная для вывода символов на индикаторе
10
byte
RazrDisplay;
// переменная для включения разрядов
11
12
// Настройка комбинации для отображения каждого номера на дисплее.
13
14
byte
g_digits[11]={
15
B00111111, B00000110,
// 0 1
16
B01011011, B01001111,
// 2 3
17
B01100110, B01101101,
// 4 5
18
B01111101, B00000111,
// 6 7
19
B01111111, B01101111,
// 8 9
20
B00000000, };
// все сегменты выключены
21
22
byte
g_registerArray[4]={8,4,2,1};
//массив цифр, указывающий разряды
23
24
void
setup
() {
25
Wire.begin();
26
27
// обозначаем все пины как выходы
28
pinMode(latchPin, OUTPUT);
29
pinMode(clockPin, OUTPUT);
30
pinMode(dataPin, OUTPUT);
31
}
32
33
void
loop
() {
34
int
hour,minute,disp = 0;
35
36
hour = 99;
// Считываем значение часов
37
minute = 89;
// Считываем значение минут
38
39
disp = (hour * 100) + minute;
//"Собираем" значения часов и минут в одну цифру
40
41
// Разбиваем цифру по разрядам индикатора
42
for
(
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
54
void
Indicate(
int
r,
int
x)
55
{
56
SegDisplay=g_digits[x];
// получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре.
57
RazrDisplay=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
}
что такое shiftOut. цикл от 0 до 8 (или наоборот) и перебор битов с дерганьем clock.
можно залезть в файлы, и найти что делает конктено shiftOut, переделать, добавить инверсию или доп. параметр boolean через & и радоваться жизни
да и незачем делать такое
1
disp = (hour * 100) + minute;
если умеешь выводить цифрц в нужном месте, и разбивать число по разрядам
а то получается собираем число сотни и тысячи + десятки и еденицы, а потом снова разделяем
Sirox, посмотрите повнимательнее, может где соединили не так. У меня такое было :). Долго мучался, потом нашел и все запустилось. Порой даже проще все провода повыдё1ргивать и заново подключить.
Ноги Вашего индикатора, судя по представленному даташиту, полностью совпадают с моим индикатором. Так что тут все должно быть нормально.
Пока еще не разобрал свою схему, залил Ваш скетч. Все нормально работает.
jeka_tm, из всех найденных мною вариантов, только этот мне показался понятным, поэтому я и сделал по этому принципу.
Буду Вам очень признателен, да думаю и не я один, если Вы покажете Ваше решение вывода цифр в заданном разряде. Если Ваш код будет короче и понятнее, то буду использовать его ;) !
Спасибо за отзывчивость ! Проверял уже раза 3, буду ковыряться дальше, приносит это дело удовольствие мне )
1
disp = (hour * 100) + minute;
я этот вариант предлагал так как ТС мог выводить число, но не умел похоже выводить отдельную цифру в нужном разряде
вот посмотри код. может наведет на мысли переделать
переменная anod кстати задает общий анод или катод подключен
01
//==================================================================================
02
// Зажигаем сегменты
03
//==================================================================================
04
void
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);
Sirox, дело это интересное, и представленный мною скетч, для кого-то, сущая фигня, но для меня он такой выстраданный :). Недели две сидел вникал в работу регистров и собирал этот код из других кусочков :).
Вы отключите катоды индикатора от второго регистра и поочерёдно их подключите к минусу. Посмотрите что будет. Должно на тех что подключены отображаться какое-то число.
Если вновь ничего не получиться, то попробуйте для начала с одним регистром 74HC595 например такой скетч:
001
/*
002
********************************************************************
003
Name : shiftOutAnalogueDisplay, Test code
004
Author : Benjo Charlie
005
Date : 13 Sept, 2013
006
Version : 1.0
007
Notes : This is an adaptation of the ReadAnalogVoltage tutorial.
008
:
009
: The idea is to map the analogue input voltage and display that
010
: mapped value on a 7 segment display via a shiftbit register.
011
Tutorial: 74HC595 Shift Bit Register using a 7 Segment Display, ...
012
013
<a href="http://www.youtube.com/watch?v=shcumKPTcTk" title="http://www.youtube.com/watch?v=shcumKPTcTk" rel="nofollow">http://www.youtube.com/watch?v=shcumKPTcTk</a>
014
Shift Bit Registers can be a little tricky to map out and setup. I designed this simple bit of code to help you do just that. A simple bit shift operation that sends a HIGH signal down each of the Shift Bit Registers pins in turn. i.e. shiftOutDisplay
015
I've also developed this very simple method that goes hand in hand with the code and should be a good starting point for anyone who is not too familiar with Binary.
016
Finally, I've added some useful code to display the map that you've created. i.e.
017
I hope you find it useful, I know I've had a lot of fun with this stuff :)
018
019
LINKS:
020
shiftOutDisplay
021
<a href="https://gist.github.com/benjjo/6559436" title="https://gist.github.com/benjjo/6559436" rel="nofollow">https://gist.github.com/benjjo/6559436</a>
022
023
shiftOutAnalogueDisplay
024
<a href="https://gist.github.com/benjjo/6559456" title="https://gist.github.com/benjjo/6559456" rel="nofollow">https://gist.github.com/benjjo/6559456</a>
025
026
ShiftOut Reference:
027
<a href="http://arduino.ru/Reference/ShiftOut" title="http://arduino.ru/Reference/ShiftOut" rel="nofollow">http://arduino.ru/Reference/ShiftOut</a>
028
029
ShiftOut Tutorial:
030
<a href="http://arduino.cc/en/Tutorial/ShiftOut" title="http://arduino.cc/en/Tutorial/ShiftOut" rel="nofollow">http://arduino.cc/en/Tutorial/ShiftOut</a>
031
032
Music written by Tom Cusack
033
Composer -- Tom Cusack
034
Music from <a href="http://www.freemusicforvideos.com" title="www.freemusicforvideos.com" rel="nofollow">www.freemusicforvideos.com</a>
035
********************************************************************
036
037
7 Segment (Common Anode) Display Map: (This can be altered to reflect your HW)
038
039
D E 5V F G
040
___|___|___|___|___|____
041
| |
042
| F |
043
| E G |
044
| D |
045
| A C |
046
| B H(Dot) |
047
|________________________|
048
| | | | |
049
A B 5V C H
050
051
74HC595 Map:
052
_______
053
Q1 |1 * 16| Vcc PINS 1-7, 15 Q0 - Q7 Output Pins
054
Q2 |2 15| Q0 PIN 8 GND Ground, Vss
055
Q3 |3 14| DS PIN 9 Q7" Serial Out
056
Q4 |4 13| OE PIN 10 MR Master Reclear, active low
057
Q5 |5 12| ST_CP PIN 11 SH_CP Shift register clock pin
058
Q6 |6 11| SH_CP PIN 12 ST_CP Storage register clock pin (latch pin)
059
Q7 |7 10| MR PIN 13 OE Output enable, active low
060
GND |8_____9| Q7" PIN 14 DS Serial data input
061
PIN 16 Vcc Positive supply voltage
062
_______
063
LED Q1-|1 * 16|-5V
064
LED Q2-|2 15|-LED Q0
065
LED Q3-|3 14|-PIN 11
066
LED Q4-|4 13|-GND
067
LED Q5-|5 12|-PIN 8
068
LED Q6-|6 11|-PIN 12 ; 1uF TO GND
069
DOT Q7-|7 10|-5V
070
GND-|8_____9|-NILL
071
072
*/
073
074
int
latchPin = 8;
//Pin connected to ST_CP of 74HC595
075
int
clockPin = 12;
//Pin connected to SH_CP of 74HC595
076
int
dataPin = 11;
//Pin connected to DS of 74HC595
077
byte
SegDisplay;
078
int
sensorPin=A0;
079
080
// Setup the combination to display each number on the display
081
byte
ZERO = 1;
// A number value goes here.
082
byte
ONE = 2;
083
byte
TWO = 4;
084
byte
THREE = 8;
085
byte
FOUR = 16;
086
byte
FIVE = 32;
087
byte
SIX = 64;
088
byte
SEVEN = 128;
089
byte
EIGHT = 512;
090
byte
NINE = 144;
091
byte
MAX = 128;
092
093
void
setup
() {
094
pinMode(8, OUTPUT);
095
pinMode(12, OUTPUT);
096
pinMode(11, OUTPUT);
097
Serial
.begin(9600);
098
}
099
100
void
loop
() {
101
int
analogueValue = analogRead(sensorPin);
102
103
analogueValue = map(analogueValue, 0, 1023, 0, 10);
104
105
digitalWrite(latchPin, LOW);
106
107
if
(analogueValue==0) SegDisplay=ZERO;
// Min value
108
if
(analogueValue==1) SegDisplay=ONE;
109
if
(analogueValue==2) SegDisplay=TWO;
110
if
(analogueValue==3) SegDisplay=THREE;
111
if
(analogueValue==4) SegDisplay=FOUR;
112
if
(analogueValue==5) SegDisplay=FIVE;
113
if
(analogueValue==6) SegDisplay=SIX;
114
if
(analogueValue==7) SegDisplay=SEVEN;
115
if
(analogueValue==8) SegDisplay=EIGHT;
116
if
(analogueValue==9) SegDisplay=NINE;
117
if
(analogueValue>9) SegDisplay=MAX;
// Max Value: illuminate Dot
118
119
shiftOut(dataPin, clockPin, MSBFIRST, SegDisplay);
120
121
digitalWrite(latchPin, HIGH);
//take the latch pin high so the LEDs will light up:
122
123
// Print out the corresponding Shift Bit Register pin with it's value.
124
Serial
.print(
"analogueValue = "
);
125
Serial
.println(analogueValue);
126
Serial
.print(
"SegDisplay = "
);
127
Serial
.println(SegDisplay, BIN);
128
129
delay(100);
// Allow to settle
130
}
Я с него начинал :). Только тут надо еще переменный резистор подключить к A0, выше есть схема подключения. В скетче есть ссылка на ролик ютубовкий, он на английском, но, даже если Вы им и не владеете, то думаю в общих чертах поймете о чем речь идет.
jeka_tm, правильно ли я понимаю что предложенный Вами код это фрагмент какого-то большого кода? Вы его выкладывали куда-нибудь? Можно ли его целиком посмотреть? Просто судя по незакрытой скобке функции void F_Seg там должен быть еще код.
Если Вам не трудно, можете прокомментировать, для таких бестолковых как я, смысл каждой строки в представленном Вами фрагменте.
да весь смысла нет
01
void
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 и делает тоже самое, ну почти. шим не отрубает на выходе
jeka_tm, правильно ли я понял, что этот код некая альтернатива shiftOut? Или тут есть и средство разбиения цифр на разряды, т.е. записи каждой цифры в нужный разряд?
это не альтернатива. это код для управления индикатором без 74HC595. а точнее 1 цифрой просто ногодрыганьем
короче это долго. если работает оставь как есть
Sirox, инвертировать нужно не только массив g_digits, но и g_registerArray тоже.
В остальном - всё так же, по-моему. Должно работать.
1
byte
g_registerArray[4]={8,4,2,1};
А каким образом? 1,2,4,8 делал, не получается. Может цифры другие должны быть?
1
byte
g_registerArray[4]={~8,~4,~2,~1};
//массив цифр, указывающий разряды
Одна голова хорошо, а две лучше, спасибо все заработало!
Доброго дня, дисплей я планирую приспособить для авто по типу (без верхней шкалы)
Есть проблемы по выводу дробных и отрицательных чисел , а также по избавлению от delay
Вот код для вывода temp, цифры моргают, как правильно использовать millis или библиотеку которая это просто сделает?
01
#include <Wire.h>
02
#include <OneWire.h>
03
#include <DallasTemperature.h>
04
#define ONE_WIRE_BUS 5
05
06
int
latchPin = 2;
//Пин "защелки" первого регистра подключен к ST_CP входу первого регистра отвечающего за сегменты
07
int
clockPin = 3;
//Пин подключен к SH_CP входу 74HC595
08
int
dataPin = 4;
//Пин подключен к DS входу 74HC595
09
10
int
TimeLight = 5;
//время для разогрева сегментов
11
12
byte
SegDisplay;
// переменная для вывода символов на индикаторе
13
byte
RazrDisplay;
// переменная для включения разрядов
14
15
// Настройка комбинации для отображения каждого номера на дисплее.
16
17
byte
g_digits[11]={
18
B00111111, B00000110,
// 0 1
19
B01011011, B01001111,
// 2 3
20
B01100110, B01101101,
// 4 5
21
B01111101, B00000111,
// 6 7
22
B01111111, B01101111,
// 8 9
23
B00000000, };
// все сегменты выключены
24
25
byte
g_registerArray[4]={~8,~4,~2,~1};
//массив цифр, указывающий разряды
26
27
OneWire oneWire(ONE_WIRE_BUS);
28
DallasTemperature sensors(&oneWire);
29
30
float
temp = 0;
31
32
void
setup
() {
33
34
// start serial port
35
Serial
.begin(9600);
36
// Start up the library
37
sensors.begin();
38
39
// обозначаем все пины как выходы
40
pinMode(latchPin, OUTPUT);
41
pinMode(clockPin, OUTPUT);
42
pinMode(dataPin, OUTPUT);
43
}
44
45
void
loop
() {
46
int
disp = 0;
47
48
sensors.requestTemperatures();
49
temp=sensors.getTempCByIndex(0);
50
Serial
.print(temp);
51
52
disp = temp;
53
// Разбиваем цифру по разрядам индикатора
54
for
(
int
i = 0; i < 4; i++ )
55
{
56
if
( i == 0 || disp != 0 )
57
Indicate( i, disp % 10 );
58
else
59
Indicate( i, 10 );
60
61
disp /= 10;
62
}
63
64
}
65
66
void
Indicate(
int
r,
int
x)
67
{
68
SegDisplay=g_digits[x];
// получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре.
69
RazrDisplay=g_registerArray[r];
// получаем цифру и выводим номер регистра, из массива цифр, соответствующий этой цифре.
70
digitalWrite(latchPin, LOW);
// устанавливаем синхронизацию "защелки" на LOW
71
shiftOut(dataPin, clockPin, MSBFIRST, RazrDisplay);
// Записываем информацию для второго регистра (Номер разряда)
72
shiftOut(dataPin, clockPin, MSBFIRST, SegDisplay);
// Записываем информацию для первого регистра (Номер символа)
73
digitalWrite(latchPin, HIGH);
//"защелкиваем" регистр, тем самым устанавливая значения на выходах
74
75
delay(TimeLight);
// пауза, чтобы сегменты "разгорелись"
76
}
По дробным и отрицательным нашол код по преобразованию , но там напрямую без регистров подключено, как совместить?
01
void
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
59
void
setup
()
60
{
61
62
}
63
64
65
66
void
loop
()
67
{
68
ledDigitDisplay(3.14, 2);
69
ledDigitDisplay(123, 2);
70
ledDigitDisplay(-5, 2);
71
}
по millis():
unsigned long a; Объявили переменную
if (a<=millis()) {Выполнили; a=millis()+5000;} Проверили, произвели действия, обновили значение задержки (5 секунд)
Все.
Sirox, delay в обоих схемах используется для свечения сегментов. Сама по себе задержка минимальна и я думаю что она сильно не должна мешать. Как я понимаю delay не всегда плохо и порой без него сложно (но задействуя разные прерывания, можно) обойтись. Ну это мое ламерское заключение :).
По поводу предложенного Вами кода. А можете его целиком и под спойлер выложить, или ссылочку на него дать? Думаю я смогу их "объединить", ну или по крайней мере попробую :). Самому интересно себя проверить.
Для свечения сегментов - нет претензий, у меня там есть еще один который дает задержку при опросе датчика. А код, это был весь, ссылка вот http://nextable.ru/144-4-razryadnyy-7-segmentnyy-indikator-i-arduino.html. было б замечательно если получится.
Спасибо! Бубду пробывать
CheBuraw, привет!
Есть какие нибудь успехи по числам ?
Sirox, Извините, но пока порадовать не чем :(. Все попытки успехом не увенчались. Я, ведь тоже, програмист тот еще :) сам ардуиной и програмерством в целом где-то полгода занимаюсь. Буду продолжать попытки. Я думаю Datak бы Вам помог, он мне вон сколько конструктивных советов давал, да и Вам тоже помочь успел.
Да я отвлёкся как-то, извините. К тому же, думаю, вдруг там у вас спортивный интерес, или азарт какой-нибудь - а тут я со своими советами. :)
Вывод цифр там происходит в строках 41...55. Для начала можно просто заменить их на вызов нашей Indicate( i, temp ), но придётся добавить дополнительные проверки для вывода точки и минуса, и незначащие нули у них гасятся немного по-другому... так что проще получится своё написать. :)
Для начала разбираемся с минусом:
01
#define SPACE 10
02
#define MINUS 11
03
04
int
disp;
05
bool
minus;
06
07
.......
08
09
disp = -123;
// получаем какое-то значение, например с датчика
10
11
.......
12
13
minus = ( disp < 0 );
14
15
if
( minus ) disp = -disp;
16
17
for
(
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, разумеется, надо добавить ещё одно значение - для вывода знака "минус". Попробуйте, должно работать.
Останется добавить "точку" для дробных чисел, и ещё, желательно, проверку на переполнение. Но не сейчас, попозже, ладно?
Спасибо огромное! Вечером буду пробывать, да конечно подождем
Подскажите пожалуйста, купил вот такой вот шилд. http://www.aliexpress.com/snapshot/6494994863.html?orderId=65798713751283
Не могу понять как правильно подключить на 8 11 и 12 входы андруино что куда.
QH; RCLK; SCLK - на шилде, и
DS; ST_CP; SH_CP - в данной теме.
Что куда чтобы ничего не спалить?
Nemo, я думаю спалить Вам там ничего не удастся, если правильно подключите GND и VCC. А вот остальные пины я бы советовал Вам прозвонить тестером, на какие ноги регистров они разведены. Нам нужны 11, 12 и 14 ножки регистров.
Описание у продавца данного шильдика крайне непонятное :). Если подключить получиться. то решение очень компактное. Мне же вон что нагородить пришлось :)

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

Судя по ней на данном шилде с одной стороны выходы именуются SCLK, RCLK и DIO , что для нашего подключения значит SH_CP, ST_CP и DS соответственно. Я так думаю что именно на этих контактах и распаены контакты для подключения на данном шилде.
Еще я обратил внимание, что тут к первому регистру подключены разряды, а ко второму сегменты. Таким образом для работы с нашим скетчем Вам потребуется поменять очередность регистров в функции Indicate. Ниже уже подкорретированный для Вас вариант.
01
void
Indicate(
int
r,
int
x)
02
{
03
SegDisplay=g_digits[x];
// получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре.
04
RazrDisplay=g_registerArray[r];
// получаем цифру и выводим номер регистра, из массива цифр, соответствующий этой цифре.
05
digitalWrite(latchPin, LOW);
// устанавливаем синхронизацию "защелки" на LOW
06
shiftOut(dataPin, clockPin, MSBFIRST, SegDisplay);
// Записываем информацию для второго регистра (Номер символа)
07
shiftOut(dataPin, clockPin, MSBFIRST, RazrDisplay);
// Записываем информацию для первого регистра (Номер разряда)
08
digitalWrite(latchPin, HIGH);
//"защелкиваем" регистр, тем самым устанавливая значения на выходах
09
10
delay(TimeLight);
// пауза, чтобы сегменты "разгорелись"
11
}
CheBuraw Большое спасибо. По коду сам допетрил. Все подключил, индикация работает. Девайсик действительно компактный получился.
Правильный ответ на мой вопрос, который задан постом выше такой:
RCLK - это защелка (SS, STcp); SCLK - тактовый (CLK, SHcp); а QH - остается пин данных (SDI, DS)
(Люди на соседнем ресурсе подсказали.)
Теперь вот ломаю голову как отобразить числа с плавающей точкой. Например "-3.75"
Собираю термометр на ds18b20. По индикации с минусом - получилось. К стати, по поводу минуса: как переделать цыкл for на минус так и не допетрил. Пришлось идти более длинным путем. А если брать модуль числа и после вывода подставлять минус вперед, то мерцение всех цыфр получается не здоровое. Теперь у меня в коде по if проверяется число на минус, затем через if выводится минусовое значение, а ниже в случае положительного значения - выводится через for. Может кому сгодиться.
А вот с точкой - пока ваяю.
Ну как то так:
001
int
latchPin = 8;
// Пин "защелки" первого регистра подключен к RCLK (SS, ST_CP) входу
002
int
clockPin = 12;
// Пин "тактовый" подключен к SCLK (CLK, SH_CP) входу 74HC595
003
int
dataPin = 11;
// Пин "данных" подключен к QH (SDI, DS) входу 74HC595
004
005
int
TimeLight = 5;
// Время для разогрева сегментов
006
007
byte
SegDisplay;
// Переменная для вывода символов на индикаторе
008
byte
RazrDisplay;
// Переменная для включения разрядов
009
010
// Настройка комбинации для отображения каждого номера на индикаторе
011
// Массив цифр, генерирующий на сегментах цифры в двоичной системе исчисления
012
byte
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, };
// все сегменты выключены
019
byte
g_registerArray[4]={1,2,4,8};
//массив цифр, указывающий разряды
020
021
void
setup
()
022
{
// обозначаем все пины как выходы
023
pinMode(latchPin, OUTPUT);
024
pinMode(clockPin, OUTPUT);
025
pinMode(dataPin, OUTPUT);
026
}
027
028
void
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
122
void
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 !
Отличная работа, благодарствую! У тебя с датчиком получилось? А то при опросе датчика задержка которая мешает (мерцают цифры)
Отличная работа, благодарствую! У тебя с датчиком получилось? А то при опросе датчика задержка которая мешает (мерцают цифры)
Спсибо. Сейчас кумекаю как эту красоту в функцию запихнуть. У меня будет датчик не один. С датчиком поке не пробовал. Привинчу - отпишусь.
К стати: переменные TimeLight, SegDisplay, RazrDisplay можно объявлять непосредственно в самой функции Indicate. Я их туда перенес.
И еще: баг какой то. Если поставить температуру 36,6 - показывает 36,59 Где то арифметика с округлениями шалит наверное. Но погрешность в 1 сотую думаю не критично.
p/s/ а как код свернуть, чтобы страницу не раздувать?
4 дисплея сразу это сильно) Можно проще - выводить на одном по кнопке или по интервалу, чтобы различать датчики можно докупить одноразрядный индикатор и поставить рядом, на котом будет меняться символ или цифра обозначающая тот или иной датчик.