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

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

Задача несколько другая.

датчики стоят по разным помещениям. Индикаторы - на входе в каждое помещение. (Не дом) Перед дверью видишь индикатор с температурой внутри конкретного помещения. 3 двери = 3 индикатора. А отдельно, в кабинете (ну или дома лежа не диване) через комп видишь показания датчиков на мониторе. Processing - рулит. Прогу с датчиками своял (на комп показания идут) теперь задача - интегрировать туда индикацию с индикаторами.

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

Nemo пишет:

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

Сам недавно этот вопрос задавал :)

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

Нашел интересный вариант отображения с использованием прерываний. С прерываниями я не знаком, пока еще.
Проект часов от Ghost_D - http://robocraft.ru/blog/3095.html

Из всего проекта выдернул только фрагмент для индикаторов. Правда Ghost_D использовал один регистр, но оченнь интересная реализация ShiftOut.


/*
Автор кода: Ghost_D
Проект: Wall-E Clock Shield. Своими руками.
Адрес исходный кода: http://robocraft.ru/blog/3095.html
*/

byte lckPin=9; //подключение 74HC595
byte clockPin=10; //подключение 74HC595
byte dataPin=8; //подключение 74HC595

//предустановка, времени нахождения в текущем режиме
#define timeReturnMode 5000

byte showDisp[4]; //это массив, который будет отображаться на индекаторах
byte segmNum[4]={6,4,5,3}; //массив пинов, к которым подключены катоды индикаторов, 1сегм. - pin 6, 2 сегм. - pin 4 и т.д.

// Это массив значений, которые нужно "загнать" в 74HC595, для отображения нужной цифры
//                  0   1    2    3    4    5   6    7    8   9 
byte Encode7seg[]={252,192, 181, 213, 201, 93, 125, 196, 253,221};
byte cur_digit=0;

void setup(){
  pinMode(lckPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
   for (byte z=0;z<4;z++)
 {
   pinMode(segmNum[z],OUTPUT);
 }
 
 //start ----------------- настраиваем прерывание по таймеру  --------------
// для Atmega8 здесь нужно вносить изменения
// А тут на прерывания по таймеру будет вызываться процедура отображения сегментов
  uint8_t prescaler = _BV(CS10); //ставим предделитель в 1
  ICR1    = 28000;                      // задаем верхнее значение счетчика.
  if (TCNT1 > 1024) TCNT1 = 28000;      // Если значение счетчика больше, чем верхнее значение - корректируем.
  TCCR1B  = _BV(WGM13)  | prescaler;   // Ставим режим (PWM, phase and frequency corrected) и значение предделителя.
  TCCR1A  = _BV(COM1B0);
  TIMSK1 |= _BV(OCIE1A);             // Активируем прерывание.
 //частота обновления одного сегмента  ISR(TIMER1_COMPA_vect), будет 16000000/28000=571 
 //end ----------------- настраиваем прерывание по таймеру  --------------  

} //end setup  

 
void loop(){
  
  pushDataToDisp(10,30);
}  
  //-----------------------------------------------
// ОЧЕНЬ нужные процедуры и функции
//-----------------------------------------------
// Процедура отображения "содержимого" showDisp
  ISR(TIMER1_COMPA_vect) {
 
 /* Этот цикл - "кривой вариант обнуления" сегментов
 if (cur_digit==0){
 digitalWrite(segmNum[3],LOW);
 }
 else{
   digitalWrite(segmNum[cur_digit-1],LOW);
 }
 */
 // а этот вариант обнуления сегментов гораздо красивее - 1 строчка
 digitalWrite(segmNum[(cur_digit-1) & 3],LOW);
 
 
 /*
 Так как долго "висеть" на прерывании не рекомендуется, попробуем ускориться (переделаем ShiftOut)
В качестве аксиомы возьмем следующее: Как установить определенный пин в порту (не зацепив все остальные)?
PORTB |= _BV(PB5); - HIGH (установка Pin13 в HIGH)
PORTB &= ~_BV(PB5); -LOW  (установка Pin13 в LOW)
--------------------------
Arduino Pin  -  Name
8 -             PB0
9 -             PB1
10 -            PB2
11 -            PB3
12 -            PB4
13 -            PB5
--------------------------
Но почему-то для Atmega328 нужно указывать не PB2, а PORTB2 ?!?!?! На куя????
Смотри ATMEGA8 and ATMEGA168 uses: /hardware/tools/avr/avr/include/avr/iomx8.h
ATMEGA328 uses: /hardware/tools/avr/avr/include/avr/iom328p.h

Итак, для нашего случая:
dataPin=8  - это PORTB0 (или PB0 для Atmega8/168)
clockPin=10  - это PORTB2 (или PB2 для Atmega8/168)
!!!! Естественно, предварительно эти порты должны быть настроены на OUTPUT!!!
----------------cut------------------
*/
 
  digitalWrite(lckPin,LOW);
 // shiftOut(dataPin,clockPin,MSBFIRST,showDisp[cur_digit]);
//стрелками выделен фрагмент "заменяющий" команду shiftOut
 // --->  ниже фрагмент кода - "типа" САМОГО скоростного (ДЛЯ ARDUINO) ShiftOut
  for (int i=7; i>=0; i--) {
        if(showDisp[cur_digit]&(1<<i)) PORTB |= _BV(PORTB0); //побитный сдвиг и запись 1- HIGH в соотв. пин
        else PORTB &= ~_BV(PORTB0); //если 0, то пин ставим в LOW
        //делаем тактовый "тик"
        PORTB |= _BV(PORTB2);
        PORTB &= ~_BV(PORTB2);
    }//end for
//  ---> конец фрагмента кода - "типа" САМОГО скоростного (ДЛЯ ARDUINO) ShiftOut
  
  digitalWrite(lckPin,HIGH);

  digitalWrite(segmNum[cur_digit],HIGH);
  cur_digit++;

  if (cur_digit>3){
    cur_digit=0;
 }

}//end ISR


//---- процедура заполнения экранного буфера
void pushDataToDisp(byte firstInd, byte secondInd)
{
  showDisp[0]=Encode7seg[(firstInd/10)];
  showDisp[1]=Encode7seg[(firstInd%10)];
  showDisp[2]=Encode7seg[(secondInd/10)];
  showDisp[3]=Encode7seg[(secondInd%10)];
}//end pushDisp

Фрагмент полностью рабочий, но под мою идею (Вывод информации на 4 разрядный 7сегментный индикатор при помощи двух 74hc595) подходит не совсем. Тут я решил (что самый умный) и просто дважды вставил аналог ShiftOut, но реальность вновь расставила все точки над Ё :). Код рабочий, но не совсем - отображается только один разряд, первый указанный в массиве разрядов. Остальные в упор не хотят работать.
Кто будет пробовать, не забудте поменять массивы значений для символов и разрядов на свои, т.к. тут вариант для моей самопальной платы.


/*
Автор кода: Ghost_D
Проект: Wall-E Clock Shield. Своими руками.
Адрес исходный кода: http://robocraft.ru/blog/3095.html
*/

byte lckPin=9; //подключение 74HC595
byte clockPin=10; //подключение 74HC595
byte dataPin=8; //подключение 74HC595

