Классы DigOut и DigIn

Тема в разделе "Глядите, что я сделал", создана пользователем yul-i-an, 14 июн 2016.

  1. yul-i-an

    yul-i-an Гик

    Как-то решил для более удобной работы с цифровыми выходами/входами ардуино написать классы.
    Первый это DigOut (ссылка постоянная) для работы с выходами.
    Для его использования его необходимо установить его в среду ардуино как библиотеку.
    Объявление
    Объявление экземпляра класса DigOut MyPinName(pin,state);
    Объявление нескольких экземпляров DigOut led1(13), led2(3), relay(4,1), relay2(5,0), pomp(12);

    MyPinName - имя присваиваемое цифровому выходу (например Relay_1)
    pin - номер цифрового выхода
    state - состояние при объявлении (1-высокий уровень, 0-низкий уровень если не указывать то по умолчанию низкий уровень)
    При объявлении выхода через класс не требуется прописывать в секции setup режим выхода pinMode(pin,OUPUT);
    На данный момент класс имеет следующие методы:
    MyPinName.HI() - устанавливает высокий уровень на выходе
    MyPinName.LO() - устанавливает низкий уровень на выходе
    MyPinName.invert() - инвертирует выход
    MyPinName.state() - возвращает состояние выхода (0 или 1)
    MyPinName.blink(period, impuls) - этот метод организует медленный ШИМ на выходе.
    period - период ШИМ
    impuls - длина импульса (но не более длительности периода)
    это по сути blink без delay. Работу основной программы в loop не останавливает.

    Применение в качестве медленного ШИМ для управления мощностью нагревателя
    Код (C++):
    #include <DigOut.h>//класс дискретного выхода
    DigOut ten(13);//нагреватель на 13 пине
    #define t_pwm 1000//период медленного ШИМ`а
    //для симистора или твердотельного реле от 1000мс (для реле не менее 60000мс)

    void setup(){}

    void loop()
    {
    //где-то в loop рассчитывается необходимая мощность power

    //выдаем рассчитанную мощность
    ten.blink(t_pwm,(t_pwm/100)*power);
    //(t_pwm/100)*power) - перевод рассчитанной мощности (0-100%) в продолжительность импульса
    }
    Состояния экземпляров класса можно приравнивать друг другу (MyPinName1 = MyPinName2) или писать выражения типа MyPinName = 1;
    Планирую добавить методы afterHi - установить высокий уровень через заданное время и afterLo - установить низкий уровень через заданное время.

    Класс DigIn (ссылка постоянная) создан для удобной работы с цифровым входом, включает в себя анти дребезг.
    Объявление
    Объявление экземпляра класса DigIn MyPinName(pin,pullup,debounce);
    MyPinName
    - имя присваиваемое цифровому входу (например Button_Ok)
    pin - номер цифрового входу
    pullup - включение встроенного подтягивающего резистора (1-pullup on, 0-pullup off можно не указывать, тогда подтяжка установится автоматически)
    debounce -
    период времени ожидания окончания дребезга контактов (можно не указывать по умолчанию 50ms).
    При объявлении входа через класс не требуется прописывать в секции setup режим входа pinMode(pin,INPUT);
    На данный момент класс имеет следующие методы:
    MyPynName.valid(currentMillis) - возвращает 1 если вход действительно замкнут на землю и дребезг прекратился, по сути это тот же digitalRead(pin) только со встроенным антидребезгом. В метод необходимо передавать текущий millis() - но это я постараюсь решить, дабы избавить пользователя от лишней рутины.
    [​IMG]

    Пример использования.
    Код (C++):
    #include <DigIn.h>//https://yadi.sk/d/7tGp_zlVsBt7s
    #include <DigOut.h>//https://yadi.sk/d/NM4S6HmFrTRu6
    //объявляем дискретные входы
    DigIn button_ON(2), button_OFF(3);//кнопка ON на 2 пине, кнопка OFF на 3 пине
    /*или так
    DigIn button_ON(2,1);//кнопка ON на 2 пине, встроенная подтяжка вкл
    DigIn button_OFF(3,1);//кнопка OFF на 3 пине,встроенная подтяжка вкл
    */

    //объявляем дискретный выход
    DigOut led(13,0);//светодиод led на 13 пине, отключен

    unsigned long currentMillis=millis();//для хранения текущего времени

    void setup()
    {
      //прерывание от таймера 0 для опроса millis() не чаще 1 раза/мс
      OCR0A = 0xAF;//http://robotosha.ru/arduino/multitasking-and-interrupts-arduino.html
      TIMSK0 |= _BV(OCIE0A);
    }

    void loop()
    {
      // currentMillis=millis();//сохраняем текущее время
      if(button_ON.valid(currentMillis))//если ON действительно нажата
      {
        led.HI();//включаем светодиод
      }
      if(button_OFF.valid(currentMillis))//если OFF действительно нажата
      {
        led.LO();//выключаем светодиод
      }
    }
    //по прерыванию таймера получаем текущий millis
    //чтобы постоянно в loop не запрашивать millis
    SIGNAL(TIMER0_COMPA_vect)
    {
      currentMillis = millis();
    }

    //yul-i-an@mail.ru 06.2016 - Я/Д 41001603404940
    Пример блинка
    Код (C++):
    #include <DigOut.h>//https://yadi.sk/d/NM4S6HmFrTRu6
    DigOut led(13,0);//светодиод led на 13 пине, отключен
    //можно и так DigOut led(13); низкий уровень установится по умолчанию

    void setup(){}

    void loop()
    {
      led.blink(1000,500);//мигаем с периодом 1с и продолжительностью 0,5с
                                     //не тормозя основной цикл
    }
     
    Последнее редактирование: 9 июл 2018
    Максимус-Бог нравится это.
  2. Максимус-Бог

    Максимус-Бог Убийца матрёшек

    MyPinName.State();
    Код (C++):
    bool state(void) const {
            return digitalRead(_pin);
        }
    Порт настроен на выход, а вы его считываете.

    сделайте поле в котором хранится состояние, а потов возвращайте из функции.
     
  3. ИгорьК

    ИгорьК Гуру

    Код (C++):
    #define _setL(port,bit) do { port &= ~(1 << bit); } while(0)
    #define _setH(port,bit) do { port |= (1 << bit); } while(0)
    #define _clrL(port,bit) do { port |= (1 << bit); } while(0)
    #define _clrH(port,bit) do { port &= ~(1 << bit); } while(0)
    #define _bitL(port,bit) (!(port & (1 << bit)))
    #define _bitH(port,bit) (port & (1 << bit))
    #define _cpl(port,bit,val) do {port ^= (1 << bit); } while(0)
     
     
    DIYMan нравится это.
  4. yul-i-an

    yul-i-an Гик

    По моему схема вывода микроконтроллера не запрещает этого.
     
  5. yul-i-an

    yul-i-an Гик

    В класс DigOut (ссылка постоянная) добавил функцию lpwm(period, fill) - аналог функции blink(period, impuls) из этого же класса, но в отличие от неё вместо продолжительности импульса (impuls) задается процент заполнения (fill от 0 до 100%).
    Что дает. Раньше в коде когда нужен был медленный ШИМ писал так
    Код (C++):
    ten.blink(t_pwm,(setPower*(t_pwm/100)));//медленный ШИМ на тен
    Теперь так
    Код (C++):
    ten.lpwm(t_pwm, setPower);//медленный ШИМ на тен
     
    Последнее редактирование: 9 июл 2018
  6. DIYMan

    DIYMan Guest

    Вопросы: для чего? Зачем надстройка над надстройкой, по сути? Чем отличается

    digitalWrite(13,!digitalRead(13));

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

    Далее: просмотрел код - он не совсем хороший:
    Код (C++):
    DigOut (const int8_t pin=13, const bool state=0)
    Во-первых, в квалификаторах const тут смысла нет, от слова совсем, во-вторых - у нас номером пина может быть отрицательное число, оказывается? int8_t - знаковый тип, диапазоном -128 ... 127.

    Код (C++):
    void DW(const bool state) const
    const bool також не несёт никакого смысла, достаточно было просто bool.
    Код (C++):
    digitalWrite(_pin, state);
    Расходимся, ребята, нас обманули :)
    Код (C++):

    if(cms<impuls+preMillis){//если время высокого уровня не прошло
               HI();
             }
             else//иначе
             {
               LO();
             }
     
    Зачем каждый раз дёргать с бешеной частотой HI() и LO()? Установили один раз - и всё, когда надо - установили другой уровень, МК не дурак - уровни держит между вызовами.
    Код (C++):
    void blink (unsigned long period,  int impuls)
    Что будет, если я в impuls передам отрицательное значение (int - знаковый тип)?

    И вот смотрите, что мы получаем в итоге: во-первых, плохой код. Во-вторых - из-за сомнительного удобства имеем 5 байт в оперативе на 1 пин, не дай бог держать такой объект глобально, что называется.

    Прошу воспринять мою критику адекватно, считаю, что развиваться надо, но категорически против того, чтобы выкладывать подобные практические занятия под видом "библиотеки".
     
  7. ИгорьК

    ИгорьК Гуру

    Ну... я на это же пытался намекнуть. Обычно для работы с пинами идут по пути ускорения и уж точно не утяжеления.
    Но с другой стороны, товарищ просто тренируется в написании библиотек, что тоже неплохо :)
     
    DIYMan нравится это.
  8. yul-i-an

    yul-i-an Гик

    Изначально планировалось прямое управление пинами. Потом решил не заморачиватся, т.к. какаянибудь библиотека ЛСД или DS18B20 всё равно использует DigitalWrite. К чему эта гонка за скоростью. Если мне будет нужно для какой-нибудь динамической индикации скорость я её реализую на прямом управление портами.
    А класс написан для удобства (это крем для пирога Ардуино).
    Идеология Ардуино подразумевает упрощение написания кода без вникания в работу железа.
    Я же не навязываю. Кому надо пусть прямой доступ используют.
     
    ИгорьК нравится это.
  9. DIYMan

    DIYMan Guest

    Ну так и я про то же. Давайте рассмотрим на примере invert:
    Код (C++):
    #define LED 10
    pinMode(LED,OUTPUT);
    digitalWrite(LED,!digitalRead(LED));
    и ваш:
    Код (C++):
    #define LED 10
    DigOut pin(LED);
    pin.invert();
    Где упрощение то? Ткните пальцем, плз. Вижу только жирную надстройку над жирной надстройкой.
     
  10. yul-i-an

    yul-i-an Гик

    Без класса
    Код (C++):
    #define LED 10 //даем внятное имя пину
    void setup(){
    pinMode(LED,OUTPUT);//настраиваем пин как выход
    }
    void loop(){
    digitalWrite(LED,!digitalRead(LED));//нвертируем пин
    }
    С классом
    Код (C++):
    #include <DigOut.h>
    DigOut LED(10);//даем внятное имя пину
    void setup(){}
    void loop(){
    LED.invert();//нвертируем пин
    }
    И вообще эта функция сама напрашивалась чтобы запись короче была и понятней.
    Вы лучше DigOut.blink() сравните...

    По поводу
    Код (C++):
    if(cms<impuls+preMillis){//если время высокого уровня не прошло
               HI();
              }
              else//иначе
             {
                LO();
              }
    Оно быстрее работает чем выставлять флаги (тоже память занимают) и проверять их.
     
  11. yul-i-an

    yul-i-an Гик

    С этим согласен (но мы то знаем что отрицательных пинов нет). Буду править.
     
    Последнее редактирование: 23 июн 2016
  12. DIYMan

    DIYMan Guest

    С чем сравнивать? Я уже писал, что код blink написан безграмотно, мне повторить? Зачем дёргать постоянно digitalWrite, если достаточно только один раз при смене состояний? У вас МК занят бессмысленным перемешиванием бессмысленной каши.