Timer/counter for avr для начинающих

Учебный курс AVR. Таймер – счетчик Т0. Регистры. Ч1

   Это 8-ми разрядный счетный регистр. Когда таймер работает, по каждому импульсу тактового сигнала значение TCNT0 изменяется на единицу. В зависимости от режима работы таймера, счетный регистр может или увеличиваться, или уменьшаться.

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

OCR0  

   Это 8-ми разрядный регистр сравнения. Его значение постоянно сравнивается со счетным регистром TCNT0, и в случае совпадения таймер может выполнять какие-то действия – вызывать прерывание, менять состояние вывода OC0 и т.д. в зависимости от режима работы.

   Значение OCR0 можно как читать, так и записывать.

TCCR0 (Timer/Counter Control Register)



   Это конфигурационный регистр таймера-счетчика Т0, он определяет источник тактирования таймера, коэффициент предделителя, режим работы таймера-счетчика Т0 и поведение вывода OC0. По сути, самый важный регистр. 

  Биты CS02, CS01, CS00 (Clock Select) – определяют источник тактовой частоты для таймера Т0 и задают коэффициент предделителя. Все возможные состояния описаны в таблице ниже.

   
   Как видите, таймер-счетчик может быть остановлен, может тактироваться от внутренней частоты и также может тактироваться от сигнала на выводе Т0. 

   Биты WGM10, WGM00 (Wave Generator Mode) – определяют режим работы таймера-счетчика Т0. Всего их может быть четыре – нормальный режим (normal), сброс таймера при совпадении (CTC), и два режима широтно-импульсной модуляции (FastPWM и Phase Correct PWM). Все возможные значения описаны в таблице ниже.

Более подробно будем разбирать режимы в коде. Сейчас все нюансы все равно не запомнятся. 

   Биты COM01, COM00 (Compare Match Output Mode) – определяют поведение вывода OC0. Если хоть один из этих битов установлен в 1, то вывод OC0 перестает функционировать как обычный вывод общего назначения и подключается к схеме сравнения таймера счетчика Т0. Однако при этом он должен быть еще настроен как выход.

   Поведение вывода OC0 зависит от режима работы таймера-счетчика Т0. В режимах normal и СTC вывод OC0 ведет себя одинаково, а вот в режимах широтно-импульсной модуляции его поведение отличается. Не будем сейчас забивать себе голову всеми этими вариантами и разбирать таблицы для каждого режима, оставим это на практическую часть.

   И последний бит регистра TCCR0 – это бит FOC0 (Force Output Compare).Этот бит предназначен для принудительного изменения состояния вывода OC0. Он работает только для режимов Normal и CTC. При установки бита FOC0 в единицу состояние вывода меняется соответственно значениям битов COM01, COM00. FOC0 бит не вызывает прерывания и не сбрасывает таймер в CTC режиме.

TIMSK (Timer/Counter Interrupt Mask Register)


   Общий регистр для всех трех таймеров ATmega16, он содержит флаги разрешения прерываний. Таймер Т0 может вызывать прерывания при переполнении счетного регистра TCNT0 и при совпадении счетного регистра с регистром сравнения OCR0. Соответственно для таймера Т0 в регистре TIMSK зарезервированы два бита – это TOIE0 и OCIE0. Остальные биты относятся к другим таймерам.TOIE0 – 0-е значение бита запрещает прерывание по событию переполнение, 1 – разрешает. 
OCIE0 – 0-е значение запрещает прерывания по событию совпадение, а 1 разрешает.   Естественно прерывания будут вызываться, только если установлен бит глобального разрешения прерываний – бит I регистра SREG.TIFR (Timer/Counter0 Interrupt Flag Register)


   Общий для всех трех таймеров-счетчиков регистр. Содержит статусные флаги, которые устанавливаются при возникновении событий. Для таймера Т0 – это переполнение счетного регистра TCNT0 и совпадение счетного регистра с регистром сравнения OCR0. 

Если в эти моменты в регистре TIMSK разрешены прерывания и установлен бит I, то микроконтроллер вызовет соответствующий обработчик.    Флаги автоматически очищаются при запуске обработчика прерывания. Также это можно сделать программно, записав 1 в соответствующий флаг.

TOV0 – устанавливается в 1 при переполнении счетного регистра.

OCF0 – устанавливается в 1 при совпадении счетного регистра с регистром сравнения

SFIOR (Special Function IO Register)

       Начинающему про этот регистр в принципе можно и не знать, один из его разрядов сбросывает 10-ти разрядный двоичный счетчик, который делит входную частоту для таймера Т0 и таймера Т1.    Сброс осуществляется при установке бита PSR10 (Prescaler Reset Timer/Counter1 и Timer/Counter0) в единицу.

Заключение

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

У вас недостаточно прав для комментирования.

Источник: http://chipenable.ru/index.php/programming-avr/item/171