//предустановка, времени нахождения в текущем режиме
#define timeReturnMode 5000

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

// Это массив значений, которые нужно "загнать" в 74HC595, для отображения нужной цифры
byte g_digits[]={
 B01000010, B11110110,    // 0 1
 B01101000, B01110000,    // 2 3
 B11010100, B01010001,    // 4 5
 B01000001, B11110010,    // 6 7
 B01000000, B01010000,    // 8 9
 B11111111, B11111101,};   // все сегменты выключены / -

// Это массив значений, которые нужно "загнать" в 74HC595, для отображения нужных разрядов индикатора
byte g_registerArray[]={
 B00010000, B00001000,      // +4 +3
 B00000010, B00000001,      // +2 +1
 B00000100, };            // dp

void setup(){
  pinMode(lckPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);

 
 //start ----------------- настраиваем прерывание по таймеру  --------------
// для Atmega8 здесь нужно вносить изменения
// А тут на прерывания по таймеру будет вызываться процедура отображения сегментов
  uint8_t prescaler = _BV(CS10); //ставим предделитель в 1
  ICR1    = 28000;                      // задаем верхнее значение счетчика.
  if (TCNT1 > 1024) TCNT1 = 28000;      // Если значение счетчика больше, чем верхнее значение - корректируем.
  TCCR1B  = _BV(WGM13)  | prescaler;   // Ставим режим (PWM, phase and frequency corrected) и значение предделителя.
  TCCR1A  = _BV(COM1B0);
  TIMSK1 |= _BV(OCIE1A);             // Активируем прерывание.
 //частота обновления одного сегмента  ISR(TIMER1_COMPA_vect), будет 16000000/28000=571 
 //end ----------------- настраиваем прерывание по таймеру  --------------  

} //end setup  

 
void loop(){

  long disp = 7654; //создаем переменную для вывода на экран

 // Разбиваем цифру по разрядам индикатора
for( int i = 0; i < 4; i++ )
{
   if( i == 0 || disp != 0 )
      Indicate( i, disp % 10 );
   else
      Indicate( i, 10 );
   disp /= 10;
}

}  
  //-----------------------------------------------
// ОЧЕНЬ нужные процедуры и функции
//-----------------------------------------------
// Процедура отображения "содержимого" showDisp
  ISR(TIMER1_COMPA_vect) {

 /*
 Так как долго "висеть" на прерывании не рекомендуется, попробуем ускориться (переделаем ShiftOut)
В качестве аксиомы возьмем следующее: Как установить определенный пин в порту (не зацепив все остальные)?
PORTB |= _BV(PB5); - HIGH (установка Pin13 в HIGH)
PORTB &= ~_BV(PB5); -LOW  (установка Pin13 в LOW)
--------------------------
Arduino Pin  -  Name
8 -             PB0
9 -             PB1
10 -            PB2
11 -            PB3
12 -            PB4
13 -            PB5
--------------------------
Но почему-то для Atmega328 нужно указывать не PB2, а PORTB2 ?!?!?! На куя????
Смотри ATMEGA8 and ATMEGA168 uses: /hardware/tools/avr/avr/include/avr/iomx8.h
ATMEGA328 uses: /hardware/tools/avr/avr/include/avr/iom328p.h

Итак, для нашего случая:
dataPin=8  - это PORTB0 (или PB0 для Atmega8/168)
clockPin=10  - это PORTB2 (или PB2 для Atmega8/168)
!!!! Естественно, предварительно эти порты должны быть настроены на OUTPUT!!!
----------------cut------------------
*/
 
  digitalWrite(lckPin,LOW);
 // shiftOut(dataPin,clockPin,MSBFIRST,showDisp[cur_digit]);
//стрелками выделен фрагмент "заменяющий" команду shiftOut
 // --->  ниже фрагмент кода - "типа" САМОГО скоростного (ДЛЯ ARDUINO) ShiftOut
  for (int i=7; i>=0; i--) {
        if(RazrDisplay&(1<<i)) PORTB |= _BV(PORTB0); //побитный сдвиг и запись 1- HIGH в соотв. пин
        else PORTB &= ~_BV(PORTB0); //если 0, то пин ставим в LOW
        //делаем тактовый "тик"
        PORTB |= _BV(PORTB2);
        PORTB &= ~_BV(PORTB2);
    }//end for
//  ---> конец фрагмента кода - "типа" САМОГО скоростного (ДЛЯ ARDUINO) ShiftOut

 // --->  ниже фрагмент кода - "типа" САМОГО скоростного (ДЛЯ ARDUINO) ShiftOut
  for (int i=7; i>=0; i--) {
        if(SegDisplay&(1<<i)) PORTB |= _BV(PORTB0); //побитный сдвиг и запись 1- HIGH в соотв. пин
        else PORTB &= ~_BV(PORTB0); //если 0, то пин ставим в LOW
        //делаем тактовый "тик"
        PORTB |= _BV(PORTB2);
        PORTB &= ~_BV(PORTB2);
    }//end for
//  ---> конец фрагмента кода - "типа" САМОГО скоростного (ДЛЯ ARDUINO) ShiftOut
  
  digitalWrite(lckPin,HIGH);
  }

//---- процедура заполнения экранного буфера
void Indicate(int r,int x)
{
SegDisplay=g_digits[x]; // получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре.
RazrDisplay=g_registerArray[r];  // получаем цифру и выводим номер регистра, из массива цифр, соответствующий этой цифре.
}

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

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

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

#include <OneWire.h>
#include <DallasTemperature.h>

OneWire oneWire(5);
DallasTemperature sensors(&oneWire);
float temp1=0; 
DeviceAddress tempDeviceAddress;

long previousMillis1 = 0;
long interval1 = 1000; // интервал опроса датчиков температуры

int latchPin = 2;     // Пин "защелки" первого регистра подключен к RCLK (SS, ST_CP) входу 
int clockPin = 3;    // Пин "тактовый" подключен к SCLK (CLK, SH_CP) входу 74HC595
int dataPin = 4;     // Пин "данных" подключен к QH (SDI, DS) входу 74HC595

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

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

// Настройка комбинации для отображения каждого номера на индикаторе
// Массив цифр, генерирующий на сегментах цифры в двоичной системе исчисления
byte g_digits[25]={
 B00111111, B00000110, B01011011, B01001111, B01100110,   // 0 1 2 3 4
 B01101101, B01111101, B00000111, B01111111, B01101111,   // 5 6 7 8 9
 B10111111, B10000110, B11011011, B11001111, B11100110,   // 0. 1. 2. 3. 4.
 B11101101, B11111101, B10000111, B11111111, B11101111,   // 5. 6. 7. 8. 9. 
 B10000000, B01000000, B01100011, B00111001,   // точка, прочерк, градус, цельсия
 B00000000, }; 		                       // все сегменты выключены
byte g_registerArray[4]={~8,~4,~2,~1}; //массив цифр, указывающий разряды

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

}

