Button

Тема в разделе "Arduino & Shields", создана пользователем kvitko1, 29 апр 2018.

  1. kvitko1

    kvitko1 Гик

    Привет всем изучая С++ я столкнулся с проблемой у меня два кода которые мне нужно соединить в одну программу постоянно ошибки помогите пж
    Код№1
    Код (C++):

    volatile bool timerLED1On;    //переменная вкл/выкл таймера
    bool LED1On;        //переменная для хранения состояния светодиода
    volatile unsigned long int timerLED1, t
    imerLED1Loop; //переменные подсчета мс и
                                                         //хранения значения таймера
    volatile bool timerLED2On;
    bool LED2On;
    volatile unsigned long int timerLED2,
     timerLED2Loop;
    ISR (TIMER0_COMPA_vect) //функция, вызываемая таймером-счетчиком каждые 0,001 сек.
    {
      if(timerLED1On)       //если включен миллисекудный таймер для LED1
        timerLED1++;        //инкремент переменной таймера (+1)

      if(timerLED2On)       //если включен миллисекудный таймер для LED2
        timerLED2++;        //инкремент переменной таймера (+1)
    }

    void setup()
    {
      pinMode(10, OUTPUT);   //настроить 7-й порт как выход
      pinMode(11, OUTPUT);
     
    /**** настройка прерывания по таймеру каждую 0,001 сек (вызов функции ISR (TIMER0_COMPA_vect)) ****/
      TCCR0A |= (1 << WGM01);              //сброс при совпадении
      OCR0A = 0xF9;                        //начало отсчета до переполнения (249)
      TIMSK0 |= (1 << OCIE0A);             //разрешить прерывание при совпадении с регистром А
      TCCR0B |= (1 << CS01) | (1 << CS00); //установить делитель частоты на 64
      sei();                               //разрешить прерывания

    }

    void loop()
    {
      LED1(10, 1000, 1);   //функция мигания первого светодида (№ пина, длительность интервала, вкл/выкл)
      LED2(11, 500);       //функция мигания второго светодида (№ пина, длительность интервала)
      }

    void LED1(byte pin, long int interval, bool state)  //функция мигания первого светодиода (пин, инт-л, состояние)
    {
      if (timerLED1On == 0 && state == 1) //если таймер не был запущен и разрешена работа таймера
      {
        timerLED1On = 1;    //запустить таймер
      }
      if(timerLED1On == 1 && state == 0)  //если таймер был запущен и запрещена работа таймера
      {
        cli();            //остановить прерывания
        timerLED1On = 0;  //запретить пополнение переменной таймера
        timerLED1 = 0;    //обнулить переменную таймера
        sei();            //разрешить прерывания
        digitalWrite(pin, LOW);   //выключить светодиод
        LED1On = 0;       //установить флаг выключения светодиода
      }

      if(state == 1)  //если разрешена работа таймера
      {
        cli();  //остановить прерывания
        timerLED1Loop = timerLED1;  //сохранить значение переменной таймера
        sei();  //разрешить прерывания
        if(timerLED1Loop >= interval) //сравнить значение таймера с заданным интервалом
        { //если значение превысило интервал
          cli();
          timerLED1 = 0;  //обнулить таймер
          sei();
          if(LED1On == 0) //если светодиод был выключен
          {
            LED1On = 1;   //поставить флаг включения
            digitalWrite(pin, LED1On);   //включить светодиод
          }
          else  //если светодиод был включен
          {
            LED1On = 0;   //поставить флаг выключения
            digitalWrite(pin, LED1On);  //выключить светодиод
          }
        }
      }
    }

    void LED2(byte pin, long int interval)
    {
      if (timerLED2On == 0)
      {
        timerLED2On = 1;
      }

      cli();
      timerLED2Loop = timerLED2;
      sei();
      if(timerLED2Loop >= interval)
      {
        cli();
        timerLED2 = 0;
        sei();
        if(LED2On == 0)
        {
          LED2On = 1;
          digitalWrite(pin, LED2On);  
        }
        else
        {
          LED2On = 0;
          digitalWrite(pin, LED2On);
        }
      }
    }
    Код №2
    Код (C++):
    void setup()
    {
    pinMode(3, INPUT);
    }

    void loop()

    {
    if(digitalRead(3)==HIGH)//если кнопка нажата ...
    {
    // програма
    }
    else//если не нажата...
    {
    //другое действие
    }

    }
     
    Кратко о 1 коде
    2 Светодиода мигают с разной частотой
    Кратко о коде 2
    Программа для активации кнопки то есть нажал программа исполняется отпустил остановилась
     
  2. Salk

    Salk Гик

    А у меня другой вопрос, решил разобраться с прерываниями взял за основу все тот же код:
    Код (C++):
    boolean state = false;
    volatile unsigned long int timerLED1;

    void setup()
    {
      // Serial.begin(9600);
      pinMode(6, OUTPUT);

      // Настройка прерывания по таймеру - счетчик на 1 мс
      // "срабатывание прерыавния при совпадении"
      TCCR0A |= (1 << WGM01);
      // Разрешаем прерывание при совпадении с регистром А
      TIMSK0 |= (1 << OCIE0A);
      // Значение регистра А, при котором сработает прерывание
      OCR0A = 0xF9; // начало отсчета до переполнения (249)
      /*
        CS02   CS01  CS00
        0      0     0     - Таймер/счетчик Т0 остановлен
        0      0     1     - Тактовый генератор CLK (х1)
        0      1     0     - CLK/8
        0      1     1     - CLK/64
        1      0     0     - CLK/256
        1      0     1     - CLK/1024
      */

      // установка предделителей частоты
      // TCCR0B |= (1 << CS01) | (1 << CS00);  // 64
      TCCR0B = TCCR0B & B11111000 | B00000011;  // x64
      // Запуска работы всех прерываний, у которых есть на это допуск
      sei();
      // Остановка прерываний
      // cli();
    }

    void loop()
    {
      // delay(5000);
    }

    // Вызов функции ISR - прерывание
    ISR (TIMER0_COMPA_vect)
    {
      state = !state;
      digitalWrite(6, state);
    }
    Цель - получение не стандартной частоты программным путем.
    Как я понял при переполнении регистра А (OCR0A) должно срабатывать прерывание, а само значение OCR0A мы можем выставлять в ручную (т.к. счетчик 8-ми битный, значения от 0 - 255). Если автор кода сделал просто счетчик раз в 1 мс, и взял для этого значение регистра А - 249 отчетов (0xF9), то логично меняя этот "порог" я могу изменять время вызова прерывания. Но у меня ничего не изменяется, какое бы число в OCR0A я не записывал. Частота на ножке 6 всегда одна, в районе 500 Гц, что логично при задержке в 1 мс.
    А второе то, что почему-то командой
    Код (C++):
    TCCR0B |= (1 << CS01) | (1 << CS00);  // 64
    я не могу изменить предделитель, только с помощью
    Код (C++):
    TCCR0B = TCCR0B & B11111000 | B00000011;
    МК - Arduino Nano v3
     
  3. ostrov

    ostrov Гуру

    Время выполнения digitalWrite порядка 1800 мкс. То есть чаще он переключаться не может как ни уменьшай таймер. Пробуйте прямым переключением бита порта.
     
  4. Salk

    Salk Гик

    Сделал, так как Вы сказали, результата не дало. Таймер обновляется только каждую миллисекунду. И я не могу изменить это время. Почему-то..
    Код (C++):
    void setup()
    {
      // Serial.begin(9600);
      // 1 - на выход, 0 - вход
      DDRD = 0xFF;
      // 13 пин
      PORTD = 0b01000000;

      // Настройка прерывания по таймеру
      // "срабатывание прерыавния при совпадении"
      TCCR0A |= (1 << WGM01);
      // Разрешаем прерывание при совпадении с регистром А
      TIMSK0 |= (1 << OCIE0A);
      // Значение регистра А, при котором сработает прерывание
      // 7F - 127
      OCR0A = 0x7F; // начало отсчета до переполнения (0xF9 - 249)
      /*
        CS02   CS01  CS00
        0      0     0     - Таймер/счетчик Т0 остановлен
        0      0     1     - Тактовый генератор CLK (х1)
        0      1     0     - CLK/8
        0      1     1     - CLK/64
        1      0     0     - CLK/256
        1      0     1     - CLK/1024
      */

      // установка предделителей частоты
      // TCCR0B |= (1 << CS01) | (1 << CS00);  // 64
      TCCR0B = TCCR0B & B11111000 | B00000001; // x1
      // TCCR0B = TCCR0B & B11111000 | B00000101;  // 60 Гц
      // TCCR0B = TCCR0B & B11111000 | B00000011;  // x64
      // Запуска работы всех прерываний, у которых есть на это допуск
      sei();
      // Остановка прерываний
      // cli();
    }

    void loop()
    {
      /* Разгоняет выход Nano до 842 кГц
         digitalWrite только до 123 кГц
        delay(50000);
        if (PORTD == 0b01000000)
        {
        PORTD = 0b00000000;
        }
        else
        {
        PORTD = 0b01000000;
        }
      */

    }

    // Вызов функции ISR - прерывание
    ISR (TIMER0_COMPA_vect)
    {
      if (PORTD == 0b01000000)
      {
        PORTD = 0b00000000;
      }
      else
      {
        PORTD = 0b01000000;
      }
    }
    Ведь, я правильно рассуждаю? - Если Таймер 0 - 8-ми битный, а частота работы МК - 16 МГц, то максимальная частота (16 000 000 / 256) будет равна 62 500 кГц, при переполнении счетчика. А вот если заставить счетчик переполняться раньше в два раза, то можно в итоге увеличить частоту на столько же.
    В чем подвох, почему прерывание не реагирует на регистр А - OCR0A? :)
     
    Последнее редактирование: 6 май 2018
  5. ostrov

    ostrov Гуру

    Я сейчас не дома, под рукой только смартфон, на нем трудно даташит лопатить. А на память я регистры все не помню. Делитель какой стоит?
     
  6. DetSimen

    DetSimen Guest

    дак надо режим включить "прерывание по совпадению". По умолчанию он только на переполнение настроен.
     
    arkadyf нравится это.
  7. Salk

    Salk Гик

    Простите, а этот код его не включает?
    Код (C++):
      // "срабатывание прерыавния при совпадении"
      TCCR0A |= (1 << WGM01);
    // Разрешаем прерывание при совпадении с регистром А
      TIMSK0 |=(1<< OCIE0A);
    Делитель х1 стоит, пытаюсь получить частоту ножкидерга выше 100 кГц.
    Код (C++):
    TCCR0B = TCCR0B & B11111000 | B00000001; // установить Таймер 0 делитель на 1
     
  8. ostrov

    ostrov Гуру

    Правильнее писать:
    Код (C++):
    if (PIND == 0b01000000)
    AVR калькулятор мне выдал такие настройки:
    [​IMG]
    Это по совпадению.
     
  9. Salk

    Salk Гик

    Все заработало :) Спасибо. В итоге код получился такой:
    Код (C++):
    void setup()
    {
      // Serial.begin(9600);
      // 1 - на выход, 0 - вход
      DDRD = 0xFF;
      // 13 пин
      PORTD = 0b01000000; // 00 не исп. с 13 => 8

      // Настройка прерывания по таймеру - счетчик на 1 мс
      // "срабатывание прерыавния при совпадении"
      TCCR0A = (1 << WGM01);
      // Значение регистра А, при котором сработает прерывание
      /*
        CS02   CS01  CS00
        0      0     0     - Таймер/счетчик Т0 остановлен
        0      0     1     - Тактовый генератор CLK (х1)
        0      1     0     - CLK/8
        0      1     1     - CLK/64
        1      0     0     - CLK/256
        1      0     1     - CLK/1024
      */

      // установка предделителей частоты
      TCCR0B = (1 << CS00) | (0 << CS01); // Тактировать с делителем 64
      // TCCR0B = TCCR0B & B11111000 | B00000001;
      // Запуска работы всех прерываний, у которых есть на это допуск
      // 7F - 127
      OCR0A = 0x39; // начало отсчета до переполнения (F9 - 249)
      // Разрешаем прерывание при совпадении с регистром А
      TIMSK0 |= (1 << OCIE0A);
      sei();
      // Остановка прерываний
      // cli();
    }

    void loop()
    {
      /* Разгоняет выход Nano до 842 кГц
         digitalWrite только до 123 кГц
        delay(50000);
        if (PORTD == 0b01000000)
        {
        PORTD = 0b00000000;
        }
        else
        {
        PORTD = 0b01000000;
        }
      */

    }

    // Вызов функции ISR - прерывание
    ISR (TIMER0_COMPA_vect)
    {
      if (PIND == 0b01000000)
      {
        PORTD = 0b00000000;
      }
      else
      {
        PORTD = 0b01000000;
      }
    }
    Ошибки были в
    Код (C++):
    TCCR0B = (1 << CS00) | (0 << CS01); // Тактировать с делителем 64
    и в TCCR0A = (1 << WGM01);
    Не нужно было |= ставить. Максимальную частоту удалось поднять до 216 кГц. Но таймер можно OCR0A = 0x39 еще уменьшать, но частота при этом уже не увеличивается. Во что-то упирается. Пока не разобрался.
     
  10. ostrov

    ostrov Гуру

    Я поднимал до 4 что ли МГц, не помню уже.