Программирование микроконтроллеров: таймер — drive2

Для самых маленьких познавателей микроконтроллеров.Поговорим про таймеры-счетчики микроконтроллеров AVR и конкретно ATTiny13A.

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

Обычно описание работы начинают как в даташите сверху вниз, а я начну снизу вверх, так более понятно начинающим.

Работа таймера-счетчика очень похожа на работу механического колесика одометра в панели приборов автомобиля. Вот и с ним будем сравнивать.

Долее по даташиту:

TCNT0 Timer/Counter Register. Это регистр таймера счетчика. Это колесико одометра. Если этому колесику придать вращение от какого нибудь сигнала, то он начнет крутиться. У колесика 255 положений, а не от нуля до девяти, как у одометра авто.

Крутится он по кругу, то есть 0,1,2,3…254,255,0,1,2,3… Этот регистр открыт для чтения и записи, то есть можно считывать его значение и писать свое.

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

if(TCNT0==127) {TCNT0=0};

По-русски:
Если значение счетчика равно 127 if(TCNT0==127)
То сбрасываем этот же счетчик в ноль (присваиваем регистру нулевое значение ) {TCNT0=0}

В этом примере есть и чтение регистра TCNT0 и запись в этот же регистр.

Теперь выше по даташиту: как и чем и отчего заставить крутится это колесико одометра?

Для этого есть два способа:

1.- От тактового генератора микроконтроллера.
2. — От состояние входа( ножки) Т0

От тактового генератора:

Счетчик крутится от тактового генератора, “скорость” вращения колесика можно выбирать делителем. Отвечает за делитель регистр TCCR0B

Пример расчета “скорости”: тактовый генератор лопатит на 1,2МГц:

TCCR0B=0x00 счетчик выключен.

Можно использовать это значение как выключалку таймера-счетчика
TCCR0B=0x01 счетчик лопатит на 1,2МГц: деление на единицу типа)
TCCR0B=0x02 счетчик лопатит на 150кГц: деление на 8
TCCR0B=0x03 счетчик лопатит на 18,75кГц: деление на 64
TCCR0B=0x04 счетчик лопатит на 4,688кГц: деление на 256
TCCR0B=0x05 счетчик лопатит на 1,172кГц: деление на 1024

Читайте также:  Фото реле

От состоянии на входной ножке Т0 (это 7 ножка порт РВ2)

TCCR0B=0x06 по спаду сигнала
TCCR0B=0x07 по фронту сигнала

Например: на входе Т0 логический ноль. В регистре TCCR0B=0x06 стоит по спаду сигнала. Счетчик стоит. Появилась единица на входе. Счетчик почуял это и приготовился, ибо по спаду. Пропала единица — стал ноль на входе Т0 — регистр таймера счетчика TCNT0 прибавил себе единичку и опять следит за состоянием по входу Т0

Колесико то крутится, но в холостую. Надо теперь сделать так, чтоб оно делало полезную работу. А вот тут уже много возможностей.

Есть несколько основных выводов полезной работы счетчика-таймера.

Делать работу, можно если значение счетчика (колесико TCNT0) сравняется с регистром сравнения-совпадения OCR0х. Это ещё составная часть таймера счетчика, состоящая из двух равнозначных регистра OCR0A и OCR0B.
OCR0A и OCR0B — это как колесики на кодовом навесном замке. Если уж совсем так сравнивать, то это два отдельных кодовых навесных замка с одним колесиком:

Ну как то так, только не на десять положений, а на 255

То есть можно выставлять свое значение колесика замка OCR0A или OCR0B, затем крутить колесико таймера одометра TCNT0, при совпадении значений замок открывается и происходит какое либо событие.

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

Режимы можно посмотреть в мастере CodeVisionAVR:

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

Теперь примеры, созданные для среды разработки CodeVisionAVR:
значение фьюзов по умолчанию, поэтому тактовая частота равна 1.2МГц. Значения настройки портов и т.п. не указано, только мясо:

TCCR0B=0x03; //Запускаем таймер в обычном счетном режиме на 18,750 kHz
OCR0A=0xF0; // Указываем значение регистра сравнения равное 0хF0
TIMSK0=0x04;//Разрешаем выполнение прерываний по совпадению в OCR0A
#asm(“sei”) // Разрешаем сами глобальные прерывания
interrupt [TIM0_COMPA] void timer0_compa_isr(void){// Здесь малюем кодTCNT0=0x00;

}

Скриншот мастера:

Описание:

Таймер-счетчик прибавляет единичку 18750 раз в секунду (то самое колесико одометра TCNT0), значение OCR0A=0xF0; как и так понятно равно F0, в десятичной системе это равно числу 240. Если колесико одометра насчитает 240 “тиков”, то сработает прерывание: основной цикл программы останавливается, и начинается выполнения кода “здесь малюем код”:

interrupt [TIM0_COMPA] void timer0_compa_isr(void){// Здесь малюем кодTCNT0=0x00;

}

