Вывод информации на 6 разрядов 7ми сегментного индикатора

Ferit
Offline
Зарегистрирован: 03.02.2016

Здравствуйте!

Для одного проекта потребовалось выводить 6 цифр подряд, т.е. нужно шесть разрядов. (За основу была взята работа отсуда.) Т.к.  под рукой небыло ничего кроме индикаторов KEM-4021BS (сдвоенный семисегментный с ОА) соединил их на макетке и вывел с каждого в один A,B,C,D,E,F,G и на каждый сегмент "+".

Все это должно! работать в динамической индикации с двумя 74НС595.

НО! Вот тут и начинается проблема. Не хатает знаний в программировании.

int latchPin = 8;     //Пин "защелки" первого регистра подключен к ST_CP входу первого регистра отвечающего за сегменты 
int clockPin = 12;    //Пин подключен к SH_CP входу 74HC595
int dataPin = 11;     //Пин подключен к DS входу 74HC595

int TimeLight = 5;  //время для разогрева сегментов
int sensorPin=A0;

byte SegDisplay; // переменная для вывода символов на индикаторе
byte RazrDisplay; // переменная для включения разрядов

// Настройка комбинации для отображения каждого номера на дисплее.
// Комбинация выбрана на основе таблицы отображаемого знака данным порта
// Соответственно { 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[6]={1,2,4,8,16,32}; //массив цифр, указывающий разряды


void setup() {
// обозначаем все пины как выходы
  pinMode(latchPin, OUTPUT); 
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}

