Этюды для начинающих: blink и без delay, и без millis

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

bwn пишет:

Узрей чудо - вот она истинная многозадачность (правда из другого манускрипта).

PORTD |=B00110000, правда количество задач ограничено восемью.))))

Нещитова! Это еретическое, "внеардуинное" читерство!

Green
Offline
Зарегистрирован: 01.10.2015

И с внешним регистером сколько хош можно задач иметь. Без читерства.)

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Green пишет:

И с внешним регистером сколько хош можно задач иметь. Без читерства.)

Клапауций 298 пишет:

аппаратные хаки не пердлогать. О_О

AndreyTU
Offline
Зарегистрирован: 24.03.2018

Прошу совета, так как своих знаний еще не хватает.

Есть код стробоскопа, управляемого от энкодера (частота и скважность), все работает, только вот дрожание импульса довольно большое. Особенно это заметно на верхних частотах. Смотрел осциллографом.

Пробовал вот этот код 

 
#include <avr/io.h>
#include <util/delay.h>
long k = 1;
#define LED_PIN 5
int main( void )
{
  DDRB |= 1 << LED_PIN;      // вывод 9 как выход
  while (1) { // вечный цикл, аналог loop() 
    PORTB &= ~(1 << LED_PIN); // низкий уровень на выводе
    _delay_us(834 * k); // задержка 
    PORTB |= 1 << LED_PIN; // высокий уровень на выводе
    _delay_us(48 * k);
  }
  return 0;
}
Импульс стоит как вкопанный, но при вставке в основной код вместо цикла с micros, не компилится.
Возможно ли, если не победить, то хотя бы уменьшить дрожание импульса?
Сам код


// Выводы ЭНКОДЕРА
#define CLK 3  // Clock Подключаем к INT1, нельзя переназначать
#define DT 4  // второй вывод энкодера
#define SW 5  // switch кнопка энкодера, скважность при вращении

#define Min 66 // минимальное значение 
#define Max 1135 //максимальное значение
#define led_pin 13        // светодиод


#define step_freq 66.667       // шаг изменения частоты 
volatile uint32_t freq = 66.667; // нач. частота в Гц
volatile uint32_t paus;
volatile uint32_t time_light=819; // нач.время свечения светодиода в мкс
uint32_t oldcount;
boolean DT_last; // последнее состояние энкодера

void setup()
{
  pinMode(CLK, INPUT_PULLUP); // Clock Подключаем к INT1, нельзя переназначать
  pinMode(DT, INPUT_PULLUP); // второй вывод энкодера
  pinMode(SW, INPUT_PULLUP); // кнопка энкодера
  pinMode(led_pin, OUTPUT);  // светодиод 

  attachInterrupt(1, encoderTick, CHANGE); // прерывания от Энкодера

  DT_last = digitalRead(CLK);         // считываем положение CLK
}

void loop()
{
  paus = 17.31667*time_light;
  time_light=(28500/freq);
  digitalWrite(led_pin, 1);

  oldcount = micros();
  while ( (micros() - oldcount) < time_light) {} // длительность импульса светодиода
  digitalWrite(led_pin, 0);
  
  while ( (micros() - oldcount) < paus) {} // положительный полупериод
  oldcount = micros();
  
  while ( (micros() - oldcount) < paus) {} //отрицательный полупериод
}

//********************обработчики прерываний Энкодера*******************************
void encoderTick()     // Обратка прерываний от Энкодера
{
  uint8_t DT_now = digitalRead(CLK);       // считываем текущее положение CLK

  if (DT_now != DT_last && digitalRead(SW))   // если предыдущее и текущее положение не равны, значит был поворот
  {
    if (digitalRead(DT) != DT_now)    // если DT не равен CLK, значит вращение по часовой стрелке
    {
      if ( freq < Max ) freq += step_freq;   // прибавить
    } else {                                   // если DT равен CLK, значит вращение против часовой
      if ( freq > Min ) freq -= step_freq; // убавить
    }
  }
}

 

Понял свою ошибку, " Важно — параметр указанных функций может быть только константой!". Так что этот код не удастся вставить, т.к. энкодер изменяет параметры volatile

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AndreyTU пишет:
Понял свою ошибку, " Важно — параметр указанных функций может быть только константой!". Так что этот код не удастся вставить, т.к. энкодер изменяет параметры volatile
Не, не понял. Вернее, это-то верно, но ошибка в другом.

AndreyTU
Offline
Зарегистрирован: 24.03.2018