Внутри фигурных скобок есть сброс колесика одометра в ноль: TCNT0=0x00;, то есть после выполнения кода счетчик сбрасывается и начинается счет с нуля. И так циклично.

Этот код применяется, если необходимо производить какое либо действо через определенный точно заданный промежуток времени: делать опрос какого либо устройства, мерять температуру, сканировать состояние энкодера да еще много что можно. Ну или например, если настроить вызов прерывания ровно раз в секунду, то можно сделать секундомер. Конкретно данный пример срабатывает 18750/240=78,125 раза в секунду.

Теперь интереснее: запускаем ШИМ:

TCCR0A=0x81;//запускаем ШИМ с фазовой коррекцией и назначаем выход ножки PB0(OC0A) на выход импульсов ШИМа
TCCR0B=0x02;//частота работы таймера 150 кГц
TIMSK0=0x02;//разрешаем прерывания по переполнению таймера
#asm(“sei”)// Разрешаем сами глобальные прерывания
interrupt [TIM0_OVF] void timer0_ovf_isr(void){// Малюем код}

Ну а здесь описание совсем короткое: на выходе PB0 микроконтроллера (ножка 5) будет присутствовать ШИМ сигнал (если будет правильно сконфигурирован этот порт на выход), с заполнением пропорционально значению регистра OCR0AПримеры:OCR0A=0; — ШИМа небудет, ноль на выходеOCR0A=127; — на выходе ровный меандр с заполнением 50/50

OCR0A=255; — на выходе единица, ШИМа нет

Так как включено прерывание по переполнению таймера, то когда счетчик насчитает максимальное значение, то будет срабатывать прерывание (выполняться код “Малюем код”)Скриншот мастера:

Теперь, освоив и поняв принцип работы таймера, несложно понять, как работает таймер в других режимах, чем отличается ШИМ с фазовой коррекцией от обычного Fast PWM и так далее и тому подобное. Но это вы уже сами.

Источник: https://www.drive2.ru/b/768372/

AVR130: настройка и использование таймеров AVR

Источник: http://AVRproject.ru/publ/capture_timer1_avr/1-1-0-24

Ссылка на основную публикацию
Adblock
detector
",css:{backgroundColor:"#000",opacity:.6}},container:{block:void 0,tpl:"
"},wrap:void 0,body:void 0,errors:{tpl:"
",autoclose_delay:2e3,ajax_unsuccessful_load:"Error"},openEffect:{type:"fade",speed:400},closeEffect:{type:"fade",speed:400},beforeOpen:n.noop,afterOpen:n.noop,beforeClose:n.noop,afterClose:n.noop,afterLoading:n.noop,afterLoadingOnShow:n.noop,errorLoading:n.noop},o=0,p=n([]),h={isEventOut:function(a,b){var c=!0;return n(a).each(function(){n(b.target).get(0)==n(this).get(0)&&(c=!1),0==n(b.target).closest("HTML",n(this).get(0)).length&&(c=!1)}),c}},q={getParentEl:function(a){var b=n(a);return b.data("arcticmodal")?b:(b=n(a).closest(".arcticmodal-container").data("arcticmodalParentEl"),!!b&&b)},transition:function(a,b,c,d){switch(d=null==d?n.noop:d,c.type){case"fade":"show"==b?a.fadeIn(c.speed,d):a.fadeOut(c.speed,d);break;case"none":"show"==b?a.show():a.hide(),d();}},prepare_body:function(a,b){n(".arcticmodal-close",a.body).unbind("click.arcticmodal").bind("click.arcticmodal",function(){return b.arcticmodal("close"),!1})},init_el:function(d,a){var b=d.data("arcticmodal");if(!b){if(b=a,o++,b.modalID=o,b.overlay.block=n(b.overlay.tpl),b.overlay.block.css(b.overlay.css),b.container.block=n(b.container.tpl),b.body=n(".arcticmodal-container_i2",b.container.block),a.clone?b.body.html(d.clone(!0)):(d.before("
"),b.body.html(d)),q.prepare_body(b,d),b.closeOnOverlayClick&&b.overlay.block.add(b.container.block).click(function(a){h.isEventOut(n(">*",b.body),a)&&d.arcticmodal("close")}),b.container.block.data("arcticmodalParentEl",d),d.data("arcticmodal",b),p=n.merge(p,d),n.proxy(e.show,d)(),"html"==b.type)return d;if(null!=b.ajax.beforeSend){var c=b.ajax.beforeSend;delete b.ajax.beforeSend}if(null!=b.ajax.success){var f=b.ajax.success;delete b.ajax.success}if(null!=b.ajax.error){var g=b.ajax.error;delete b.ajax.error}var j=n.extend(!0,{url:b.url,beforeSend:function(){null==c?b.body.html("
"):c(b,d)},success:function(c){d.trigger("afterLoading"),b.afterLoading(b,d,c),null==f?b.body.html(c):f(b,d,c),q.prepare_body(b,d),d.trigger("afterLoadingOnShow"),b.afterLoadingOnShow(b,d,c)},error:function(){d.trigger("errorLoading"),b.errorLoading(b,d),null==g?(b.body.html(b.errors.tpl),n(".arcticmodal-error",b.body).html(b.errors.ajax_unsuccessful_load),n(".arcticmodal-close",b.body).click(function(){return d.arcticmodal("close"),!1}),b.errors.autoclose_delay&&setTimeout(function(){d.arcticmodal("close")},b.errors.autoclose_delay)):g(b,d)}},b.ajax);b.ajax_request=n.ajax(j),d.data("arcticmodal",b)}},init:function(b){if(b=n.extend(!0,{},a,b),!n.isFunction(this))return this.each(function(){q.init_el(n(this),n.extend(!0,{},b))});if(null==b)return void n.error("jquery.arcticmodal: Uncorrect parameters");if(""==b.type)return void n.error("jquery.arcticmodal: Don't set parameter \"type\"");switch(b.type){case"html":if(""==b.content)return void n.error("jquery.arcticmodal: Don't set parameter \"content\"");var e=b.content;return b.content="",q.init_el(n(e),b);case"ajax":return""==b.url?void n.error("jquery.arcticmodal: Don't set parameter \"url\""):q.init_el(n("
"),b);}}},e={show:function(){var a=q.getParentEl(this);if(!1===a)return void n.error("jquery.arcticmodal: Uncorrect call");var b=a.data("arcticmodal");if(b.overlay.block.hide(),b.container.block.hide(),n("BODY").append(b.overlay.block),n("BODY").append(b.container.block),b.beforeOpen(b,a),a.trigger("beforeOpen"),"hidden"!=b.wrap.css("overflow")){b.wrap.data("arcticmodalOverflow",b.wrap.css("overflow"));var c=b.wrap.outerWidth(!0);b.wrap.css("overflow","hidden");var d=b.wrap.outerWidth(!0);d!=c&&b.wrap.css("marginRight",d-c+"px")}return p.not(a).each(function(){var a=n(this).data("arcticmodal");a.overlay.block.hide()}),q.transition(b.overlay.block,"show",1*")),b.overlay.block.remove(),b.container.block.remove(),a.data("arcticmodal",null),n(".arcticmodal-container").length||(b.wrap.data("arcticmodalOverflow")&&b.wrap.css("overflow",b.wrap.data("arcticmodalOverflow")),b.wrap.css("marginRight",0))}),"ajax"==b.type&&b.ajax_request.abort(),p=p.not(a))})},setDefault:function(b){n.extend(!0,a,b)}};n(function(){a.wrap=n(document.all&&!document.querySelector?"html":"body")}),n(document).bind("keyup.arcticmodal",function(d){var a=p.last();if(a.length){var b=a.data("arcticmodal");b.closeOnEsc&&27===d.keyCode&&a.arcticmodal("close")}}),n.arcticmodal=n.fn.arcticmodal=function(a){return e[a]?e[a].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof a&&a?void n.error("jquery.arcticmodal: Method "+a+" does not exist"):q.init.apply(this,arguments)}}(jQuery)}var debugMode="undefined"!=typeof debugFlatPM&&debugFlatPM,duplicateMode="undefined"!=typeof duplicateFlatPM&&duplicateFlatPM,countMode="undefined"!=typeof countFlatPM&&countFlatPM;document["wri"+"te"]=function(a){let b=document.createElement("div");jQuery(document.currentScript).after(b),flatPM_setHTML(b,a),jQuery(b).contents().unwrap()};function flatPM_sticky(c,d,e=0){function f(){if(null==a){let b=getComputedStyle(g,""),c="";for(let a=0;a=b.top-h?b.top-h{const d=c.split("=");return d[0]===a?decodeURIComponent(d[1]):b},""),c=""==b?void 0:b;return c}function flatPM_testCookie(){let a="test_56445";try{return localStorage.setItem(a,a),localStorage.removeItem(a),!0}catch(a){return!1}}function flatPM_grep(a,b,c){return jQuery.grep(a,(a,d)=>c?d==b:0==(d+1)%b)}function flatPM_random(a,b){return Math.floor(Math.random()*(b-a+1))+a}
");let k=document.querySelector(".flat_pm_modal[data-id-modal=\""+a.ID+"\"]");if(-1===d.indexOf("go"+"oglesyndication")?flatPM_setHTML(k,d):jQuery(k).html(b+d),"px"==a.how.popup.px_s)e.bind(h,()=>{e.scrollTop()>a.how.popup.after&&(e.unbind(h),f.unbind(i),j())}),void 0!==a.how.popup.close_window&&"true"==a.how.popup.close_window&&f.bind(i,()=>{e.unbind(h),f.unbind(i),j()});else{let b=setTimeout(()=>{f.unbind(i),j()},1e3*a.how.popup.after);void 0!==a.how.popup.close_window&&"true"==a.how.popup.close_window&&f.bind(i,()=>{clearTimeout(b),f.unbind(i),j()})}f.on("click",".flat_pm_modal .flat_pm_crs",()=>{jQuery.arcticmodal("close")})}if(void 0!==a.how.outgoing){let b,c="0"==a.how.outgoing.indent?"":" style=\"bottom:"+a.how.outgoing.indent+"px\"",e="true"==a.how.outgoing.cross?"":"",f=jQuery(window),g="scroll.out"+a.ID,h=void 0===flatPM_getCookie("flat_out_"+a.ID+"_mb")||"false"!=flatPM_getCookie("flat_out_"+a.ID+"_mb"),i=document.createElement("div"),j=jQuery("body"),k=()=>{void 0!==a.how.outgoing.cookie&&"false"==a.how.outgoing.cookie&&h&&(jQuery(".flat_pm_out[data-id-out=\""+a.ID+"\"]").addClass("show"),j.on("click",".flat_pm_out[data-id-out=\""+a.ID+"\"] .flat_pm_crs",function(){flatPM_setCookie("flat_out_"+a.ID+"_mb",!1)})),(void 0===a.how.outgoing.cookie||"false"!=a.how.outgoing.cookie)&&jQuery(".flat_pm_out[data-id-out=\""+a.ID+"\"]").addClass("show")};switch(a.how.outgoing.whence){case"1":b="top";break;case"2":b="bottom";break;case"3":b="left";break;case"4":b="right";}jQuery("body > *").eq(0).before("
"+e+"
");let m=document.querySelector(".flat_pm_out[data-id-out=\""+a.ID+"\"]");-1===d.indexOf("go"+"oglesyndication")?flatPM_setHTML(m,d):jQuery(m).html(e+d),"px"==a.how.outgoing.px_s?f.bind(g,()=>{f.scrollTop()>a.how.outgoing.after&&(f.unbind(g),k())}):setTimeout(()=>{k()},1e3*a.how.outgoing.after),j.on("click",".flat_pm_out .flat_pm_crs",function(){jQuery(this).parent().removeClass("show").addClass("closed")})}countMode&&(flat_count["block_"+a.ID]={},flat_count["block_"+a.ID].count=1,flat_count["block_"+a.ID].click=0,flat_count["block_"+a.ID].id=a.ID)}catch(a){console.warn(a)}}function flatPM_start(){let a=flat_pm_arr.length;if(0==a)return flat_pm_arr=[],void jQuery(".flat_pm_start, .flat_pm_end").remove();flat_body=flat_body||jQuery("body"),!flat_counter&&countMode&&(flat_counter=!0,flat_body.on("click","[data-flat-id]",function(){let a=jQuery(this),b=a.attr("data-flat-id");flat_count["block_"+b].click++}),flat_body.on("mouseenter","[data-flat-id] iframe",function(){let a=jQuery(this),b=a.closest("[data-flat-id]").attr("data-flat-id");flat_iframe=b}).on("mouseleave","[data-flat-id] iframe",function(){flat_iframe=-1}),jQuery(window).on("beforeunload",()=>{jQuery.isEmptyObject(flat_count)||jQuery.ajax({async:!1,type:"POST",url:ajaxUrlFlatPM,dataType:"json",data:{action:"flat_pm_ajax",data_me:{method:"flat_pm_block_counter",arr:flat_count}}})}).on("blur",()=>{-1!=flat_iframe&&flat_count["block_"+flat_iframe].click++})),flat_userVars.init();for(let b=0;bflat_userVars.textlen||void 0!==a.chapter_sub&&a.chapter_subflat_userVars.titlelen||void 0!==a.title_sub&&a.title_subc&&cc&&c>d&&(b=flatPM_addDays(b,-1)),b>e||cd||c-1!=flat_userVars.referer.indexOf(a))||void 0!==a.referer.referer_disabled&&-1!=a.referer.referer_disabled.findIndex(a=>-1!=flat_userVars.referer.indexOf(a)))&&(c=!0),c||void 0===a.browser||(void 0===a.browser.browser_enabled||-1!=a.browser.browser_enabled.indexOf(flat_userVars.browser))&&(void 0===a.browser.browser_disabled||-1==a.browser.browser_disabled.indexOf(flat_userVars.browser)))){if(c&&void 0!==a.browser&&void 0!==a.browser.browser_enabled&&-1!=a.browser.browser_enabled.indexOf(flat_userVars.browser)&&(c=!1),!c&&(void 0!==a.geo||void 0!==a.role)&&(""==flat_userVars.ccode||""==flat_userVars.country||""==flat_userVars.city||""==flat_userVars.role)){flat_pm_then.push(a),flatPM_setWrap(a),flat_body.hasClass("flat_pm_block_geo_role")||(flat_body.addClass("flat_pm_block_geo_role"),flatPM_ajax("flat_pm_block_geo_role")),c=!0}c||(flatPM_setWrap(a),flatPM_next(a))}}}let b=jQuery(".flatPM_sticky");b.each(function(){let a=jQuery(this),b=a.data("height")||350,c=a.data("top");a.wrap("
");let d=a.parent()[0];flatPM_sticky(this,d,c)}),debugMode||countMode||jQuery("[data-flat-id]:not([data-id-out]):not([data-id-modal])").contents().unwrap(),flat_pm_arr=[],jQuery(".flat_pm_start, .flat_pm_end").remove()}

В этом переводе апноута AVR130 [1] рассматриваются следующие вопросы:

• Описание событий таймеров/счетчиков• Оповещение о событиях таймера/счетчика• Опции тактирования• Пример кода для Timer0 (прерывание по переполнению)• Пример кода для Timer1 (Input Capture, прерывание по захвату входного сигнала)• Пример кода для Timer2 (асинхронная работа, прерывание по совпадению Compare Match)• Базовые сведения о ШИМ (PWM)

• Пример генерации ШИМ на основе Timer2

В апноуте описано, как использовать различные таймеры AVR на примере микроконтроллера AT90S8535. Назначение документа – дать общий обзор таймеров, показать их возможности и разъяснить конфигурирование.

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

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

[Общий обзор]

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

Почему существуют разные таймеры? Ответ очень прост: для создания подходящего таймера для разных задач нужны некоторые разные (аппаратные) ресурсы.

Обычно в микроконтроллерах серий 90S, megaAVR и tinyAVR имеется два 8-битных таймера и один 16-битный. Таймер, у которого 16-битное разрешение, обычно более гибок в настройке и обладает расширенным функционалом в сравнении с 8-битным таймером.

Однако правило “чем больше тем лучше” не всегда справедливо для мира микроконтроллеров, когда нужно решить узкоспециализированную задачу. Для многих приложений достаточно 8-разрядной разрешающей способности.

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

Гибкость таймеров AVR позволяет приспособить их для решения различных задач. Количество таймеров определяет количество различных конфигураций. Далее будут более подробно описаны эти опции конфигурации.

[События таймеров]

Таймер AVR может быть настроен на обработку некоторых событий. Флаги состояния в регистре TIMSK покажут, произошло ли какое-то событие. Микроконтроллер AT90S8535 может быть сконфигурирован для отслеживания до 3 событий на таймер. Ниже описаны эти события.

Переполнение (Timer Overflow). Переполнение таймера (timer overflow) означает, что счетчик таймера досчитал до своего предельного значения (255 для 8-битного таймера и 65535 для 16-битного) и сбросился в 0 при следующем тактовом цикле. Разрешение таймера (т. е.

диапазон его счета) определяется разрядностью счетчика в таймере. В микроконтроллере AT90S8535 есть 2 таймера с 8-битным разрешением и 1 таймер с 16-битным разрешением.

Максимальное значение, до которого может считать таймер, вычисляется по следующей формуле (здесь Res, стоящая в показателе степени, это разрешающая способность в битах, или 8 или 16):

MaxVal = 2Res – 1 (Формула 1)

Событие переполнения взведет флаг Timer Overflow (TOVx) в регистре Timer Interrupt Flag Register (TIFR).

Совпадение (Compare Match). В тех случаях, когда недостаточно отслеживать переполнение таймера, может использоваться прерывание по совпадению счетчика с неким заданным значением (compare match interrupt). Регистр Output Compare Register (OCRx) может быть загружен значением [0..

MaxVal] которое будет проверяться на совпадение со счетчиком при каждом тактовом цикле таймера. Когда таймер достигнет значения сравнения, будет установлен соответствующий флаг Output Compare Flag (OCFx) в регистре TIFR.

Таймер может быть сконфигурирован для очистки регистра счетчика в 0 при событии совпадения.

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

Эта функция предоставляет много возможностей для реализации DAC (преобразование цифровых данных в аналоговый сигнал). Режим PWM специально предназначен для наилучшей генерации сигналов синусоидальной и другой формы. Подробнее см. раздел “Базовые сведения о PWM”, даташит [4].

Захват входа (Input Capture). У AVR есть входной порт, предназначенный для срабатывания от входных событий, т. е. происходит событие захвата входного события (input capture event).

Изменение сигнала на этом входе приведет к тому, что значение из счетчика таймера будет прочитано и сохранено в регистре захвата Input Capture Register (ICRx). Одновременно с этим установится флаг Input Capture Flag (ICFx) в регистре TIFR.

Функция захвата полезна для измерения длительности внешних импульсов.

[Как происходит оповещение о событиях]

Таймер работает независимо от выполнения кода программы. Для каждого события таймера есть соответствующий флаг состояния в регистре флагов прерывания (Timer Interrupt Flag Register, TIFR).

Произошедшее событие таймера требует оповещения процессора, чтобы он предпринимал по событию соответствующие действия.

Это как раз и делается установкой определенного флага, когда происходит определенное событие.

Есть три различных способа отслеживать события таймера и реагировать на них:

1. Постоянный опрос флагов статуса – флагов прерывания и по ним определять запуск соответствующего кода.
2. Остановка основного потока программы и выполнение обработчика прерывания Interrupt Service Routines (ISR).
3. Автоматическое измерение уровня выходного порта.

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

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

Достоинства этого решения – простота, и возможность очень быстрой реакции, если используется очень короткие циклы опроса.

Реализация на ассемблере этого метода для Timer0 может выглядеть примерно как показано в примере ниже. Эти три строки кода должны быть размещены в главном цикле, который прокручивается с большой частотой.

loop: in r16,TIFR ; загрузка TIFR в регистр 16 sbrs r16,TOV0 ; пропуск следующей инструкции, если установлен бит TOV0 rjmp loop ; если не было переполнения Timer0, то переход по метке loop ; в этом месте должен начинаться код обработки события

Оповещение по прерываниям. Микроконтроллер AVR может быть сконфигурирован так, что будет запускаться обработчик прерывания, если произошло событие таймера (если установится соответствующий флаг прерывания в регистре TIFR).

В этом случае главный поток программы немедленно (почти всегда немедленно) останавливается (прерывается, отсюда и пошел термин “прерывание”), и процессор переходит к выполнению кода обработчика прерывания (Interrupt Service Routine, сокращенно ISR).

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

Прерывания таймера разрешаются установкой соответствующих битов в регистре маски прерываний таймера Timer Timer Interrupt Mask Register (TIMSK). В следующем примере показано, как разрешить Output Compare Interrupt для Timer2:

ldi r16, 1

Источник: http://microsin.net/programming/avr/avr130-setup-and-use-timers.html

Таймеры Счётчики AVR

У микроконтроллеров AVR есть несколько таймеров-счетчиков. Они могут быть 8 (2^8 = 256) или 16 (2^16 = 65536) разрядными.

  • Таймеры могут тикать с разной скоростью и подсчитывать количество тиков (также могут считать время).
  • Тикать от внешнего кварца.
  • формировать точные временные интервалы.
  • считать длительность и количество внешних импульсов.
  • Генерировать несколько видов ШИМ.
  • формировать прерывания.

Предделитель / делитель частоты

Таймер может считать импульсы с частотой на которой работает МК (микроконтроллер). И для того чтобы не выдумывать как из миллионов герц считать импульсы в 1 герц используют делитель частоты. Делить импульсы можно на 8, 32, 64, 128, 256 и 1024.

Предделитель это 10-битный регистр, который “тикает” с той же частотой что и МК, но мы можем выбрать когда таймер будет увеличивать своё значение относительно предделителя.

К примеру если мы хотим чтобы таймер работал в 2 раза медленнее мы настраиваем его так чтобы он “тикал” когда в 0 бите предделителя появляется 1 -> 00, 01, 10, 11.

 
МК тикнул 4 раза, но единичка появилась в 0 бите предделителя лишь 2 раза, значит наш таймер увеличил своё значение лишь на 2.

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

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

Для того чтобы его сбросить нужно записать 1 в “Регистр специальных функций ввода/вывода” – SFIOR 0 бит == PSR10.

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

Счётный регистр

При поступлении импульса на счётчик, он изменяет значение своего счётного регистра TCNTx на 1  (может увеличивать или уменьшать в зависимости от настройки), где вместо x номер таймера. 

Из этого регистра можно как читать так и задавать значения,  можно сказать таймеру откуда он должен считать, определять сколько времени прошло и определённого момента.

16 разрядный таймер состоит из 2 регистров TCNTxH и TCNTxL – старший и младший байты.

Но значение в 2 регистра нужно записывать одновременно, иначе пройдет 1 такт, таймер изменит значение регистра, записываем 2 байт, а в регистре уже не то значение которое нам нужно.

Инженеры ATMEL сделали регистр TEMP, который является служебным и нам не доступен.

Сначала нужно записать старший байт в TCNTxH, значение на самом деле запишется в TEMP, теперь нужно записать младший байт TCNTxL и в этот момент в настоящий
регистр TCNTxH запишется значение из TEMP.

Получается что 2 байта записываются одновременно. Но нужно соблюдать порядок сначала старший, затем младший байт.
Также при записи лучше отключать прерывания, чтобы пока идёт запись 1 байта значение регистров программа не могла изменить.

Регистр управления TCCRx

Через этот регистр мы настраиваем работу таймера. Он является самым важным, именно он определяет частоту делителя, режим работы и источник импульсов. У разных таймеров немного по разному, здесь я опишу для таймера 0

Биты COM01 и COM00 отвечают за то что происходит с ножкой микроконтроллера который связан с данным таймером (1 таймер == OC1A/OC1B, 2 таймер = OC2)

Биты CS02, CS01 и CS00 (Clock Select) определяют коэффициент делителя частоты.


Биты WGM10, WGM00 (Wave Generator Mode) определяют режим работы таймера.

Регистр TIMSK (Timer/Counter Interrupt Mask Register)

Это регистр масок прерываний, если в какой то бит записано 1, значит разрешено определённое прерывание (если конечно прерывания разрешены глобально через 7 бит регистра состояний SREG).

Бит 7OCIE2: прерывание по совпадению ТС2

Бит 6TOIE2: прерывание по переполнению таймера ТС2

Бит 5TICIE1: прерывание по захвату ТС1
Если на выводе ICP1 измениться значение, то значение таймера ТС1 запишется в регистр ICR1 и сработает прерывание.

Бит 4OCIE1A: прерывание по совпадению A ТС1

Бит 3OCIE1B: прерывание по совпадению В ТС1

Бит 2TOIE1: прерывание по переполнению таймера  ТС1

Бит 1 – не используется

Бит 0TOIE0: прерывание по переполнению таймера  ТС0

Теперь можно это использовать к примеру для работы с сервомоторами.

Информация взята отсюда

Источник: http://4a4ik.blogspot.com/2013/10/blog-post_24.html

работа с TIMER1 в режиме захвата. Измеряем частоту сигнала

 Таймеры помимо прерывания по переполнению, могут работать в режиме захвата значения, это означает что по пришествии импульса на ногу ICP значение счетчика копируется в регистр хранеия Input Capture.

Это дает нам возможность измерять время между соседними импульсами изменяющегося сигнала, тобишь его период и далее, если требуется, высчитать частоту. Для примера использую atmega32 и выведу показания на ЖКИ дисплей.

Вывод ICP в atmega32 находится на 20 ноге (PortD.6), туда и заводим сигнал:

 Настройка таймера в режим захвата практически такая-же как и в режиме прерывания по переполнению. Необходимо указать предделитель счетчика:

 

Prescale = 1|8|64|256|1024

и фронт по которому будет происходить захват значения:

 

Capture Edge = Rising|Falling

 От того какой предделитель выбран зависит минимальная частота измеряемого сигнала. Например при значении предделителя 64, переполнение таймера при частоте кварца 16 МГц будет происходить каждые 0,26214 сек. Значит минимальная частота которую точно сможем измерить ~ 4Гц.

 Максимальная же частота (по идее) упирается в тактовую частоту применяемого кварца. Но proteus почему-то некисло врет после 50 кГц. Поэтому пока оставлю этот вопрос =)

 В программе предусмотрена проверка значения таймера1, на случай того, если в нем окажется 0, для того чтобы предотвратить деление на этот 0. Что может произойти с МК в противном случаем, можете глянуть здесь.

$regfile = “m32def.dat”
$crystal = 16000000

' указываем конфигурацию подключения дисплея к портам МК

Config Lcdpin = Pin, Rs=Portc.5, E=Portc.4, Db4=Portc.0, Db5=Portc.1, Db6=Portc.2, Db7=Portc.3

Config Lcd = 16*2                      ' тип используемого дисплея

'настраиваем таймер в режим захвата по восходящему фронту

Config Timer1 = Timer , Prescale = 64 , Capture Edge = Rising

Dim Timercounter As Word

Dim Period As Single                   ' период измеряемого сигнала
Dim F1 As Single
Dim F As Word                          ' переменная для хранения значения частоты

Const T = 0.000004                     ' примерное время в секундах за которое значение

                                       ' счетчика увеличивается на 1

On Capture1 Zaxvat

Timercounter = 0

Waitms 50
Enable Interrupts
Enable Capture1

Cursor Off

Do                                    ' главный цикл программы

If Timercounter = 0 Then              ' проверка значения переменной

 F = 0                                ' если 0, то частота тоже 0

 Else                                 ' в обратном случае высчитываем частоту

 Period = Timercounter * T            ' определяем период

 F1 = 1 / Period                      ' считаем частоту
 F = Abs(F1)                          ' округляем до целого

EndIf

'выводим показания на дисплей

Cls

Lcd “Frequency, Hz:”
Lowerline
Lcd F

Waitms 100

Loop

Zaxvat:

 Timercounter = Timer1                ' копируем значение таймера в переменную
 Timer1 = 0                           ' обнуляем таймер
Return

End

 Нога ICP у меня висит в воздухе и ни к чему не подключена. 

 Как видите, ловит нормальный радиационный электромагнитный фон =) 

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

 Файлы проекта, можно скачать ниже:

(ошибся с делителем поэтому заместо 50 Гц показывает ~65 Гц)