Главная страница
Навигация по странице:

  • Использование таймеров

  • Временные задержки, таймеры, прерывания


    Скачать 226.59 Kb.
    НазваниеВременные задержки, таймеры, прерывания
    Дата31.03.2022
    Размер226.59 Kb.
    Формат файлаdocx
    Имя файлаKonspekt (1).docx
    ТипДокументы
    #432656

    Временные задержки, таймеры, прерывания.

    Задержки

    Вариант 1 – функция Delay(ms);

    void setup() {

    pinMode(13, OUTPUT); // 13 пин объявляется выходным

    }

    void loop() {

    digitalWrite(13, HIGH); // включаем светодиод, подключенный к 13 пину

    delay(1000); // задержка в 1с (1000 мс)

    digitalWrite(13, LOW); // выключаем светодиод, подключенный к 13 пину

    delay(1000);

    }

    Недостаток – пока идёт задержка по delay процессор ничего не выполняет (простаивает), не происходит опорос портов, т.е. процессор может пропустить сигнал, пришедший в порт.

    Вариант 2 ­­– использование millis() (функция встроенная, работает по таймеру, сообщает количество миллисекунд, прошедших с начала работы процессора).

    long int timer = 0; // объявление глобальных переменных

    void setup() { // предустановка, задаются начальные параметры

    digitalWrite(13, 0); // сброс 13 пина в 0

    }

    void loop() { // основной цикл программы

    if (millis() - timer >= 500) { //разница (500 мс)

    timer = millis();

    digitalWrite(13,!digitalRead(13)); // 13 пин ставится в противоположное состояние

    }

    }

    Недостаток ­ ­- если в основном цикле что-то вызовет задержку во времени, то период может «уйти».

    Использование таймеров

    Вариант 3 – использование написанных библиотек для работы с таймерами.

    #include "GyverTimer.h" // подключили библиотеку для работы с таймерами
    GTimer TIM1(MS); // объявили таймер, считающий в миллисиекундах
    void setup() {

    TIM1.setInterval(2000); // задали интервал отсчёта

    }
    void loop() {

    if (TIM1.isReady()) // проверка условия, если таймер отсичтал интервал, то выполнить действие

    digitalWrite(13, !digitalRead(13));

    }

    Вариант 4 – работа со встроенными таймерами напрямую.

    #include

    #include

    #define LED 13

    void setup() { // инициализация Timer1

    cli(); // отключить глобальные прерывания

    TCCR1A = 0; // установить регистры в 0

    TCCR1B = 0;

    OCR1A = 7812; // установка регистра совпадения

    TCCR1B |= (1 << WGM12); // включить CTC режим

    //TCCR1B |= (1 << CS10); // Установить биты на коэффициент деления 1024

    TCCR1B |= (1 << CS12);

    TIMSK1 |= (1 << OCIE1A); // включить прерывание по совпадению таймера

    sei(); // включить глобальные прерывания

    pinMode(LED, OUTPUT);

    }
    ISR(TIMER1_COMPA_vect){

    digitalWrite(LED, !digitalRead(LED));

    }

    void loop() {}

    Так как наш микроконтроллер работает на частоте 16 МГц, а мы хотим управлять светодиодом, для увеличения времени счета нашего таймера, мы поделим его тактовую частоту на 1024:

    TCCR1B |= (1 << CS10); 
    TCCR1B |= (1 << CS12);

    Таким образом мы получаем скорость счета (тактирования) 15625 Гц или 64,0е-6 секунды. Нам нужно, что бы счетчик менял свое состояние раз в 0,5 секунду, разделив 0,5/64,0е-6 мы получаем 7812,5. Таким образом в регистр OCR1A нам необходимо записать 7813. Но с учетом того, что сброс счетчика в ноль занимает один такт, нам необходимо записать в регистр OCR1A  – 7812.

    Регистр TCCR1A :



    Регистр TCCR1В :







    Прерывания.

    Пример 1.

    void setup() {

    attachInterrupt(0, led1, RISING); // добавили нулевое прерывание (пин 2) , вызывающее функцию led1, срабатывает по восходящему фронту (RISING)

    attachInterrupt(1, led2, FALLING); // добавили первое прерывание (пин 3) , вызывающее функцию led2, срабатывает по восходящему фронту (FALLING)

    }
    void loop() { // в основном цикле программы ничего не происходит

    }
    void led1() {

    digitalWrite(12, !digitalRead(12));

    }
    void led2() {

    digitalWrite(11, !digitalRead(11));

    }

    Задача – написать код, который при нажатии одной кнопки выдаёт сигнал «бегущий огонь», с промежутком переключения между светодиодами 500 мс, при нажатии второй кнопки промежуток увеличивается. Добавить ограничение промежутка до 3000 мс. (Рекомендуется использовать прерывания).



    long int counter = 0;

    volatile int Period = 500; // переменная, использующаяся в функции прерывания имеет приставку volatile

    volatile bool flag = false;

    void setup() {
    attachInterrupt(0, runnig_fire, RISING);

    attachInterrupt(1, change_period, FALLING);

    }
    void loop() {

    if (flag)

    {

    digitalWrite(11, HIGH);

    delay(Period);

    digitalWrite(12, HIGH);

    digitalWrite(11, LOW);

    delay(Period);

    digitalWrite(10, HIGH);

    digitalWrite(12, LOW);

    delay(Period);

    flag = false;

    }

    else

    {

    digitalWrite(12, LOW);

    digitalWrite(11, LOW);

    digitalWrite(10, LOW);

    }

    }
    void runnig_fire() {

    flag = true;

    }
    void change_period() {

    Period += 1000;

    if (Period > 3000)

    Period = 500;

    }

    Второй вариант без delay.

    long int counter = 0;

    volatile int Period = 500;

    volatile bool flag = false;

    void setup() {

    Serial.begin(9600);

    attachInterrupt(0, runnig_fire, RISING); // прерывание по кнопке, которое вызывает функцию бегущего огня

    attachInterrupt(1, change_period, FALLING); // прерывание по кнопке, увеличивает период

    }
    void loop() {

    if (flag)

    { counter=millis();

    while (millis() - counter < Period)

    {

    digitalWrite(11, HIGH);

    }

    digitalWrite(11, LOW);

    counter=millis();

    while (millis() - counter < Period)

    {

    digitalWrite(12, HIGH);

    }

    digitalWrite(12, LOW);

    counter=millis();

    while (millis() - counter < Period)

    {

    digitalWrite(10, HIGH);

    }

    flag = false;

    }

    else

    {

    digitalWrite(12, LOW);

    digitalWrite(11, LOW);

    digitalWrite(10, LOW);

    }

    }
    void runnig_fire() {

    flag = true;

    }
    void change_period() {

    Period += 1000;

    if (Period > 3000)

    Period = 500;

    }


    написать администратору сайта