void loop()
{
  //Модуль опроса датчиков и получения сведений о температуре
  //Вызывается 1 раз в секунду
  unsigned long currentMillis1 = millis();
  if(currentMillis1 - previousMillis1 > interval1) {
  previousMillis1 = currentMillis1; 
  
//Запуск процедуры измерения температуры
  sensors.requestTemperatures();
//Считывание значения температуры
  sensors.getAddress(tempDeviceAddress, 0);
  temp1=sensors.getTempC(tempDeviceAddress);
}
  // Можете подставить любые значения. Следите чтобы стояла именно . (например 5.75 а не 5,75) иначе - ошибка компаиляции вам обеспечена
  int disp;                  // Переменная для целых чисел температуры               
  int disp_sot;              // Переменная для дробной части числа
  
  disp = int (temp1);                 // Избавляемся от десятых и сотых (оставляем челую часть числа)
  temp1 = (temp1 - disp) * 100; // Переводим десятые и сотые в целую часть числа
  disp_sot = int (abs(temp1));        // Обрубаем значения после запятой (оставляем целую часть числа) модуль - для избавления от минуса
  
  // Разбиваем цифру по разрядам индикатора
  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); // пауза, чтобы сегменты "разгорелись"
}

 

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

Sirox пишет:

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

Я смотрю вы уже датчик прикрутили. Я пока не делал. Буду на выходных кумекать. Про проблему мерцания слышал. Это и есть призрачность простоты Arduino. Надо работать с 1-wire в прерываниях чтоб не останавливать динамику индикации.

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

Сам пока не дошел. Если кто в курсе - подскажите.

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

Nemo пишет:

Как реализовать короткий цыкл с плавающей точкой с десятыми и сотыми, пока не придумал

void ledDigitDisplay(float num, float time)
{
	unsigned long ltime = millis();
	
	// Настройки
	// 6, 8, 9, 12 - GND
	int pin[] = {6, 7, 8, 9, 10, 2, 11, 3, 4, 12, 13, 5}; // Пины
	int settingsSegments[] = {pin[10], pin[6], pin[3], pin[1], pin[0], pin[9], pin[4], pin[2]}; // Порядок сегментов
	int segments[] = {0b00111111, 0b00000110, 0b01011011, 0b01001111, 0b01100110, 0b01101101, 0b01111101, 0b00000111, 0b01111111, 0b01101111, 0b10000000, 0b01000000}; // 1, 2, 3, 4, 5, 6, 7, 8, 9, '.', '-'
	for(int i = 0; i < 12; ++i) pinMode(pin[i], OUTPUT); // Определяем пины как выход

	int floatingPoint = 0, minus = 4;

	if(num > -1000 && num < 0) // Разбираемся с отрицательными числами
	{
		minus--;
		if(num > -100) minus--;
		if(num > -10) minus--;
		num = -num;
	}

	for(int i = 0; num < 1000 && minus == 4; ++i) // Разбираемся с дробными числами
	{
		if(int(num * 10) != int(num)*10)
		{
			floatingPoint++;
			num *= 10;
		}
		else
			break;
	}
	
	for(int i = 0, temp; millis() - ltime <= time * 1000; i++)
	{
		if(i == 4) i = 0;

		temp = int(num / pow(10, i)) % 10; // Цифра которую передадим индикатору
		if(num >= 10000 || num <= -10000 || minus == i) // Если минус или переполнение, передаем '-'
			temp = 11;

		if(i == 3 && (num >= 1000 || floatingPoint == i || minus == i)) pinMode(pin[11], OUTPUT); else pinMode(pin[11], INPUT); // Работаем с 4 разрядом
		if(i == 2 && (num >= 100 || floatingPoint == i || minus == i)) pinMode(pin[8], OUTPUT); else pinMode(pin[8], INPUT); // Работаем с 3 разрядом
		if(i == 1 && (num >= 10 || floatingPoint == i || minus == i)) pinMode(pin[7], OUTPUT); else pinMode(pin[7], INPUT); // Работаем с 2 разрядом
		if(i == 0) pinMode(pin[5], OUTPUT); else pinMode(pin[5], INPUT); // Работаем с 1 разрядом

		for(int j = 0; j < 8; j++) // Передаем число
			if(segments[temp] & (1 << j))
				digitalWrite(settingsSegments[j], HIGH);

		if(floatingPoint && floatingPoint == i) // Передаем точку
			digitalWrite(settingsSegments[7], HIGH);

		delay(1); // Небольшая пауза, чтобы светодиоды разгорелись

		for(int j = 0; j < 8; j++) digitalWrite(settingsSegments[j], LOW); // Выключаем все светодиоды
	}
}

void setup()
{

}



void loop()
{
	ledDigitDisplay(3.14, 2);
	ledDigitDisplay(123, 2);
	ledDigitDisplay(-5, 2);
}

Тут вроде компактно высчитывается с точкой и минусами, может что пригодится.

По поводу избавления мерцания нашол щас темку, может тоже поможет http://arduino.ru/forum/programmirovanie/otkaz-ot-delay. В коде у меня знаний не хватает, не програмист я ни разу.

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

По DS18B20, подали команду на конвертацию, ушли, через 750мС вернулись и считали температуру - это чисто по 1-Wire. По DHT - надо библиотеку править, так просто не выходит.

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

bwn пишет:

По DS18B20, подали команду на конвертацию, ушли, через 750мС вернулись и считали температуру - это чисто по 1-Wire. По DHT - надо библиотеку править, так просто не выходит.

Может есть пример кода, где можно посмотреть как реализовано.

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

Вот в этом коде так сделано.

Чет с него улетает - 270 пост.

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

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

#include <OneWire.h>

OneWire ds (A5);
byte data[12];
float celsius;
int raw;
unsigned long time=0;
boolean flag=1;

void setup() {
  
}

void loop(){
  if(flag) {
    DS_start();
    time=millis();
    flag=0;
  }
  if((millis()-time)>750 && !flag){
    DS_read();
    flag=1;
  }
   //а здесь постоянно выводим. температуру брать из celsius
    
}

void DS_start(){
  ds.reset();
  ds.write(0xCC);
  ds.write(0x44); // start conversion, with parasite power on at the end
}

void DS_read(){
  ds.reset();
  ds.write(0xCC);
  ds.write(0xBE); // Read Scratchpad
  for (byte i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read ();
  }
  raw =  (data[1] << 8) | data[0];//=======Пересчитываем в температуру
  celsius =  (float)raw / 16.0;
}

 

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

jeka_tm пишет:

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

#include <OneWire.h>

OneWire ds (A5);
byte data[12];
float celsius;
int raw;
unsigned long time=0;
boolean flag=1;

void setup() {
  
}

void loop(){
  if(flag) {
    DS_start();
    time=millis();
    flag=0;
  }
  if((millis()-time)>750 && !flag){
    DS_read();
    flag=1;
  }
   //а здесь постоянно выводим. температуру брать из celsius
    
}

void DS_start(){
  ds.reset();
  ds.write(0xCC);
  ds.write(0x44); // start conversion, with parasite power on at the end
}

void DS_read(){
  ds.reset();
  ds.write(0xCC);
  ds.write(0xBE); // Read Scratchpad
  for (byte i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read ();
  }
  raw =  (data[1] << 8) | data[0];//=======Пересчитываем в температуру
  celsius =  (float)raw / 16.0;
}

 

 

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

 

#include <OneWire.h>

OneWire ds (5);
byte data[12];
float temperature;
int raw;
unsigned long time=0;
boolean flag=1;

