|
|
  |
Ламерский вопрос по timer1 Atmega88 |
|
|
|
Sep 15 2014, 20:43
|
Профессионал
    
Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046

|
Привет всем! Собственно в сабже есть режим CTC и в нем есть фичи Clear OC1A/OC1B on Compare Match (Set output to low level) и Set OC1A/OC1B on Compare Match (Set output to high level). Как ими пользоватся?  В смысле, если я настрою выход OC1B как Clear OC1A/OC1B on Compare Match, то как сделать Set? Получается только путем переконфигурировать и дождатся события(или форс вручную)? Вообще задача стоит так. Таймер T считает от 0 до X, при достижении X сбрасывается в 0 и так по кругу. Когда T==0 set OC1A(или B,не важно). Когда T= a clear OC1A/B, при чем a<X. Тоесть обычный PWM. Но, таймер должен еще сбрасыватся по компаратору(или внешнему пину), при чем с определенной задержкой. Пока реализация вот такая. Режим CTC TOP=OCR1A. Clear OC1B on Compare Match и в OCR1B=a; OCR1A изначально равно X. Код ISR(TIMER1_CAPT_vect){ OCR1A=ICR1+delay; // сброс таймера при достижении OCR1A }
ISR(TIMER1_COMPA_vect){ OCR1A=X; } Все было бы ок, если бы можно было заставить выход OC1B установится в лог1, когда таймер сбрасывается. Ржим PWM не канает из за буфферизации OCR1x... Можно как-то так, но эт как-то слишком глючно. На пример, если a слишком маленькое - есть риск что таймер его обгонит еще до того, как мы успеем обновить OCR1B и выход будет всегда висеть в единице, а это чревато последствиями  Код init(){ TCCR1A=(1<<COM1B1)|(0<<COM1B0); //Clear OC1B on Compare Match }
ISR(TIMER1_CAPT_vect){ int t=ICR1+delay; // сброс таймера при достижении OCR1A OCR1A=t; OCR1B=t; TCCR1A=(1<<COM1B1)|(1<<COM1B0); // Set OC1B on Compare Match }
ISR(TIMER1_COMPA_vect){ OCR1A=X; OCR1B=a; TCCR1A=(1<<COM1B1)|(0<<COM1B0); //Clear OC1B on Compare Match }
|
|
|
|
|
Sep 16 2014, 05:38
|

Профессионал
    
Группа: Свой
Сообщений: 1 080
Регистрация: 16-11-04
Из: СПб
Пользователь №: 1 143

|
Цитата(brag @ Sep 16 2014, 00:43)  Собственно в сабже есть режим CTC и в нем есть фичи Clear OC1A/OC1B on Compare Match (Set output to low level) и Set OC1A/OC1B on Compare Match (Set output to high level). Как ими пользоватся?  В смысле, если я настрою выход OC1B как Clear OC1A/OC1B on Compare Match, то как сделать Set? Получается только путем переконфигурировать и дождатся события(или форс вручную)? на память: TCNT1 считает от 0 до 256 если стоит OCR1A = 100 и Set OC1A/OC1B on Compare Match то при TCNT1=0...99 на ножке будет 0, при TCNT1=100...255 на ножке будет 1 если же стоит Clear то будет инвертированно, и в 1 встанет само при TCNT1=0
--------------------
Марс - единственная планета, полностью населенная роботами (около 7 штук).
|
|
|
|
|
Sep 16 2014, 07:35
|
Местный
  
Группа: Участник
Сообщений: 298
Регистрация: 26-01-09
Из: Пермь
Пользователь №: 43 940

|
Цитата(megajohn @ Sep 16 2014, 11:38)  на память: TCNT1 считает от 0 до 256 может все таки до 255?
|
|
|
|
|
Sep 16 2014, 07:58
|
Профессионал
    
Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046

|
Цитата то при TCNT1=0...99 на ножке будет 0, при TCNT1=100...255 на ножке будет 1 если же стоит Clear то будет инвертированно, и в 1 встанет само при TCNT1=0 не верно. это для режима PWM так, а для CTC нет. в CTC ножка только сбрасывается/устанавливается при compare match. если стоит OCR1A = 100 и Set OC1A/OC1B on Compare Match то когда TCNT1=100 нога установится в лог 1 и будет висеть в нем вечно. Цитата может все таки до 255? ta хоть до 65535 скорее всего врядли что-то дельное получится из этой avr, прийдется наверное вешать сверху платку с простенькой cpld, на которой и сделать вменяемый таймер.
|
|
|
|
|
Sep 16 2014, 10:28
|
Профессионал
    
Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046

|
WGM14 не подходит тк When the ICR1 is used as TOP value (see description of the WGM13:0 bits located in the TCCR1A and the TCCR1B Register), the ICP1 is disconnected and consequently the Input Cap-ture function is disabled. WGM15 не подходит из за using OCR1A for defining TOP (WGM13:0 = 15) since the OCR1A then will be double buffered. Тоесть, когда я в обработчике TIMER1_CAPT запишу OCR1A - изменения вступят в силу уже после срабатывания compare event. вот так это выглядит графически. пунктиром показано поведение, если прерывание(capture event) не возникнет параметры pusle width и delay должны быть настраиваемые разве что вот так можно сделать. Режим WGM14 Код init(){ ICR1=FGD_MIN; OCR1B=pw; } ISR(ANALOG_COMP_vect){ U16 t,t0; t=TCNT1; t0=OCR1B; if(t<t0+200)return; ICR1=t+((t-t0)>>2)-48; // add delay, subtract interrupt-process time OCR1B=pw; }
ISR(TIMER1_CAPT_vect){ // end of cycle ICR1=FGD_MIN; // reset ICR1 } Других прерываний быть не должно, иначе глюкнется. Джиттер будет в 1-2 такта.
Эскизы прикрепленных изображений
|
|
|
|
|
Sep 17 2014, 08:17
|
Профессионал
    
Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046

|
Цитата Не пойдет, ICP1 отключена и прерывание TIMER1_CAPT_vect никогда не сработает. Все там нормально срабатывает: When the Input Capture Register(ICR1) is set by the WGM13:0 to be used as the TOP value, the ICF1 Flag is set when the counter reaches the TOP value. режим WGM14. В принципе TIMER1_CAPT_vect можно заменить на TIMER1_OVF_vect, будет точно такое же поведение. Данный алгоритм работает, но прерываний других использовать нельзя(кроме аварийных). Что в принципе не является особой проблеммой, работать с остальной периферией можно в вечном цикле. Цитата Ещё один путь - взять МК с двумя ICP1 и ICP3 модулями, таймеры пусть работают синхронно, один модуль будет срабатывать от входного события, а второй будет выдавать fast pwm (14/15). Как-то так. На сколько я помню, у AVR нету синхронизации между T1 и T3. Если даже изначально TCNT1==TCNT3 ( хотя как это сделать я не представляю синхронизацию сделать можно через TSM,PSR) - если ICP1 словит входное событие, запишет ICP3=ICP1+блабла, Т3 сбросится при достижении ICP3, a T1 продолжит дальше считать - вот тут они и рассинхронизируются. Если уж менять железо, то лучше рядом с Atmega88 поставить CPLD и сделать на нем нужную логику. Таймер нужен 12-битный максимум, + еще 2 регистра(типа OCR1A и OCR1B) тоже 12-битных, + сумматор + немного логики. EPM3064 должно хватить - 36 MC уйдет под регистры и еще 28 останется для логики. А,да еще как-то надо загружать туда регистр из атмеги, допустим по spi, тогда нужен еще 1 буфферный 12-битный регистр, тогда возможно понадобится cpld на больше макроячеек. Ну или найти другой МК, где это можно реализовать аппаратными средствами.
|
|
|
|
|
Sep 17 2014, 09:58
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Ничего не сработает. Вы спутали ICR с ICP. Внешнее событие никогда не наступит, поскольку InputCapturePin отключен в режиме 14/15. Цитата(brag @ Sep 17 2014, 07:17)  На сколько я помню, у AVR нету синхронизации между T1 и T3. Если даже изначально TCNT1==TCNT3 (хотя как это сделать я не представляю синхронизацию сделать можно через TSM,PSR) - если ICP1 словит входное событие, запишет ICP3=ICP1+блабла, Т3 сбросится при достижении ICP3, a T1 продолжит дальше считать - вот тут они и рассинхронизируются
Ерунду говорите. Таймеры работают от одного источника, поэтому всегда "засинхронизированы". Если ICP1 словит входное событие, то текущее значение счетчика перепишется в ICP1, а таймер1 как считал, так и будет продолжать считать.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Sep 17 2014, 10:37
|
Профессионал
    
Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046

|
Цитата Ничего не сработает. Вы спутали ICR с ICP. Внешнее событие никогда не наступит, поскольку InputCapturePin отключен в режиме 14/15. посмотрите внимательно код, TIMER1_CAPT_vect ловит не внешнее событие, а TCNT1==ICR1 (режим WGM14). Внешнее событие ловит ANALOG_COMP_vect (вторая точка на графике). Сейчас девайс лежит на столе и именно так и работает. Цитата Таймеры работают от одного источника, поэтому всегда "засинхронизированы". Если ICP1 словит входное событие, то текущее значение счетчика перепишется в ICP1, а таймер1 как считал, так и будет продолжать считать. Ну не совсем всегда, их нужно еще засинхронизировать вручную через ТSМ, но это не столь важно. Важно, что таймер1 как считал, так и будет продолжать считать, а таймер Т3 сбросится при достижении ICR3(который равен ICR1+блабла) и теперь TCNT1!=TCNT3. Это можно заставить работать корректно, вычислять "истинный" ICR1(время между первой и второй точкой на графике) зная ICR1,ICR3,OCR3B и разрядность TCNT1. + такого 'двухтаймерного' решения перед предложенным в посту #6 в отсутствии джиттера в 4(кажись) такта. - обеих решений в том, что нельзя использовать другие прерывания(нужно работаь с периферией в вечном цикле), поскольку время(delay на графике) между второй точкой(ICP1) и ICR3 может быть довольно коротким, если прерывание ICP1 не выполнится вовремя - есть риск,тчо timer3 обгонит ICR1+блабла еще до того, как мы его туда запишем в ICR3.
|
|
|
|
|
Sep 17 2014, 11:11
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(brag @ Sep 17 2014, 10:37)  Внешнее событие ловит ANALOG_COMP_vect (вторая точка на графике) Ну раз так, то не надо его называть "capture event" Цитата(brag @ Sep 17 2014, 10:37)  Ну не совсем всегда, их нужно еще засинхронизировать вручную через ТSМ, но это не столь важно Нет ничего проще, как засинхронизировать. В один таймер пишете 0, в другой 1. Запускаете первый, потом второй.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Sep 17 2014, 12:05
|
Профессионал
    
Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046

|
Цитата Ну раз так, то не надо его называть "capture event" ну вообще то событие (точка 2) названо comparator IRQ/capture event  В данном случаи(код для атмега88 ANALOG_COMP_vect) правильно будет software capture event или тип того. Но в идеале это должен быть настоящий железный capture Цитата В один таймер пишете 0, в другой 1. Запускаете первый, потом второй. разве что на ассемблере с точным подсчетом тактов между запусками таймеров, и скорее не 1, а где-то 4 + не совсем известно сколько проходит тактов с момента начала выполнения инструкции до собственно старта таймера(мож в даташите и написано). это костыль, есть же бит TSM для этих целей.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|