Регулируемый таймер обратного отсчета на arduino mega 2560

Содержание

“Универсальное” электромагнитное реле

Электромагнитное реле является по сути управляемым механическим выключателем: подали на него ток – оно замкнуло контакты, сняли ток – разомкнуло. Контакты являются именно контактами: металлическими “пятаками”, которые прижимаются друг к другу. Именно поэтому такое реле может управлять как нагрузкой постоянного, так и переменного тока.

Сама катушка реле является неслабой индуктивной нагрузкой, что приводит к дополнительным проблемам (читай ниже), поэтому для управления “голым” реле нам понадобится дополнительная силовая и защитная цепь.

После изучения данного урока вы сами сможете её составить (транзистор и диод), а сейчас мы поговорим о модулях реле: готовая плата, на которой стоит само реле, а также цепи коммутации, защиты и даже оптическая развязка. Такие модули бывают “семейными” – с несколькими реле на борту. Спасибо китайцам за это! Смотрите варианты у меня в каталоге ссылок на Али.

Такое реле сделано специально для удобного управления с микроконтроллера: пины питания VCC (Vin, 5V) и GND подключаются к питанию, а далее реле управляется логическим сигналом, поданным на пин IN. С другой стороны стоит клеммник для подключения проводов, обычно контакты подписаны как NO, NC и COM. Это общепринятые названия пинов кнопок, переключателей и реле:

  • COM – Common, общий. Реле является переключающим, и пин COM является общим.
  • NO – Normal Open, нормально открытый. При неактивном реле данный контакт не соединён с COM. При активации реле он замыкается с COM.
  • NC – Normal Closed, нормально закрытый. При неактивном реле данный контакт соединён с COM. При активации реле он размыкается с COM.

Подключение нагрузки через реле думаю для всех является очевидным:

Важный момент: катушка реле в активном режиме потребляет около 60 мА, то есть подключать больше одного модуля реле при питании платы от USB не рекомендуется – уже появятся просадки по напряжению и помехи:

Такие модули реле бывают двух типов: низкого и высокого уровня. Реле низкого уровня переключается при наличии низкого сигнала (GND) на управляющем пине . Реле высокого уровня соответственно срабатывает от высокого уровня . Какого типа вам досталось реле можно определить экспериментально, а можно прочитать на странице товара или на самой плате. Также существуют модули с выбором уровня:

На плате, справа от надписи High/Low trigger есть перемычка, при помощи которой происходит переключение уровня. Электромагнитное реле имеет ряд недостатков перед остальными рассмотренными ниже способами, вы должны их знать и учитывать:

  • Ограниченное количество переключений: механический контакт изнашивается, особенно при большой и/или индуктивной нагрузке.
  • Противно щёлкает!
  • При большой нагрузке реле может “залипнуть”, поэтому для больших токов нужно использовать более мощные реле, которые придётся включать при помощи… маленьких реле. Или транзисторов.
  • Необходимы дополнительные цепи для управления реле, так как катушка является индуктивной нагрузкой, и нагрузкой самой по себе слишком большой для пина МК (решается использованием китайского модуля реле).
  • Очень большие наводки на всю линию питания при коммутации индуктивной нагрузки.
  • Относительно долгое переключение (невозможно поставить детектор нуля, читай ниже), при управлении индуктивными цепями переменного тока можно попасть на большой индуктивный выброс, необходимо ставить искрогасящие цепи.

Важный момент связан с коммутацией светодиодных светильников и ламп, особенно дешёвых: у них прямо на входе стоит конденсатор, который при резком подключении в цепь становится очень мощным потребителем и приводит к скачку тока. Скачок может быть настолько большим, что 15-20 Ваттная светодиодная лампа буквально сваривает контакты реле и оно “залипает”! Данный эффект сильнее выражен на дешёвых лампах, будьте с ними аккуратнее (за инфу спасибо DAK). При помощи реле можно плавно управлять сильно инерционной нагрузкой, такой как большой обогреватель. Для этого нужно использовать сверхнизкочастотный ШИМ сигнал, у меня есть готовая библиотека. Не забываем, что реле противно щёлкает и изнашивается, поэтому для таких целей лучше подходит твердотельное реле, о котором мы поговорим ниже.

