#1 2020-11-24 11:26:16

runaway
Учасник
Зареєстрований: 2020-11-24
Повідомлень: 4

Барограф / барометр / термометр / bmp180 / nokia 5110 / 3V3 / pro mini

Здравствуйте, уважаемые участники. Ниже - немножко подпиленный код из одноимённого топика на форуме ардуино.ру, адаптированный под свои нужды.

Всё работает, кроме одного - не засыпает (с потреблением единиц микроампер) по достижении заданного в скетче минимального напряжения на литиевом аккумуляторе 14500. Ток потребления остаётся в районе нескольких сот микроампер, причём до "полного не могу", уже с потухшим дисплеем, проваливая напругу на аккумуляторе глубоко ниже 2 В...

Пробовал разбираться с библиотекой LowPower. Пытался, "по образцу и подобию", вставлять строчки из скетча гайверовского "Предсказателя погоды" (там тоже используется эта же библиотека), но что-то ничего не выходит... Всё компилируется без замечаний, но устройство продолжает потреблять значительный ток при напряжении питания ниже заданного порога, с уже погасшим экраном. Ниже привожу рабочий исходник, без моих правок, в котором работает всё, кроме вечного сна. Может кому-то покажется интересным для повторения. Буду благодарен за любую помощь.

#include <LCD5110_Graph.h>    //  rinkydinkelectronics.com/library.php
#include <Wire.h>
#include <Adafruit_BMP085.h>  //  github.com/adafruit/Adafruit-BMP085-Library
#include <LowPower.h>         //  github.com/rocketscream/Low-Power

Adafruit_BMP085 dps;

// ********** Опции компиляции **************
//#define SeaLevel            // раскоментировать для коррекции на высоту
//#define debug               // для тестирования графиков (ан.вход a1 как задатчик давления)
#define cont 67             // для изменения раскоментировать эту строку (70 по умолчанию)
#define zapolnen            // Заполнение графика 1
//#define gasim_lcd           // если экономим батарейки гашением LCD


long P_win = 165 * 133.3;    // Верхняя граница абс. графика по умолчанию до сдвига (600 + 165) = 765мм

#if defined (SeaLevel)  // если не включена коррекция, экономим память
float Alt_corr = 32.4;  // Коррекция высоты в метрах.
#endif

uint32_t Pressure; 
float temp;
unsigned char sotki ;    // сотые для давления
unsigned char p_count, p2;
long P_Min, P_Max, P_Dt, P_Mid; 
uint16_t P_Mem[217]; //-79980 = 600мм (3 day 20min memory, 72 per 24 hour) 
signed char x, y, last_x, last_y;
// nokia 5110 connect
// pin d3 - Serial clock out (SCLK)
// pin d4 - Serial data out (DIN)
// pin d5 - Data/Command select (D/C)
// pin d6 - LCD reset (RST)
// pin d7 - LCD chip select (CS)

LCD5110 myGLCD(3, 4, 5, 6, 7);


// bmp180 connect
// sda  - a4
// scl  - a5

// Use pin 2 as wake up pin
const char wakeUpPin = 2; // d2 для кнопки
const char lightPin1 = 12; // d11 подсветка дисплея
const char lightPin2 = 11; // d12 инверсная подсветка дисплея
const char batPin = 0;    // a0 - ан. вход для контроля батареи 220к/51к

volatile char scr_num = 0;          // Номер экрана для отображения
volatile boolean key_pressed = false; // Признак что кнопку жали
volatile boolean in_int = false;      // Признак нахождения в прерывании
volatile boolean Refresh = true;      // Признак что нужно обновить отрисовку (для экономии батарей)
volatile boolean Lcd_On = true;      // Признак что дисплей включен
volatile char light_on = 1;         // длительность подсветки при включении 4*4 = 16с. 

