мерцает (скачет) значение температуры на семисегментном индикаторе

fanps
Offline
Зарегистрирован: 22.04.2016

Пытаюсь сдетать термометр на ардуино-нано, DS18B20, и четырехразрядном семисегментном индикаторе.

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

Если добавить в код вывод в последовательный порт, то в нем (в порту) все отображается корректно. 

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

/*   - Pin d1 to digital pin  15
 *   - Pin d2 to digital pin  14
 *   - Pin d3 to digital pin  3
 *   - Pin d4 to digital pin  4
 *   - Pin a  to digital pin 11
 *   - Pin b  to digital pin 13
 *   - Pin c  to digital pin  8
 *   - Pin d  to digital pin  6
 *   - Pin e  to digital pin  5
 *   - Pin f  to digital pin 12
 *   - Pin g  to digital pin  7
 *   - Pin dp to digital pin  9
 */


#include <OneWire.h>
#include <SevenSegmentDisplay.h>

SevenSegmentDisplay<false, QuadriDigit<15, 14, 3, 4> > ss(11, 13, 8, 6, 5, 12, 7, 9);

int nc;
OneWire  ds(10);  // датчик
byte addr[8];
byte i;
byte present = 0;
byte data[12];
int Temp10;
int znak10;
int Temp;
 
void setup()
{
   ds.search(addr);
   pinMode(3,OUTPUT);      //7сегмент дисплей
   pinMode(4,OUTPUT);      //7сегмент дисплей
   pinMode(5,OUTPUT);      //7сегмент дисплей
   pinMode(6,OUTPUT);      //7сегмент дисплей
   pinMode(7,OUTPUT);      //7сегмент дисплей
   pinMode(8,OUTPUT);      //7сегмент дисплей
   pinMode(9,OUTPUT);      //7сегмент дисплей
   pinMode (14, OUTPUT);   //7сегмент дисплей
   pinMode (15, OUTPUT);   //7сегмент дисплей  
}
 
void loop()
{                  
 {
    ds.reset();                //включаем датчик
    ds.select(addr);
    ds.write(0x44,1);
    delay (1000);              //ждем
    present = ds.reset();      //опрашиваем датчик
    ds.select(addr);
    ds.write(0xBE);      
  
    for ( i = 0; i < 9; i++) 
      {
      data[i] = ds.read();
      }
    Temp10=(data[1]<<8)+data[0];
    Temp10=Temp10;
    znak10=((Temp10%16)*100)/16;    //вычисляем температуру
    if (znak10<0)
      {
      znak10=znak10*-1;
      }   
  }   
unsigned z = Temp10/16;  
ss.print(z);                        //выводим температуру на 7сегмент
}

 

Штирлиц
Штирлиц аватар
Offline
Зарегистрирован: 13.06.2015

Строка 51 -delay(1000). Используйте миллис для опроса датчика температуры.

fanps
Offline
Зарегистрирован: 22.04.2016

Пробовал. Без изменений.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А если строки 48-68 закомментировать и на экране показывать просто число 321 (строку 69 заменить на  ss.print(321); ) - работает? Сдаётся мне, что проблема не в замере, а в показе.

axill
Offline
Зарегистрирован: 05.09.2011

SevenSegmentDisplay на таймере работает?

fanps
Offline
Зарегистрирован: 22.04.2016

Штирлиц пишет:

Строка 51 -delay(1000). Используйте миллис для опроса датчика температуры.

переписал. Стало лучше. Но теперь обратная ситуация. Нормально показывает температуру, но раз в секунду моргает всеми сегментами.

/*   - Pin d1 to digital pin  15
 *   - Pin d2 to digital pin  14
 *   - Pin d3 to digital pin  3
 *   - Pin d4 to digital pin  4
 *   - Pin a  to digital pin 11
 *   - Pin b  to digital pin 13
 *   - Pin c  to digital pin  8
 *   - Pin d  to digital pin  6
 *   - Pin e  to digital pin  5
 *   - Pin f  to digital pin 12
 *   - Pin g  to digital pin  7
 *   - Pin dp to digital pin  9
 */