int latchPin = 2;     // Пин "защелки" первого регистра подключен к RCLK (SS, ST_CP) входу 
int clockPin = 3;    // Пин "тактовый" подключен к SCLK (CLK, SH_CP) входу 74HC595
int dataPin = 4;     // Пин "данных" подключен к QH (SDI, DS) входу 74HC595

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

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

// Настройка комбинации для отображения каждого номера на индикаторе
// Массив цифр, генерирующий на сегментах цифры в двоичной системе исчисления
byte g_digits[25]={
 B00111111, B00000110, B01011011, B01001111, B01100110,   // 0 1 2 3 4
 B01101101, B01111101, B00000111, B01111111, B01101111,   // 5 6 7 8 9
 B10111111, B10000110, B11011011, B11001111, B11100110,   // 0. 1. 2. 3. 4.
 B11101101, B11111101, B10000111, B11111111, B11101111,   // 5. 6. 7. 8. 9. 
 B10000000, B01000000, B01100011, B00111001,   // точка, прочерк, градус, цельсия
 B00000000, }; 		                       // все сегменты выключены
byte g_registerArray[4]={~8,~4,~2,~1}; //массив цифр, указывающий разряды

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

void loop(){
 if(flag) {
    DS_start();
    time=millis();
    flag=0;
  }
  if((millis()-time)>750 && !flag){
    DS_read();
    flag=1;
  }
    // Можете подставить любые значения. Следите чтобы стояла именно . (например 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); 
        }       

}
}



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); // пауза, чтобы сегменты "разгорелись"
}

void DS_start(){
  ds.reset();
  ds.write(0xCC);
  ds.write(0x44); // start conversion, with parasite power on at the end
}

void DS_read(){
  ds.reset();
  ds.write(0xCC);
  ds.write(0xBE); // Read Scratchpad
  for (byte i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read ();
  }
  raw =  (data[1] << 8) | data[0];//=======Пересчитываем в температуру
  temperature =  (float)raw / 16.0;
}

 

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

как то замороченно сделано по моему

например десятые. это проще понять если отправить измеренную температуру в uart

насколько помню там один или два знака после запятой (смотреть в терминале). и значит просто домножать на 10 или 100. и не нужно доп. переменных что до запятой, что после

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

когда выводишь цифру с точкой просто к коду который передается просто цифры , например 3 B01001111. первый ноль управляет точкой

значит когда передаешь для 2 разряда (например у тебя 2 разряд с точкой, всегда в одном месте!!!) нужно передать еще точку B01001111|B10000000. и все)

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

jeka_tm пишет:

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

Не согласен. У меня в коде точка ни на одом месте. Плавает да еще как! Да если и в одном поставить, то получится что плюсовая температура максимум будет 99,99 и минусовая -9,99

Я у себя могу видеть плюслвую 999,9 и 99,99 а минусовую -99,9 и -9,99 т.е. значительно расширяется диапазон измеряемых температур, а ноль (если чистый ноль без десятых и сотых) - вообще выводится как 0 градусов (значек) С. Спросите для чего? Проекты могут быть разные: для погоды - одно (можно и без сотых обойтись); для инкубатора - другое (там и сотые играют роль) в коптильне или автоклаве - третье (там температуры зачастую превышают 100 градусов... и т.д.

Терятеся универсальность.

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

jeka_tm пишет:

как то замороченно сделано по моему

например десятые. это проще понять если отправить измеренную температуру в uart

насколько помню там один или два знака после запятой (смотреть в терминале). и значит просто домножать на 10 или 100. и не нужно доп. переменных

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

когда выводишь цифру с точкой просто к коду который передается просто цифры , например 3 B01001111. первый ноль управляет точкой

значит когда передаешь для 2 разряда (например у тебя 2 разряд с точкой, всегда в одном месте!!!) нужно передать еще точку B01001111|B10000000. и все)

Точка будет плавать, это заготовка для Борт комп авто (будут и другие переменные кроме темп). Это ничего страшного, просто нужно как то организовать структуру подругому чтобы было удобно выводить разные переменные и не было морганий. Я особо в коде не разбираюсь, код писали CheBuraw и Nemo. 

 

 

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

Sirox пишет:

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

А вот тут я согласен полностью. У меня в проекте тоже предусмотрены и другие переменные, и другие индикаторы. Обещаю подумать, но только на выходных. Ща, цука, некогда. Работа мешает. Но решение где то рядом. Стулом чую.

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

Nemo пишет:

Sirox пишет:

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

А вот тут я согласен полностью. У меня в проекте тоже предусмотрены и другие переменные, и другие индикаторы. Обещаю подумать, но только на выходных. Ща, цука, некогда. Работа мешает. Но решение где то рядом. Стулом чую.

А я с работы захожу к себе на рабочий стол через TeamViewer там меняю код и смотрю что получится на индикаторе через ваб камеру ))

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

так вот оно что. делаете универсальный код значит

тогда вопрос. допустим температура 18,75 и -18,75. как каждая будет выглядеть?

так? 18,75 и -18,7

или так? 18,7 и -18,7

то есть минус съедает разряд  или для него всегда пустое место? и вместо него например + выводится

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

Плюс не выводится. Если без знака, то априори - положительное значение. Выводится будет 18,75 и -18,7

Считаю это оптимальным, так как при положительных температурах гораздоо чаще сотые играют роль чем при отрицательных. ИХМО. На вскидку - не придумал проекта где сотые в отрицательных значениях играют роль. При положительных - тот же инкубатор.

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

сотые ничего не играют. на них лучше не смотреть вообще. так что это не сущетсвенно хотя бы лично для меня

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

Nemo пишет:

Плюс не выводится. Если без знака, то априори - положительное значение. Выводится будет 18,75 и -18,7

Считаю это оптимальным, так как при положительных температурах гораздоо чаще сотые играют роль чем при отрицательных. ИХМО. На вскидку - не придумал проекта где сотые в отрицательных значениях играют роль. При положительных - тот же инкубатор.

Неа, как птицевод говорю, не родилась еще та курица, которая свой терморежим с сотыми поддерживает. Десятые и те плюс минус.

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

так и сотым верить нельзя

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

Интересный момент получается.

Код из поста №47 при компиляции в памяти занимает:

Sketch uses 1 378 bytes (4%) of program storage space. Maximum is 32 256 bytes.
Global variables use 45 bytes (2%) of dynamic memory, leaving 2 003 bytes for local variables. Maximum is 2 048 bytes.

А перенеся основной код в функцию (добавив буквально пару строк) и оставив в основном цыкле 1 строку - вызов функции, при компиляции получаем уже:

Sketch uses 2 772 bytes (8%) of program storage space. Maximum is 32 256 bytes.
Global variables use 45 bytes (2%) of dynamic memory, leaving 2 003 bytes for local variables. Maximum is 2 048 bytes.

т.е. в 2 раза больше от первоначального варианта. Получается - чем больше мы чистим код и переносим действий в функции (сокращая тем самым основное тело программы), тем больше места мы занимаем в памяти Дуни?

А что же будет, если функции перенести в библиотеки? Еще больше?
 

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

неа. ты что то намудрил. разница 6 байт