https://youtube.com/watch?v=m3bF54wr4U0

Видео. Освещение дома на Ардуино

— Для питания платы и LED ленты используется блок питания на 12 Вольт с выходным напряжением 1 Ампер. При этом общее потребление электроэнергии, если включить все освещение сразу, не превышает 15 Ватт, что сравнимо с одной энергосберегающей лампочкой. Но при этом освещение на Arduino работает в санузле (туалет совмещен с ванной), в прихожей, в коридоре на 2 этаже, в гостиной (зона отдыха и зона кухни). Для управления освещением на Arduino используется пульт от телевизора. Кроме того, что автоматическое включение подсветки в ванной и коридоре — это очень удобно, можно еще и сэкономить на оплате за электроэнергию. Также в скетче прописан цикл для создания эффекта присутствия, когда вы уезжаете из дома на несколько дней. Освещение включается и выключается в разных комнатах по заданному алгоритму.

Шаг первый. Подключаем светодиод

Самая яркая деталь устройства — RGB-светодиод. В его прозрачном корпусе спрятаны сразу три источника света: красный (R, от английского red), зелёный (G — green)и синий (B — blue) светодиоды. Поэтому ног у него больше, чем у одноцветных диодов. Самая длинная из четырёх — это общий минус. Чуть короче — плюс зелёного светодиода. Самые короткие — плюсы красного и синего цветов. Соедините минус с сопротивлением, а сопротивление подключите к контакту GND на Arduino. Теперь подключите красный, зелёный и синий плюс к контактам 4,3 и 2.

Это стандартная схема подключения, но вы всегда можете проверить свой светодиод. Просто подключите плюс к контакту 5V на Ардуино. На этом контакте всегда есть напряжение, поэтому светодиод загорится. Главное, не забывайте подключать минус через сопротивление, иначе светодиод сгорит.

Проверим как работает светодиод. Для этого прошьём плату простым скетчем. Эта программа раз в секунду будет переключать цвет светодиода.

Основной код программы находится в закольцованной функции (loop в переводе означает петля). Эта функция будет повторятся снова и снова, пока не выключить плату. Это удобно для повторяющихся событий и постоянного опроса датчиков.

Объяснение программы для Arduino

Полный код программы приведен в конце статьи, здесь же рассмотрим его наиболее существенные фрагменты.
Сначала в программе необходимо подключить библиотеки для работы с клавиатурой и ЖК дисплеем и инициализировать необходимые переменные.

Arduino

#include <LiquidCrystal.h>
#include <Keypad.h>

long int set1;
long int set2;
long int set3;
long int set4;
long int j;
int t1, t2, t3, t4, t5, t6;
int r1, r2, r3;
char key;
String r;
String hours;
String minutes;
String seconds;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

#include <LiquidCrystal.h>
#include <Keypad.h>
 

longintset1;

longintset2;

longintset3;

longintset4;

longintj;

intt1,t2,t3,t4,t5,t6;

intr1,r2,r3;

charkey;

Stringr8;

Stringhours;

Stringminutes;

Stringseconds;

Далее в программе мы сообщаем количество строк и столбцов в используемой нами клавиатуре и задаем карту клавиш клавиатуры.

Arduino

const byte ROWS = 4; // четыре строки
const byte COLS = 4; // четыре столбца

