Бортовой компьютер для минитрактора

Тема в разделе "Arduino & Shields", создана пользователем Промах, 10 мар 2017.

  1. rkit

    rkit Гуру

    Начнем с того, что это не таймер, а часы.
    В вашем коде есть все то же, что я делал. Чтение времени библиотекой iarduino_rtc.
     
  2. rkit

    rkit Гуру

    Код (C++):

    #include <iarduino_RTC.h>
    iarduino_RTC time(RTC_DS1302,36,32,34);

    void printTime() {
      char* d = time.gettime("md");
      SerialOut.print("rkit\ta:timeDay\t");
      int out = time.minutes + time.Hours*60;
      if (out >= 1440) out = 0;
      SerialOut.print(out);
      SerialOut.print("\tend\n");

      SerialOut.print("rkit\ta:date\t");
      SerialOut.print(d);
      SerialOut.print("\tend\n");

      SerialOut.print("rkit\ta:year\t");
      SerialOut.print(time.year);
      SerialOut.print("\tend\n");

    }
    Ну вот, откопал
     
  3. Промах

    Промах Нерд

    Помогло однако , помогло сильно , теперь ещё и с эти
    C:\Users\promah\Documents\Arduino\sketch_mar13a\sketch_mar13a.ino: In function 'void printTime()':

    sketch_mar13a:6: error: 'SerialOut' was not declared in this scope

    SerialOut.print("rkit\ta:timeDay\t");

    ^

    exit status 1
    'SerialOut' was not declared in this scope
    неделю разбираться буду
     
  4. rkit

    rkit Гуру

    А зачем вам компилировать отрывок кода?
     
  5. Промах

    Промах Нерд

    Я ж не в курсе , и писать не умею, можно сказать только азбуку купил, а не институт окончил, я ж Русский , умею грабить и обмениваться награбленным , потому и грю - надо действующая модель, 100% провереная, надо убедится что мой модуль RTC исправлен.
     
  6. rkit

    rkit Гуру

    Откуда у кого-то возьмется код для проверки исправности модулей? Код у людей выполняет практические вещи.
    Не получится чужими силами ничего сделать, было ж уже сказано.
     
  7. Промах

    Промах Нерд

    Видать, только Алекс здесь реально помогает, ну чтож, спасибо и на этом.
     
  8. rkit

    rkit Гуру

    Вам бы помогли, если бы вы не просили сделать за вас всю работу.
     
  9. Промах

    Промах Нерд

    Ваша позиция мне ясна. Я не знаю на каком ещё языке надо спрашивать , и пояснять - не кодер я, но что-то да могу сам написать, если не хотите помогать - дело Ваше, осуждать , равно как и выпрашивать я не намерен.
     
  10. serg_admin

    serg_admin Гик

    LCD и RTC у Вас работают по шине I2C.
    Максимальная скорость шины 400KBit. Не надо так часто обновлять время

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

    Если правильно помню -
    Код (C++):
    lcd.setCursor(0, 0);
    Довольно длительная операция. По времени эквивалентна полному заполнению дисплея.
     
  11. Промах

    Промах Нерд

    По ходу мой RTC1302 проблемный , или библиотеки не очень то подходят . Сделал модуль из выпаяной 1307 , нормально отображается , даже настроить с кнопок получилось , тикает.
     
  12. Промах

    Промах Нерд

    Спасибо большое человеческое serg_admin , практически с нуля написал код !
    Вчера свершилось , запустили и вроде как всё работает , правда от RTC отказался , за ненадобностью.
    показывает обороты. скорость , моторчасы с привязкой к оборотам двигателя, и путевой одометр. Показания моторчасов записывает в еепром , со смещением ячейки через 5000 циклов.
    Код (C++):
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>
    //#include <Adafruit_RGBLCDShield.h> //с
    //#include <utility/Adafruit_MCP23017.h> //с
    #include <EEPROM.h>
    // два первых байта eeprom будут содержать номер текущей ячейки
    // Дальше по шесть байт
    struct __values {
      uint32_t value;
      uint16_t count;
    };

    union rph_val {
      byte data[6];
      __values values;
    };

    // Оборотов час
    //#define RPH 192000 // 3200 оборотов двигателя в минуту *час = моторчас
    #define RPH 3200 // тест , пишем каждую минуту
    // МАксимальное количество перезаписей одной ячейки
    #define EEPROM_REWRITE 5000

    #define ODO 2

    volatile int val;
    volatile int val1;

    volatile int val_z;
    volatile int val_z1;

    volatile int val_rez = 0;
    volatile int val_rez1 = 0;


    boolean isCount = false; // Включаем выключаем счетчик
    uint32_t global_tacho_counter = 0; // Счетчик оборотов
    uint32_t global_rph = 0;
    boolean need_write = false; // Флаг необходимости обновить EEPROM
    int timer_lcd = 0; // Таймер обновления экрана
    int timer_calc = 5; // Расчет раз в пол секунды
    int timer_blink = 1; // Мигаем диодом - его можно использовать для тестовых импульсов
    byte calc_flag = 0;
    uint16_t eeprom_adress; // Адрес последней записи в eeprom

    uint32_t global_odo_counter = 0; // Счетчик
    uint32_t global_odo = 0;

    void rpm() {
      val++;
      //if (isCount) {
       if (true) {
        global_rph++;
        if (global_rph >= RPH)
        {
          global_rph = 0;
          global_tacho_counter++;
          need_write = true;
        }
      }
    }
    void rpm1() {
      val1++;

      if (isCount) {
        global_odo++;
        if (global_odo >= ODO)
        {
          global_odo = 0;
          global_odo_counter++;
        }
      }
    }

    // Функция вызывается 10 раз в секунду
    ISR (TIMER1_CAPT_vect) {
      if (timer_lcd) timer_lcd--; // Перерисовка LCD длительная опирация - делаем в loop

      // Копируем счетчики для обработки и начинаем считать заново
      // Так как пока не знаем формул расчета - выносим их в loop
      timer_calc--;
      if (timer_calc == 0) {
        val_z = val;
        val = 0;
        val_z1 = val1;
        val1 = 0;
        calc_flag = 1;
        timer_calc = 5; // Перезапуск таймера
      }

      // Включаем выключаем мигалку с периодом 0.2 секунды
      //  timer_blink = (timer_blink == 0) ? 1 : timer_blink - 1;
      //  if (timer_blink == 1)
      //    digitalWrite(13, HIGH);
      //  if (timer_blink == 0)
      //    digitalWrite(13, LOW);
    }

    //Прерывание для порта 'C' A0-A3 или 14-17pin
    ISR(PCINT1_vect) {
      static byte prev14value; // Эта переменная будет сохранять значение даже после завершения функции
      byte value14 = digitalRead(A0);

      // Условие определящие моментт нажатия кнопки
      if ((value14 == LOW) && (prev14value == HIGH)) {
        isCount = !isCount; // Включаем выключаем счетчик

      }
      digitalWrite(13, isCount);
      prev14value = value14;
    }

    /**
       Читаем ячейку содержащию указатель на текущую запись с данными
    */

    uint16_t getCellAddress(void)
    {
      return (( EEPROM.read(1) << 8) | (EEPROM.read(0))); // Читаем два байта в одну переменную
    }

    /**
       Пишем ячейку содержащию указатель на текущую запись с данными
    */

    void setCellAddress(uint16_t data)
    {
      EEPROM.write(0, ((byte*) &data)[0]);
      EEPROM.write(1, ((byte*) &data)[1]);
    }


    uint32_t getRPH_EEPROM(rph_val* data = 0) {
      uint16_t eeprom_adress = getCellAddress();
      rph_val d;

      // Читаем 6 байт из eeprom
      for (byte i = 0; i < sizeof(rph_val); i++) {
        d.data[i] = EEPROM.read(eeprom_adress + i);
        if (data != 0) {
          data->data[i] = EEPROM.read(eeprom_adress + i);
        }
      }
      return d.values.value;
    };

    /**
       Записываем данные моточасов в EEPROM

       data - моточасы
       init - первая запись в эту ячейку
    */

    void setRPH_EEPROM(uint32_t data, boolean init = false) {
      uint16_t eeprom_adress = getCellAddress();
      rph_val d;
      getRPH_EEPROM(&d);
      if (init) { // При стартовой инициализации
        d.values.count = 0;
      };
      d.values.count++;

      // При достижении максимального количества перезаписей берем новую ячейку
      if (d.values.count > EEPROM_REWRITE) {
        eeprom_adress += 6;
        d.values.count = 1;
      }
      d.values.value = data;
      // Данные и адрес выставлены, записываем
      for (byte i = 0; i < sizeof(rph_val); i++) {
        EEPROM.write((eeprom_adress + i), d.data[i]);
      }
      // Если производилась запись в новую ячеку, обновляем адресс
      if ((d.values.count == 1) && (! init)) {
        setCellAddress(eeprom_adress);
      }
      Serial.print(eeprom_adress); Serial.print('\n');
    }


    LiquidCrystal_I2C lcd(0x3f, 16, 2);
    ////Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
    void setup() {
      eeprom_adress = getCellAddress();

      // Если запись в eeprom еще не производилась инициализируем данные
      if ((eeprom_adress == 0) ||  (eeprom_adress > 1024)) {
        eeprom_adress = 6; // Начинать будем с ячейки с адрессом 6
        setCellAddress(eeprom_adress);
        setRPH_EEPROM(0, true);
      }
      // Если адресс ячейки корректный - читаем даные
      else {
        global_tacho_counter = getRPH_EEPROM();
      }

      // Настройка таймера
      TCCR1A = 0; // CTC mode - считаем от 0 до ICR1
      ICR1 = 24999; // 10 раз в секунду (16 000 000 / 64 / ICR1)
      TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11) | _BV(CS10); // Делитель таймера 8
      TIMSK1 = _BV(ICIE1); // Включить прерывание для TOP*/
      pinMode(13, OUTPUT);

      // Включить прерывание на pin A0
      PCICR = _BV(PCIE1);
      PCMSK1 = _BV(PCINT8);
      pinMode(A0,  INPUT_PULLUP); // Кнопка будет замыкаться на GND

      Serial.begin(9600);
      //Serial.print(getCellAddress());  Serial.print('\n');

      attachInterrupt(digitalPinToInterrupt(2) , rpm, RISING); //контакт 2 на плате притяжка к +5 вольтам через 10к
      attachInterrupt(digitalPinToInterrupt(3) , rpm1, RISING); //контакт 3 на плате притяжка к +5 вольтам через 10к
      //rtc.halt(false);
      // rtc.writeProtect(false);
      lcd.init();
      lcd.begin(16, 2);
      lcd.backlight();
      //lcd.setBacklight(2);
      lcd.setCursor(0, 0);
      lcd.print("PCMT by promah");
      lcd.setCursor(0, 1);
      lcd.print("CODE serg_admin");
      delay (1000);
      lcd.clear();

      pinMode(5, OUTPUT);
      analogWrite(5, 100);
      pinMode(2,  INPUT_PULLUP);
      pinMode(3,  INPUT_PULLUP);
    }

    void loop() {
      if (calc_flag) {
        cli(); // Воизбежании конфликта блокируем прерывания
        val_rez = val_z * 60; // калибровка тахометра , смотрим так же 19 или 20 строку
        sei();
        cli(); // Воизбежании конфликта блокируем прерывания
        val_rez1 = (val_z1 * 60) / 60; // калибровка спидометра
        sei();
        calc_flag = 0;
      }

      if (timer_lcd == 0) { // Подошло время обновлять LCD
        timer_lcd = 5 ; // Следующее обновление через пол секунды
        /*    Serial.write("z=");
            Serial.print(val_rez);
            Serial.write('\n');
            Serial.write("z1=");
            Serial.print(val_rez1);
            Serial.write('\n');*/

        //lcd.clear();
        lcd.setCursor(0, 0); // обороты
        lcd.print(val_rez);
        lcd.print("    ");
        lcd.setCursor(4, 0);
        lcd.print("Rpm");
        lcd.setCursor(8, 0);    //Моторчасы
        lcd.print(global_tacho_counter);
        lcd.setCursor(13, 0);
        lcd.print("min");
        lcd.setCursor(0, 1);
        lcd.print(val_rez1);  //изменением значений откалибровать спидометр
        lcd.setCursor(2, 1);
        lcd.print("Km/H");
        lcd.setCursor(6, 1);
        lcd.print(" ");
        lcd.setCursor(7, 1);   //  текущий одометр запуск и стоп с кнопки , сброса нет , сброс либо резетом , либо откл.питание
        lcd.print(global_odo_counter) ;
        lcd.setCursor(12, 1);
        lcd.print("metr");
      }
      // Насчитали новый мото час
      if (need_write) {
        setRPH_EEPROM(global_tacho_counter);
        need_write = false;
      }
    }
     
  13. ostrov

    ostrov Гуру

    У меня на RTC1302 школьный звонок работает с августа, полет нормальный, только батарейку один раз сменил. Но предпочитаю DS3231, он нравится больше.
     
  14. Промах

    Промах Нерд

    Как я понял 3231 - гораздо ловчее , но нет их, есть 02 и 07, 3102 с бубном завелся, а 3107 сразу.
    Но отказались действительно за ненадобностью, весь учёт и расчёт идёт относительно оборотов, и точности таймеров дуни - за глаза хватит.