mag155, дайте определение динамической индикации, а не выжимайте из AVR невозможного. Если динамику делать на ардуинке, то считаем: время затухания светодиода, после того как убираете напряжение и скорость обновления (полного прохода) по коду. Тут, как писано в старых учебниках, надо, при большом количестве диодов, повышать напряжение, что бы горели лучше. Но, индикатор может сгореть, если что то не так пойдет. Если мигает - результат большого времени работы программного кода.
Есть отдельные драйвера, которые сами делают индикацию, а ардуинка подает только данные для определенного диода.
А, так получается, Вы пытаетесь что выжать из ее максимума. Я не хочу Вас обидеть. Просто надо искать ошибки не только кода, но и железа.
Я и пытаюсь с ардуинки сделать драйвер чтоб можно было подключать любой индикатор. И к моему восторгу это таки получилось. Сейчас просто передаю значение с другой ардуины потенциометра но что то голова совсем зависла передает только от 0до 250 а надо от 0 до 1023??? Пойду наверно кофе бахну.
void loop() {
if (radio.available()) {
while (radio.available()) {
val = radio.read();
}
float numbers[] = {val};
Serial.println(val);
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
getDigits(numbers[numindex]);
numindex += 1;
if (numindex >= sizeof(numbers)/sizeof(float)) numindex = 0;
}
displayMessage(arr);
}
}
фигня получилась - скобки расставьте правильно, а то получается что отображение на дисплей происходит с периодом interval только в том случае если по SErial вам что то придет иначе ничего не отображается
нарисуте на бумаге (или в голове мысленно) что должно происходить
1. т.е. каждые полсекунды чтение датчика
2. при каждом loop отображение значения датчика
3. при приеме байта (слова) из Serial выводить в монитор число и что то делать
и все это должно работать независимо друг от друга
То что индикатор работает только если пришли данные мне подходит . Но я не пойму где вы видите что он моргает с периодом интервал ??? Подскажите а то реально не пойму где?
void loop() {
if (radio.available()) {
while (radio.available()) {
val = radio.read();
}
float numbers[] = {val};
Serial.println(val);
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
getDigits(numbers[numindex]);
numindex += 1;
}
if (numindex >= sizeof(numbers)/sizeof(float)) numindex = 0;
displayMessage(arr);
}
}
вот и разбирайтесь почему, т.е. эту переменную надо сделать или глобальной и учитывать в функции рисования или передавать значение как второй параметр в процедуру.
Чтоб отображать точку, надо установить нужный бит в нужное состояние, соответственно в вашей процедуре заполняющей нужные биты необходимо дополнить нужное условие, например если второй разряд = установить 7 бит - одна строка программы
В начале темы автор сделал схему подключения скетч для индикатора с общим анода. Что можно сделать если индикатор с общим катодом? без транзисторов не обойтись?
Только у вас там где 1 должен быть 0. К примеру цифра "0" при общем аноде имеет
бинарный вид: 11000000 = 192 в десятичном виде, при общем катоде:
бинарный вид: 00111111 = 63 в десятичном виде, и так далее для остальных символов.
При этом не забудте поправить и массив для разрядов. там так же нужно пересчитать по тому же принципу:
общий анод, первый разряд 00000001 = 1
общий катод, 11111110 = 254
а можно еще проще для разрядов - имеющийся адрес вычитать из 255:
255-1=254, 255-2=253, 255-4=251, 255-8=247 и тогда для разрядов адреса будут такие:
А нужны ли эти заморочки когда есть дешевая микросхема TM1650, а также TM1637 TM1638
Лично я затеял все это потому что было много трофейных 74hc595 и думал куда их можно пристроить, хотелось вообще разобраться как с ними можно работать и нужен был индикатор для одной поделки.
Лично я затеял все это потому что было много трофейных 74hc595 и думал куда их можно пристроить, хотелось вообще разобраться как с ними можно работать и нужен был индикатор для одной поделки.
Да я тоже самое делал. Просто сейчас если и ставить только расширения выходных портов, для семисегментного уже пожалуй нет
Есть статья на радиокоте https://www.radiokot.ru/lab/controller/08/ с использованием 9 разрядов 7 сегментного индикатора от телефона Русь 25-27. Лежал у меня подобный индикатор но сравнив схемы я обнаружил в своем варианте некоторые отличия и решил отрисовать свой вариант. Плата панельки построена на 3-х индикаторах TOT-3361AH-1N с общим катодом и двух сдвиговых регистра 74HC595D.
Сегменты распаяны хаотично. Первым идет сдиговый регистр разрядов а потом сегментов.
Вывести что то адекватное на него не получается. Код привожу ниже, адаптировав его под Общий катод и сдвиговые регистры.
1) То есть нужно воять свою таблицу символов под данную распайку сегментов?
int latchPin = 10; //Пин "защелки" первого регистра подключен к ST_CP входу первого регистра отвечающего за сегменты
int clockPin = 13; //Пин подключен к SH_CP входу 74HC595
int dataPin = 12; //Пин подключен к DS входу 74HC595
int TimeLight = 2; //время для разогрева сегментов
int sensorPin = A0;
byte SegDisplay; // переменная для вывода символов на индикаторе
byte RazrDisplay; // переменная для включения разрядов
// Настройка комбинации для отображения каждого номера на дисплее.
// Комбинация выбрана на основе таблицы отображаемого знака данным порта
// Соответственно { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , dp, - }
byte g_digits[12] = {63, 6, 91, 79, 102, 109, 125, 7, 127, 111, 128, 64}; //OK, массив цифр, генерирующий из сегментов цифры
byte g_registerArray[9] = {254, 253, 251, 247, 239, 223, 191, 127, 255}; //OK, массив цифр, указывающий разряды
void setup() {
// обозначаем все пины как выходы
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}
void loop() {
int disp = 0; //создаем переменную для вывода на экран
int analogueValue = analogRead(sensorPin); // читаем аналоговый пин A0
analogueValue = map(analogueValue, 0, 1023, 0, 8888); //преобразуем диапазон с А0 (0-1023) в нужный нам (0-8888)
disp = analogueValue; // записываем получившуюся после преобразования цифру в переменну для вывода на экран
// Разбиваем цифру по разрядам индикатора
if (disp < 10) // если наша цифра меньше 10, то
{
Indicate(5, 11); // пишем в первый разряд пусто
Indicate(6, 11); // пишем во второй разряд пусто
Indicate(7, 11); // пишем в третий разряд пусто
Indicate(8, disp); // пишем в четвертый разряд нашу цифру
}
else if (disp < 100) // если наша цифра меньше 100, то
{
Indicate(5, 11); // пишем в первый разряд пусто
Indicate(6, 11); // пишем во второй разряд пусто
Indicate(7, disp / 10); // пишем в третий разряд - цифру делёную на 10
Indicate(8, disp % 10); // пишем в четвертый разряд цифру оставшуюся от деления на 10
/*
Допустим наша цифра 25.
Если мы ее поделим на 10, то у нас получится 2,5. Цифры после запятой, в данном случае,
у нас не остаются. Таким образом мы имеем в третем разряде цифру 2.
В чевертый разряд мы, как раз и записываем цифру-остаток полученную в результате деления.
В нашем случае это и есть та самая 5.
Аналогичным образом разбивается наша цифра и далее.
*/
}
else if (disp < 1000)
{
Indicate(5, 11);
Indicate(6, disp / 100);
Indicate(7, (disp % 100) / 10);
Indicate(8, disp % 10);
}
else
{
Indicate(5, disp / 1000);
Indicate(6, (disp % 1000) / 100);
Indicate(7, (disp % 100) / 10);
Indicate(8, disp % 10);
}
}
void Indicate(int r, int x)
{
SegDisplay = g_digits[x]; // получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре.
RazrDisplay = g_registerArray[r]; // получаем цифру и выводим номер регистра, из массива цифр, соответствующий этой цифре.
digitalWrite(latchPin, LOW); // устанавливаем синхронизацию "защелки" на LOW
shiftOut(dataPin, clockPin, MSBFIRST, RazrDisplay); // Записываем информацию для второго регистра (Номер разряда)
shiftOut(dataPin, clockPin, MSBFIRST, SegDisplay); // Записываем информацию для первого регистра (Номер символа)
digitalWrite(latchPin, HIGH); //"защелкиваем" регистр, тем самым устанавливая значения на выходах
delay(TimeLight); // пауза, чтобы сегменты "разгорелись"
}
2) Как адаптировать код на радиокоте под 9 разрядов к данной реализации?
Ну судя по решению с радиокота, автор там четко описал как юзая связку пина 9 и 14 двух регистров сдвига он смог использовать 9 разряд. Вот бы его решение перенести на ардуино код. Жалко терять 9 разряд!
Ну судя по решению с радиокота, автор там четко описал как юзая связку пина 9 и 14 двух регистров сдвига он смог использовать 9 разряд. Вот бы его решение перенести на ардуино код. Жалко терять 9 разряд!
ну там вроде все понятно обьяснено. Загружаете последовательно, сначала данные для 9-ого разраяда - в виде 0b00000000 для включения, 0b11111111 для выключения. а потом биты остальных восьми разрядов. Защелкиваете Latch и наслаждаетесь
Ну судя по решению с радиокота, автор там четко описал как юзая связку пина 9 и 14 двух регистров сдвига он смог использовать 9 разряд. Вот бы его решение перенести на ардуино код. Жалко терять 9 разряд!
ну там вроде все понятно обьяснено. Загружаете последовательно, сначала данные для 9-ого разраяда - в виде 0b00000000 для включения, 0b11111111 для выключения. а потом биты остальных восьми разрядов. Защелкиваете Latch и наслаждаетесь
Все оказалось намного проще, мал мал поправил код для 328p (Ардуино нано) и все получилось!
// WinAvr
#include <avr/io.h>
#include <avr/interrupt.h>
#define DATA 5
#define SHIFT 6
#define STORAGE 7
#define PORTSERIAL PORTD
#define DDRSERIAL DDRD
#define BUT 0
#define BIT(bit) (1<<(bit))
unsigned char lcd_buffer[9] = {0xEB, 0x48, 0x73, 0x7A, 0xD8, 0xBA, 0xBB, 0x68, 0xFB};
//*************************************************************
void data_shift(unsigned char data)
{
// выводим бит данных, сдвигаем и так 8 раз.
unsigned char i = 0;
for (i = 8; i ; i--) {
if (data & BIT(i - 1) ) PORTSERIAL |= BIT(DATA); // выводим бит данных
else PORTSERIAL &= ~BIT(DATA);
PORTSERIAL |= BIT(SHIFT); // сдвиг данных
PORTSERIAL &= ~BIT(SHIFT);
}
}
//*************************************************************
void num_out(unsigned char znmesto)
{
unsigned char i = 0;
PORTSERIAL |= BIT(STORAGE); // выводы микросхем в Z состояние
data_shift(lcd_buffer[znmesto]);// загружаем символ в первый регистр
if (znmesto == 7) i = 1; //7 знакоместо
if (znmesto == 8) i = 2; //8 знакоместо
znmesto = ~(1 << (znmesto)); // число в бит места (пример 0х3->0b11110111)
data_shift(znmesto);// вывод знакоместа, символ сдвигается в второй регистр
if ( i == 0 )
{
PORTSERIAL &= ~BIT(STORAGE);
PORTSERIAL |= BIT(STORAGE); // сохранили
PORTSERIAL &= ~BIT(STORAGE); // и вывели
}
else if (i >= 1) { // 7 знакоместо
PORTSERIAL &= ~BIT(STORAGE);
PORTSERIAL |= BIT(SHIFT) | BIT(STORAGE); // сохранили и вывели
PORTSERIAL &= ~(BIT(SHIFT) | BIT(STORAGE));
//shift нужен потому что 0 переместился из Q6 в -Q7
}
if (i == 2) data_shift(0x0); //9 разряд.
//Сейчас все выходы первого регистра уст в 1,
//загружаем регистр нулями в итоге -Q7 = 0, но не сохроняем.
PORTSERIAL &= ~(BIT(DATA) | BIT(SHIFT) | BIT(STORAGE));
}
//*************************************************************
int main( void )
{
unsigned char i = 0;
PORTSERIAL = BIT(BUT) | BIT(STORAGE);
DDRSERIAL = 0xf0;
TCCR0B = 3;
while (1) {
TCNT0 = 127;
while (!(TIFR0 & BIT(0))); // Задержка такая :-) по идеи 2ms
TIFR0 |= 1;
//if ( !TESTBIT(PIND,BUT) ) //если включить то вывод цифры
{
//while ( !TESTBIT(PIND,BUT) );// будет только по нажатию
if (i > 8) i = 0;
num_out(i);
i++;
}
}
}
http://arduino.ru/Reference/Serial/Available
if (gsm.available()) { while (gsm.available()) { . . . . } . . . }Получилось вот так
void loop() { if (radio.available()) { while (radio.available()) { val = radio.read(); } float numbers[] = {val}; Serial.println(val); unsigned long currentMillis = millis(); if(currentMillis - previousMillis > interval) { previousMillis = currentMillis; getDigits(numbers[numindex]); numindex += 1; if (numindex >= sizeof(numbers)/sizeof(float)) numindex = 0; } displayMessage(arr); } }Значение через val не могу вывести больше 250 ???
mag155, дайте определение динамической индикации, а не выжимайте из AVR невозможного. Если динамику делать на ардуинке, то считаем: время затухания светодиода, после того как убираете напряжение и скорость обновления (полного прохода) по коду. Тут, как писано в старых учебниках, надо, при большом количестве диодов, повышать напряжение, что бы горели лучше. Но, индикатор может сгореть, если что то не так пойдет. Если мигает - результат большого времени работы программного кода.
Есть отдельные драйвера, которые сами делают индикацию, а ардуинка подает только данные для определенного диода.
А, так получается, Вы пытаетесь что выжать из ее максимума. Я не хочу Вас обидеть. Просто надо искать ошибки не только кода, но и железа.
Точнее передать только 0-250
val = analogRead(potent_pin); val = map(val, 0, 1023, 0, 1023); //val = constrain(val, 0, 250); Serial.println(val); analogWrite(3,val); radio.write(val);Я и пытаюсь с ардуинки сделать драйвер чтоб можно было подключать любой индикатор. И к моему восторгу это таки получилось. Сейчас просто передаю значение с другой ардуины потенциометра но что то голова совсем зависла передает только от 0до 250 а надо от 0 до 1023??? Пойду наверно кофе бахну.
Получилось вот так
void loop() { if (radio.available()) { while (radio.available()) { val = radio.read(); } float numbers[] = {val}; Serial.println(val); unsigned long currentMillis = millis(); if(currentMillis - previousMillis > interval) { previousMillis = currentMillis; getDigits(numbers[numindex]); numindex += 1; if (numindex >= sizeof(numbers)/sizeof(float)) numindex = 0; } displayMessage(arr); } }фигня получилась - скобки расставьте правильно, а то получается что отображение на дисплей происходит с периодом interval только в том случае если по SErial вам что то придет иначе ничего не отображается
нарисуте на бумаге (или в голове мысленно) что должно происходить
1. т.е. каждые полсекунды чтение датчика
2. при каждом loop отображение значения датчика
3. при приеме байта (слова) из Serial выводить в монитор число и что то делать
и все это должно работать независимо друг от друга
а щас у вас каша и в голове и в коде
} float numbers[] = {val}; Serial.println(val); unsigned long currentMillis = millis(); if(currentMillis - previousMillis > interval) { previousMillis = currentMillis; getDigits(numbers[numindex]); numindex += 1; } if (numindex >= sizeof(numbers)/sizeof(float)) numindex = 0;Так кажись лучше отображается когда что-то пришло и без периода интерва
} float numbers[] = {val}; Serial.println(val); unsigned long currentMillis = millis(); if(currentMillis - previousMillis > interval) { previousMillis = currentMillis; getDigits(numbers[numindex]); numindex += 1; } if (numindex >= sizeof(numbers)/sizeof(float)) numindex = 0;Так кажись лучше отображается когда что-то пришло и без периода интерва
и как можно разобраться по этому огрызку кода, в котором даже не понятно где начало и конец фигурных скобок
Пардон
void loop() { if (radio.available()) { while (radio.available()) { val = radio.read(); } float numbers[] = {val}; Serial.println(val); unsigned long currentMillis = millis(); if(currentMillis - previousMillis > interval) { previousMillis = currentMillis; getDigits(numbers[numindex]); numindex += 1; } if (numindex >= sizeof(numbers)/sizeof(float)) numindex = 0; displayMessage(arr); } }и чем последний код отличается от кода в сообщении 252?
ЗЫ. Вы мне напоминаете одного программиста из одной очень известной компании России,
промышленный банковский продукт, ошибка в работе его части кода,
он частенько тупо менял названия переменных, и типа исправил :)
естественно ошибка так и осталась.
То что индикатор работает только если пришли данные мне подходит . Но я не пойму где вы видите что он моргает с периодом интервал ??? Подскажите а то реально не пойму где?
void loop() { if (radio.available()) { while (radio.available()) { val = radio.read(); } float numbers[] = {val}; Serial.println(val); unsigned long currentMillis = millis(); if(currentMillis - previousMillis > interval) { previousMillis = currentMillis; getDigits(numbers[numindex]); numindex += 1; } if (numindex >= sizeof(numbers)/sizeof(float)) numindex = 0; displayMessage(arr); } }вот так попробуйте
void loop() { unsigned long currentMillis = millis(); if (radio.available()) { while (radio.available()) { val = radio.read(); } float numbers[] = {val}; Serial.println(val); } if((currentMillis - previousMillis) > interval) { previousMillis = currentMillis; getDigits(numbers[numindex]); numindex += 1; if (numindex >= sizeof(numbers)/sizeof(float)) numindex = 0; } displayMessage(arr); }В порту данные есть а на индикаторе Err .??
В порту данные есть а на индикаторе Err .??
ниче не понял в чем вопрос
В порту цифры 66 на индикаторе Err а должно быть тоже 66 ?
вот смотрите:
приходят данные , переводятся в переменную val, выводяться в монитор,
далее каждые interval времени процедура getDigits формирует строку символов для вывода на экран - правильно?
возникает вопрос: а эта процедура которая формирует строку - она использует переменную val с исходными данными?
Получается что нет.
Получается что нет.
вот и разбирайтесь почему, т.е. эту переменную надо сделать или глобальной и учитывать в функции рисования или передавать значение как второй параметр в процедуру.
Ок.
Здялал так
void loop() { unsigned long currentMillis = millis(); if (radio.available()) { while (radio.available()) { val = radio.read(); } // Serial.println(val); } float numbers[] = {val}; if(currentMillis - previousMillis > interval) { previousMillis = currentMillis; getDigits(numbers[numindex]); numindex += 1; if (numindex >= sizeof(numbers)/sizeof(float)) numindex = 0; } displayMessage(arr); }И видимость переменной
Пкретикуйте если не сложно ??
Работает? Устраивает? Значит нефиг ломать работающее.
Работает устраивает. Но чё то точку не отображает?
void loop() { unsigned long currentMillis = millis(); if (radio.available()) { while (radio.available()) { val = radio.read(); } //val = map(val, 0, 500, 1, 500); val = constrain(val, 0, 500); Serial.println(val); } float numbers[] = {val}; if(currentMillis - previousMillis > interval) { previousMillis = currentMillis; getDigits(numbers[numindex]); numindex += 1; if (numindex >= sizeof(numbers)/sizeof(float)) numindex = 0; } displayMessage(arr); } void getDigits (float value) { Serial.println(""); // Выдаем ошибку на те значения, которые не можем показать if ((value >= 10000) || (value <= -1000) || (value > -0.01 && value < 0.001)) { for (int i = 0; i < 4; i++) { // Каждый разряд по очереди for (int k = 0; k < 8; k++) {// Каждый сегмент по очереди - исходя из заданной карты arr[i][k] = err[i][k]; } } return; // Выходим } int digits = 4; // У нас 4 разряда if (value < 0) digits = 3; // Из-за минуса один символ убирается*/ // Делим число на 2 группы - отдельно целую часть и дробную. int intPart = (int)abs(value); int intLength = ((String)intPart).length(); // Смотрим, сколько разрядов занимает целая часть // На дробную часть у нас остается разрядов: digits-intLength int fracPart = (int)((abs(value) - abs(intPart)) * 1000); // Мы можем показать максимум 3 знака после запятой - 0,000 int fracDigits = digits - intLength; fracPart = (((String)fracPart).substring(0, fracDigits)).toInt(); // Собираем строку для отображения String output = (value < 0) ? "-" : ""; output += (String)intPart; String outputFrac = ((digits - intLength <= 0) || (fracPart == 0)) ? "" : ((String)"." + ((String)fracPart).substring(0, digits - intLength)); output += (String)outputFrac; // Дополняем символы спереди, если цифр слишком мало, например для "-1" делаем " -1" String spaces = " "; digits = 4; if (~output.indexOf(".")) digits += 1; if (output.length() < digits) output = spaces.substring(0, digits - output.length()) + output; // Формирум данные для показа: int dig = -1; for (int i = 0; i < output.length(); i++) { String _char = output.substring(i, i + 1); if (_char != ".") dig += 1; // Точка не занимает сегмент - увеличиваем на 1 int actualdigit = 11; // По умолчанию пустой символ if ((_char == "-")) { actualdigit = 10; } else if (_char == " " || _char == ".") { } else { actualdigit = _char.toInt(); } if (_char == ".") { arr[dig][7] = 1; // Если нужно - ставим точку } else { for (int n = 0; n <= 7; n++) { arr[dig][n] = seg[actualdigit][n]; } } } } void displayMessage(int dig[4][8]) { for (int i = 0; i < 4; i++) { // Каждый разряд по очереди for (int k = 0; k < 8; k++) {// Каждый сегмент по очереди - исходя из заданной карты digitalWrite(segmentsPins[k], ((dig[i][k] == 1) ? 1 : 0)); } digitalWrite(anodPins[i], 0); delay(2); digitalWrite(anodPins[i], 1); } }Даже если вот так пишу показует только 9
float numbers[] = {9.3};Чтоб отображать точку, надо установить нужный бит в нужное состояние, соответственно в вашей процедуре заполняющей нужные биты необходимо дополнить нужное условие, например если второй разряд = установить 7 бит - одна строка программы
А разве 45 и 46 строки не для этого ?
Или все дело в 63 строке?
И 73 с 74 ?
Вроде они, но как видите не работает)
Разбираться надо - некогда
ПРОБЛЕМА ОКАЗАЛАСЬ В БИБЛИОТЕКЕ
Доброго времени суток решил добить тему с индикатором. Вопрос как допилить код чтоб работатл со здвиговыми регистрами как например в 174 сообщении ???
Доброго времени суток.
В начале темы автор сделал схему подключения скетч для индикатора с общим анода. Что можно сделать если индикатор с общим катодом? без транзисторов не обойтись?
Нужно управлять минусом тоест low.
Делаю все по схеме так же?
по части скетча где нужно поменять?
Буду благодарен за совет?
А нужны ли эти заморочки когда есть дешевая микросхема TM1650, а также TM1637 TM1638
Делаю все по схеме так же?
по части скетча где нужно поменять?
Буду благодарен за совет?
Вам нужно поправить только в этом месте:
// Настройка комбинации для отображения каждого номера на дисплее. // Комбинация выбрана на основе таблицы отображаемого знака данным порта // Соответственно { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , dp, - } byte g_digits[12]={192,249,164,176,153,146,130,248,128,144,127,255}; //массив цифр, генерирующий из сегментов цифры byte g_registerArray[4]={1,2,4,8}; //массив цифр, указывающий разрядыА рассчитать можно по аналогии с табличкой:
Соответствие отображаемого знака данным порта общий анод __________________________________________________ | двоичный вид по сегментам | | Цифра|dp | G | F | E | D | C | B | A | Десятичный | -----|---|---|---|---|---|---|---|---|------------| 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 192 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 249 | 2 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 164 | 3 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 176 | 4 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 153 | 5 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 146 | 6 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 130 | 7 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 248 | 8 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 128 | 9 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 144 | dp | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 127 | -----*---*---*---*---*---*---*---*---*------------*Только у вас там где 1 должен быть 0. К примеру цифра "0" при общем аноде имеет
бинарный вид: 11000000 = 192 в десятичном виде, при общем катоде:
бинарный вид: 00111111 = 63 в десятичном виде, и так далее для остальных символов.
При этом не забудте поправить и массив для разрядов. там так же нужно пересчитать по тому же принципу:
общий анод, первый разряд 00000001 = 1
общий катод, 11111110 = 254
а можно еще проще для разрядов - имеющийся адрес вычитать из 255:
255-1=254, 255-2=253, 255-4=251, 255-8=247 и тогда для разрядов адреса будут такие:
byte g_registerArray[4]={254,253,251,247}; //массив цифр, указывающий разрядыЕсли лень вспоминать школьный курс информатики ;)

А нужны ли эти заморочки когда есть дешевая микросхема TM1650, а также TM1637 TM1638
Лично я затеял все это потому что было много трофейных 74hc595 и думал куда их можно пристроить, хотелось вообще разобраться как с ними можно работать и нужен был индикатор для одной поделки.
Лично я затеял все это потому что было много трофейных 74hc595 и думал куда их можно пристроить, хотелось вообще разобраться как с ними можно работать и нужен был индикатор для одной поделки.
Да я тоже самое делал. Просто сейчас если и ставить только расширения выходных портов, для семисегментного уже пожалуй нет
Получилось спасибо большое!
Всем привет.
Есть статья на радиокоте https://www.radiokot.ru/lab/controller/08/ с использованием 9 разрядов 7 сегментного индикатора от телефона Русь 25-27. Лежал у меня подобный индикатор но сравнив схемы я обнаружил в своем варианте некоторые отличия и решил отрисовать свой вариант. Плата панельки построена на 3-х индикаторах TOT-3361AH-1N с общим катодом и двух сдвиговых регистра 74HC595D.
Сегменты распаяны хаотично. Первым идет сдиговый регистр разрядов а потом сегментов.
Вывести что то адекватное на него не получается. Код привожу ниже, адаптировав его под Общий катод и сдвиговые регистры.
1) То есть нужно воять свою таблицу символов под данную распайку сегментов?
int latchPin = 10; //Пин "защелки" первого регистра подключен к ST_CP входу первого регистра отвечающего за сегменты int clockPin = 13; //Пин подключен к SH_CP входу 74HC595 int dataPin = 12; //Пин подключен к DS входу 74HC595 int TimeLight = 2; //время для разогрева сегментов int sensorPin = A0; byte SegDisplay; // переменная для вывода символов на индикаторе byte RazrDisplay; // переменная для включения разрядов // Настройка комбинации для отображения каждого номера на дисплее. // Комбинация выбрана на основе таблицы отображаемого знака данным порта // Соответственно { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , dp, - } byte g_digits[12] = {63, 6, 91, 79, 102, 109, 125, 7, 127, 111, 128, 64}; //OK, массив цифр, генерирующий из сегментов цифры byte g_registerArray[9] = {254, 253, 251, 247, 239, 223, 191, 127, 255}; //OK, массив цифр, указывающий разряды void setup() { // обозначаем все пины как выходы pinMode(latchPin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT); } void loop() { int disp = 0; //создаем переменную для вывода на экран int analogueValue = analogRead(sensorPin); // читаем аналоговый пин A0 analogueValue = map(analogueValue, 0, 1023, 0, 8888); //преобразуем диапазон с А0 (0-1023) в нужный нам (0-8888) disp = analogueValue; // записываем получившуюся после преобразования цифру в переменну для вывода на экран // Разбиваем цифру по разрядам индикатора if (disp < 10) // если наша цифра меньше 10, то { Indicate(5, 11); // пишем в первый разряд пусто Indicate(6, 11); // пишем во второй разряд пусто Indicate(7, 11); // пишем в третий разряд пусто Indicate(8, disp); // пишем в четвертый разряд нашу цифру } else if (disp < 100) // если наша цифра меньше 100, то { Indicate(5, 11); // пишем в первый разряд пусто Indicate(6, 11); // пишем во второй разряд пусто Indicate(7, disp / 10); // пишем в третий разряд - цифру делёную на 10 Indicate(8, disp % 10); // пишем в четвертый разряд цифру оставшуюся от деления на 10 /* Допустим наша цифра 25. Если мы ее поделим на 10, то у нас получится 2,5. Цифры после запятой, в данном случае, у нас не остаются. Таким образом мы имеем в третем разряде цифру 2. В чевертый разряд мы, как раз и записываем цифру-остаток полученную в результате деления. В нашем случае это и есть та самая 5. Аналогичным образом разбивается наша цифра и далее. */ } else if (disp < 1000) { Indicate(5, 11); Indicate(6, disp / 100); Indicate(7, (disp % 100) / 10); Indicate(8, disp % 10); } else { Indicate(5, disp / 1000); Indicate(6, (disp % 1000) / 100); Indicate(7, (disp % 100) / 10); Indicate(8, disp % 10); } } void Indicate(int r, int x) { SegDisplay = g_digits[x]; // получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре. RazrDisplay = g_registerArray[r]; // получаем цифру и выводим номер регистра, из массива цифр, соответствующий этой цифре. digitalWrite(latchPin, LOW); // устанавливаем синхронизацию "защелки" на LOW shiftOut(dataPin, clockPin, MSBFIRST, RazrDisplay); // Записываем информацию для второго регистра (Номер разряда) shiftOut(dataPin, clockPin, MSBFIRST, SegDisplay); // Записываем информацию для первого регистра (Номер символа) digitalWrite(latchPin, HIGH); //"защелкиваем" регистр, тем самым устанавливая значения на выходах delay(TimeLight); // пауза, чтобы сегменты "разгорелись" }2) Как адаптировать код на радиокоте под 9 разрядов к данной реализации?
1) [РЕШЕНО]
Изменил кодовую страницу под данное подключение сегментов так
byte g_digits[12] = {235, 72, 115, 122, 216, 186, 187, 104, 251, 250, 4, 16};Все цифры отображаются нормально!
2) 9 разряд подключен на Q7S (14 и 9 пин регистра сдвига) [НЕ РЕШЕНО]
Как решение с радиокота перенести на ардуино код?
1) Только Вам хотел написать, что надо под свою распайку индивидуально коды указывать, а Вы уже всё решили :)
2) Могу заблуждаться, но предположу что 9 разряд не подключить, так как у 595 всего 8 выходов, а Q7S создан для иных задач- Выход для последовательного соединения регистров. Тут хорошая статья про 74hc595: https://codius.ru/articles/Arduino_Сдвиговый_регистр_74НС595_или_размножаем_экономим_выходы_платы
Ну судя по решению с радиокота, автор там четко описал как юзая связку пина 9 и 14 двух регистров сдвига он смог использовать 9 разряд. Вот бы его решение перенести на ардуино код. Жалко терять 9 разряд!
Ну судя по решению с радиокота, автор там четко описал как юзая связку пина 9 и 14 двух регистров сдвига он смог использовать 9 разряд. Вот бы его решение перенести на ардуино код. Жалко терять 9 разряд!
ну там вроде все понятно обьяснено. Загружаете последовательно, сначала данные для 9-ого разраяда - в виде 0b00000000 для включения, 0b11111111 для выключения. а потом биты остальных восьми разрядов. Защелкиваете Latch и наслаждаетесь
Знаний маловато, можно Вас попросить показать на примере?
Ну судя по решению с радиокота, автор там четко описал как юзая связку пина 9 и 14 двух регистров сдвига он смог использовать 9 разряд. Вот бы его решение перенести на ардуино код. Жалко терять 9 разряд!
ну там вроде все понятно обьяснено. Загружаете последовательно, сначала данные для 9-ого разраяда - в виде 0b00000000 для включения, 0b11111111 для выключения. а потом биты остальных восьми разрядов. Защелкиваете Latch и наслаждаетесь
Все оказалось намного проще, мал мал поправил код для 328p (Ардуино нано) и все получилось!
// WinAvr #include <avr/io.h> #include <avr/interrupt.h> #define DATA 5 #define SHIFT 6 #define STORAGE 7 #define PORTSERIAL PORTD #define DDRSERIAL DDRD #define BUT 0 #define BIT(bit) (1<<(bit)) unsigned char lcd_buffer[9] = {0xEB, 0x48, 0x73, 0x7A, 0xD8, 0xBA, 0xBB, 0x68, 0xFB}; //************************************************************* void data_shift(unsigned char data) { // выводим бит данных, сдвигаем и так 8 раз. unsigned char i = 0; for (i = 8; i ; i--) { if (data & BIT(i - 1) ) PORTSERIAL |= BIT(DATA); // выводим бит данных else PORTSERIAL &= ~BIT(DATA); PORTSERIAL |= BIT(SHIFT); // сдвиг данных PORTSERIAL &= ~BIT(SHIFT); } } //************************************************************* void num_out(unsigned char znmesto) { unsigned char i = 0; PORTSERIAL |= BIT(STORAGE); // выводы микросхем в Z состояние data_shift(lcd_buffer[znmesto]);// загружаем символ в первый регистр if (znmesto == 7) i = 1; //7 знакоместо if (znmesto == 8) i = 2; //8 знакоместо znmesto = ~(1 << (znmesto)); // число в бит места (пример 0х3->0b11110111) data_shift(znmesto);// вывод знакоместа, символ сдвигается в второй регистр if ( i == 0 ) { PORTSERIAL &= ~BIT(STORAGE); PORTSERIAL |= BIT(STORAGE); // сохранили PORTSERIAL &= ~BIT(STORAGE); // и вывели } else if (i >= 1) { // 7 знакоместо PORTSERIAL &= ~BIT(STORAGE); PORTSERIAL |= BIT(SHIFT) | BIT(STORAGE); // сохранили и вывели PORTSERIAL &= ~(BIT(SHIFT) | BIT(STORAGE)); //shift нужен потому что 0 переместился из Q6 в -Q7 } if (i == 2) data_shift(0x0); //9 разряд. //Сейчас все выходы первого регистра уст в 1, //загружаем регистр нулями в итоге -Q7 = 0, но не сохроняем. PORTSERIAL &= ~(BIT(DATA) | BIT(SHIFT) | BIT(STORAGE)); } //************************************************************* int main( void ) { unsigned char i = 0; PORTSERIAL = BIT(BUT) | BIT(STORAGE); DDRSERIAL = 0xf0; TCCR0B = 3; while (1) { TCNT0 = 127; while (!(TIFR0 & BIT(0))); // Задержка такая :-) по идеи 2ms TIFR0 |= 1; //if ( !TESTBIT(PIND,BUT) ) //если включить то вывод цифры { //while ( !TESTBIT(PIND,BUT) );// будет только по нажатию if (i > 8) i = 0; num_out(i); i++; } } }Всем спасибо за пинОК )))
Пофиксенный вариант.
// WinAvr // Fix by iStarCom 2020 for ATMEGA328P. #include <avr/io.h> #include <avr/interrupt.h> #define DATA 5 #define SHIFT 6 #define STORAGE 7 #define PORTSERIAL PORTD #define DDRSERIAL DDRD #define BUT 0 #define BIT(bit) (1<<(bit)) unsigned char lcd_buffer[9] = {0xEB, 0x48, 0x73, 0x7A, 0xD8, 0xBA, 0xBB, 0x68, 0xFB}; // РУСЬ 27 (ОК) //unsigned char lcd_buffer[9] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F}; // СТАНДАРТ (ОК) //************************************************************* void data_shift(unsigned char data) { // выводим бит данных, сдвигаем и так 8 раз. unsigned char i = 0; for (i = 8; i ; i--) { if (data & BIT(i - 1) ) PORTSERIAL |= BIT(DATA); // выводим бит данных else PORTSERIAL &= ~BIT(DATA); PORTSERIAL |= BIT(SHIFT); // сдвиг данных PORTSERIAL &= ~BIT(SHIFT); } } //************************************************************* void num_out(unsigned char znmesto) { unsigned char i = 0; PORTSERIAL |= BIT(STORAGE); // выводы микросхем в Z состояние data_shift(lcd_buffer[znmesto]);// загружаем символ в первый регистр if (znmesto == 7) i = 1; //7 знакоместо if (znmesto == 8) i = 2; //8 знакоместо znmesto = ~(1 << (znmesto)); // число в бит места (пример 0х3->0b11110111) data_shift(znmesto);// вывод знакоместа, символ сдвигается в второй регистр if ( i == 0 ) { PORTSERIAL &= ~BIT(STORAGE); PORTSERIAL |= BIT(STORAGE); // сохранили PORTSERIAL &= ~BIT(STORAGE); // и вывели } else if (i >= 1) { // 7 знакоместо PORTSERIAL &= ~BIT(STORAGE); PORTSERIAL |= BIT(SHIFT) | BIT(STORAGE); // сохранили и вывели PORTSERIAL &= ~(BIT(SHIFT) | BIT(STORAGE)); //shift нужен потому что 0 переместился из Q6 в -Q7 } if (i == 2) data_shift(0x0); //9 разряд. //Сейчас все выходы первого регистра уст в 1, //загружаем регистр нулями в итоге -Q7 = 0, но не сохроняем. PORTSERIAL &= ~(BIT(DATA) | BIT(SHIFT) | BIT(STORAGE)); } //************************************************************* int main( void ) { unsigned char i = 0; PORTSERIAL = BIT(BUT) | BIT(STORAGE); DDRSERIAL = 0xf0; TCCR0B = 3; while (1) { TCNT0 = 127; while (!(TIFR0 & BIT(0))); // Задержка такая :-) по идеи 2ms TIFR0 |= 1; // if ( !bitRead(PIND, BUT) ) //если включить то вывод цифры { // while ( !bitRead(PIND, BUT) ); // будет только по нажатию if (i > 8) i = 0; num_out(i); i++; } } }