А по вопросу: Возможно ли, если не победить, то хотя бы уменьшить дрожание импульса?,

Видимо простыми средствами победить джиттер не получится.

По поводу - " не, не понял" есть какие-либо подсказки, как встроить управление портами через регистры?

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Главная проблема не в том, константы там или нет, можено переписать код так, чтобы были переменные (или наоборот, обйтись константами, Вы же не будете номера ног по ходу работы менять). Проблема в том, что Вы пытаетесь брать код, написанный для голого контроллера и вставляете есго в среду Ардуино. А это две большие разницы.

Что имеем:

1. Каждые 4 мкс Вашу программу прерывают и говорят: "ты покури пока, тут миллис-сервису надо свои дела подсчитать, чтобы миллис правильно пказывался".

2. Если захотите использовать Serial, то там тоже Ваша программа будет периодически прерываться и "курить" пока Serial делает свои дела.

Ну и как же её быть стабильной, если её в каждый момент могут неожиданно прервать на неопределённый период времени (он там не постоянный).

Почитайте пост #9 в этой теме, там это прямо на осциллограмме показано. Потом гляньте пост #19, всё поймёте.

Поймите, когда говорят, что ардуина - среда для блондинок, то имеется в виду "помигать светодиодом, желательно розовым". А если Вы используете слова "стробоскоп", "энкодер", "частота", "скважность" (которые с точки зрения любой блондинки, разумеется, ругательные), да ещё хотите, чтобы импульс не дрожал, так будьте любезны вести себя как мужчина, а не как блондинка. Вырубайте нахрен все ардуиновские "облегчалки жизни" и управляйте контроллером сами - держите ситуацию полностью под контролем, а не полагайтесь, что кто-то за Вас волшебным образом миллис подсчитает.

AndreyTU
Offline
Зарегистрирован: 24.03.2018

Спасибо, примерно так и думал, когда писал что просто сделать не получится.

Это сначала надо подучить Си и  asm, а потом курить Datasheet 328

Green
Offline
Зарегистрирован: 01.10.2015

Проще покурить таймер1 и получать сигнал с его выхода. Где то тут в проектах есть генератор, только там исходник безобразный.(

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

AndreyTU, в принципе есть готовый пример стробоскопа на таймере. Но лучше конечно самостоятельно до этого дорости :)

Cadil
Offline
Зарегистрирован: 27.06.2018

Свою проблему решил, поэтому снимаю вопрос. Успехов!

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

bwn пишет:

Клапауций 298 пишет:

да. или

digitalWrite (4 and 5, 1);

О_О

я же хочу пример многозадачности, как в манускрипте...

Узрей чудо - вот она истинная многозадачность (правда из другого манускрипта).

PORTD |=B00110000, правда количество задач ограничено восемью.))))

Не только! Смотрим процессор BI-671
Исполнение до 4-х инструкций в такт

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Для проверки возможности управления блинком набросал простенький скетч, всё работает как надо:
 

// Остановка таймера и перевод пина D10 в режим OUTPUT - TCCR1A &= ~0x30;
// Для проверки работы алгоритма стандартными средствами ардуино задействуем
// на пине 13 (синхронное тактирование с D10), для проверки сброса и установки таймера
// воспользуемся функцией millis()

unsigned long int old_Millis = 0;
unsigned int pause = 15000;

enum Prescalers {
   PRESCALER_1 = 1, PRESCALER_8 = 2, PRESCALER_64 = 3, PRESCALER_256 = 4, PRESCALER_1024 = 5
};

void set_Timer(){
   pinMode(13, OUTPUT);
   uint8_t prescaler = PRESCALER_256;
   uint16_t topValue = 62499;
   pinMode(10, OUTPUT);
   TCCR1A = 0x10;              // Инвертирование пина 10 по сравнению
   TCCR1B = 0x08 | prescaler;  // Установить СТС режим и делитель частоты
   OCR1A = topValue;           // установить TOP равным topValue
}

void start_Timer(){
  TCCR1A = 0x10;              // Инвертирование пина 10 по сравнению
}

void end_Timer(){
 TCCR1A &= ~0x30;
 digitalWrite(10,LOW);
}

void sync_Timer(){
    if (digitalRead(10)==HIGH){
    digitalWrite(13,HIGH);
        } else {
    digitalWrite(13,LOW);}
}

void setup() {
  set_Timer();
  old_Millis = millis();
}