хотя может разница в том что ты используешь наверно версию 1.6.0, а я 1.0.6

поставь  1.0.6 и меньше проблемм у тебя будет

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

jeka_tm пишет:

хотя может разница в том что ты используешь наверно версию 1.6.0, а я 1.0.6

поставь  1.0.6 и меньше проблемм у тебя будет

Наверное. У меня стоит 1.5.8

Проверил на версии 1.0.6

Размер скетча в двоичном коде: 2 782 байт (из 32 256 байт максимум)

В версии 1.6.0

Sketch uses 2 772 bytes (8%) of program storage space. Maximum is 32 256 bytes.
Global variables use 45 bytes (2%) of dynamic memory, leaving 2 003 bytes for local variables. Maximum is 2 048 bytes.
 

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

jeka_tm пишет:

jeka_tm, какая у Вас интересная модификация Arduino IDE. Подскажите, пожалуйста как себе сделать такую же? Где и какие плагины скачать или это как-то подругому делается?

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

CheBuraw пишет:

jeka_tm, какая у Вас интересная модификация Arduino IDE. Подскажите, пожалуйста как себе сделать такую же? Где и какие плагины скачать или это как-то подругому делается?

просто внешний вид изменен

http://arduino.ru/forum/obshchii/novichkam-podskazki#comment-104199

Nemo вот один и второй код. проверь еще раз. хз что ты тестируешь

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

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

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

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

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

void loop()
{
  float temperature = 1.23;  // Можете подставить любые значения. Следите чтобы стояла именно . (например 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, SegDisplay);  // Записываем информацию для первого регистра (Номер символа)
      shiftOut(dataPin, clockPin, MSBFIRST, RazrDisplay); // Записываем информацию для второго регистра (Номер разряда)
    digitalWrite(latchPin, HIGH);  //"защелкиваем" регистр, тем самым устанавливая значения на выходах
  
    delay(TimeLight); // пауза, чтобы сегменты "разгорелись"
  }
int latchPin = 8;     // Пин "защелки" первого регистра подключен к RCLK (SS, ST_CP) входу 
int clockPin = 12;    // Пин "тактовый" подключен к SCLK (CLK, SH_CP) входу 74HC595
int dataPin = 11;     // Пин "данных" подключен к QH (SDI, DS) входу 74HC595

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

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

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

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

void loop()
{
  temper();
}
  
  void temper(){
  float temperature = 1.23;  // Можете подставить любые значения. Следите чтобы стояла именно . (например 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, SegDisplay);  // Записываем информацию для первого регистра (Номер символа)
      shiftOut(dataPin, clockPin, MSBFIRST, RazrDisplay); // Записываем информацию для второго регистра (Номер разряда)
    digitalWrite(latchPin, HIGH);  //"защелкиваем" регистр, тем самым устанавливая значения на выходах
  
    delay(TimeLight); // пауза, чтобы сегменты "разгорелись"
  }

 

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

jeka_tm Да тот же код и тестирую. Вот что в версии 1.6.1 :

Sketch uses 2 772 bytes (8%) of program storage space. Maximum is 32 256 bytes.
Global variables use 45 bytes (2%) of dynamic memory, leaving 2 003 bytes for local variables. Maximum is 2 048 bytes.

Вот код:

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

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

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

void loop()
{
  ledDigitDisplay(17.25); // Можете подставить любые значения. Следите чтобы стояла именно . (например 5.75 а не 5,75) иначе - ошибка компаиляции вам обеспечена
}

void ledDigitDisplay(float temperature)
  { // функция работы с числом: определение целой и дробной частей, положительного или отрицательного значения
  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(byte r, byte x) // Функция собственно, отображения цыфр на индикаторе.
  {
    byte TimeLight = 5;    // Время для разогрева сегментов
    byte SegDisplay=g_digits[x]; // получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре.
    byte RazrDisplay=g_registerArray[r];  // получаем цифру и выводим номер регистра, из массива цифр, соответствующий этой цифре.
    digitalWrite(latchPin, LOW);   // устанавливаем синхронизацию "защелки" на LOW
      shiftOut(dataPin, clockPin, MSBFIRST, SegDisplay);  // Записываем информацию для первого регистра (Номер символа)
      shiftOut(dataPin, clockPin, MSBFIRST, RazrDisplay); // Записываем информацию для второго регистра (Номер разряда)
    digitalWrite(latchPin, HIGH);  //"защелкиваем" регистр, тем самым устанавливая значения на выходах
  
    delay(TimeLight); // пауза, чтобы сегменты "разгорелись"
  }

Если не трудно, прогони у себя. Сам в шоке.

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

да где же он один и тотже)))

разговор шел просто перенести в функцию. про передачу значений разговора не было

2886 получается

а если передавать не float а int число  и byte число знаков после запятой то остается как есть))

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

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

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

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

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

void loop()
{
  temper(123, 2);
}
  
  void temper(int temperature, byte razryad){
  
  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, SegDisplay);  // Записываем информацию для первого регистра (Номер символа)
      shiftOut(dataPin, clockPin, MSBFIRST, RazrDisplay); // Записываем информацию для второго регистра (Номер разряда)
    digitalWrite(latchPin, HIGH);  //"защелкиваем" регистр, тем самым устанавливая значения на выходах
  
    delay(TimeLight); // пауза, чтобы сегменты "разгорелись"
  }

 

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

jeka_tm пишет:

да где же он один и тотже)))

разговор шел просто перенести в функцию. про передачу значений разговора не было

2886 получается

а если передавать не float а int число  и byte число знаков после запятой то остается как есть))

Ясно. Значит всё из за float...

Двумя переменным не хочу передавать, я ж с плавающей точкой все мучу. Поэтому передавать четко 2 знака после запятой не хотел. Передаю только 1 параметр, а внутри уже определяюсь с разрядами, минусами и т.д.

Но на мой вопрос вы ответили. Спасибо.

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

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

работа с float тяжелая для меги. при использовании автоматически используется математика, библиотка math кажется

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

jeka_tm пишет:

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

Да. Но для этого нужно значение разкладывать на три переменные до вызова функции. А у меня получается вся работы выполняется уже внутри функции. А передаем только конкретное значение температуры. И в основном цыкле программы фигурирует только одна строка:

void loop()
{
  ledDigitDisplay(17.25); // Можете подставить любые значения. Следите чтобы стояла именно . (например 5.75 а не 5,75) иначе - ошибка компаиляции вам обеспечена
}

Я это делал для того делал, чтобы следующим шагом запихнуть две функции void ledDigitDisplay() и void Indicate() в библиотеку, тем самым минимизировать до самого небалуйся код основной программы.

На выходных - допишу, покажу что получиться.

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

ну тогда смирись что объем больше))) да и места вроде еще вагон остается

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

Nemo пишет:

jeka_tm пишет:

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

Да. Но для этого нужно значение разкладывать на три переменные до вызова функции. А у меня получается вся работы выполняется уже внутри функции. А передаем только конкретное значение температуры. И в основном цыкле программы фигурирует только одна строка:

void loop()
{
  ledDigitDisplay(17.25); // Можете подставить любые значения. Следите чтобы стояла именно . (например 5.75 а не 5,75) иначе - ошибка компаиляции вам обеспечена
}

