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

EvgenBar
Offline
Зарегистрирован: 19.11.2020

Помогите разобраться.

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

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

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

int sensorPin=A0;



// Настройка комбинации для отображения каждого номера на дисплее.

byte g_digits[25] = {
  B11000000, B11111001, B10100100, B10110000, B10011001,   // 0 1 2 3 4
  B10010010, B10000010, B11111000, B10000000, B10010000,   // 5 6 7 8 9
  B01000000, B01111001, B00100100, B00110000, B00011001,   // 0. 1. 2. 3. 4.
  B00010010, B00000010, B01111000, B00000000, B00010000,   // 5. 6. 7. 8. 9.
  B01111111, B10111111, B10011100, B11000110,   // точка, прочерк, градус, цельсия
  B11111111,
};
byte g_registerArray[4] = {8, 4, 2, 1}; //массив цифр, указывающий разряды

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

}

void loop() {
int tem = 0;
int raw = analogRead(sensorPin);
float val2 = (raw/1023.0 )*5.0*1000/10;
  Serial.println(val2);

  tem = 999;
  
  
 
 float temperature = val2;  // Можете подставить любые значения. Следите чтобы стояла именно . (например 5.75 а не 5,75) иначе - ошибка компаиляции вам обеспечена
  int disp;                  // Переменная для целых чисел температуры               
  int disp_sot;              // Переменная для дробной части числа
  
  disp = int (temperature);                 // Избавляемся от десятых и сотых (оставляем челую часть числа)
  temperature = (temperature - disp) * 100; // Переводим десятые и сотые в целую часть числа
  disp_sot = int (abs(temperature));        // Обрубаем значения после запятой (оставляем целую часть числа) модуль - для избавления от минуса
  
  // Разбиваем цифру по разрядам индикатора
  if (disp < 0) // Если значение минусовое, то выполняется следующее условие
    {
      disp = abs(disp); // используем модуль дабы избавиться от минуса. Его мы подставим в процессе
        /* Допустим наша цифра 25. 
           Если мы ее поделим на 10, то у нас получится 2,5. Цифры после запятой, в данном случае,
           у нас не остаются. Таким образом мы имеем в третем разряде цифру 2.
           В чевертый разряд мы, как раз и записываем цифру-остаток полученную в результате деления. 
           В нашем случае это и есть та самая 5.
           Аналогичным образом разбивается наша цифра и далее.
        */
      if (disp < 10) // если наша цифра меньше 10, то
        {
        Indicate(0, disp_sot % 10);      // пишем в первый разряд сотую долю цифры
        Indicate(1, disp_sot / 10);      // пишем во второй разряд десятую долю цифры
        Indicate(2, disp + 10);          // пишем в третий разряд нашу цифру с точкой
        Indicate(3, 21);                 // пишем в четвертый разряд минус
        }
      else if (disp < 100) // если наша цифра меньше 100, то
        {
        Indicate(0, disp_sot / 10);      // пишем в первый разряд десятую долю цифры
        Indicate(1, (disp % 10) + 10);   // пишем во второй разряд - цифру оставшуюся от деления на 10 с точкой
        Indicate(2, disp / 10);          // пишем в третий разряд - цифру делёную на 10
        Indicate(3, 21);                 // пишем в четвертый разряд минус
        }
      else
        {
        Indicate(0, 21);    // Думаю что температура ниже 99 градусов
        Indicate(1, 21);    // вряд ли возможна, поэтому
        Indicate(2, 21);    // выводим прочерки во всех регистрах
        Indicate(3, 21); 
        }     
    }
  else if (disp == 0)    // Значение температуры ровно 0 градусов
    {
        Indicate(0, 23);      // пишем в первый разряд - символ цельсия "С"
        Indicate(1, 22);      // пишем во второй разряд - символ градуса
        Indicate(2, disp);    // пишем в третий разряд - цифру ноль
        Indicate(3, 24);      // пишем в четвертый разряд пусто
    }
  else // Если значение положительное, то выполняется следующий цикл
    {        
      if (disp < 10) // если наша цифра меньше 10, то
        {
        Indicate(0, 22);                 // пишем в первый разряд символ градуса
        Indicate(1, disp_sot % 10);      // пишем во второй разряд сотую долю цифры
        Indicate(2, disp_sot / 10);      // пишем в третий разряд десятую долю цифры
        Indicate(3, disp + 10);          // пишем в четвертый разряд нашу цифру с точкой
        }
      else if (disp < 100) // если наша цифра меньше 100, то
        {
        Indicate(0, disp_sot % 10);      // пишем в первый разряд - сотую долю цифры
        Indicate(1, disp_sot / 10);      // пишем во второй разряд - десятую долю цифры
        Indicate(2, (disp % 10) + 10);   // пишем в третий разряд - цифру оставшуюся от деления на 10 с точкой
        Indicate(3, disp / 10);          // пишем в четвертый разряд - цифру делёную на 10
        }
      else if (disp < 1000) // если наша цифра меньше 1000, то
        {
        Indicate(0, disp_sot / 10);      // пишем в первый разряд - десятую долю цифры
        Indicate(1, (disp % 10) + 10);   // пишем во второй разряд - последнюю целую цифру с точкой
        Indicate(2, (disp % 100) / 10);  // пишем в третий разряд - цифру оставшуюся от деления на 100 
        Indicate(3, (disp / 100));       // пишем в четвертый разряд - цифру делёную на 100
        }
       else // перестраховаться, на случай если вы засунете свой термометр в доменную печь
        {
        Indicate(0, 21);    // Думаю что температура выше 999 градусов
        Indicate(1, 21);    // вряд ли возможна, поэтому
        Indicate(2, 21);    // выводим прочерки во всех регистрах
        Indicate(3, 21); 
        }       

/*  Как реализовать короткий цыкл с плавающей точкой с десятыми и сотыми, пока не придумал
    for( int i = 0; i < 4; i++ )
      {
      if( i == 0 || disp != 0 )
          Indicate( i, disp % 10 );
      else
          Indicate( i, 24 );
      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); // пауза, чтобы сегменты "разгорелись"
}

При использования этого кода показания аналогового датчика LM35 некорректно выводятся.

хотя при простом выводе показаний датчика в серийный порт, правильно.

b707
Offline
Зарегистрирован: 26.05.2017

"некорректно" - это как?

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

одно разбиение числа на разряды аж 60 строчек... когда реально достаточно 4-6 строк

apg_777
Offline
Зарегистрирован: 22.09.2020

Для начала закомментировать весь loop, затем просто выводить разные числа и смотреть что получается. Скорее всего будет бардак. Разобраться с динамической индикацией и добиться нормального отображения. Только после этого переходить к отображению показаний. Если опять ерунда будет проверить пересчёт значений.