char keys = {
{‘1′,’2′,’3′,’A’},
{‘4′,’5′,’6′,’B’},
{‘7′,’8′,’9′,’C’},
{‘*’,’0′,’#’,’D’}
};

1
2
3
4
5
6
7
8
9

constbyteROWS=4;// четыре строки

constbyteCOLS=4;// четыре столбца

charkeysROWSCOLS={

{‘1′,’2′,’3′,’A’},

{‘4′,’5′,’6′,’B’},

{‘7′,’8′,’9′,’C’},

{‘*’,’0′,’#’,’D’}

};

Затем мы сообщаем плате Arduino к каким ее контактам подключены контакты строк и столбцов клавиатуры, а также контакты ЖК дисплея.

Arduino

byte rowPins = { 6, 7, 8, 9 }; // подсоедините контакты клавиатуры ROW0, ROW1, ROW2 и ROW3 к этим контактам Arduino
byte colPins = { 10, 11, 12, 13 };// подсоедините контакты клавиатуры COL0, COL1, COL2 и COL3 к этим контактам Arduino
LiquidCrystal lcd(A0, A1, 5, 4, 3, 2); // создаем объект ЖК дисплея с параметрами (rs, enable, d4, d5, d6, d7)

1
2
3

byterowPinsROWS={6,7,8,9};// подсоедините контакты клавиатуры ROW0, ROW1, ROW2 и ROW3 к этим контактам Arduino

bytecolPinsCOLS={10,11,12,13};// подсоедините контакты клавиатуры COL0, COL1, COL2 и COL3 к этим контактам Arduino

LiquidCrystallcd(A0,A1,5,4,3,2);// создаем объект ЖК дисплея с параметрами (rs, enable, d4, d5, d6, d7)

Следующая команда создает объект клавиатуры в программе.

Arduino

Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

1 Keypadkpd=Keypad(makeKeymap(keys),rowPins,colPins,ROWS,COLS);

В функции setFeedingTime() после нажатия кнопки мы можем ввести время, с которого начнется отсчет, для начала счета после этого необходимо нажать клавишу D на клавиатуре.

Arduino

void setFeedingTime()
{
feed = true;
int i=0;

lcd.clear();
lcd.setCursor(0,0);
lcd.print(«Set feeding Time»);
lcd.clear();
lcd.print(«HH:MM:SS»);
lcd.setCursor(0,1);

while(1){
key = kpd.getKey();
char j;

if(key!=NO_KEY){
lcd.setCursor(j,1);
lcd.print(key);
r = key-48;
i++;
j++;

if (j==2 || j == 5)
{
lcd.print(«:»); j++;
}
delay(500);
}

if (key == ‘D’)
{key=0; break; }
}
lcd.clear();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

voidsetFeedingTime()

{

feed=true;

inti=;

lcd.clear();

lcd.setCursor(,);

lcd.print(«Set feeding Time»);

lcd.clear();

lcd.print(«HH:MM:SS»);

lcd.setCursor(,1);

while(1){

key=kpd.getKey();

charj;

if(key!=NO_KEY){

lcd.setCursor(j,1);

lcd.print(key);

ri=key-48;

i++;

j++;

if(j==2||j==5)

{

lcd.print(«:»);j++;

}

delay(500);

}

if(key==’D’)

{key=;break;}

}

lcd.clear();

}

В функции void setup() мы инициализируем ЖК дисплей и последовательную связь, а также задаем режим работы (на ввод или вывод данных) для используемых контактов.

Arduino

void setup()
{
lcd.begin(16,2);
Serial.begin(9600);
pinMode(A0, OUTPUT);
pinMode(A1, OUTPUT);
pinMode(A3, INPUT);
pinMode(A4, OUTPUT);
}

1
2
3
4
5
6
7
8
9

voidsetup()

{

lcd.begin(16,2);

Serial.begin(9600);

pinMode(A0,OUTPUT);

pinMode(A1,OUTPUT);

pinMode(A3,INPUT);

pinMode(A4,OUTPUT);

}

Реле времени на микросхемах

Транзисторные схемы таймеров имеют много недостатков: сложность определения времени задержки, необходимость разрядки конденсатора перед следующим пуском, малые интервалы срабатывания. Микросхема NE555, получившая название «интегральный таймер», давно завоевала популярность. Ее применяют в промышленности, но можно увидеть множество схем, по которым делают реле времени своими руками.

Временная выдержка задается сопротивлениями R2, R4 и конденсатором С1. Контакт подключения нагрузки К1.1 замыкается при нажатии на кнопку SB1, а затем он самостоятельно размыкается после задержки, продолжительность которой определяется из формулы: tи = 1.1R2∙R4∙C1.

При повторном нажатии на кнопку процесс повторяется.

Во многих бытовых приборах применяются микросхемы с реле времени. Инструкция для пользования — это необходимый атрибут правильной эксплуатации. Она также составляется для таймеров, созданных своими руками. От этого зависит их надежность и долговечность.

Схема работает от простейшего блока питания на 12 В из трансформатора, диодного моста и конденсатора. Ток потребления составляет 50 мА, а реле коммутирует нагрузку до 10 А. Регулируемую задержку можно сделать от 3 до 150 с.

Blinking LED with timer overflow interrupt

same example like before but now we use the timer overflow interrupt. In this case Timer1 is running in normal mode.

The timer must be pre loaded every time in the interrupt service routine.

/*
* timer and interrupts
* Timer1 overflow interrupt example
* more infos: https://oscarliang.com
*/

#define ledPin 13

void setup()
{
pinMode(ledPin, OUTPUT);

// initialize Timer1
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;

TCNT1 = 34286; // preload timer 65536-16MHz/256/2Hz
TCCR1B |= (1 &lt;&lt; CS12); // 256 prescaler
TIMSK1 |= (1 &lt;&lt; TOIE1); // enable timer overflow interrupt
interrupts(); // enable all interrupts
}

ISR(Timer1_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
TCNT1 = 34286; // preload timer
digitalWrite(ledPin, digitalRead(ledPin) ^ 1);
}

void loop()
{
// your program here…
}

Кухонный таймер Ардуино с энкодером

Сейчас рассмотрим, как сделать таймер на Ардуино своими руками с энкодером и LCD. Принцип управления, подобен предыдущему варианту. Поворотом ручки энкодера можно задать необходимый временной интервал, а нажатием на ручку можно запускать и останавливать обратный отсчет времени. Далее размещена схема сборки проекта на Arduino Nano, этот проект можно собрать и на плате Arduino Uno.

Скетч таймера обратного отсчета времени

#include <Wire.h>                              // библиотека для протокола I2C
#include <LiquidCrystal_I2C.h>        // библиотека для LCD 1602 
LiquidCrystal_I2C LCD(0x27, 20, 2);  // присваиваем имя дисплею

#include <RotaryEncoder.h>                // библиотека для энкодера
RotaryEncoder encoder(4, 2);       // пины подключение энкодера (DT, CLK)

// задаем шаг энкодера, максимальное и минимальное значение
#define STEPS  1
#define POSMIN 0
#define POSMAX 30

int lastPos, newPos;
boolean buttonWasUp = true;

byte w = 0;

int SEC = 0;
int MIN = 0;
unsigned long timer;

void setup() {
   pinMode(6, INPUT_PULLUP);   // пин для кнопки энкодера
   encoder.setPosition(0 / STEPS);

   pinMode(10, OUTPUT);   // подключаем светодиод и зуммер
   pinMode(12, OUTPUT);
   digitalWrite(10, HIGH);

   LCD.init();                        // инициализация дисплея
   LCD.backlight();              // включение подсветки

   LCD.setCursor(2, 0);
   LCD.print("TIMER  STOP");
   LCD.setCursor(5, 1);
   LCD.print(MIN);
   LCD.print(" : ");
   LCD.print(SEC);
}

void loop() {

   // проверяем положение ручки энкодера
   encoder.tick();
   newPos = encoder.getPosition() * STEPS;
   if (newPos < POSMIN) {
      encoder.setPosition(POSMIN / STEPS);
      newPos = POSMIN;
   }
   else if (newPos > POSMAX) {
      encoder.setPosition(POSMAX / STEPS);
      newPos = POSMAX;
   }

   // если положение изменилось - меняем переменную MIN и выводим на дисплей
   if (lastPos != newPos) {
      MIN = newPos;
      lastPos = newPos;
      LCD.clear();
      LCD.setCursor(2, 0);
      LCD.print("TIMER  STOP");
      LCD.setCursor(5, 1);
      LCD.print(MIN);
      LCD.print(" : ");
      LCD.print(SEC);
   }

   // если была нажата кнопка энкодера запускаем отсчет времени
   boolean buttonIsUp = digitalRead(6);
   if (buttonWasUp && !buttonIsUp && MIN > 0) {
      delay(10);
      buttonIsUp = digitalRead(6);
      if (!buttonIsUp) {
         if (SEC == 0) { SEC = 60; MIN = MIN - 1; }
         if (MIN < 0 ) { MIN = 0; }
         digitalWrite(10, LOW);
         w = 1;
      }
   }
   buttonWasUp = buttonIsUp; // запоминаем состояние кнопки

   while (w == 1 ) {
      // если прошло 995 мс - вычитаем одну секунду от переменной SEC
      if (millis() - timer > 993) {
         timer = millis();
         SEC = SEC - 1;
 
      // если отсчет закончился - обнуляемся, включаем сигнал и выходим из цикла
      if (SEC == 0 && MIN == 0) {
         lastPos = 0; newPos = 0; MIN = 0; SEC = 0;
         LCD.clear();
         LCD.setCursor(2, 0);
         LCD.print("TIMER  STOP");
         LCD.setCursor(5, 1);
         LCD.print(MIN);
         LCD.print(" : ");
         LCD.print(SEC);
         digitalWrite(10, HIGH);
         tone(12, 100);
         delay(500);
         noTone(12);
         w = 0;
      }

      // если секунды дошли до нуля - вычитаем одну минуту
      if (SEC == 0 && w==1) {
         SEC = 59; MIN = MIN - 1;
         if (MIN < 0 ) { MIN = 0; }
      }

      // если из цикла while еще не вышли - выводим информацию на дисплей
      if (w == 1) {
         LCD.clear();
         LCD.setCursor(2, 0);
         LCD.print("TIMER START");
         LCD.setCursor(5, 1);
         LCD.print(MIN);
         LCD.print(" : ");
         LCD.print(SEC);
      }
    }

    // если была нажата кнопка - обнуляем переменные и выходим из цикла
    buttonIsUp = digitalRead(6);
    if (buttonWasUp && !buttonIsUp) {
       delay(10);
       buttonIsUp = digitalRead(6);
       if (!buttonIsUp) {
          lastPos = 0; newPos = 0; MIN = 0; SEC = 0;
          LCD.clear();
          LCD.setCursor(2, 0);
          LCD.print("TIMER  STOP");
          LCD.setCursor(5, 1);
          LCD.print(MIN);
          LCD.print(" : ");
          LCD.print(SEC);
          digitalWrite(10, HIGH);
          w = 0;
       }
    }
    buttonWasUp = buttonIsUp; // запоминаем состояние кнопки
  }
}

Пояснения к коду:

  1. частоту звукового сигнала можно изменить через команду tone();
  2. для скетча потребуется установить библиотеку RotaryEncoder.

Step 5: Example 3: DAC

In this project I used a timer interrupt to output a sine wave of a specific frequency from the Arduino. I soldered a simple 8 bit R2R DAC to digital pins 0-7.  This DAC was constructed from 10k and 20k resistors arranged in a multi-leveled voltage divider.  I’ll be posting more about the construction of the DAC in another instructable, for now I’ve included the photo’s above.
I connected the output from the DAC up to an oscilloscope.  If you need help understanding how to use/read the oscilloscope check out this tutorial.  I loaded the following code onto the Arduino:

//63Hz sine wave
//by Amanda Ghassaei 2012
//https://www.instructables.com/id/Arduino-Timer-Interrupts/

/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
*/

//sends 63Hz sine wave to arduino PORTD DAC
float t = 0;

void setup() {
  //set port/pin  mode. see http://www.arduino.cc/en/Reference/PortManipulation for more info
  DDRD = 0xFF;//port d (digital pins 0-7) all outputs
 
  cli();//stop interrupts

  //set timer2 interrupt at 40kHz
  TCCR2A = 0;// set entire TCCR2A register to 0
  TCCR2B = 0;// same for TCCR2B
  TCNT2  = 0;//initialize counter value to 0
  // set compare match register for 40khz increments
  OCR2A = 49;// = (16*10^6) / (8*40000)-1
  // turn on CTC mode
  TCCR2A |= (1 << WGM21);
  // Set CS21 bit for 8 prescaler
  TCCR2B |= (1 << CS21);  
  // enable timer compare interrupt
  TIMSK2 |= (1 << OCIE2A);
 
  sei();//allow interrupts
}

ISR(TIMER2_COMPA_vect) {
  //increment t
  t+=1;
  if (t==628){//40kHz/628 =~ 63Hz
    t=0;
  }
}


void loop(){
  //sine wave of frequency ~63Hz
  //send sine values to PORTD between 0 and 255
  PORTD=byte(127+127*sin(t/100));
}


I set up a timer interrupt that increments the variable t at a frequency of 40kHz.  Once t reaches 627 it resets back to zero (this happens with a frequency of 40,000/628 = 63Hz).  Meanwhile, in the main loop the Arduino sends a value between 0 (00000000 in binary) and 255 (11111111 in binary) to digital pins 0 through 7 (PORTD).  It calculates this value with the following equation:PORTD=byte(127+127*sin(t/100));
So as t increments from 0 to 627 the sine function moves through one complete cycle.  The value sent to PORTD is a sine wave with frequency 63Hz and amplitude 127, oscillating around 127.  When this is sent through the 8 bit resistor ladder DAC it outputs an oscillating signal around 2.5V with an amplitude of 2.5V and frequency of 63Hz.
The frequency of the sine wave can be doubled by multiplying the (t/100) term by 2, quadrupled by multiplying by 4, and so on…
Also notice that if you increase the frequency of the timer interrupt too much by decreasing the prescaler or OCR2A the sine wave will not output correctly.  This is because the sin() function is computationally expensive, and at high interrupt frequencies it does not have enough time to execute.  If you are using high frequency interrupts, instead of performing a computation during the interrupt routine, considering storing values in an array and simply calling these values using some kind of index.  You can find an example of that in my arduino waveform generator- by storing 20,000 values of sin in an array, I was able to output sine waves with a sampling frequency of 100kHz.

Выбор таймера

На всех платформах доступно значение TIMER_DEFAULT, которое указывает на рабочий таймер по умолчанию.

Если есть необходимость использовать другой таймер, можно указать его имя напрямую: _TIMER1…TIMER9, _TIMER1_32BIT…_TIMER9_32BIT

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

Доступные таймеры:

  • AVR ATmega1280, ATmega2560: _TIMER1, _TIMER3,_TIMER4, _TIMER5; TIMER_DEFAULT = _TIMER5

  • AVR AT90USB646, AT90USB1286, ATmega128, ATmega1281, ATmega1284, ATmega1284P, AVR_ATmega2561: _TIMER1, _TIMER3; TIMER_DEFAULT = _TIMER3

  • AVR ATmega32U4: _TIMER1; TIMER_DEFAULT = _TIMER1

  • AVR другие чипы: _TIMER1; TIMER_DEFAULT = _TIMER1

  • PIC32 (ChipKIT): _TIMER1, _TIMER2, _TIMER3, _TIMER4, _TIMER5, _TIMER2_32BIT, _TIMER4_32BIT; TIMER_DEFAULT = _TIMER4_32BIT

  • SAM (Arduino Due): _TIMER1/_TIMER1_32BIT, _TIMER2/_TIMER2_32BIT, _TIMER3/_TIMER3_32BIT, _TIMER4/_TIMER4_32BIT, _TIMER5/_TIMER5_32BIT, _TIMER6/_TIMER6_32BIT, _TIMER7/_TIMER7_32BIT, _TIMER8/_TIMER8_32BIT, _TIMER9/_TIMER9_32BIT (все таймеры 32-битные, _TIMERX_32BIT == _TIMERX); TIMER_DEFAULT = _TIMER3/_TIMER3_32BIT;

Проблемы с контекстом прерываний

Для обмена данными между кодом обработчика прерывания и остальной частью вашей программы необходимо принять дополнительные меры.

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

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

Методы библиотек TimerOne и TimerThree

Настройка

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

Обратите внимание, что это нарушает работу на цифровых выводах 9 и 10 на Arduino.

Устанавливает период в микросекундах. Минимальный период и максимальная частота, поддерживаемые данной библиотекой, равны 1 микросекунде и 1 МГц, соответственно

Максимальный период равен 8388480 микросекунд, или примерно 8,3 секунды. Обратите внимание, что установка периода изменит частоту срабатывания прикрепленного прерывания и частоту, и коэффициент заполнения на обоих ШИМ выходах.

Управление запуском

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

Управление выходным ШИМ сигналом

Генерирует ШИМ сигнал на заданном выводе . Выходными выводами таймера Timer1 являются выводы 1 и 2, поэтому вы должны выбрать один из них, всё остальное игнорируется. На Arduino это цифровые выводы 9 и 10, эти псевдонимы также работают. Выходными выводами таймера Timer3 являются выводы , соответствующие выводам 2, 3 и 5 на Arduino Mega. Коэффициент заполнения задается, как 10-битное значение в диапазоне от 0 до 1023 (0 соответствует постоянному логическому нулю на выходе, а 1023 – постоянной логической единице)

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

Быстрый способ для настройки коэффициента заполнения ШИМ сигнала, если вы уже настроили его, вызвав ранее метод. Этот метод позволяет избежать лишних действий по включению режима ШИМ для вывода, изменению состояния регистра, управляющего направлением движения данных, проверки необязательного значения периода и прочих действий, которые являются обязательными при вызове .

Выключает ШИМ на заданном выводе, после чего вы можете использовать этот вывод для чего-либо другого.

Прерывания

Вызывает функцию через заданный в микросекундах интервал. Будьте осторожны при попытке выполнить слишком сложный обработчик прерывания при слишком большой тактовой частоте, так как CPU может никогда не вернуться в основной цикл программы, и ваша программа будет «заперта»

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

Отключает прикрепленное прерывание.

Минимальные частоты и разрядность таймеров

Варианты вызовов timer_init_ISR_2Hz (2Гц, период 500мс) и timer_init_ISR_1Hz (1Гц, период 1с) на PIC32MX 80МГц будут работать только с 32-битными таймерами (_TIMER2_32BIT и _TIMER4_32BIT; TIMER_DEFAULT — по умолчанию = _TIMER4_32BIT), т.к. при 16-битных режимах таймеров PIC32MX 80МГц комбинация «делитель частоты» (prescaler — максимальный вариант 1/256) + «поправка периода» (adjustment — максимальный вариант 2^16=65536-1) дают минимальную частоту 5Гц (период — 200мс):
80000000/256/65536 = 4.8Гц

На PIC32 32-битные таймеры создаются комбинацией 2х 16-битных таймеров:

  • Timer4(32бит) = Timer4(16бит)+Timer5(16бит)
  • Timer2(32бит) = Timer2(16бит)+Timer3(16бит)

поэтому при использовании таймера _TIMER2_32BIT, обычные таймеры _TIMER2 и _TIMER3 будут заняты, при использовании _TIMER4_32BIT — заняты будут _TIMER4 и _TIMER5.

На AVR/Arduino можно получить частоту 1Гц стандартными делителями на 16-битном таймере.

На SAM/Arduino Due все таймеры 32-битные.

Тип данных для параметра adjustment — unsigned int.

  • На PIC32 разрядность int — 32 бит, этого хватит и для 16-тибитного режима таймера (если не закладывать значение более 2^16=65536-1) и для 32-битного (пойдет любое значение до 2^32=4294967296-1).
  • На SAM разрядность int — 32 бит, все таймеры 32-битные.
  • На AVR разрядность int — 16 бит, это опять же, как раз достаточно для 16-битных таймеров.

Таким образом, хотя разрядность параметра adjustment с типом int будет разной на разных платформах, во всех случаях значение будет соответствовать аппаратным свойствам таймеров.