void loop() {
  unsigned long int new_Millis = millis();
  if (new_Millis - old_Millis <= pause){
   sync_Timer();
    }else{
      end_Timer();
      sync_Timer();
      delay(10000);
      start_Timer();
      old_Millis = millis();
     }
    }

 

VadimS
Offline
Зарегистрирован: 28.11.2018

Помогите разобраться с Timer1. Не пойму, где затык :(

Генерирую импульсы переменной частоты на 9-м пине. К пину подключена пьезопищалка компьютерная. При работе скетча ясно слышны провалы в последовательности импульсов. Не могу понять, откуда они возникают. Если менять переменные "vStart", "vFinish", "a" то меняется минимальная, максимальная частота и скорость изменения частоты. Вся работа с таймером в функции mySetPeriod()

Вот скетч:

// Имитируется воспроизведение данных, полученных с датчика скорости мотоцикла
// при равномерном разгоне/торможении мотоцикла
// С ускорением а
// От скорости vStart 
// До скорости vFinish 
// С интервалом между замерами tInterval (миллисекунды - float)
// Данные по частотам предварительно собираются в массив, затем с помощью
// Timer1 на 9 пине генерируются импульсы переменной частоты (которые слушаем пьезопищалкой)
// За основу взяты библиотека TimerOne (расчет прескалера)
// и скетчи из "Этюдов для начинающих (blink без delay и millis)"

#define RESOLUTION 65536    // Timer1 is 16 bit

// Глобальные константы
const float a = 0.2;                           // Задаем ускорение  (м/с2) 
const float vStart = 0.0;                      // Начальная скорость (км/ч)
const float vFinish = 10.0;                   // Конечная скорость (км/ч)
const float tInterval = 100.0;                 // Интервал между измерениями (миллисекунды)

const float roundOfWheel = 1.956;              // Длина окружности колеса
const float gearRatio = 2.733;                 // Передаточное число колесо -> вторичный вал коробки
const float numberOfPulsesPerRevolution = 4.0; // Количество импульсов на один оборот вала

void initial()
{
  TCCR1A = 0x40;  //00101000 Переключение пина 9 по сравнению
  TCCR1B = 0x08;  //00001000 Установить СТС режим (Mode 4) и остановить таймер
}

void mySetPeriod(long microseconds) {
  char oldSREG;          // To hold Status Register while ints disabled
  unsigned char clockSelectBits = 0; // 00000000
  long cycles = (F_CPU / 2000000) * microseconds;
  // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
  if (microseconds > 0) {
    if (cycles < RESOLUTION)              clockSelectBits = _BV(CS10);               // no prescale, full xtal 00000001 или
    else if ((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11);               // prescale by /8         00000010 или
    else if ((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10);   // prescale by /64        00000011 или
    else if ((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12);               // prescale by /256       00000100 или
    else if ((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10);   // prescale by /1024      00000101 или
    else        cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10);    // request was out of bounds, set as maximum 00000101
  }
  //oldSREG = SREG;     // Сохраняем состояние регистра (?всех регистров)
  //cli();              // Запрещаем прерывания для записи 2-х байтового числа
  //OCR1A = cycles;     // OCR1A is TOP in CTM mode (4)
  //SREG = oldSREG;     // Восстанавливаем состояние регистра (?всех регистров)
  
  TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));     // 00001000
  OCR1A = cycles;     // OCR1A is TOP in CTM mode (4)
  if (microseconds > 0) {
    TCCR1B |= clockSelectBits;
  }
  //OCR1A = cycles;     // OCR1A is TOP in CTM mode (4)
}

void setup() {
  unsigned long currentMillis;                // для организации паузы вместо delay()
  unsigned long previousMillis = 0;           // храним время последнего измерения
  bool myDirection = true;                    // увеличиваем (истина) или уменьшаем (ложь) значение адреса массива i
  unsigned long rpm;

  // Предварительная подготовка массива
  float vStartMS = vStart * 1000.0 / 3600.0;   // Начальная скорость в м/с
  float vFinishMS = vFinish * 1000.0 / 3600.0; // Конечная скорость в м/с
  float vTMP = vStartMS;                       // Текущая скорость в м/с
  //Serial.begin(115200);
  // Сначала подсчитаем каким будет размер массива
  int j = 0;
  while (vTMP <= vFinishMS) {
    vTMP = vTMP + a * tInterval / 1000.0;      // Новая скорость в м/с ч/з tInterval миллисекунд
    j++;
  }
  // Создаем массив для данных размером j
  long arrayPeriod[j]; 

  // Заполняем массив данными
  vTMP = vStartMS;
  j = 0;
  while (vTMP <= vFinishMS) {
    float newV = vTMP + a * tInterval / 1000.0;         // Новая скорость в м/с ч/з tInterval миллисекунд
    float sTMP = (newV * newV - vTMP * vTMP)/(2.0 * a); // Путь в м, пройденный за tInterval миллисекунд
    float numberOfPulses = sTMP / roundOfWheel * gearRatio * numberOfPulsesPerRevolution; // Количество импульсов, сгенерированных за интервал tInterval
    long lengthOfImpuls = long(1000.0 / (numberOfPulses / tInterval));  // Средняя длина одного импульса в интервале (в микросекундах)
    //Serial.println( lengthOfImpuls );
    arrayPeriod[j] = lengthOfImpuls;
    vTMP = newV;                                      // Запомнили новую скорость
    j++;
  }
  //Serial.println( "===========" );
  // И запоминаем количество элементов в массиве
  int i = j;
   // Начинаем пищать в пищалку
  pinMode(9, OUTPUT);
  initial();
  
  j = 0;
  unsigned long longInterval = long(tInterval);

  //  Serial.println(k);
  while (true) {
    currentMillis = millis();
    if (currentMillis - previousMillis > longInterval) {
      previousMillis = currentMillis;
      rpm = arrayPeriod[j];
      //Serial.println( rpm );
      mySetPeriod(rpm);

      if (j == (i - 1)) { // Последний элемент массива, меняем направление на обратное ("тормозим")
        myDirection = false;
      }
      if (j == 0) { // Первый элемент массива, меняем направление на прямое ("разгоняемся")
        myDirection = true;
      }
      if (myDirection) {
        j++;
      }
      else {
        j--;
      }
    }
  }
}

void loop() {

}

 

VadimS
Offline
Зарегистрирован: 28.11.2018

Да, забыл сказать. IDE версии 1.8.7. Плата клон Arduino UNO на 328P, USB на CH340G (вроде правильно выразился)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

VadimS пишет:

Да, забыл сказать. IDE версии 1.8.7. Плата клон Arduino UNO на 328P, USB на CH340G (вроде правильно выразился)

Таймер работает сам по себе, то-есть асихронно от вашего скетча, это данность

lego1
Offline
Зарегистрирован: 09.03.2018

Здравствуйте форумчане. Подскажите пожалуйста, почему в этом коде не гаснет второй диод с задержкой? Обычная кнопка и простая временная задержка. 
 

// Задача: по нажатию кнопки включить два диода, по второму нажатию выключить один диод с задержкой
#include "OneButton.h"

 unsigned long currentTime;  //

typedef enum {
  ACTION_OFF,  // set LED "OFF".
  ACTION_ON,   // set LED "ON"
  } 
MyActions; 
OneButton button(A1, true);
int pin_Led = 4;
int pin_Ven = 7;
MyActions nextAction = ACTION_OFF; //  действия при запуске отсутствуют

void setup() {
  
  pinMode (pin_Led, OUTPUT); 
  pinMode (pin_Ven, OUTPUT); 
  button.attachClick(myClickFunction);  
  button.setDebounceTicks(80);
  currentTime = millis();       // считываем время, прошедшее с момента запуска программы
 }
 
void loop() {
  button.tick(); 
  
  if (nextAction == ACTION_OFF) {  
     currentTime = millis();                     // зафиксил время отсчёта
   digitalWrite (pin_Led, LOW);                   // погасил первый диод
   if(millis()- currentTime >=  10000){           // выждал 10 секунд
  digitalWrite (pin_Ven, !digitalRead (pin_Ven)); // Почему не гаснет?!
  } 
  
  } else if (nextAction == ACTION_ON) {
  digitalWrite (pin_Led, HIGH);
  digitalWrite (pin_Ven, HIGH);  
  }
            } 

void myClickFunction() {
  if (nextAction == ACTION_OFF)
    nextAction = ACTION_ON;
  else
    nextAction = ACTION_OFF;
} 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А с чего ему гаснуть? Условие в строке №31 всегда ложно. Вы же только что присволили currentTime = millis(), двумя строками выше, ну и с какого перепугу условие в №31 вдруг истинным станет?

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

потому что условие в строке 31 не выполнится никогда !

строка 29 не на своем месте.

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

что то форум глючит .... дубль за дублем

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Весь день сегодня

bwn
Offline
Зарегистрирован: 25.08.2014

ЕвгенийП пишет:

А с чего ему гаснуть? Условие в строке №31 всегда ложно. Вы же только что присволили currentTime = millis(), двумя строками выше, ну и с какого перепугу условие в №31 вдруг истинным станет?

Добрый Вы, Евгений Петрович, я бы пня дал. К этюду, как включение реле к кнопкам. ИМХО.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Весь день сегодня

Он не глючит, походу его заломали )))