extern unsigned char BigNumbers[];
extern unsigned char MediumNumbers[];
extern unsigned char SmallFont[];  
extern unsigned char TinyFont[];  // внешние шрифты  
unsigned char tik = 0;           // счетчики для времени
unsigned char Count_Minute = 0; 
uint32_t Son_count    = 0;

//******************************** START ***************************************
void setup() {
  
  
  myGLCD.InitLCD();
#if defined (cont)
  myGLCD.setContrast(cont); //регулировка контраста при необходимости
#endif
  myGLCD.setFont(SmallFont);
  Wire.begin();
  
  analogReference(INTERNAL); //1.1v internal op.source
  pinMode(batPin,INPUT);     //Вход для контроля батареи
  
#if defined (debug) 
  pinMode(1,INPUT);  // а1 - задание давления
  analogRead(1);
#endif  
    
  LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF);

  //dps.begin(BMP085_ULTRALOWPOWER);
  dps.begin(BMP085_STANDARD);
  //dps.begin(BMP085_HIGHRES);
  //dps.begin(BMP085_ULTRAHIGHRES);
 

  pinMode(wakeUpPin, INPUT);  // Configure wake up pin as input.  
  digitalWrite(wakeUpPin, 1); // pullup
  
  pinMode(lightPin1, OUTPUT);// lcd light pin as output;
  pinMode(lightPin2, OUTPUT);// lcd light inv pin as output;

  
#if defined (SeaLevel)
  Pressure = dps.readSealevelPressure(Alt_corr); // с коррекцией на уровень моря
#else
  Pressure = dps.readPressure();                 // без коррекции к уровню моря
    #endif

  P_Mid = Pressure - 79980; // (79980 = 600mm) отсекаем лишнее
  P_Mem[p_count] = P_Mid; // заносим в память первое значение давления для правильной работы усреднения

//  Serial.begin(9600);
//  while (!Serial) ; // wait for Arduino Serial Monitor
//  delay(200); 
}



