Digispark - Attiny85

Тема в разделе "Arduino & Shields", создана пользователем Salk, 14 фев 2017.

  1. Salk

    Salk Гик

    Добрый день, люди добрые.
    Такая незадача случилась с программированием проекта на Digispark, не могу подружить энкодер и ШИМ библиотеку (TinySoftPwm.h).
    Код (C++):
    // digispark не понимает 'byte' и 'boolean'
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>
    #include <TinySoftPwm.h> // PWM

    // Энкодер
    #define pin_A 3      // (D-)
    #define pin_B 5      // (RESET)
    #define APOT 2
    #define PWM_IRL540  1
    // 4 и 0 - I2c

    // Частота обновления экрана
    #define TIME_LCD 200
    unsigned long int time_lcd;
    unsigned long int time_pwm_motor;

    #define TIME_ENCODER 15
    unsigned long time_encoder;
    unsigned char encoder_A;
    unsigned char encoder_B;
    unsigned char encoder_old;
    int val;

    float VOLTS;
    float VOLTS_SUMM;
    float R1 = 51000.0;               // сопротивление R1
    float R2 = 9100.0;                // сопротивление R2

    LiquidCrystal_I2C lcd(0x3F, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display

    void setup()
    {
      pinMode(APOT, INPUT);
      pinMode(pin_A, INPUT_PULLUP);
      pinMode(pin_B, INPUT_PULLUP);
      pinMode(PWM_IRL540, OUTPUT);
      lcd.init();
      lcd.backlight();
      lcd.setCursor(1, 0);
      lcd.print("Hello, world!");
      lcd.setCursor(0, 1);
      lcd.print("Ywrobot Arduino!");
      // Инициализация, как я понял, портов ШИМ, 0 - задействовать все возможные ШИМ-пины
      // Первое число, видимо, задержка (в мкс) между сменой стостояния лог.уровня, т.е. частота
      // TinySoftPwm_begin(3, 0); // 20kHz/defolt - 128 x TinySoftPwm_process() calls before overlap (Frequency tuning), 0 = PWM init for all declared pins
      delay(1000);
      lcd.clear();
    }

    void loop()
    {
      // Че то там нужное для библиотеки ШИМ :)
      static uint32_t StartUs = micros();
      if ((micros() - StartUs) >= 60)
      {
        StartUs = micros();
        TinySoftPwm_process();
      }
      // Опрашиваем энкодер
      ENCODER();
      // управляем полевичком ШИМ
      TinySoftPwm_analogWrite(PWM_IRL540, val);

      /*
        for (int i = 0; i < 128; i++)
        {
        VOLTS = ((analogRead(APOT) * 5.0) / 1024) / (R2 / (R1 + R2));
        VOLTS_SUMM = VOLTS_SUMM + VOLTS;
        }
        if (millis() - time_lcd > TIME_LCD)
        {
        lcd.setCursor(5, 1);
        lcd.print(VOLTS_SUMM / 127);
        lcd.print("V    ");
        time_lcd = millis();
        }
        VOLTS_SUMM = 0.0;
      */

    }

    void ENCODER()
    {
      // Если прошло больше 15 мс
      if (millis() - time_encoder > TIME_ENCODER)
      {
        time_encoder = millis();
        encoder_A = digitalRead(pin_A);     // считываем состояние выхода А энкодера
        encoder_B = digitalRead(pin_B);     // считываем состояние выхода B энкодера

        if (encoder_A == LOW && encoder_old == HIGH)
        {
          if (encoder_B == HIGH)
          {
            val = constrain(val - 5, 0, 255);
            // TinySoftPwm_analogWrite(PWM_IRL540, val);
            lcd.setCursor(6, 0);
            lcd.print(val);
            lcd.print("    ");
          }
          else
          {
            val = constrain(val + 5, 0, 255);
            // TinySoftPwm_analogWrite(PWM_IRL540, val);
            lcd.setCursor(6, 0);
            lcd.print(val);
            lcd.print("    ");
          }
        }
        encoder_old = encoder_A;
      }
    }
    Вместе не работает энкодер, буд-то его пины не опрашиваются, может библиотека ШИМ переконфигурирует эти пины, не знаю. Без строчки
    Код (C++):
    TinySoftPwm_begin(3, 0); // 20kHz/defolt - 128 x TinySoftPwm_process() calls before overlap (Frequency tuning), 0 = PWM init for all declared pins
    Энкодер начинает работать, но перестает ШИМ :)
    Пробовал в строчке TinySoftPwm_begin(3, 0); Значение 0 менять на другие (1,2,3,4,5), думал может нужно включить ШИМ только для одного вывода (1 используется у меня), но ничего не менялось.
    Как можно исправить, что предпринять и почему так происходит, как думаете? Спасибо.
     
  2. Salk

    Salk Гик

    Тогда помогите написать код для программного ШИМ, вообще не могу разобраться, что я делаю не так, пожалуйста.
    Вот, что у меня получилось, точнее не получилось. Принцип: если увеличиваем скважность, то уменьшаем время паузы и увеличиваем время импульса от 0-50% и наоборот от 50-100%. Но чтото совсем запутался.
    Код (C++):

    // 25 мкс время между периодами, должна ровняться примерно около 15 кГц
    void PWM()
    {
      if ((micros() - time_pwm) > value_pwm + 25)
      {
        digitalWrite(PWM_IRL540, HIGH);
        if (c != 1)
        {
          time_pwm = micros();
          c = 1;
        }
        // меняя значение value_pwm, меняем скважность
        if ((micros() - time_pwm) > 25 - value_pwm)
        {
          c = 0;
          digitalWrite(PWM_IRL540, LOW);
          time_pwm = micros();
        }
      }
    }
     
  3. rkit

    rkit Гуру

    Условие вложено в противоречащую ему ветку.
     
  4. serg_admin

    serg_admin Гик

    При таком подходе процессор будет только PWM обслуживать. Больше ни чего он делать не сможет, в противном случае погрешность частоты и скважности очень быстро начнет стремится к бесконечности (это именно касательно 15 KHz). Тогда проще два delayMicroseconds поставить вместо всего кода, и все сразу понятно станет.
    Кстати в Вашей реализации базовая погрешность будет начинаться примерно с 30%, но это конечно не точно, на вскидку.

    На мой взгляд использования Arduino для одного PWM это мягко говоря не оптимально.
    Чем Вам аппаратные PWM не угодили? напишите может лучше в этом направлении поправить. Они то же могут 15 KHz выдовать, и даже много больше.

    А функция micros(); я так понимаю весьма примерная.
     
    Последнее редактирование: 15 фев 2017
  5. Salk

    Salk Гик

    Digispark используется для измерения напряжения на моторе и управления им же. ШИМ как раз используется для управления полевиком, управляющий мотором. Стандартная частота ШИМ Digispark не выше 500 Гц (490 заявлено). При такой частоте обмотка мотора начинает "пищать" т.к. частота попадает в звуковой диапазон.
    Знаю, что на обычных Atmega, есть пред делители, с помощью которых можно выставлять частоты от ~300 Гц до 31 или 62 кГц, в зависимости от таймера. Но что-то подобное на Attiny85 не смог найти.
    Есть библиотека, в 1 посту, ШИМа на Digispark, но она видимо переконфигурирует порты использующиеся у меня для энкодера. Замкнутый круг какой-то. Хотелось бы конечно, чтобы не только на ШИМ работал МК.
     
  6. serg_admin

    serg_admin Гик

    У Attiny85 один восьми битный таймер. Думаю он задействован ядром Arduino на частоте 1 KHz. Если хотите использовать Arduino IDE то можно извратится с прерываниями "Compare Match A Interrupt" или "Compare Match B Interrupt" и двигать значение регистра сравнения прямо внутри прерывания.

    Но я бы этот процессор в Arduino IDE не шил. Уж очень много от его скудных ресурсов/возможностей она отъедает.
    Если у Вас только шим и измерение напряжения (ADC) то легко реализуется в штатной среде Atmega Studio. Знаючи, работы на пол дня с тестированием. Не знаючи с подсказками 3-4 дня пока в DataSheet научитесь разбираться.
     
    Последнее редактирование: 15 фев 2017
  7. serg_admin

    serg_admin Гик

    Ошибочка. Таймеров там все таки два.
     
  8. serg_admin

    serg_admin Гик

    Вот запуск двух шимов на Atmega328

    Код (C++):
     91 void init_motors(){
        // Отмечаем выводы как OUTPUT
    92   DDRD  |= _BV(DDD6) | // PWM двигателя A
    93            _BV(DDD7) | // Направление двигателя A
    94            _BV(DDD5) | // PWM двигателя B
    95            _BV(DDD4) ; // Направление двигателя B
    96   PORTD = 0;
    97   TCCR0B |= _BV(CS00);//Делитель таймера 1
    98   TCCR0A = _BV(WGM01) | _BV(WGM00) | // fast mode PWM верхнее значение 0xFF
    99            _BV(COM0A1) |        // Спадающий фронт вывода OC0A при OCR0A compare match
    100            _BV(COM0B1) ;        // Спадающий фронт вывода OC0B при OCR0B compare match
    101   OCR0A = 0; // Скважность 1..255
    102   OCR0B = 0; // Скважность 1..255
    103 }
     
    timer1 на tinny85 делитель 16 надо ставить
    Код (Text):
    PWM       Frequency Clock Selection CS1[3:0] OCR1C RESOLUTION
    20 kHz           PCK/16               0101   199        7.6
    Если не сможешь портировать пиши завтра возьму с собой tinny85.
     
    Последнее редактирование: 15 фев 2017
  9. Salk

    Salk Гик

    Спасибо, огромное. Но, да, трудности возникли, ардуинщик, что сказать :)
    compare match - это прерывание?
     
  10. serg_admin

    serg_admin Гик

    Да это пара прерываний A/B
     
  11. Salk

    Salk Гик

    Без Вас не разберусь.
    Код (C++):
    #define PWM_MOTOR 1 // пин для ШИМ

    void setup()
    {
      // конфигуриурем пин ШИМ на выход "DDRD  |= _BV(DDD5) | // PWM двигателя"
      pinMode(PWM_MOTOR, OUTPUT);
      // устанавливаем LOW уровень "PORTD = 0;"
      digitalWrite(PWM_MOTOR, LOW);
      TCCR0B |= _BV(0101); // Делитель таймера 16
      // Включаем фаст ШИМ режим
      TCCR0A = _BV(WGM01) | _BV(WGM00) | // fast mode PWM верхнее значение 0xFF
               _BV(COM0A1);        // Спадающий фронт вывода OC0A при OCR0A compare match
      OCR0A = 0; // Скважность 1..255
    }

    void loop()
    {

    }
    Сказать, что я что-то понимаю, что написал, ничего не сказать. compare match - прерывания по совпадению, можете объяснить принцип его работы и помочь с написанием кода программного ШИМ. Спасибо.
     
  12. serg_admin

    serg_admin Гик

    Вот у меня скважность регулируется.
    Код (C++):
    OCR1A = 230;
    По частоте не скажу не мерил.


    Код (C++):
    #define PWM_MOTOR 1 // пин для ШИМ

    void setup()
    {
      // конфигуриурем пин ШИМ на выход
      pinMode(PWM_MOTOR, OUTPUT);

      TCCR1 |= _BV(CS12) | _BV(CS10) | // Делитель таймера 16
               _BV(COM1A1 ) |         // Спадающий фронт вывода OC0A при OCR0A compare match
               _BV(PWM1A) ; //Запустить генерацию импульсов
      OCR1A = 230;
    }

    void loop()
    {

    }
    Если поставить максимальный делитель
    Код (C++):
    TCCR1 |= _BV(CS13) |_BV(CS12) | _BV(CS11) | _BV(CS10) |
    То скважность можно увидеть визуально. Частота что-то около одного герца.

    Ну и максимальная частота:
    Код (C++):
    TCCR1 |= _BV(CS10) |
     
    Последнее редактирование: 17 фев 2017
  13. serg_admin

    serg_admin Гик

    Если частота не достаточно высокая добавьте в setup()

    Код (C++):
      PLLCSR |= _BV(PLLE);
      PLLCSR |= _BV(PCKE);
    Тогда ШИМ будет тактироваться от генератора 64MHz вместо тактовой частоты процессора
     
  14. Salk

    Salk Гик

    Безумное вам спасибо. На работе есть осциллограф, померю фактическую частоту. Вроде должно получиться!
     
  15. Salk

    Salk Гик

    Хм, померил сейчас дома обычным мультиметром с возможностью замера частоты. При таком коде:
    Код (C++):
    #define PWM_MOTOR 1 // пин для ШИМ

    void setup()
    {
      // конфигуриурем пин ШИМ на выход
      pinMode(PWM_MOTOR, OUTPUT);
      TCCR1 |= _BV(CS12) | _BV(CS10) | // Делитель таймера 16
               _BV(COM1A1 ) |         // Спадающий фронт вывода OC0A при OCR0A compare match
               _BV(PWM1A) ; //Запустить генерацию импульсов
      PLLCSR |= _BV(PLLE);
      PLLCSR |= _BV(PCKE);
      OCR1A = 50;
    }

    void loop()
    {
    }
    Выдает 4 кГц.
    Без строчек
    Код (C++):
      PLLCSR |= _BV(PLLE);
      PLLCSR |= _BV(PCKE);
    вовсе 1 кГц. Хотя может мультик неправильно считает, но вроде не должен (лимит у него 20 кГц).
    При "TCCR1 |= _BV(CS10)| _BV(CS10)|" тоже разницы в частоте нет.
    А скважность меняется, все хорошо. Надо будет протестировать на 4 кГц, может мотор не так сильно пищать будет, в любом случае - СПАСИБО! :)
     
  16. serg_admin

    serg_admin Гик

    Забавная проблема!
    Видимо среда Arduino инициализирует регистры сама поэтому частота не соответствует заданной
    Добавьте в начало setup() строчку:
    Код (C++):
    TCCR1 = 0;
    При этом минимальный делитель будет _BV(CS10), частота примерно 250KHz|