Ошибка SMTP: не удается подключиться к серверу SMTP. Ошибка SMTP: не удается подключиться к серверу SMTP. Ошибка SMTP: не удается подключиться к серверу SMTP.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Попробовал новый калькулятор от ЕвгенияП
Хочется примеров для таймера 0 и 2 в режиме CTC

 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Так, сделайте! :)))

И дополните топик!

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Ворота пишет:

Так, сделайте! :)))

И дополните топик!

Так Евгений Петрович для Таймера2 уже точно сделал, смысл?

А впрочем для Таймера два надо для начала изменить предделители:
Останавливать таймер, можно загрузив в предделитель значение 0





enum Prescalers {
   PRESCALER_STOP = 0,
   PRESCALER_1 = 1, 
   PRESCALER_8 = 2, 
   PRESCALER_32 = 3, 
   PRESCALER_64 = 4, 
   PRESCALER_128 = 5, 
   PRESCALER_256 = 6, 
   PRESCALER_1024 = 7
};

// Таймера|   Делитель    |    Счетчик   |           Частоты |  Отклонение 
//      (2) Prescaler: 32; MaxValue: 138; Frequency: 1798.56Hz; Diff: 1.44Hz
//      (2) Prescaler: 32; MaxValue: 110; Frequency: 2252.25Hz; Diff: 2.25Hz
//  (0,1,2) Prescaler: 256; MaxValue: 138; Frequency: 224.82Hz; Diff: 0.18Hz