void loop() {
  int disp = 0; //создаем переменную для вывода на экран

 
  disp = 8888;
   
  
 // Разбиваем цифру по разрядам индикатора
  if (disp < 10) // если наша цифра меньше 10, то
  {
    Indicate(0, 11); // пишем в первый разряд пусто
    Indicate(1, 11); // пишем во второй разряд пусто
    Indicate(2, 11); // пишем в третий разряд пусто
    Indicate(3, 11); // пишем в третий разряд пусто
    Indicate(4, 11); // пишем в третий разряд пусто
    Indicate(5, disp); // пишем в четвертый разряд нашу цифру
  }
  else if (disp < 100) // если наша цифра меньше 100, то
  {
    Indicate(0, 11); // пишем в первый разряд пусто
    Indicate(1, 11); // пишем во второй разряд пусто
    Indicate(2, 11); // пишем во второй разряд пусто
    Indicate(3, 11); // пишем во второй разряд пусто
    Indicate(4, disp / 10); // пишем в третий разряд - цифру делёную на 10
    Indicate(5, disp % 10); // пишем в четвертый разряд цифру оставшуюся от деления на 10

  }
  else if (disp < 1000)
  {
    Indicate(0, 11);
    Indicate(1, 11);
    Indicate(2, 11);
    Indicate(3, disp / 100);    
    Indicate(4, (disp % 100) / 10);
    Indicate(5, disp % 10); 
  }
  else if (disp < 10000)
  {
    Indicate(0, 11);
    Indicate(1, 11);
    Indicate(2, disp / 1000);
    Indicate(3, (disp % 1000) / 100);    
    Indicate(4, (disp % 100) / 10);
    Indicate(5, disp % 10);
  }
   else if (disp < 100000)
  {
    Indicate(0, 11);
    Indicate(1, disp / 10000);
    Indicate(2, (disp % 10000) / 1000); 
    Indicate(3, (disp % 1000) / 100);    
    Indicate(4, (disp % 100) / 10);
    Indicate(5, disp % 10);
  }
   else 
  {
    Indicate(0,  disp / 1000000);
    Indicate(1, (disp % 100000) / 10000); 
    Indicate(2, (disp % 10000) / 1000); 
    Indicate(3, (disp % 1000) / 100);    
    Indicate(4, (disp % 100) / 10);
    Indicate(5, 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); // пауза, чтобы сегменты "разгорелись"
}

 

Как видно из кода, за вывод цифр (значений) отвечает переменная disp.

Если число из 4х знаков, то все отображается отлично 

disp=7777;

Если знаков больше четырех, то показывает все что угодно.

disp=77777;

По этому прошу помочь. Расскажите где я ошибся и как это исправить. Буду очень благодарен!

at0mix
at0mix аватар
Offline
Зарегистрирован: 23.11.2015
Ferit
Offline
Зарегистрирован: 03.02.2016

Я в курсе существования  Aliexpress и что на нем есть. Я же сказал, что использовал то что было у меня в наличии. 

at0mix
at0mix аватар
Offline
Зарегистрирован: 23.11.2015

Когда я задумал 3 месяца назад свой проект и хотел хоть прикинуть варианты реализации - поставил протеуса и нарисовал в минимальном варианте схему. Т.к. модуль 4-секционного индикатора в моделях протеуса не нашел - подкинул 4 индикатора и 595, на нем и опробовал как будет выглядеть. Но перед этим заказал индикаторы с али. После НГ они приехали - и через пару недель на макете все заработало.

Могу кинуть на свой проект в протеусе - но там 4 секции. Но можно добавить еще 2 и разбираться с кодом....

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Причина в строке 26

int disp = 0;

максимальное значение 32767. Надо

long disp;

Ferit
Offline
Зарегистрирован: 03.02.2016

Andy, огромное спасибо. Я бы наверное и не додумался.

Теперь все нормально работает. 

disp=123456;

и еще сразу обнаружилась ошибка в строке 81.

ее заменить на 

Indicate(0,  disp / 100000);

 

Ferit
Offline
Зарегистрирован: 03.02.2016

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


#include <Wire.h>
#include "RTClib.h"
#include "DHT.h"   // подключаем библиотеку
#define DHTPIN 2     // вывод, к которому подключается датчик
DHT dht(DHTPIN, DHT11); // определяем тип датчика: 22 или 11
RTC_DS1307 RTC;
int latchPin = 8;     //Пин "защелки" первого регистра подключен к ST_CP входу первого регистра отвечающего за сегменты
int clockPin = 12;    //Пин подключен к SH_CP входу 74HC595
int dataPin = 11;     //Пин подключен к DS входу 74HC595
int TimeLight = 4;  //время для разогрева сегментов
byte SegDisplay; // переменная для вывода символов на индикаторе
byte RazrDisplay; // переменная для включения разрядов
byte g_digits[12] = {192, 249, 164, 176, 153, 146, 130, 248, 128, 144, 127, 255}; //массив цифр, генерирующий из сегментов цифры
byte g_registerArray[6] = {1, 2, 4, 8, 16, 32}; //массив цифр, указывающий разряды

void setup() {
  dht.begin();  // датчик передает данные
  Wire.begin();
  RTC.begin();

  // обозначаем все пины как выходы
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}

void loop() {

  long hour, minute, sec, disp = 0;
  DateTime now = RTC.now();
  hour = now.hour();
  minute = now.minute();
  sec = now.second();
  if (sec > 10 && sec < 20) {
    disp = dht.readHumidity();
  }
  else {
    disp = (hour * 10000) + (minute * 100) + sec;
  }
  // Разбиваем цифру по разрядам индикатора
  if (disp < 10) // если наша цифра меньше 10, то
  {
    Indicate(0, 11); // пишем в первый разряд пусто
    Indicate(1, 11); // пишем во второй разряд пусто
    Indicate(2, 11); // пишем в третий разряд пусто
    Indicate(3, 11); // пишем в третий разряд пусто
    Indicate(4, 11); // пишем в третий разряд пусто
    Indicate(5, disp); // пишем в четвертый разряд нашу цифру
  }
  else if (disp < 100) // если наша цифра меньше 100, то
  {
    Indicate(0, 11); // пишем в первый разряд пусто
    Indicate(1, 11); // пишем во второй разряд пусто
    Indicate(2, 11); // пишем во второй разряд пусто
    Indicate(3, 11); // пишем во второй разряд пусто
    Indicate(4, disp / 10); // пишем в третий разряд - цифру делёную на 10
    Indicate(5, disp % 10); // пишем в четвертый разряд цифру оставшуюся от деления на 10

  }
  else if (disp < 1000)
  {
    Indicate(0, 11);
    Indicate(1, 11);
    Indicate(2, 11);
    Indicate(3, disp / 100);
    Indicate(4, (disp % 100) / 10);
    Indicate(5, disp % 10);
  }
  else if (disp < 10000)
  {
    Indicate(0, 11);
    Indicate(1, 11);
    Indicate(2, disp / 1000);
    Indicate(3, (disp % 1000) / 100);
    Indicate(4, (disp % 100) / 10);
    Indicate(5, disp % 10);
  }
  else if (disp < 100000)
  {
    Indicate(0, 11);
    Indicate(1, disp / 10000);
    Indicate(2, (disp % 10000) / 1000);
    Indicate(3, (disp % 1000) / 100);
    Indicate(4, (disp % 100) / 10);
    Indicate(5, disp % 10);
  }
  else
  {
    Indicate(0,  disp / 100000);
    Indicate(1, (disp % 100000) / 10000);
    Indicate(2, (disp % 10000) / 1000);
    Indicate(3, (disp % 1000) / 100);
    Indicate(4, (disp % 100) / 10);
    Indicate(5, 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); // пауза, чтобы сегменты "разгорелись"
}

Вот как выглядит проблема:

 

Думал записывать данные в EEPROM, но не помогло.

Вот в чем вопрос- как убрать мигание значений температуры? И если такое возможно, как добавить после темпетаруты знак "С"?

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Ferit пишет:
Вот в чем вопрос- как убрать мигание значений температуры?
Перенести динамическую индикацию в прерывание от таймера.

Ferit пишет:
И если такое возможно, как добавить после темпетаруты знак "С"?
Код символа С = 198. Если я правильно вычислил...

at0mix
at0mix аватар
Offline
Зарегистрирован: 23.11.2015

Ferit пишет:

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

Некорректное отображение данных - это отображение заведомо неправильных данных.

Мигание индикатора - это неправильная работа системы отображения.

Что есть совсем разные вещи %(

Ferit пишет:
Думал записывать данные в EEPROM, но не помогло.

Вот в чем вопрос- как убрать мигание значений температуры? И если такое возможно, как добавить после темпетаруты знак "С"?

Запись в еепром еще более длительная процедура. Кстати о птичках - память еепром имеет таки ограниченное число циклов записи - и использование ее вместо РАМ просто убьет чип. Впрочем 150р не деньги даже в условиях кризиса - можно и поменять... Только ждать с али долго, а покупать у нас дорого.

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

Знак С в HEX==12

Т.е. нормальный контроллер с библой знает как минимум 16-ю ситему - 0-9,A,b,C,d,E,F

другие символы нужно лепить самому правкой библиотеки. Если понимаешь что и как делать.

PS - мне пока не надо - потому не делал.

Да, орфографию поправь плиз....

Ferit
Offline
Зарегистрирован: 03.02.2016

Andy пишет:

Ferit пишет:
Вот в чем вопрос- как убрать мигание значений температуры?
Перенести динамическую индикацию в прерывание от таймера.

Ferit пишет:
И если такое возможно, как добавить после темпетаруты знак "С"?
Код символа С = 199. Если я правильно вычислил...

С динамической индикацией я вообще не знаком поэтому буду разбираться как эт о вообще работает.

К вопросу о символе "С", не могу правильно записать строчку, что-то неправильно делаю.

 disp = dht.readHumidity(), 199; - так не работает

 

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Добавить в массив цифру

byte g_digits[13] = {192, 249, 164, 176, 153, 146, 130, 248, 128, 144, 127, 255, 198}; //массив цифр, генерирующий из сегментов цифры

Попробовать в какй нибудь разряд, например в 0:

Indicate(0, 12);

Код нужно несколько переписать.... завтра набросаю.

at0mix
at0mix аватар
Offline
Зарегистрирован: 23.11.2015

Возьми библу от тм1637 например - там 16 шестнадцеритьчных цифр....

static int8_t TubeTab[] = {0x3f,0x06,0x5b,0x4f,
                           0x66,0x6d,0x7d,0x07,
                           0x7f,0x6f,0x77,0x7c,
                           0x39,0x5e,0x79,0x71};//0~9,A,b,C,d,E,F

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Вот так для начала

char g_digitsArray[6];

void loop() 
{
  byte hour, minute, sec;
  DateTime now = RTC.now();
  hour = now.hour();
  minute = now.minute();
  sec = now.second();
  if (sec > 10 && sec < 20) {TempToDigits(dht.readHumidity());}
  else {TimeToDigits(hour, minute, sec);}
  Indicate();
}

void TimeToDigits(byte hour, byte minute, byte sec)
{
  g_digitsArray[0]=g_digits[hour/10];
  g_digitsArray[1]=g_digits[hour%10];
  g_digitsArray[2]=g_digits[minute/10];
  g_digitsArray[3]=g_digits[minute%10];
  g_digitsArray[4]=g_digits[sec/10];
  g_digitsArray[5]=g_digits[sec%10];
}
void TempToDigits(byte temp)
{
  g_digitsArray[0]=255;
  g_digitsArray[1]=255;
  g_digitsArray[2]=255;
  g_digitsArray[3]=g_digits[temp/10];
  g_digitsArray[4]=g_digits[temp%10];
  g_digitsArray[5]=198;
}

void Indicate()
{
  for (byte r=0; r<6; r++)
  {
   SegDisplay = g_digitsArray[r]; // получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре.
   RazrDisplay = g_registerArray[r]; // получаем цифру и выводим номер регистра, из массива цифр, соответствующий этой цифре.
   digitalWrite(latchPin, LOW);  // устанавливаем синхронизацию "защелки" на LOW
   shiftOut(dataPin, clockPin, MSBFIRST, RazrDisplay); // Записываем информацию для второго регистра (Номер разряда)
   shiftOut(dataPin, clockPin, MSBFIRST, SegDisplay);  // Записываем информацию для первого регистра (Номер символа)
   digitalWrite(latchPin, HIGH);  //"защелкиваем" регистр, тем самым устанавливая значения на выходах
   delay(TimeLight); // пауза, чтобы сегменты "разгорелись"
  }
  shiftOut(dataPin, clockPin, MSBFIRST, 255);  // Выключаем индикацию
}