Seelenkind

wettervorhersage

Jan 10th, 2021
146
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.   Электронный предсказатель погоды по изменению давления
  3.   Измеряет давление каждые 10 минут, находит разницу с давлением час назад
  4.   При расчёте давления использовано среднее арифметическое из 10 измерений
  5.   для уменьшения шумности сигнала с датчика
  6.  
  7.   AlexGyver 2017
  8. */
  9.  
  10.  
  11. //-----------------------НАСТРОЙКИ---------------------
  12. #define servo_invert 1       // если серва крутится не в ту сторону, изменить значение (1 на 0, 0 на 1)
  13. #define battery_min 3000     // минимальный уровень заряда батареи для отображения
  14. #define battery_max 5200     // максимальный уровень заряда батареи для отображения
  15. // диапазон для 3 пальчиковых/мизинчиковых батареек: 3000 - 4700
  16. // диапазон для одной банки литиевого аккумулятора: 3000 - 4200
  17. //-----------------------НАСТРОЙКИ---------------------
  18.  
  19. #define servo_Vcc 12           // пин питания, куда подключен мосфет
  20.  
  21. //------ИНВЕРСИЯ------
  22. #if servo_invert == 1
  23. #define servo_180 0
  24. #define servo_0 180
  25. #else
  26. #define servo_0 0
  27. #define servo_180 180
  28. #endif
  29. //------ИНВЕРСИЯ------
  30.  
  31. //------БИБЛИОТЕКИ------
  32. #include <Servo.h>             // библиотека серво
  33. #include <Wire.h>              // вспомогательная библиотека датчика
  34. #include <Adafruit_BMP085.h>   // библиотека датчика
  35. #include <LowPower.h>          // библиотека сна
  36. //------ИНВЕРСИЯ------
  37.  
  38. boolean wake_flag, move_arrow;
  39. int sleep_count, angle, delta, last_angle = 90;
  40. float k = 0.8;
  41. float my_vcc_const = 1.080;    // константа вольтметра
  42. unsigned long pressure, aver_pressure, pressure_array[6], time_array[6];
  43. unsigned long sumX, sumY, sumX2, sumXY;
  44. float a, b;
  45.  
  46. Servo servo;
  47. Adafruit_BMP085 bmp; //объявить датчик с именем bmp
  48.  
  49. void setup() {
  50.   Serial.begin(9600);
  51.   pinMode(servo_Vcc, OUTPUT);
  52.   pinMode(A3, OUTPUT);
  53.   pinMode(A2, OUTPUT);
  54.   digitalWrite(servo_Vcc, 1);      // подать питание на серво
  55.   digitalWrite(A3, 1);             // подать питание на датчик
  56.   digitalWrite(A2, 0);
  57.   delay(500);
  58.   bmp.begin(BMP085_ULTRAHIGHRES);  // включить датчик
  59.   servo.attach(2);                 // подключить серво
  60.   servo.write(servo_0);            // увести серво в крайнее левое положение
  61.   delay(1000);
  62.   int voltage = readVcc();         // считать напряжение питания
  63.  
  64.   // перевести его в диапазон поворота вала сервомашинки
  65.   voltage = map(voltage, battery_min, battery_max, servo_0, servo_180);
  66.   voltage = constrain(voltage, 0, 180);
  67.   servo.write(voltage);            // повернуть серво на угол заряда
  68.   delay(3000);
  69.   servo.write(90);                 // поставить серво в центр
  70.   delay(2000);
  71.   digitalWrite(servo_Vcc, 0);      // отключить серво
  72.   pressure = aver_sens();          // найти текущее давление по среднему арифметическому
  73.   for (byte i = 0; i < 6; i++) {   // счётчик от 0 до 5
  74.     pressure_array[i] = pressure;  // забить весь массив текущим давлением
  75.     time_array[i] = i;             // забить массив времени числами 0 - 5
  76.   }
  77. }
  78.  
  79. void loop() {
  80.   if (wake_flag) {
  81.     delay(500);
  82.     pressure = aver_sens();                          // найти текущее давление по среднему арифметическому
  83.     for (byte i = 0; i < 5; i++) {                   // счётчик от 0 до 5 (да, до 5. Так как 4 меньше 5)
  84.       pressure_array[i] = pressure_array[i + 1];     // сдвинуть массив давлений КРОМЕ ПОСЛЕДНЕЙ ЯЧЕЙКИ на шаг назад
  85.     }
  86.     pressure_array[5] = pressure;                    // последний элемент массива теперь - новое давление
  87.  
  88.     sumX = 0;
  89.     sumY = 0;
  90.     sumX2 = 0;
  91.     sumXY = 0;
  92.     for (int i = 0; i < 6; i++) {                    // для всех элементов массива
  93.       sumX += time_array[i];
  94.       sumY += (long)pressure_array[i];
  95.       sumX2 += time_array[i] * time_array[i];
  96.       sumXY += (long)time_array[i] * pressure_array[i];
  97.     }
  98.     a = 0;
  99.     a = (long)6 * sumXY;             // расчёт коэффициента наклона приямой
  100.     a = a - (long)sumX * sumY;
  101.     a = (float)a / (6 * sumX2 - sumX * sumX);
  102.     // Вопрос: зачем столько раз пересчитывать всё отдельными формулами? Почему нельзя считать одной большой?
  103.     // Ответ: а затем, что ардуинка не хочет считать такие большие числа сразу, и обязательно где-то наё*бывается,
  104.     // выдавая огромное число, от которого всё идёт по пи*зде. Почему с матами? потому что устал отлаживать >:O
  105.     delta = a * 6;                   // расчёт изменения давления
  106.  
  107.     angle = map(delta, -250, 250, servo_0, servo_180);  // пересчитать в угол поворота сервы
  108.     angle = constrain(angle, 0, 180);                   // ограничить диапазон
  109.  
  110.     // дальше такая фишка: если угол несильно изменился с прошлого раза, то нет смысла лишний раз включать серву
  111.     // и тратить энергию/жужжать. Так что находим разницу, и если изменение существенное - то поворачиваем стрелку    
  112.     if (abs(angle - last_angle) > 7) move_arrow = 1;
  113.  
  114.     if (move_arrow) {
  115.       last_angle = angle;
  116.       digitalWrite(servo_Vcc, 1);      // подать питание на серво
  117.       delay(300);                      // задержка для стабильности
  118.       servo.write(angle);              // повернуть серво
  119.       delay(1000);                     // даём время на поворот
  120.       digitalWrite(servo_Vcc, 0);      // отключить серво
  121.       move_arrow = 0;
  122.     }
  123.  
  124.     if (readVcc() < battery_min) LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); // вечный сон если акум сел
  125.     wake_flag = 0;
  126.     delay(10);                       // задержка для стабильности
  127.   }
  128.  
  129.   LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);      // спать 8 сек. mode POWER_OFF, АЦП выкл
  130.   sleep_count++;            // +1 к счетчику просыпаний
  131.   if (sleep_count >= 70) {  // если время сна превысило 10 минут (75 раз по 8 секунд - подгон = 70)
  132.     wake_flag = 1;          // рарешить выполнение расчета
  133.     sleep_count = 0;        // обнулить счетчик
  134.     delay(2);               // задержка для стабильности
  135.   }
  136. }
  137.  
  138. // среднее арифметичсекое от давления
  139. long aver_sens() {
  140.   pressure = 0;
  141.   for (byte i = 0; i < 10; i++) {
  142.     pressure += bmp.readPressure();
  143.   }
  144.   aver_pressure = pressure / 10;
  145.   return aver_pressure;
  146. }
  147.  
  148. long readVcc() { //функция чтения внутреннего опорного напряжения, универсальная (для всех ардуин)
  149. #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  150.   ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  151. #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
  152.   ADMUX = _BV(MUX5) | _BV(MUX0);
  153. #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
  154.   ADMUX = _BV(MUX3) | _BV(MUX2);
  155. #else
  156.   ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  157. #endif
  158.   delay(2); // Wait for Vref to settle
  159.   ADCSRA |= _BV(ADSC); // Start conversion
  160.   while (bit_is_set(ADCSRA, ADSC)); // measuring
  161.   uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
  162.   uint8_t high = ADCH; // unlocks both
  163.   long result = (high << 8) | low;
  164.  
  165.   result = my_vcc_const * 1023 * 1000 / result; // расчёт реального VCC
  166.   return result; // возвращает VCC
  167. }
Add Comment
Please, Sign In to add comment