void setup() {
   uint8_t prescaler = PRESCALER_32;
   uint16_t topValue = 110;
   pinMode(11, OUTPUT);
   TCCR2A = 0x42;              // Инвертирование пина 11 по сравнению и режим CTC то OCR2A
   TCCR2B = 0x00 | prescaler;  // Установить СТС режим и делитель частоты
   OCR2A = topValue;           // установить TOP равным topValue
}

void loop() {
  delay(20000);
  uint8_t prescaler = PRESCALER_STOP;
  TCCR2B = 0x00 | prescaler;
}

enum Prescalers {
   PRESCALER_STOP = 0,
   PRESCALER_1 = 1, 
   PRESCALER_8 = 2, 
   PRESCALER_64 = 3, 
   PRESCALER_256 = 4, 
   PRESCALER_1024 = 5
};

// Таймера|   Делитель    |    Счетчик   |           Частоты |  Отклонение 
//      (2) Prescaler: 32; MaxValue: 138; Frequency: 1798.56Hz; Diff: 1.44Hz
//      (2) Prescaler: 32; MaxValue: 110; Frequency: 2252.25Hz; Diff: 2.25Hz
//  (0,1,2) Prescaler: 256; MaxValue: 138; Frequency: 224.82Hz; Diff: 0.18Hz


void setup() {
   uint8_t prescaler = PRESCALER_256;
   uint8_t topValue = 138;
   pinMode(6, OUTPUT);
   TCCR0A = 0x42;              // Инвертирование пина 6 по сравнению и режим CTC то OCR0A
   TCCR0B = 0x00 | prescaler;  // Установить СТС режим и делитель частоты
   OCR0A = topValue;           // установить TOP равным topValue
}

void loop() {
  
}

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Значит так, будем тактировать таймер №1 от внешнего сигнала.

Это всегда делается через пин 5 и ни через какой другой.

Тактироваться будем по нисходящему фронту, т.е. когда пин переходит с HIGH на LOW (по восходящему фронту тоже можно, в программе это закомментировано - см. текст)

Чтобы не  не дергать проводочком на землю, я для теста соединил пин 5 с пином 9 через резистор и подаю сигнал на пин 9 (простым digitalWrite), а т.к. он соединён с пином 5, таймер должен этот сигнал посчитать.

Вот текст

// Источник внешнего тактирования таймера 1 - ВСЕГДА пин 5!
static const uint8_t pinT1 = 5;	

// на этом пине мы иммитируем сигнал - любой пин
static const uint8_t pinSignal = 9;	