#include <OneWire.h>
#include <SevenSegmentDisplay.h>

SevenSegmentDisplay<false, QuadriDigit<15, 14, 3, 4> > ss(11, 13, 8, 6, 5, 12, 7, 9);

int nc;
OneWire  ds(10);  // датчик
byte addr[8];
byte i;
byte present = 0;
byte data[12];
int Temp10;
int znak10;
int Temp;
int flagT1=0;
unsigned long currentTime=0;
unsigned long tTime=0;
 
void setup()
{
   ds.search(addr);
   pinMode(3,OUTPUT);      //7сегмент дисплей
   pinMode(4,OUTPUT);      //7сегмент дисплей
   pinMode(5,OUTPUT);      //7сегмент дисплей
   pinMode(6,OUTPUT);      //7сегмент дисплей
   pinMode(7,OUTPUT);      //7сегмент дисплей
   pinMode(8,OUTPUT);      //7сегмент дисплей
   pinMode(9,OUTPUT);      //7сегмент дисплей
   pinMode (14, OUTPUT);   //7сегмент дисплей
   pinMode (15, OUTPUT);   //7сегмент дисплей  
}
 
void loop()
{
  currentTime = millis();  //запускаем счетчик                  
 {
  if(flagT1==0)
    {
    ds.reset();                //включаем датчик
    ds.select(addr);
    ds.write(0x44,1);
    flagT1=1;
    } 
     if((flagT1==1)&&(currentTime>=(tTime+1000)))    //ждем
    {   
    present = ds.reset();      //опрашиваем датчик
    ds.select(addr);
    ds.write(0xBE);      
  
    for ( i = 0; i < 9; i++) 
      {
      data[i] = ds.read();
      }
    Temp10=(data[1]<<8)+data[0];
    Temp10=Temp10;
    znak10=((Temp10%16)*100)/16;    //вычисляем температуру
    if (znak10<0)
      {
      znak10=znak10*-1;
      }   
      flagT1=0;
    tTime=currentTime;
    }
  }   
unsigned z = Temp10/16;  
ss.print(z);                        //выводим температуру на 7сегмент
}

 

axill
Offline
Зарегистрирован: 05.09.2011

если ss.print поставить один раз в setup, а строку 81 закоментировать дисплей что будет показывать?

fanps
Offline
Зарегистрирован: 22.04.2016

ЕвгенийП пишет:

А если строки 48-68 закомментировать и на экране показывать просто число 321 (строку 69 заменить на  ss.print(321); ) - работает? Сдаётся мне, что проблема не в замере, а в показе.

тоже метцает. 

С другой стороны, если меняю датчик температуры на переменный резистор, то все отлично работает и не мерцает.

Похоже на конфликт с датчиком.

fanps
Offline
Зарегистрирован: 22.04.2016

axill пишет:

если ss.print поставить один раз в setup, а строку 81 закоментировать дисплей что будет показывать?

поставил ss.print   в    setup, а строку 81 закоментировал "1234"

результат - компилятор выдал ошибку "exit status 1       'z' was not declared in this scope"

поставил ss.print и строку 81   в    setup,  строку 81 (уже в setup) закоментировал "1234"

результат - на дисплее один раз моргнуло "1234", и сразу "234" погасло, а осталось только "1"

fanps
Offline
Зарегистрирован: 22.04.2016

axill пишет:

SevenSegmentDisplay на таймере работает?

если залить пример из библиотеки SevenSegmentDisplay , то отлично отсчитывает цифры

/*!
 * \file QuadriDigit.ino
 * \brief demo for four 7-segement displays with common cathode.
 * \author Like Ma <likemartinma@gmail.com>
 * 
 * This sketch counts down from 9999 to 0, while each value keeps displaying for 0,05 seconds.

 * The circuit:
 *   - Pin d1 to digital pin 15
 *   - Pin d2 to digital pin 14
 *   - Pin d3 to digital pin  3
 *   - Pin d4 to digital pin  4
 *   - Pin a  to digital pin 11
 *   - Pin b  to digital pin 13
 *   - Pin c  to digital pin  8
 *   - Pin d  to digital pin  6
 *   - Pin e  to digital pin  5
 *   - Pin f  to digital pin 12
 *   - Pin g  to digital pin  7
 *   - Pin dp to digital pin  9
 */