Я это делал для того делал, чтобы следующим шагом запихнуть две функции void ledDigitDisplay() и void Indicate() в библиотеку, тем самым минимизировать до самого небалуйся код основной программы.

На выходных - допишу, покажу что получиться.

 

Жду с нетерпением! ))

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

Переделал код. В старом около-нулевые значения не корректно обрабатывались.

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

// Диапазон отражения температурных значений на индикаторе max = 327.67 min = 99.99
  
int latchPin = 8;     // Пин "защелки" первого регистра подключен к RCLK (SS, ST_CP) входу 
int clockPin = 12;    // Пин "тактовый" подключен к SCLK (CLK, SH_CP) входу 74HC595
int dataPin = 11;     // Пин "данных" подключен к QH (SDI, DS) входу 74HC595

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

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

void loop()
{
  ledDigitDisplay(12.34); // Можете подставить любые значения. 
  // Следите чтобы стояла именно "." (например 5.75 а не 5,75) иначе - ошибка компаиляции вам обеспечена
  // Диапазон отражения температурных значений на индикаторе max = 327.67 min = 99.99
  // max - потому что int-диапазон только до 32767
  // min - потому что в не думаю что где то меньше значение потребуется
}

void ledDigitDisplay(float temperature)
  {
    int disp;                  // Переменная для целых чисел температуры               
    int floatingPoint = 0;     // Переменная "плавающая точка" для хранения номера регистра в котором стоит "."
    int index;
  
    disp = temperature * 100;   // Избавляемся от десятых и сотых (оставляем челую часть числа)
    if (disp < 0) disp = abs(disp); // используем модуль дабы избавиться от минуса. Его мы подставим в процессе 
    if (disp > 9999) disp = int (disp / 10); // сдвиг до отображения только десятых в положительном диапазоне > 99.99
    if (temperature <= -10) disp = int (disp / 10); // сдвиг до отображения только десятых в отрицательных диапазонах < -10

    // Определяемся в каком именно разряде ставить точку
    if ((temperature <= -10 && temperature > -100) || (temperature > 100 && temperature < 1000))
        floatingPoint = 1;
    else 
        if ((temperature < 0 && temperature > -10) || (temperature > 0 && temperature < 100)) 
            floatingPoint = 2;
        else floatingPoint = 4;

    if (temperature < -99.99 || temperature > 327.67)
      {
        // Обработаем выход за пределы min и max температур
        for (int i = 0; i < 4; i++)
            Indicate( i, 21 ); // Ставим во всех разрядах прочерки
      }
    else
      {
        if(temperature < 0) Indicate( 3, 21 );   // если значение минусовое то ставим минус в первом индикаторе
        if((disp / 100) < 1) Indicate( 2, 10 );
        if((disp / 10) < 1) Indicate( 1, 0 ); 
        if(temperature >= 0) index = 4;
          else index = 3;
        
        // Собственно, основной цыкл. Тут все и происходит
        for (int i = 0; i < index; i++)
            {
              if (i == 0 || disp != 0)
                  if (i == 1 && floatingPoint == 1 || i == 2 && floatingPoint == 2)
                      Indicate( i, (disp % 10) + 10 );
                  else
                      Indicate( i, disp % 10 );
              else
                Indicate( i, 24 );
              disp /= 10;
            }
      }  
  }

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

Sketch uses 1 536 bytes (4%) of program storage space. Maximum is 32 256 bytes.
Global variables use 45 bytes (2%) of dynamic memory, leaving 2 003 bytes for local variables. Maximum is 2 048 bytes.

Из минусов - перестал отображаться 0 в формате "0 градусов цельсия" как было в старой версии кода. Но подумав, не стал дописывать, так как все равно все остальные значения отображаются без знака градуса.

Пошел прикручивать датчик температуры.....

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

Nemo пишет:

Переделал код. В старом около-нулевые значения не корректно обрабатывались.

Да и код получился покороче. Хотя и по замороченей.

Да я бы не сказал, что замороченней. По-моему наоборот, что-то понятное вырисовывается.







	      if (i == 1 && floatingPoint == 1 || i == 2 && floatingPoint == 2)

а почему не так? :)





              if (i == floatingPoint)

 

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

Datak пишет:

Да я бы не сказал, что замороченней. По-моему наоборот, что-то понятное вырисовывается.

а почему не так? :)


              if (i == floatingPoint)

Спасибо. Поправил.

Прикрутил датчик. С помощью своего кода и использованием библиотеки DallasTemperature.h не получилось пока. Взял предложенный jeka_tm код.

jeka_tm пишет:

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

#include <OneWire.h>

OneWire ds (A5);
byte data[12];
float celsius;
int raw;
unsigned long time=0;
boolean flag=1;

void setup() {
  
}

void loop(){
  if(flag) {
    DS_start();
    time=millis();
    flag=0;
  }
  if((millis()-time)>750 && !flag){
    DS_read();
    flag=1;
  }
   //а здесь постоянно выводим. температуру брать из celsius
    
}

void DS_start(){
  ds.reset();
  ds.write(0xCC);
  ds.write(0x44); // start conversion, with parasite power on at the end
}

void DS_read(){
  ds.reset();
  ds.write(0xCC);
  ds.write(0xBE); // Read Scratchpad
  for (byte i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read ();
  }
  raw =  (data[1] << 8) | data[0];//=======Пересчитываем в температуру
  celsius =  (float)raw / 16.0;
}

Температуру выводит, но подмигивает немного. Нужно еще смотреть. Попробую код, предложенный bwn в 59 посту данной темы. 

bwn пишет:

Вот в этом коде так сделано.

Чет с него улетает - 270 пост.

Правда там код длинный. Придется разбираться долго. Чужие коды мне сложно для чтения даются. Не программист я по жизни. Так. Любитель.

Да. Код забыл:

#include <OneWire.h>

// Диапазон отражения температурных значений на индикаторе max = 327.67 min = 99.99
  
byte latchPin = 8;     // Пин "защелки" первого регистра подключен к RCLK (SS, ST_CP) входу 
byte clockPin = 12;    // Пин "тактовый" подключен к SCLK (CLK, SH_CP) входу 74HC595
byte dataPin = 11;     // Пин "данных" подключен к QH (SDI, DS) входу 74HC595

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

OneWire ds (10);    // Пин где подвешен ds18b20
byte data[12];
float celsius;      // Переменная для хранения измеренной температуры
int raw;
unsigned long time=0;
boolean flag=1;


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

void loop()
{
  if(flag) 
  {
    DS_start();
    time=millis();
    flag=0;
  }
  if((millis()-time) > 750 && !flag)
  {
    DS_read();
    flag=1;
  }
   //а здесь постоянно выводим. температуру брать из celsius
  ledDigitDisplay(celsius); // Можете подставить любые значения. 
  // Следите чтобы стояла именно "." (например 5.75 а не 5,75) иначе - ошибка компаиляции вам обеспечена
  // Диапазон отражения температурных значений на индикаторе max = 327.67 min = 99.99
  // max - потому что int-диапазон только до 32767
  // min - потому что в не думаю что где то меньше значение потребуется
}

void DS_start()
{
  ds.reset();
  ds.write(0xCC);
  ds.write(0x44); // начать преобразования, с паразитным питанием на в конце
}