//
//	Инициализация таймера для внешнего тактирования
//
static void timerOneInit(void) {
	TCCR1A = 0; // на всякий сулчай, если кто-то до нас туда что-то записал
	TIMSK1 = 0; // на всякий сулчай, если кто-то до нас туда что-то записал
	//
	// Тактирование с пина T1 по ниспадающему фронту
	TCCR1B = bit(CS12) | bit(CS11); 
	// Тактирование с пина T1 по восходящему фронту
	//TCCR1B = bit(CS12) | bit(CS11) | bit(CS10); 
}

//
//	Сброс счётчика таймера 1
//
static inline void clearTimerOne(void) {
	TCNT1 = 0;
}

//
//	Чтение и, если надо, сброс счётчика таймера 1
//
static inline uint16_t readTimerOne(const bool clear = true) {
	const uint16_t res = TCNT1;
	if (clear) clearTimerOne();
	return res;
}

//
//	Выдать сигнал 
// (пин "pinSignal" соединён с пятым пином через резистор)
//
static void issueSignal(void) {
	digitalWrite(pinSignal, HIGH);
	digitalWrite(pinSignal, LOW);
}

void setup() {
	pinMode(pinT1, INPUT_PULLUP);
	pinMode(pinSignal, OUTPUT);
	Serial.begin(115200);
	Serial.println("Fun begins!");
	timerOneInit(); // Подготовить таймер
	clearTimerOne(); // очистить таймер
	issueSignal(); // выдать сигнал
	issueSignal(); // выдать сигнал
	issueSignal(); // выдать сигнал
	issueSignal(); // выдать сигнал
	Serial.print("Signals captured:");
	Serial.println(readTimerOne()); // напечатать количество пойманных сигналов.
}

void loop() {
}

Печатает число 4, т.к. мы подаём 4 сигнала (строки 52-55). Размножьте эти строки, скажем до 9 - будет печатать число 9.

Техника работы понятна?

Теперь спокойно конфигурируете таймер, подключаете свой источник сигнала, а секунду считаете хоть через millis, хоть другим таймером - и все дела.

Позапускайте, поменяйте и убедитесь, что пример понятен.

Smith2007 пишет:

И если не затруднит - второй пример как вместо управления пинами (none, toggle, clear, set) инициировать программное прерывание и выполнить указанную процедуру.

На каком таймере?

А такая схема как реализуется? (используем Таймер 1 и Таймер 2), тактировать Таймер 2 от Таймера 1 настроенного на выдачу меандра нужной частоты, при этом таймер 2 тоже выдает меандр, кратный меандру 1-го Таймера, к примеру делим частоту тактирования на 10, тактирование по переднему фронту, для синхронизации частот

И еще вопрос, если тактировать по восходящему сигналу, надо ли пин тактирования (5) подтягивать вверх?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

не, ну правда, Вы радиолюитель, а я программист - кто кому должен вопросы задавать про пины и сигналы? Думаю, Вы лучше меня знаете.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

не, ну правда, Вы радиолюитель, а я программист - кто кому должен вопросы задавать про пины и сигналы? Думаю, Вы лучше меня знаете.

Я неплохо знаком с ТТЛ логикой, там неиспользуемые пины тянут к питанию, для снижения энергопотребления и улучшения помехозащищенности, ток то вытекающий, рабочие пины соединяют напрямую и никаких подтяжек, подумалось, что есть особенности применения при стороннем тактировании, там жеж у нутрях коммутатор видимо )))

Таймер 2 тоже видимо можно внешне тактировать?

Buldakov
Offline
Зарегистрирован: 17.01.2016

Вопрос по таймерам.

Был стандартный контроллер Arduino Uno на 328Р. Приобрел Arduino micro на 32U4. Там, как я понял работа с таймерами осуществляется по другому. Раньше таймер 2 был настроен на прерывание с частотой 2500 раз в секунду.

TCCR2A  = (0<<COM2A1)|(1<<COM2A0)|(1<<WGM21)|(0<<WGM20); //CTC mode
TCCR2B  = (0<<CS22) |(1<<CS21)| (1<<CS20);//делитель CLK/32
OCR2A   = 199 ;                    //Регистр сравнения. частота таймера 2 2500 Гц.
TIMSK2 |= (1 << OCIE2A);   //enable timer compare interrupt

Сейчас этот код естественно не работает. Как я понял необходимо перейти на таймер 4 и настроить на частоту тактирования 48 мгц. Пока нашел только это. На английском.