#include <SevenSegmentDisplay.h>

SevenSegmentDisplay<false, QuadriDigit<15, 14, 3, 4> > ss(11, 13, 8, 6, 5, 12, 7, 9);

void setup() {
}

void loop() {
	unsigned i = 9999;
	do {
		ss.print(i, -1, 50);
	} while (i--);
}

 

axill
Offline
Зарегистрирован: 05.09.2011

я к чему спрашиваю

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

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

пока не ясно. то есть у вас после того, что я попросил отображается только первая цифра, так?

fanps
Offline
Зарегистрирован: 22.04.2016

Да. Сначала вспыхивают все цифры, и сразу три гаснут. Остается гореть только первая.

axill
Offline
Зарегистрирован: 05.09.2011

У вас сканирование как устроено? Что за дисплей?

fanps
Offline
Зарегистрирован: 22.04.2016

Про сканирование не понял. Что это?
Дисплей примерно такой http://files.freks.webnode.com/200001866-60ade62a27/7segm_ind.jpg

axill
Offline
Зарегистрирован: 05.09.2011

динамическая индикация http://we.easyelectronics.ru/Shematech/dinamicheskaya-indikaciya_2.html

как дисплей подключен?

fanps
Offline
Зарегистрирован: 22.04.2016

Подключен напрямую к ардуино (через резисторы) без драйверов.
Индикация динамическая, поразрядная.
В скетче, в начале, все пины описаны.

fanps
Offline
Зарегистрирован: 22.04.2016

использована эта библиотека

/*!
 * \file SevenSegmentDisplay.h
 * \brief Arduino 7-Segment Display
 * \author Like Ma <likemartinma@gmail.com>
 */

#ifndef SEVENSEGMENTDISPLAY_H
#define SEVENSEGMENTDISPLAY_H

#if defined(ARDUINO) && ARDUINO >= 100
#	include "Arduino.h"
#else
#	include "WProgram.h"
#endif

template <byte D1>
struct UniDigit {
	enum { N = 1 };
	static byte pin[N];
};

template <byte D1, byte D2>
struct BiDigit {
	enum { N = 2 };
	static byte pin[N];
};

template <byte D1, byte D2, byte D3>
struct TriDigit {
	enum { N = 3 };
	static byte pin[N];
};

template <byte D1, byte D2, byte D3, byte D4>
struct QuadriDigit {
	enum { N = 4 };
	static byte pin[N];
};

template <boolean ANODE, typename DIGITS, unsigned DELAY = 20>
class SevenSegmentDisplay {
public:
	/*!
	 * \brief Initialize 7-segment display.
	 *
	 * See the following ascii diagram for parameters:
	 *
	 *      a
	 *    _____
	 *   |     | 
	 * f |  g  | b
	 *   |_____|
	 *   |     |
	 * e |     | c 
	 *   |_____|    . dp
	 * 
	 *      d
	 */
	SevenSegmentDisplay(byte a, byte b, byte c, byte d, byte e, byte f, byte g, byte dp);

	/*!
	 * \brief Display fixed point number.
	 * \param n The number to display.
	 * \param pt The position of the point ranged from 0 to DIGITS::N - 1, while 0 denotes the lowest digit.
	 * \param duration The duration for displaying.
	 */
	void print(unsigned n, byte pt = -1, unsigned long duration = 0);

	/*!
	 * \brief Display float point number.
	 * \param n The number to display.
	 * \param duration The duration for displaying.
	 */
	void print(float n, unsigned long duration = 0);

	/*!
	 * \brief light off all segments.
	 */
	void clear ();
protected:
	void pickDigit(byte i);
	void printDigit(byte n, bool dp = false);
	void printUnsigned(unsigned n, byte dp);
	void printFloat(float n);

	enum { 
		MAX_SEGMENTS = 8,
		DP_IDX = MAX_SEGMENTS - 1
	};