void loop() {          // *********************************************************
  // Allow wake up pin to trigger interrupt on low.
#if defined (debug)
#else
if ((Son_count < 5)||((!(Son_count % 5))&&(tik==0))) {    // через 5 минут активности, не заходим в тело по 5 минут
#endif

//  Serial.print("S=");Serial.print(Son_count);Serial.print(" %=");Serial.println(Son_count % 5);
detachInterrupt(0); // запрет прерываний
#if defined (SeaLevel)
  Pressure = dps.readSealevelPressure(Alt_corr); // с коррекцией на уровень моря
#else
  Pressure = dps.readPressure()+0; // без коррекции к уровню моря; "-73" = коррекция данных давления (подставить нужный знак и число Па)
  #endif
  temp = dps.readTemperature()-0; // "-0.5" = коррекция данных температуры (подставить нужный знак и число градусов Цельсия)
attachInterrupt(0, wakeUp, LOW); // восстановить прерывания от кнопки

#if defined (debug) 
  Pressure = map(analogRead(1),0,1023,730*133.3,790*133.3);  // для отладки резистор на а1 - задатчик давления
#endif    
 // для экранов с инверсным подсветом использовать lightPin2
  if  (light_on > 0) {
    digitalWrite(lightPin1, 1);digitalWrite(lightPin2, 0);
    light_on--;
  }
  else {digitalWrite(lightPin1, 0);digitalWrite(lightPin2, 1);} // lcd light on/off
  
 


  if (Pressure > 79900){  // 600mm
    P_Mid = (P_Mid + (Pressure - 79980))/2; // усреднение замеров, отбрасываем показания ниже 600мм.(сбоит бывает)
  }
#if defined (debug)
    if (Count_Minute >= 2){ Refresh = true;  // раз в секунду
#else
    if (Count_Minute >= 20){ Refresh = true; // каждые 20 мин. запоминаем усредненное значение в память и обновляем графики
#endif 

 
    if (p_count == 216) {
      for (int i = 0; i < 216; i++) // сдвигаем если буфер полон
      {
        P_Mem[i] = P_Mem[i+1];
      }
    } 
    else {
      p_count++;
    }
    P_Mem[p_count] = P_Mid; 
    if (Pressure > 79980){
      P_Mid = Pressure - 79980; // новый старт усреднения
    }
    Count_Minute = 0;
  }


#if defined (gasim_lcd)
    if ((Son_count < 3)&&(!Lcd_On)) {myGLCD.disableSleep(); Lcd_On = true;}   // Если разрешено, гасим дисплей через 15 мин.
    if ((Son_count >= 3)&&(Lcd_On)) {myGLCD.enableSleep(); Lcd_On = false;}
#endif
//  Отображение экранов
if (Lcd_On) {switch (scr_num)



  {
  case 0:  // summary screen
    Refresh = true;          // Обновить отрисовку каждый цикл
 
    myGLCD.clrScr(); // Очистка экрана
    myGLCD.setFont(BigNumbers);

    //Давление с BMP180
    myGLCD.printNumI((Pressure / 133.3), 15, 5, 3); //расчет атмосферного давления; 
    myGLCD.setFont(SmallFont);
    myGLCD.print(".", 57, 22);
    sotki = ((Pressure / 133.3)-int(Pressure / 133.3))*100;
    myGLCD.printNumI((sotki / 10), 63, 22, 1);// десятые; 
    myGLCD.printNumI((sotki % 10), 69, 22, 1);// сотые
    myGLCD.print("Hg", 63, 6);
    myGLCD.print("C", 29, 35);
    myGLCD.printNumF(temp, 1, LEFT, 35);  //температура
    myGLCD.print("V", RIGHT, 35);    
    myGLCD.printNumF(analogRead(batPin)/176.5, 2, 53, 35);  //напряжение питания (коэффициент xxx.x подбирается, точка и десятые обязательны)
                                                            //одна единица коэффициента (ххХ.х) =~ 0,02 В; (чем коэффициент >, тем напряжение <)
    myGLCD.setFont(TinyFont);
    myGLCD.print("o", 26, 33);
    break;



  case 1:  // давление в кПа    *****************************************************
      Refresh = true;          // Обновить отрисовку каждый цикл
 
    myGLCD.clrScr(); // Очистка экрана
    myGLCD.setFont(MediumNumbers);

    //Давление с BMP180
    myGLCD.printNumI(Pressure, CENTER, 1); //расчет атмосферного давления; 
    myGLCD.setFont(SmallFont);
    //myGLCD.print(".", 57, 22);
   // sotki = ((Pressure/1) - int (Pressure/1))*100;
    //myGLCD.printNumI((sotki / 10), 63, 22, 1);// десятые; 
   // myGLCD.printNumI((sotki % 10), 69, 22, 1);// сотые
    myGLCD.print("Pa", CENTER, 22);
    myGLCD.print("C", 29, 35);
    myGLCD.printNumF(temp, 1, LEFT, 35);  //температура
    myGLCD.print("V", RIGHT, 35);    
    myGLCD.printNumF(analogRead(batPin)/176.5, 2, 53, 35);  //напряжение питания (коэффициент xxx.x подбирается, точка и десятые обязательны)
                                                            //одна единица коэффициента (ххХ.х) =~ 0,02 В; (чем коэффициент >, тем напряжение <)
    myGLCD.setFont(TinyFont);
    myGLCD.print("o", 26, 33);
    break;



  case 2:  // график давления за сутки с масштабированием
    if (Refresh){    // Рисуем если разрешено обновить
    
    P_Min = P_Mem[p_count]; 
    P_Max = P_Min; // сбросить значения
    if (p_count < 72) {
      p2 = 0;
    } 
    else {
      p2 = p_count - 72;
    }

    for (int i=p_count; i>p2 ; i--) { 
      if (P_Min > P_Mem[i]) {
        P_Min = P_Mem[i];
      } 
      if (P_Max < P_Mem[i]) {
        P_Max = P_Mem[i];
      } 
    }
    P_Dt = P_Max - P_Min;      // макс. разница

    myGLCD.clrScr(); // Очистка экрана
    myGLCD.setFont(TinyFont); // Установка набора символов 
    x=77;
    if (P_Dt > 0){
      for (int i=p_count; i>p2 ; i--) {
        y = ((36 * (P_Max - P_Mem[i]))/P_Dt)+6;  
        if (x == 77) {
          myGLCD.setPixel(x, y);
        } 
        else {
          myGLCD.drawLine(last_x, last_y, x, y);
        }
        last_x = x; 
        last_y = y; 
        x--;
      }
    }

    myGLCD.print("Max:", LEFT, 0);
    myGLCD.printNumF((P_Max +79980)/ 133.3, 2, 20, 0);
    myGLCD.print("24 Hrs", RIGHT, 0);
    myGLCD.print("Min:", LEFT, 42); 
    myGLCD.printNumF((P_Min+79980) / 133.3, 2, 20, 42);
    }
    break;



  case 3:  // график давления за трое суток  
    if (Refresh){    // Рисуем если разрешено обновить
    P_Min = P_Mem[p_count]; 
    P_Max = P_Min; // сбросить значения
    for (int i=p_count; i>0 ; i = i - 3) { 
      if (P_Min > P_Mem[i]) {
        P_Min = P_Mem[i];
      } 
      if (P_Max < P_Mem[i]) {
        P_Max = P_Mem[i];
      } 
    }
    P_Dt = P_Max - P_Min;      // макс. разница

    myGLCD.clrScr(); // Очистка экрана
    myGLCD.setFont(TinyFont); // Установка набора символов 

    x=77;
    if (P_Dt > 0){
      for (int i=p_count; i>0 ; i = i - 3) {
        y = ((36 * (P_Max - P_Mem[i]))/P_Dt)+6;  
        if (x == 77) {
          myGLCD.setPixel(x, y);
        } 
        else {
          myGLCD.drawLine(last_x, last_y, x, y);
        }

        last_x = x; 
        last_y = y; 
        x--;
      }
    }

    myGLCD.print("Max:", LEFT, 0);
    myGLCD.printNumF((P_Max +79980)/ 133.3, 2, 20, 0);
    myGLCD.print("72 Hrs", RIGHT, 0);
    myGLCD.print("Min:", LEFT, 42); 
    myGLCD.printNumF((P_Min+79980) / 133.3, 2, 20, 42);
    }
    break;   

  /*case 4: // напряжение аккумулятора для контроля
    Refresh = true;          // Обновить отрисовку каждый цикл
    myGLCD.clrScr(); // Очистка экрана
    myGLCD.setFont(SmallFont); // Установка набора символов
    myGLCD.print("Bat:", LEFT, 15);    
    myGLCD.printNumF(analogRead(batPin)/176.6, 2, 24, 15);  //напр.батареи (коэфф. подобрать при желании)
    break; */
  }



  if (Refresh) {myGLCD.update(); Refresh = false;} // Вывод вместимого буфера на дисплей и сброс признака обновления
} // if (Lcd_On)



#if defined (debug)
#else
    }  // скобка для условия сна в начале цикла в отладке не спим
#endif


  attachInterrupt(0, wakeUp, LOW); // Проснемся от кнопки


  //    Отключить питание на 4с
#if defined (debug)
     LowPower.powerDown(SLEEP_500MS, ADC_OFF, BOD_OFF); 
 #else    
     LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF); 
#endif   

   if (!key_pressed) {tik++;} else {key_pressed = false; Son_count = 0;} // в зачёт 4с. если не тыкали кнопку
   
#if defined (debug)
    if (tik >=1) {Count_Minute++; Son_count++; tik = 0;} // минута натикала
#else    
    if (tik >=15) {Count_Minute++; Son_count++; tik = 0;} // минута натикала
#endif   
} // Конец цикла