http://forum.arduino.cc/index.php?topic=261869.0

Может кто нибудь отосласть к описанию с конкретнымы примерами в коде на русском языке? Из описания на английском ничего не понятно. На русском нашел только описание регистров таймера . Но с непонятными примерами.

http://microsin.net/programming/avr/10-bit-high-speed-timer-counter4.html

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

По-русски не знаю. 

Но имейте в виду, что с таймерами на 32U4 есть засада. Там их то ли 4, то ли 5: в одних даташитах описаны 4 (0,1,3 и 4), а в других ещё и 2-ой есть.

Работают все пять. Ссылку на даташиты могу дать. Но он не по-русски.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Про таймер2 в 32u4 как то обсуждали. Он там есть, но не для всех :)

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

dimax пишет:

Он там есть, но не для всех :)

Для нормальных пацанов :)

Buldakov
Offline
Зарегистрирован: 17.01.2016

Поскольку примеры на буржуинском вместе с описанием. Вернемся к стандартным контроллерам с внешней микросхемой usb. Лучше использовать старое оборудование, чем непонятное новое.

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Buldakov пишет:

Лучше использовать старое оборудование, чем непонятное новое.

Лучше освоить язык, чтобы не ограничивать себя.

Buldakov
Offline
Зарегистрирован: 17.01.2016

Можно было просто сказать что таймер1 32u4 работает аналогично 328P. И ничего менять не надо.

int n;
void setup(){
pinMode(17, OUTPUT);
//---Настройка таймера 1--------------------------------------------
TCCR1A = 0;TCCR1B = 0;TCNT1  = 0;
TCCR1B |= (1<<WGM12);   // Режим CTC (сброс по совпадению)
TCCR1B |= (1<<CS10)|(1<<CS11);    // Тактирование от CLK/64.
OCR1A=24999; //отсчитать 2 5000 входных импульсов до прерывания F=10 гц.
TIMSK1 |= (1 << OCIE1A);  // Разрешить прерывание по совпадению
}
//---Прерывание по таймеру 1----------------------------------------
ISR(TIMER1_COMPA_vect)          // timer compare interrupt service routine
{
if (n<2) digitalWrite(17, LOW) ;                 
if (n>=2) {digitalWrite(17, HIGH);n=0;}    
n=n+1;                                                      
}
void loop(){}

Иван_
Offline
Зарегистрирован: 23.02.2018

Вначале выражаю благодарность ЕвгенийП за создание данной темы с благодаря ей почти разобрался в работе таймеров но остались некоторые вопросы которые прошу пояснить.  Как заставить работать два выхода на одном таймере работать с разной частотой. То есть один пин допустим 46 (использую Мегу) работал с регистром OCR5A  а второй 45 работал с регистром OCR5B. Пока знаний хватило что бы  два выхода работали с одинаковой частотой.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Иван_ пишет:

Вначале выражаю благодарность ЕвгенийП за создание данной темы с благодаря ей почти разобрался в работе таймеров но остались некоторые вопросы которые прошу пояснить.  Как заставить работать два выхода на одном таймере работать с разной частотой. То есть один пин допустим 46 (использую Мегу) работал с регистром OCR5A  а второй 45 работал с регистром OCR5B. Пока знаний хватило что бы  два выхода работали с одинаковой частотой.

В таблице 17-2 не увидел возможности такого режима, хотя несколько выше писалось - На рис. 17-4 показана структурная схема блока сравнения выходных данных. Маленькая буква " n” в именах регистров и битов указывает на то, что номер устройства (n = n для таймера / счетчика n), а “x” обозначает выходной блок сравнения (A/B/C). То
элементы структурной схемы, которые не являются непосредственно частью выходного блока сравнения, заштрихованы серым цветом.
Ждём, знающие уточнят.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Иван_, вот подумайте сами, как работает СТС режим?

Допустим, что мы управляем длительностью через ICRn.

Тогда счётчик ходит от 0 до ICRn, затем снова сбрасывается в 0. Уровни же на пинах OCnA/B/C изменяются в момент достижения счётчиком значений, сохранённых в регистрах OCRnA/B/C соответственно.

Это всё. Получается, что разные частоты на пинах OCnA/B/C Вы не получите, правда, можно поиграть фазами. Например, если в  OCRnA лежит значение вдвое меньшее, чем в  OCRnВ, то он будет изменять вдвое раньше, но и ждать следующего изменения будет дольше. Т.е. частота останется одинаковой, а вот фазу мы сдвинули.