	byte pin_[MAX_SEGMENTS];
	byte digit_[10];
};

#include "SevenSegmentDisplay.inl"

#endif /* SEVENSEGMENTDISPLAY_H */

 

fanps
Offline
Зарегистрирован: 22.04.2016

сделал индикацию без библиотек, с выводом в порты В и D. 

показывает нормально, но раз в секунду моргает.

как убрать это моргание?

#include <OneWire.h>

int nc;
OneWire  ds(14);  // датчик
byte addr[8];
byte i;
byte present = 0;
byte data[12];
int Temp14;
int znak14;
int Temp;
int flagT1=0;
unsigned long currentTime=0;
unsigned long tTime=0;

int x;
int tys;
int sot;
int des;
int ed;
byte t=0, s=0, e=0, d=0, a=0; //объявляем переменные единиц, десятков, сотен, тысяч переменную мерцания
byte cif[10]={252,96,218,242,102,182,190,224,254,246}; // массив цифр

 
void setup()
{
   DDRD=255; // пины порта D и B обозначаем выходными
   DDRB=63;
  
   ds.search(addr);
   
   pinMode (14, INPUT);   //7сегмент дисплей
   
}
 
void loop()
{
  currentTime = millis();  //запускаем счетчик                  
 {
  if(flagT1==0)
    {
    ds.reset();                //включаем датчик
    ds.select(addr);
    ds.write(0x44,1);
    flagT1=1;
    } 
     if((flagT1==1)&&(currentTime>=(tTime+1000)))    //ждем
    {   
    present = ds.reset();      //опрашиваем датчик
    ds.select(addr);
    ds.write(0xBE);      
  
    for ( i = 0; i < 9; i++) 
      {
      data[i] = ds.read();
      }
    Temp14=(data[1]<<8)+data[0];
    Temp14=Temp14;
    znak14=((Temp14%16)*100)/16;    //вычисляем температуру
    if (znak14<0)
      {
      znak14=znak14*-1;
      }   
      flagT1=0;
    tTime=currentTime;
    }
  }   
x=Temp14/16;
  tys=x/1000;
  sot=(x-tys*1000)/100;
  des=(x-tys*1000-sot*100)/10;
  ed=(x-tys*1000-sot*100-des*10);

  PORTB=62; // активируем разряд тысяч
PORTD=cif[tys]; // пишем нужную цифру тысяч в порт D
delay(6); // пауза, чтобы сегменты "разгорелись"
PORTB=61;// активируем разряд сотен
PORTD=cif[sot]; // пишем нужную цифру сотен в порт D
delay(6);// пауза, чтобы сегменты "разгорелись"
PORTB=59;// пишем нужную цифру десятков в порт D
PORTD=cif[des]; // пишем нужную цифру десятка в порт D
delay(6);// пауза, чтобы сегменты "разгорелись"
PORTB=55;// пишем нужную цифру единиц в порт D
PORTD=cif[ed]; // пишем нужную цифру единиц в порт D
delay(6);// пауза, чтобы сегменты "разгорелись"


}

 

axill
Offline
Зарегистрирован: 05.09.2011

Обновление цифр необходимо делать в прерывании

посмотрите библиотеку mstimer2

 У вас вывод как организован? За один проход одна цифра или за один проход один сегмент сразу на всех цифрах?

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

fanps пишет:
как убрать это моргание?
Посредством правильной работы с датчиком. Время 12-битного преобразования 0.75 сек. Поэтому динамическая индикация замирает на это время. Надо один раз запускать преобразование и один раз считывать. У тебя в основном цикле, подается команда 0х44 - запуск преобразования, взводится flagT1 и закрывает вход в этот блок, а сброс флага внутри этого блока - бред какой-то. Раз в секунду вроде бы должно происходить считывание - очевидно, что чтение будет ждать завершения преобразования. Разумнее раз в секунду сначала считать значение предыдущего измерения и сразу же запустить очередное преобразование, чем запускать преобразование ждать 0.75 сек, затем считывать.

В строке 47 у тебя заложены "грабли", надо делать так: (currentTime-tTime>=1000)