void DS_read()
{
  ds.reset();
  ds.write(0xCC);
  ds.write(0xBE); // Чтение Scratchpad
  for (byte i = 0; i < 9; i++) 
    { //  нам нужно 9 байт (с сотыми после запятой)
      data[i] = ds.read ();
    }
  raw =  (data[1] << 8) | data[0];  //  Пересчитываем в температуру
  celsius =  (float)raw / 16.0;
}

void ledDigitDisplay(float temperature)
  {
    int disp;                  // Переменная для целых чисел температуры               
    int floatingPoint = 0;     // Переменная "плавающая точка" для хранения номера регистра в котором стоит "."
    int index;
  
    disp = temperature * 100;   // Избавляемся от десятых и сотых (оставляем челую часть числа)
    if (disp < 0) disp = abs(disp); // используем модуль дабы избавиться от минуса. Его мы подставим в процессе 
    if (disp > 9999) disp = int (disp / 10); // сдвиг до отображения только десятых в положительном диапазоне > 99.99
    if (temperature <= -10) disp = int (disp / 10); // сдвиг до отображения только десятых в отрицательных диапазонах < -10

    // Определяемся в каком именно разряде ставить точку
    if ((temperature <= -10 && temperature > -100) || (temperature > 100 && temperature < 1000))
        floatingPoint = 1;
    else 
        if ((temperature < 0 && temperature > -10) || (temperature > 0 && temperature < 100)) 
            floatingPoint = 2;
        else floatingPoint = 4;

    if (temperature < -99.99 || temperature > 327.67)
      {
        // Обработаем выход за пределы min и max температур
        for (int i = 0; i < 4; i++)
            Indicate( i, 21 ); // Ставим во всех разрядах прочерки
      }
    else
      {
        if(temperature < 0) Indicate( 3, 21 );   // если значение минусовое то ставим минус в первом индикаторе
        if((disp / 100) < 1) Indicate( 2, 10 );
        if((disp / 10) < 1) Indicate( 1, 0 ); 
        if(temperature >= 0) index = 4;
          else index = 3;
        
        // Собственно, основной цыкл. Тут все и происходит
        for (int i = 0; i < index; i++)
            {
              if (i == 0 || disp != 0)
                  if (i == floatingPoint)
                      Indicate( i, (disp % 10) + 10 );
                  else
                      Indicate( i, disp % 10 );
              else
                Indicate( i, 24 );
              disp /= 10;
            }
      }  
  }

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

 

maksim
Offline
Зарегистрирован: 12.02.2012

Два варианта:

1. Писать неблокирующий 1-Wire.
2. Вывод индикации делать в прерывании по таймеру, а в библиотеке OneWire убрать запрет прерываний.

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

Если код Жеки мигает, можете не возиться, у меня тот же самый.

Могу добавить к maksim, меряйте температуру с разумными интервалами 1-2 минуты и тогда станет практически незаметно. Это наверно самое простое.

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

bwn пишет:

Могу добавить к maksim, меряйте температуру с разумными интервалами 1-2 минуты и тогда станет практически незаметно. Это наверно самое простое.

Мне для этого часы нужно прикручивать? Или через паузу минуту отсчитывать?

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

Nemo пишет:

bwn пишет:

Могу добавить к maksim, меряйте температуру с разумными интервалами 1-2 минуты и тогда станет практически незаметно. Это наверно самое простое.

Мне для этого часы нужно прикручивать? Или через паузу минуту отсчитывать?

Через millis().

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

maksim пишет:

Два варианта:

1. Писать неблокирующий 1-Wire.
2. Вывод индикации делать в прерывании по таймеру, а в библиотеке OneWire убрать запрет прерываний.

А можно подробнее? Просто край как необходимо разобраться. Все мои проекты с дуней связаны с датчиком ds18b20. Как это - неблокирующий 1-Wire? Читал что можно отправить запрос на измерение, потом продолжить индикацию, а после ответа от датчика уже обработать результат. Но как это реализовать - непонятно. Ткните носом пожалуйста куда посмотреть?

bwn пишет:

Через millis().

если в теории, мне нужно накопить минуту в переменной после запуска программы, затем измерить температуру, затем снова вернуться к накоплению минуты? А как быть с обнулением через 50 суток? И можно ли производить другие действия пока millis() будет минуту накапливать?

Читал что проблему мерцания через millis() решить можно. Только чет не пойму я этот оператор. Без параметров. Возвращает кол-во милисекунд с моментв выполнения текущей программы: т.е. с момента загрузки скетча в дуню или с момента включения уже загруженной дуни в сеть питания? А если она не выключалась? Работает круглосуточно? Сплошная каша.

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

Я тут подумал, если это возможно, выводимую переменную сделать как типа long которая запоминает последнее значение и ее обновлять уже датчиком, тоесть если не будет цифры с датчика то она покажет предыдущее значение, прокатит? )

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

Sirox пишет:

Я тут подумал, если это возможно, выводимую переменную сделать как типа long которая запоминает последнее значение и ее обновлять уже датчиком, тоесть если не будет цифры с датчика то она покажет предыдущее значение, прокатит? )

Если я правильно понимаю, наша проблема с мерцанием именно в измерении датчика. Он меряет примерно 0,5 сек. на это время и происходит мигание. Т.е. если делать как вы предлагаете, то от измерения мы никуда не уходим. И сохранять его хоть в переменную, хоть сразу на вывод пускать, все равно теряем 0,5 сек. Да? Или я туплю?

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

Да, скорее всего мое предположение ошибочно

maksim
Offline
Зарегистрирован: 12.02.2012

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

Но для вашей задачи думаю есть еще и третий вариант - более равномерно пользоваться методами библиотеки OneWire при помощи конечного автомата. И да измерять раз в секунду температуру безссмысленно, более чем достаточно раз в 30 секунд.

maksim
Offline
Зарегистрирован: 12.02.2012

Так же возможен и 4 вариант - просто оптимизировать код:

#include <OneWire.h>

OneWire ds (10);    // Пин где подвешен ds18b20

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

byte digits[4] = {255,255,255,255}; //


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


void loop()
{
  static uint32_t premillis = 0;
  if(!premillis)
  {
    ds.reset();
    ds.write(0xCC);
    ds.write(0x44);
    premillis = millis();
  }
  else if(millis()-premillis > 10000)
  {
    ds.reset();
    ds.write(0xCC);
    ds.write(0xBE); // Чтение Scratchpad
    byte data[9];
    for (byte i = 0; i < 9; i++) data[i] = ds.read();
    int raw = (data[1] << 8) | data[0];  //  Пересчитываем в температуру
    ledDigitDisplay((float)raw / 16.0);
    premillis = 0;
  }
  Indicate();
}



const byte table[11] = {
  B11000000, B11111001, B10100100, B10110000, B10011001,   // 0 1 2 3 4
  B10010010, B10000010, B11111000, B10000000, B10010000,   // 5 6 7 8 9
  B10111111};   // минус 