Вот в этом скетче OCR5C вдвое меньше, чем OCR5B и втрое меньше, чем OCR5А. Цвета линий на осциллограмме прописаны в комментариях. Полюбуйтесь на сигнал (на сдвиг фаз)

void setup(void){
	pinMode(44, OUTPUT); // OC5C - красный
	pinMode(45, OUTPUT); // OC5B - cиний
	pinMode(46, OUTPUT); // OC5A - жёлтый
	
	TCCR5A = bit(COM5A0) | bit(COM5B0) |bit(COM5C0);
	TCCR5B = bit(WGM52) | bit(WGM53) | bit(CS52) | bit(CS50);
	ICR5 = 75;
	OCR5A = 75;
	OCR5B = 50;
	OCR5C = 25;
}

void loop(void) {}

Что же касается того, можно ли их заставить работать с разной частотой, то, как мы уже выяснили, без дополнительных телодвижений - нет, нельзя. А вот, с дополнительными - есть у меня одно идейка, но сейчас я в гостиничном номере и живой меги у меня нет, есть только протеус. На симуляторе моя идея не заработала - то ли идея тухлая, то ли симулятор кривой. Могу вернуться к экспериментам, когда доберусь домой и возьму живую, железную мегу, если Вам это будет всё ещё актуально.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

... если Вам это будет всё ещё актуально.

Это и мне интересно, получить на одном таймере с разных пинов частоту отличающуюся в два - два с половиной раза, сама возможность интересна

sadman41
Offline
Зарегистрирован: 19.10.2016

Если колхозить, то выбрал кратную частоту и сиди в обработчике, перебрасывай биты на раз-два-три ;)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Не, ну это-то понятно, речь-то как СТС заставить. Я вот попробовал было из прерывания по совпадению для одной форсить совпадения для других через биты FOCnA/B/C - не обломилось (по крайней мере, в протеусе).

sadman41
Offline
Зарегистрирован: 19.10.2016

Про FOC я думал, но что-то мне внутренний голос говорит, что все равно нужно OCR-ы хитро и связно рассчитывать. Это, конечно, в итоге уменьшило бы время нахождения в обработчике, но не исключило его. А так, как требуемая частота неизвестна, то и неясен и смысл упираться в этот алгоритм. Мошт там вообще блинка хватит.

Иван_
Offline
Зарегистрирован: 23.02.2018

ЕвгенийП спасибо за ответ. Вопрос весьма интересен и актуален но быстрых ответов от меня ждать не стоит так как что бы дойти до сути ответов мне их надо перечитать не один раз и не в один день.  Перечитать даташиты поэкспериментировать и обдумать не спеша.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

ua6em пишет:

Это и мне интересно, получить на одном таймере с разных пинов частоту отличающуюся в два - два с половиной раза, сама возможность интересна

Да никаких проблем:

pinMode(11,OUTPUT);
pinMode(3,OUTPUT);
TCCR2A=(1<<COM2A0)|(3<<COM2B0)|(1<<WGM21) | (1<<WGM20); 
TCCR2B=(1<<WGM22)|(7<<CS20);
OCR2A=128;
OCR2B=64;

При указанных параметрах с 11 ноги пойдёт частота ~60 Герц, с 3й ноги ~120 Герц

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, в режиме ШИМ -  типа да, спасибо. Я вот не въеду что у меня там в режиме СТС не вышло. Но это уж дома - на железе.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

ЕвгенийП, а в СТС это невозможно :)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

dimax пишет:

Да никаких проблем:

pinMode(11,OUTPUT);
pinMode(3,OUTPUT);
TCCR2A=(1<<COM2A0)|(3<<COM2B0)|(1<<WGM21) | (1<<WGM20); 
TCCR2B=(1<<WGM22)|(7<<CS20);
OCR2A=128;
OCR2B=64;

При указанных параметрах с 11 ноги пойдёт частота ~60 Герц, с 3й ноги ~120 Герц

а как с предделителем поиграться - TCCR2B=(1<<WGM22)|(3<<CS20);?

Вот так по крупицам и собираются приёмчики программирования )))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вам верю. Но понять-то всё равно хочу. Что не так с попыткой форсить матчи через FOC биты?

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

ЕвгенийП пишет:

Вам верю. Но понять-то всё равно хочу. Что не так с попыткой форсить матчи через FOC биты?

У меня чесс гря  не хватает соображалки понять как это возможно, в смысле изменить частоту фок-ами..