Запуск функции с заданной частотой
- Войдите на сайт для отправки комментариев
Пнд, 11/04/2016 - 23:35
В этой - http://arduino.ru/forum/programmirovanie/etyudy-dlya-nachinayushchikh-bl... - теме подробно описывается, как инвертировать определённый пин по прерыванию, но не понятно, как по нему запускать процедуру.
Или я не нашел, гдк это описано.
Помогите, пожалуйста, нужно выполнять определённые команды через равные зсданные промежутки времени (раз в 3750 мсек).
Вызывай функцию в обработчике прерывания таймера, например:
ISR(TIMER2_COMPA_vect) { // прерывание Таймера2 по совпадению числа в счетном регистре TCNT2 // с числом в регистре сравнения OCR2A (для режима CTC) //ISR(TIMER2_OVF_vect) { // прерывание Таймера2 по переполнению счетного регистра TCNT2 // (для режима Normal Mode) MyFunction(); // вызываемая функция }Естественно, перед этим нужно настроить сам таймер и разрешить прерывания.
Да, можно так. А посмотреть как это делается можно открыв wiring.c "из коробки". Там есть работа и настройка только нулевого таймера и на обруботку переполнения счетчика. Для такой большой задержки ещё можно воспользоваться макросом everyOVF(). Но его точная периодичность вызова - кооперативная и зависит от остальной части программы.
А чем занят основной цикл, что для 3750 мсек таймер задействуется? Может достаточно
if (millis()-t > 3750) { t=millis(); yourFunction(); }Вычисляется текущий каденс. Нагуглил тему [на сайте, похожем на хабр], посмотрел и понял, что код там совсем не код. Пишу свой:
https://gist.github.com/ircphp/ec427a16e0ab5cb9269b9175379d62a8
хотелось бы максимально точно и оптимально считать каденс, не прибегая к усреднению, но чем меньше промежуток его подсчета тем ниже точность. Раз в 4 секунды, вроде, похоже на правду, но все равно мне кажется, что считает он не очень точно.
Тестирую на Atmega128, вместо геркона использую кнопку, но работать будет на Atmega328 и, кроме указанного кода, там еще будет чтение из последовательного порта и запись на SD-карту.
Уже и это почитал - http://avrprog.blogspot.com/2013/03/t2-8.html - всё равно не понятно.
Оставлю, навенрое, как етсь - и так работает.
Нашел почти готовте решение в теме о разряде аккумулятора.
// Начальное значение счётчика, // обеспечивающее задержку в 4 секунды. #define CLK_INIT_VAL 0b0000101111011100 void setup() { TIMSK1 = 0x01; // enabled global and timer overflow interrupt; TCCR1A = 0x00; // normal operation page 148 (mode0); TCNT1 = CLK_INIT_VAL; TCCR1B = 0b00000101; // Делитель частоты, x4 от того, что в примере. } ISR (TIMER1_OVF_vect) { TCNT1 = CLK_INIT_VAL; // Код, выполняющийся раз в 4 секунды }Теперь осталос понять, как уснанавливать значение TCNT1, чтобы получить требуемую задержку - 3750 мсек...
Счётчик считает инкрементом до переполнения, при переполнении вывзывается функция ISR (TIMER1_OVF_vect). Переполнение наступает когда счётчик доходит до 1111111111111111 - 65535. Таким образом, 65535 минус 3036 (значение из скрипта равное задержке 4 сек) = 62499 инкрементов счётчика. Из пропорции:
62499 - 4000 мсек
58592 - 3750 мсек
Для запуска функции с периодом раз в 3750 мс, нужно щёлкать 58592 тактов, а значение CLK_INIT_VAL должно быть 65535-58592=6943=0b0001101100011111.
Проверил - работает:
nkk, решение слегка кривовато. У таймера есть специальный режим сброс по совпадению (CTC).
void setup(){ TCCR1A=0; TCCR1B=(1<<WGM12)|(1<<CS12)|(1<<CS10); // mode4(CTC), divider 1024 TIMSK1=(1<<OCIE1A); OCR1A=58593; } ISR (TIMER1_COMPA_vect) { // что-то , что нужно выполнять раз в .. } void loop() { }Забавно:
Переписал скрипт, чтобы выводило только i если a-b != 3750, - выводит те же строки: 6, 8, 14, 18, 22, 27, 30
Вот пришел в ступор от таймеров.
Два примера:
Таймер Т1 код:
int n = 0; void setup(){ TCCR1A=0; TCCR1B=(1<<WGM12)|(1<<CS12)|(1<<CS10); TIMSK1=(1<<OCIE1A); OCR1A=100; } ISR (TIMER1_COMPA_vect) { n++; if (n>10) {digitalWrite(13, !digitalRead(13)); n = 0;} } void loop() { }Тот же код переделанный для таймера Т2
int n = 0; void setup(){ TCCR2A=0; TCCR2B=(1<<WGM22)|(1<<CS22)|(1<<CS20); TIMSK2=(1<<OCIE2A); OCR2A=100; } ISR (TIMER2_COMPA_vect) { n++; if (n>10) {digitalWrite(13, !digitalRead(13)); n = 0;} } void loop() { }У меня для таймера Т2 получается задействовать, или счетчик, или пресаклер, а мне нужно таймер Т2 с счетчиком и пресаклером. Что я делаю не так. Может у таймера Т2 какая то особенность.
Okmor, не ясно по какому принципу вы переделывали. 4 строкой второго скетча вы задаёте несуществующий режим для таймера 2 , (даташит страница 155, Table 18-8. Waveform Generation Mode Bit Description ) и прескалер тоже не на 1024, а на 32.
Вот.
Тут есть особенности. Не знаю документировано ли, но таймер Т2 в режиме СТС самостоятельно не обнуляется, потому использование параметра (1<<WGM21) бессмысленно. Может кто то объяснит где я ошибся.
Дял всех оставлю этот кусок работающего таймера с счетчиком и пресаклером.
int n = 0; void setup(){ TCCR2A=0; TCCR2B=(1<<CS22)|(1<<CS21)|(1<<CS20); // (1<<WGM21) Clear Timer on Compare Match (CTC) mode // Для таймера Т2 не работает, приходится вручную обнулять. //001 - CLK //010 - CLK/8 //011 - CLK/32 //100 - CLK/64 //101 - CLK/128 //110 - CLK/256 //111 - CLK/1024 OCR2A=40; // Максимум 255 TIMSK2=(1<<OCIE2A); } ISR (TIMER2_COMPA_vect) { TCNT2 = 0; // Работает, если вручную обнулять if (++n>250) {digitalWrite(13, !digitalRead(13)); n = 0;} } void loop() {;}dimax. Спасибо за наводку.
таймер Т2 в режиме СТС самостоятельно не обнуляется, потому использование параметра (1<<WGM21) бессмысленно. Может кто то объяснит где я ошибся.
Да, маленькая ошибочка у вас, поэтому и не обнуляется. Бит WGM21 "приписан" к регистру TCCR2A, а вы его пытались внести в регистр TCCR2B, поэтому он и не включался.
вам надо выполнять команду раз в 3750 милисек (3.750)секунды или раз в 3750 микросекунд.
Если первый вариант то лучше так.
uint8_t non_stop_program1(uint16_t span) { static uint32_t future = 0; if (millis()<future) return 0; future += span; return 1; } void setup() { Serial.begin(9600); } void loop() { if (non_stop_program1(3750)) { / / Здесь вы организовываете подачу команды Serial.println("knok"); } }или раз в 3750 микросекунд.
3750000 микросекунд