void ledDigitDisplay(float temperature)
{              
  int disp = temperature * 100;   // Избавляемся от десятых и сотых (оставляем челую часть числа)

  if(disp < -5500 || disp > 12500)
  {
    // Обработаем выход за пределы min и max температур
    for (int i = 0; i < 4; i++) 
      digits[4] = table[10]; // Ставим во всех разрядах прочерки
    return;
  }

  bool point = 0;
  if(disp < -999 || disp > 9999) disp /= 10;
  else point = 1;

  if(disp < 0) 
  {
    digits[3] = table[10];
    disp *= -1;
  }
  else digits[3] = table[disp/1000];

  for(byte i = 0; i < 3; i++)
  {
    digits[i] = table[disp%10];
    disp /= 10;
  }

  if(point) digits[2] &= B01111111; // точка
  else digits[1] &= B01111111; // точка
}



void Indicate() // Функция отображения цыфр на индикаторе.
{
  static uint32_t premillis = 0;
  if(millis()-premillis < 2) return;
  premillis = millis();
  static byte digit = 0;

  digitalWrite(latchPin, LOW);   
  shiftOut(dataPin, clockPin, MSBFIRST, digits[digit]);  // символ
  shiftOut(dataPin, clockPin, MSBFIRST, 1<<digit); // разряд
  digitalWrite(latchPin, HIGH);  //"защелкиваем" 

  digit++;
  if(digit == 4) digit = 0;
}

Если же все равно раз в 10 секунд будут мерцания, то возвращаемся к 3 варианту:

#include <OneWire.h>

OneWire ds (10);    // Пин где подвешен ds18b20

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

byte digits[4] = {255,255,255,255}; //


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


void loop()
{
  ds_run();
  Indicate();
}


void ds_run()
{
  static uint32_t premillis = 0, interval = 0;
  if(millis()-premillis < interval) return;
  premillis = millis();
  static byte state = 0;
  static byte data[9];

  switch(state)
  {
  case 1: // Сброс
    ds.reset(); 
    interval = 0;
    break;

  case 2: // Всем датчикам
    ds.write(0xCC); 
    break;

  case 3: // Конвертировать
    ds.write(0x44);
    interval = 750;
    break;

  case 4: // Сброс
    ds.reset();
    interval = 0;
    break;

  case 5: // Всем датчикам
    ds.write(0xCC);
    break;

  case 6: // Отдать значения
    ds.write(0xBE);
    break;

  case 7: // Читаем значения
    static byte i = 0;
    data[i] = ds.read();
    i++;
    if(i == 9) i = 0;
    else state--;
    break;

  case 8: // Расчет температуры
    int raw = (data[1] << 8) | data[0];
    ledDigitDisplay((float)raw / 16.0);
    interval = 30000;
    state = 0;
    break;
  }

  state++;
}



const byte table[11] = {
  B11000000, B11111001, B10100100, B10110000, B10011001,   // 0 1 2 3 4
  B10010010, B10000010, B11111000, B10000000, B10010000,   // 5 6 7 8 9
  B10111111};   // минус 

void ledDigitDisplay(float temperature)
{              
  int disp = temperature * 100;   // Избавляемся от десятых и сотых (оставляем челую часть числа)

  if(disp < -5500 || disp > 12500)
  {
    // Обработаем выход за пределы min и max температур
    for (int i = 0; i < 4; i++) 
      digits[4] = table[10]; // Ставим во всех разрядах прочерки
    return;
  }

  bool point = 0;
  if(disp < -999 || disp > 9999) disp /= 10;
  else point = 1;

  if(disp < 0) 
  {
    digits[3] = table[10];
    disp *= -1;
  }
  else digits[3] = table[disp/1000];

  for(byte i = 0; i < 3; i++)
  {
    digits[i] = table[disp%10];
    disp /= 10;
  }

  if(point) digits[2] &= B01111111; // точка
  else digits[1] &= B01111111; // точка
}



void Indicate() // Функция отображения цыфр на индикаторе.
{
  static uint32_t premillis = 0;
  if(millis()-premillis < 2) return;
  premillis = millis();
  static byte digit = 0;

  digitalWrite(latchPin, LOW);   
  shiftOut(dataPin, clockPin, MSBFIRST, digits[digit]);  // символ
  shiftOut(dataPin, clockPin, MSBFIRST, 1<<digit); // разряд
  digitalWrite(latchPin, HIGH);  //"защелкиваем" 

  digit++;
  if(digit == 4) digit = 0;
}

 

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

Nemo, Sirox, для начала прочтите это . Код который вам дал jeka_tm, уже убрал задержку на конвертацию и осталось только считывание данных. Разница между началом конвертации и считыванием, сделано с помощью millis(). Обнуление через 50 суток, приведет к одному пропуску считывания, дальше все пойдет по кругу.
Т.к. у maksim опыта намного больше моего, он вам предлагает более изящные, но и более сложные варианты. Чем воспользоватся в данном случае, решать вам. Мое предложение не убирает мерцание, а делает его более редким.

P/S к 97 посту это не относится.

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

maksim - Большое спасибо!

Попробовал оба кода. Оба работают без мерцания! Супер!

Не знаю, какой из них подойдет для моей затеи с несколькими датчиками, но для проекта с 1 датчиком и 1 индикатором - уже можно брать и работать.  Готовый, рабочий код. (проверял правда пока только в положительном диапазоне температур).

А несколько датчиков - пока не смогу попробовать, так как даттчики есть, а шилд-индикатор только один. Нужно решить, то ли заказать еще (маловат сам индикатор в размерах), то ли докупить микросхем 74hс595 и напаять своих (индикаторы есть побольше в размере, правда с общим анодом). Подумаю, просчитаю что выгоднее по деньгам, тогда решу... Ну это позже.

Остальсь только разобраться в самом коде.  А это посложнее будет... Можно я буду вопросы по коду задавать где непонятно?

Например:

1 )   - я правильно понял что размер задержки в первом коде (10 секунд) вы задаете единожды в строке номер 30, а во вторм коде - тоже единожды но уже 30 сек. в строке номер 75 ?

2)   - я правильно понял что как сказал выше bwn в обоих случаях мы не убираем мерцание, а делаем его более редким (раз в 10 и 30 секунд соответственно)?

bwn - спасибо за ссылку и совет. Обязательно вникну. Давно хотел разобраться с этой millis()

p/s/    Для кого критично: по ресурсоемкости первый код чуть более легче чем второй. Не на  много.

Sketch uses 3 030 bytes (9%) of program storage space. Maximum is 32 256 bytes.
Global variables use 50 bytes (2%) of dynamic memory, leaving 1 998 bytes for local variables. Maximum is 2 048 bytes.

Против

Sketch uses 3 092 bytes (9%) of program storage space. Maximum is 32 256 bytes.
Global variables use 65 bytes (3%) of dynamic memory, leaving 1 983 bytes for local variables. Maximum is 2 048 bytes.
 

 

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

Судя по тому, что у вас мерцание исчезло вовсе, дело было не в задержке от считывания с датчика, а в перерисовке дисплея. Соответственно код Жеки тоже рабочий, только надо было добавить интервал между измерениями. Во втором коде maksim-а вы упустили 48 строку, а она важная.
Погонять несколько датчиков можете и сейчас для тренировки - пожертвуйте знаком минус и выводите в этот разряд номер отображаемого датчика.
Также попробуйте понять, где грабли в первом коде maksim-а.