void wakeUp() // прерывание сна по нажатию кнопки
{             // Just a handler for the pin interrupt.
  if (!in_int){
  in_int = true;  
  detachInterrupt(0); 
  if (light_on > 0) {scr_num++;} // Первый тычок только подсвет
  light_on = 2;                  // после нажатия на кнопку подсветка 2*4 = 8с.
  Refresh = true;                // Обновить отрисовку
  key_pressed = true;            // кнопку жали
    if (scr_num > 3) {           // цифра = количество окон (case 1, case 2, case 3)
      scr_num = 0;
    }

    LowPower.powerDown(SLEEP_500MS, ADC_OFF, BOD_OFF); //задержка антидребезга      
    attachInterrupt(0, wakeUp, LOW); // восстановить прерывания от кнопки
    in_int = false;
} 
}

Остання редакція runaway (2020-11-24 12:32:39)

Неактивний

#2 2020-11-24 12:37:04

runaway
Учасник
Зареєстрований: 2020-11-24
Повідомлень: 4

Re: Барограф / барометр / термометр / bmp180 / nokia 5110 / 3V3 / pro mini

А вот строчки из проекта "Предсказатель погоды" Александра Гайвера, которые погружают устройство в вечный сон по достижении минимально допустимого напряжения на аккумуляторе:

if (analogRead(batPin) < battery_min) LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); // вечный сон если акум сел
wake_flag = 0;
delay(10);  

Пытался вставлять эту конструкцию, объявив соотв. переменные, в разные места исходника. Но в итоге неизменно получаю пустой экран с постоянно включенной подсветкой... Караул!

Остання редакція runaway (2020-11-24 13:01:54)

Неактивний

#3 2020-11-24 13:08:28

runaway
Учасник
Зареєстрований: 2020-11-24
Повідомлень: 4

Re: Барограф / барометр / термометр / bmp180 / nokia 5110 / 3V3 / pro mini

Поменял знак "<" в
if (analogRead(batPin) < battery_min)
на ">", получилось
if (analogRead(batPin) > battery_min)
- появилось изображение на экране, подсветка работает адекватно... Вышеозначенный кусок сейчас вставлен в конец "Сетапа". Проверяю лабораторным БП, с плавной регулировкой напруги...

Неактивний

#4 2020-11-24 13:27:50

runaway
Учасник
Зареєстрований: 2020-11-24
Повідомлень: 4

Re: Барограф / барометр / термометр / bmp180 / nokia 5110 / 3V3 / pro mini

Зараза... ПРОСЫПАЕТСЯ ровно с трёх вольт! При плавном повышении. Как и прописано в дефайне:
#define battery_min 3000
А засыпать при плавном понижении не хочет. Плавное понижение напряжения приводит к плавному затуханию ЖКИ и "заморозке" выводимых цифр.
зы: Этот кусок вообще не работает. (( Изменяю "3000" на "2700", потом на "3500" - всё равнобедренно: просыпается примерно ровно на трёх вольтах...

Неактивний

#5 2020-11-24 17:12:37

vvr
Учасник
Зареєстрований: 2015-04-12
Повідомлень: 878

Re: Барограф / барометр / термометр / bmp180 / nokia 5110 / 3V3 / pro mini

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

Неактивний

#6 2020-11-25 22:46:16

Carabas212
Учасник
З Chojnów
Зареєстрований: 2020-04-23
Повідомлень: 38

Re: Барограф / барометр / термометр / bmp180 / nokia 5110 / 3V3 / pro mini

Либо плата защиты аккума либо тп4056 с защитой. Но будьте осторожны с тп4056 и платами защиты бывает брак нужно мерять потребление.

Неактивний

Швидке повідомлення

Введіть повідомлення і натисніть Надіслати

Підвал форуму