вопрос по работе таймера ATtiny13

Тема в разделе "Микроконтроллеры AVR", создана пользователем forzub, 13 апр 2016.

  1. ostrov

    ostrov Гуру

    Программу в тег засуньте, так читать не удобно.

    Не понятно что такое val1. Не понятно где меняется flag11. Не понятно зачем использовать micros() там, где можно использовать millis(). Можно слегка разгрузить процедуру сравнения (которая у вас выполняется миллион раз в секунду), сперва сделать tval = micros()+1000000, потом if (tval<micros())... хотя, повторюсь, считать секунды микросекундами это расточительство мощностей.
     
    Последнее редактирование: 16 апр 2016
  2. forzub

    forzub Нуб

    Да, не тот скетч залил..
    Подправил, микросекунды изменил в миллисекунды
    val1 - считает время периода импульсов.

    Код (C++):


    volatile long val=0;
    volatile int flag11;
    volatile unsigned long tval,val0,val1;

    void setup() {
      // put your setup code here, to run once:
    attachInterrupt(1, rpm, RISING);
    Serial.begin(9600);
    tval=millis();
    flag11=0;
    }

    void rpm()
    {
     switch (flag11)
     {
      case 3:
      flag11=0;
      break;
      case 0:
      flag11=1;
      val0=micros();
      break;
      case 1:
        val1=micros()-val0;
        flag11=2;
        break;
        }
      val++;

    }

    void loop() {
      // put your main code here, to run repeatedly:
    if ((millis()-tval)>=1000)
    {
      if (flag11==2)
      {
        Serial.print(val1);
        flag11=3;
        }
       
    Serial.print(" rpm ");
    Serial.print(val);
    Serial.print(" val ");
    Serial.println((millis()-tval));
    val =0;
    tval=millis();
    }
    }

    }
     
  3. ostrov

    ostrov Гуру

    Функция rpm() зачем нужна? Она ни разу не вызывается нигде.
     
  4. forzub

    forzub Нуб

    это функция которая вызывается при прирывании
     
  5. ostrov

    ostrov Гуру

    А, вижу. Что должен этот сетч делать по задумке?
     
  6. forzub

    forzub Нуб

    Attini13 таймером выдает импульсы на PB0. Он соединен с INT0 ардуины. Как только на INT0 приходит растущий фронт импульса, выполняется rpm(). На выходе показывает количество пришедших импульсов за 1000 миллисекунд и считает, сколько микросекунд длится 1 период.
     
  7. ostrov

    ostrov Гуру

    Как то заумно. Зачем но каждое прерывание переключает режим? Не проще просто засекать время и считать импульсы прошедшее за определенный интервал? В прерывании оставить только val++. Прошла секунда, выдали на экран val (кол-во импульсов) , поделили секунду на него - вот тебе и длительность. Все равно обновление данных происходит раз в секунду. Чаще не нужно, да и тормозить будет.

    И еще, вы уверены, что так правильно?
    Код (C++):
    attachInterrupt(1, rpm, RISING);
    А не так:
    Код (C++):
    attachInterrupt(INT1, rpm, RISING);
     
  8. ostrov

    ostrov Гуру

    Вот, смотрите, не поленился написал программку по своему. Одну на UNO для генерации импульсов 36КГц (по подобию вышенаписанной для Аттини13), вторую на Мегу, для подсчета этих импульсов.

    Вот что у меня Мега выдает на экран:
    [​IMG]
    По моему, очень похоже не правду. Более того, правда и есть, т.к. подтверждается замерами анализатора. Подгонять точно под 36КГц не стал, ибо лениво.

    Вот Мегина программка (обратите внимание на исключительную компактность, половина ее занимает вывод на терминал):
    Код (C++):
    unsigned long val = 0;
    unsigned long timerIzm;
    float phaze;

    void setup() {
      // put your setup code here, to run once:
      Serial.begin (9600);
      attachInterrupt(INT1, rpm, FALLING);
      timerIzm = millis() + 1000;
    }

    void loop() {
      // put your main code here, to run repeatedly:
      if (millis() > timerIzm) {
        Serial.print ("rpm = ");
        Serial.print (val);
        Serial.print ("fps; phaze = ");
        phaze = 1000000.0/val;
        Serial.print (phaze);
        Serial.println ("us");
        val = 0;
        timerIzm = millis() + 1000;
      }
    }

    void rpm() {
      val++;
    }
     
     
  9. forzub

    forzub Нуб

    Я согласен, изначально rpm и делало только инкримент, как у Вас, потом, когда данные оказались плавающие, я добавил вычисление 1 периода. а можете попробовать подключить сюда свою Tiny, что бы посмотреть, сколько она у вас выдает? у меня показывает около 30000, при это TSOP на нее реагигует, значит частота близка к его номинальной.
     
  10. ostrov

    ostrov Гуру

    Что значит плавающие данные? Она у вас все равно выдаст на экран только один период, последний. Зачем же вычислять каждый? Тем более, время выполнения загруженного прерывания может достичь периода измерения и тогда начнутся пропуски. Если нужна точность повышенная, то следует уменьшить измеряемый период, например сделать полсекунды.

    Что такое TSOP?
     
  11. forzub

    forzub Нуб

    под плавающими данными я имел в виду то, что за один и тот же контрольный период я получаю сильно разнящиеся количества импульсов. Период он вычисляет не каждый, а второй. Ну по крайней мере я так планировал ))), что бы посмотреть через какое время срабатывает прерывание. В принципе этот код я дописал позже, что бы понять хватает прерыванию времени отработаться или нет. Размер кода прерывания на конечный подсчет не влияет, т.е. частота выдатся таже.
    TSOP1736 - это приемник модулируемого сигнала, для ИК барьера. Правда я с ним поэксперементировал и пришел к выводу, что для моей задачи он не совсем подходит, потому, что ловит отраженные сигналы и достаточно тяжело заставить его сработать при пересечении луча небольшим объектом, например падающим шариком, поэтому сейчас ищу другие варианты триггера. Вот на лазерный модуль поглядываю ))))
     
  12. ostrov

    ostrov Гуру

    Так я и не понял вашего колдунства про плавающие значения. В упор не вижу где он как то учитывает длину каждого импульса. Из 57+ тысяч до вывода в терминал доходит лишь 1.

    В качестве триггера хорошо подходит лазер + фотрезистор. Я на основе такой пары сделал триггер для вспышки и нащелкал брызг. )
     
  13. forzub

    forzub Нуб

    Круто. вот и я такую же хрень делаю, сначала тоже думал лазер и фоторезистор, но мой неокрепший ум совратили некоторые товарищи, которые утверждали, что фоторезистор крайне медленно реагирует на изменение освещенности. Ну, в итоге, совершив экскурс по ИК приемникам-передатчикам, таймерам avr вернулся в начальную гавань )))))
     
  14. ostrov

    ostrov Гуру

    Как вариант - фотодиод. По слухам он быстрее. Но мне показалось, что резистор тоже хорошо справляется.
     
  15. forzub

    forzub Нуб

    вот с него-то все и началось. Фотодиод забивается солнечным освещением. К тому же создать для него нормальный сигнал мне показалось очень нетривиальной задачей. В общем буду пробовать лазер и фоторез.
     
  16. Airbus

    Airbus Радиохулиган Модератор

    Всё уже придумано до нас и работает и под Тиню 13.У меня такой уже года 3 работает.Только код написан на непонятном языке даже не на Асме-поэтому не разобраться а так работает чётко!
     
  17. forzub

    forzub Нуб

    да, спасибо, классная штука, но не совсем то, о чем мы говорили. Вчера проверил связку : лазер - фоторезистор, остался доволен :))
     
  18. ostrov

    ostrov Гуру

    Только я так и не понял зачем было генерировать импульсы 36КГц?
     
  19. forzub

    forzub Нуб

    я собрал простенькую схему на фототранзисторе. Дело было ночью и в общем-то меня все устраивало, но... наступило утро и схема перестала работать. Что бы фототранзистор ночью ловил сигнал хотя бы метров с трех пришлось установить ему такую чувствительность, что днем от солнечного излучения не спасала никакая светоэкранирующая трубка. Поэтому я обратился к модулированию сигнала, что бы захват шел не всего подряд, а того, что работает на 36 кГц. А в качестве приемника взял TSOP1736 - єта штука как раз и хавает импульсы онной частоты. Как бы думал упростить себе жизнь. Ага. как бы не так... Лазер рулит :)))
     
  20. issida

    issida Нерд

    Правильно ли настроил таймер и прерывание?

    Код (C++):


    #include <util/delay.h>

    #define led_max 5
    #define led_mid 3
    #define led_min 4
    #define tranzistor 1
    #define battery 2
    #define out_chip 0


    byte start = 1; //1-заряжается, 0-разряжется
    long ttime = 0;



    ISR(TIMER0_OVF_vect)//прерывание по переполнению примерно раз в 0,2 сек
      {
      if (start == 1) {
        ttime++;
        if (ttime == 164794) { // прошло 10 часов, и зарядка не закончилась
          ttime = 0;
          PORTB &= ~(1 << tranzistor);//отключаем транзистор зпрядки
          start = 12;
        }
      }
      }


    byte bit_read(byte value, byte bit) { // считывание состояния отдельного бита(0 или 1)
      byte a = (((value) >> (bit)) & 0x01);//сдвигаем на указанной кол-во вправо и применяем лог И с маской
      return a;//возвращаем результат
    }

    void blin_k(byte pin) {
      _delay_ms(1000);//ждем
      PORTB &= ~(1 << pin);//выключаем
      _delay_ms(1000);//ждем
    }

    unsigned int analog_Read(byte channel) {
      noInterrupts();//запрещаем прерывания
      ADMUX = channel; // выбор входного канала
      ADCSRA |= 1 << ADEN; //разрешение работы ацп
      ADCSRA |= 1 << ADSC; //запуск преобразования ацп
      while (!(ADCSRA & (1 << ADIF))); //ждем окончания преобразования
      ADCSRA |= 1 << ADIF; //сбрасывание флага (ADLAR=0)
      byte low  = ADCL;//чтение из регистров результата
      byte high = ADCH;
      ADCSRA &= ~(1 << ADEN);  // отключаем АЦП, для уменьшения энергопотребления
      return (high << 8) | low;// перобразуем
      interrupts();//разрешаем прерывани
    }


    void setup() {
      //----устанавливаем входы-выходы 0-вход, 1-выход
      DDRB = 0x3A;//0-вход от схемы , 1-транзистор, 2-батарея, 3-диод высокий уровень, 4-диод(средний уровень), 5-диод(низкий уровень)
      PORTB = 0; //устанавливаем логические уровни в 0
      // Таймер
      TCCR0A = 0;
      TCCR0B = 0b00000101; //делитель 1024
      TCNT0  = 0;
      TIMSK0 = 0b00000010; // Разрешение прерываний по переполнению
      sei();

    }

    void loop() {
    /*
      unsigned int vol = analog_Read(battery);//читаем значение аккумулятора


      //---------Процесс слежения максимальной и минимальной зарядки-----------

      if (vol < 100) { // слишком низкое напряжение, либо короткое замыкание
        PORTB &= ~(1 << tranzistor);//отключаем транзистор зпрядки
        start = 11; //неиспраность, напряжение превысло порог
        PORTB |= (1 << led_max) | (1 << led_mid) | (1 << led_min); //включам все диоды 111xxx
        _delay_ms(200);//ждем
        PORTB &= ~((1 << led_max) | (1 << led_mid) | (1 << led_min)); //выключам все диоды xxx000
        _delay_ms(1000);//ждем

      }

      else if (vol > 1000) { //если аккумулятор был вынут либо он выщел из строя
        PORTB |= (0 << 4);//отключаем транзистор зпрядки
        start = 10; //неиспраность, напряжение превысло порог
        PORTB |= (1 << led_max) | (1 << led_mid) | (1 << led_min); //включам все диоды
        _delay_ms(1000);//ждем
        PORTB &= ~((1 << led_max) | (1 << led_mid) | (1 << led_min)); //вsключам все диоды
        _delay_ms(200);//ждем
      }



      if (start == 1 ) {//идет зарядка. ждем пока батарейка зарядится до максимального  уровня
        byte l = bit_read(PINB, out_chip);//считываем состояние пина
        if ( l == 0) { //проверяем 0 на входе РВ3 от микросхемы зарядки( зарядка закончена, тепрь будем ждать когда аккумулятор разрядится до 3,4В)
          PORTB &= ~(1 << tranzistor);//отключаем транзистор зпрядки
          start = 0; //теперь будет процесс разрядки
          ttime = 0;
        }
      }

      else if ( vol <= 540 && start == 0) { // ждем, когда на аккумуляторе меньше 3,4
        PORTB |= (1 << tranzistor);// вкл транзистор зарядки
        start = 1;//запускаем процесс зарядки
      }
      //----------------------------------------------------------------------



      //---------------отображение уровня текущей зарядки-------------
      if (start <= 1) {
        if (vol > 600 ) { //аккумулятор выше 4,2В
          PORTB &= ~((1 << led_max) | (1 << led_mid) | (1 << led_min)); // выключвкм диоды
          PORTB |= (1 << led_max);//включем высокой зарядки
          if (start == 1) { //если идет зарядка, мигаем светодиодом
            blin_k(led_max);// функция мигания светодиодомм
          }
        }

        else if (vol >= 550) {
          PORTB &= ~((1 << led_max) | (1 << led_mid) | (1 << led_min)); // выключвкм диоды
          PORTB |= (1 << led_mid);
          if (start == 1) { //если идет зарядка, мигаем светодиодом
            blin_k(led_mid);// функция мигания светодиодомм
          }
        }


        else if (vol < 550) { //если меньше 3,6в , вкл диод низной зарядки
          PORTB &= ~((1 << led_max) | (1 << led_mid) | (1 << led_min)); // выключвкм диоды
          PORTB |= (1 << led_min);
          if (start == 1) { //если идет зарядка, мигаем светодиодом
            blin_k(led_min);// функция мигания светодиодомм
          }
        }
      }
      //--------------------------------------------------------------------
    */

    }
     
    _delay_ms после такого будет корректно работать?