|
|
  |
Как считать значение аппаратно-программного таймера... |
|
|
|
Nov 7 2006, 16:47
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(prottoss @ Nov 7 2006, 19:30)  У нас счетчик считает в реалтайме, по этому каждое прерывание получит свое значения и только в одном из прерываний будет установлен 16-ый бит софтварного счетчика - OCF1A. Нет, OCF1A будет выставлен во ВСЕХ внешних прерываниях, если за время выполнения одного прерывания возникнет флаг другого, и т.д. Дело в том, что у внешних прерываний выше приоритет, и пока не выполнятся ВСЕ ждущие высокоуровневые прерывания, прерывание таймера по сравнению не отработает.
|
|
|
|
|
Nov 7 2006, 16:52
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(singlskv @ Nov 7 2006, 23:47)  Нет, OCF1A будет выставлен во ВСЕХ внешних прерываниях, если за время выполнения одного прерывания возникнет флаг другого, и т.д. Дело в том, что у внешних прерываний выше приоритет, и пока не выполнятся ВСЕ ждущие высокоуровневые прерывания, прерывание таймера по сравнению не отработает. Согласен, если в первом внешнем прерывании выставится флаг OCF1A, то это скажет всем последующим, что софт-слово времени надо скорректировать на 1 - и это будет правильно
--------------------
|
|
|
|
|
Nov 7 2006, 17:02
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(prottoss @ Nov 7 2006, 19:52)  Цитата(singlskv @ Nov 7 2006, 23:47)  Нет, OCF1A будет выставлен во ВСЕХ внешних прерываниях, если за время выполнения одного прерывания возникнет флаг другого, и т.д. Дело в том, что у внешних прерываний выше приоритет, и пока не выполнятся ВСЕ ждущие высокоуровневые прерывания, прерывание таймера по сравнению не отработает. Согласен, если в первом внешнем прерывании выставится флаг OCF1A, то это скажет всем последующим, что софт-слово времени надо скорректировать на 1 - и это будет правильно Совт-слово можно корректировать прямо в прерывании со сбросом флага OCF1A (TOV1), тогда в последующих за ним прерываниях корректировка не понадобится. P.S только имейте ввиду, что сейчас кое-кто придет и скажет что так делать низя...
|
|
|
|
|
Nov 7 2006, 17:18
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(singlskv @ Nov 8 2006, 00:02)  Совт-слово можно корректировать прямо в прерывании со сбросом флага OCF1A (TOV1), тогда в последующих за ним прерываниях корректировка не понадобится. P.S только имейте ввиду, что сейчас кое-кто придет и скажет что так делать низя... Мне все равно, кто счас придет... Он не пуп земли, и послать его далеко мне очень легко... По поводу корректировки в прерывании - я сторонник делать все что можно за пределами прерывания, а прерывание должно быстро отработать и освободить место другому, что бы не было пауз в 1 мс)))... Дак я не понял, с моей идеей Вы согласны, или нет? Так, как я предлагаю - и волки сыты и овцы целы). Дело в том, что у меня счас тоже проект, в котором МК должен мерить импульсы от датчика скорости((( В ТЗ - от ИНТ0 и с точностю десятки микросекунд. А ТС1 выполняет роль системных часов. Вот и изгаляюсь тоже. Но похоже что, то что я придумал, работает - опять же, если суммарное время поступивших внешних прерываний не превысит 1 мс... И я не пойму, а что делать низя? Что вы имели в виду?
--------------------
|
|
|
|
|
Nov 7 2006, 18:41
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(prottoss @ Nov 7 2006, 20:18)  Мне все равно, кто счас придет... Он не пуп земли, и послать его далеко мне очень легко... Он и так далеко, Oxford UK Цитата По поводу корректировки в прерывании - я сторонник делать все что можно за пределами прерывания, а прерывание должно быстро отработать и освободить место другому, что бы не было пауз в 1 мс)))... Ну дык это всего лишних тактов 10-15 Цитата Дак я не понял, с моей идеей Вы согласны, или нет? Так, как я предлагаю - и волки сыты и овцы целы). Вы о сохранении TIFR в памяти или о сохраниени TCNT и TIFR в регистрах в соседних командах ? Если первое, то согласен, только сравниваем младшее слово с 1000 при коррекции. А если второе, то ИМХО это нам ничего не дает. Представте себе что во время выполнения не относящегося к нашему делу прерывания происходит запрос на прерывание от таймера, а затем через какое-то время(пока еще не закончилось другое прерывание) происходит запрос на прерывание INT. Когда закончится другое прерывание, первым будет обработанно INT, при этом значение в TCNT будет уже довольно большим, а флаг OCF1A, будет выставлен. А теперь другая ситуация. Представте себе что во время выполнения не относящегося к нашему делу прерывания происходит запрос на прерывание INT.После окончания прерывания, начнется обработчик INT, но при считывании значений мы получили TCNT=1999 и выставленный флаг OCF1A. В каком из этих двух вариантов Вы будете производить коррекцию, а в каком нет ? Может быть все-таки так надежнее: if (((TIFR & (1 << OCF1A)) != 0)&&(lo<1000)) hi++; // OCR1A/2 =1000 Кстати, точно такуюже проверку мы можем делать и с данными сохранеными в памяти. Цитата Дело в том, что у меня счас тоже проект, в котором МК должен мерить импульсы от датчика скорости((( В ТЗ - от ИНТ0 и с точностю десятки микросекунд. А ТС1 выполняет роль системных часов. В таком варианте, когда нужно мерить только от одного датчика, значительно проще и надежнее пользоваться пином ICP1 и прерыванием захвата таймера, правда коррекцию старшего слова все равно необходимо предусмотреть. Цитата И я не пойму, а что делать низя? Что вы имели в виду? Ну я как раз считаю что можно (корректировать старшее слово системного таймера с одновременным сбросом флага OCF1A(TOV1) в любом месте программы в том числе и в других прерываниях, единственное ограничение, запрет всех прерываний на время корректировки.
|
|
|
|
|
Nov 7 2006, 19:06
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(singlskv @ Nov 8 2006, 01:41)  Вы о сохранении TIFR в памяти или о сохраниени TCNT и TIFR в регистрах в соседних командах ? Если первое, то согласен, только сравниваем младшее слово с 1000 при коррекции. А если второе, то ИМХО это нам ничего не дает. Я о сохранении TIFR и TCNT в соседних командах , а потом в памяти - дальнейший анализ в основном цикле Цитата(singlskv @ Nov 8 2006, 01:41)  Представте себе что во время выполнения не относящегося к нашему делу прерывания происходит запрос на прерывание от таймера, а затем через какое-то время(пока еще не закончилось другое прерывание) происходит запрос на прерывание INT. Когда закончится другое прерывание, первым будет обработанно INT, при этом значение в TCNT будет уже довольно большим, а флаг OCF1A, будет выставлен. Нам важно, если делать, как я, только одно значение TCNT - 1999. Если флаг OCF1A - установлен, мы будем в любом случае корректировать софт-слово, если, при этом значение счетчика 1999, мы будем корректировать (в сохраненной переменной) - устанавливать в 0 Цитата(singlskv @ Nov 8 2006, 01:41)  А теперь другая ситуация. Представте себе что во время выполнения не относящегося к нашему делу прерывания происходит запрос на прерывание INT.После окончания прерывания, начнется обработчик INT, но при считывании значений мы получили TCNT=1999 и выставленный флаг OCF1A. То же самое, что и выше Вот код, который я набросал для процедуры считывания периода: Код UINT SPEED_SENS_GetState(void) { /* запрещаем прерывание */ GICR &= ~SPEED_SENSOR_ISR_ENABLE;
/* считываем значения */ register ULONG stop = Pulse.Time[Pulse.Start ^ 1]; register ULONG start = Pulse.Time[Pulse.Start]; register UCHAR tifr_stop = Pulse.TIFR_reg[Pulse.Start ^ 1]; register UCHAR tifr_start = Pulse.TIFR_reg[Pulse.Start];
/* разрешаем прерывание */ GICR |= SPEED_SENSOR_ISR_ENABLE;
/* корректируем результат по состоянию флага OCF1A на момент считывания значений времени */ if(tifr_stop & (1 << OCF1A)) { stop += 65536; if(SYSTIMER_COMPARE_VAL == LOWORD(stop)) stop -= SYSTIMER_COMPARE_VAL; } if(tifr_start & (1 << OCF1A)) { start += 65536; if(SYSTIMER_COMPARE_VAL == LOWORD(start)) start -= SYSTIMER_COMPARE_VAL; }
/* считаем разность (STOP - START)*/ stop = (LOWORD(stop) >> 1) + /* преобразуем в мкс */ (HIWORD(stop) * 1000); start = (LOWORD(start) >> 1) + /* преобразуем в мкс */ (HIWORD(start) * 1000); /* преобразуем в Герцы и возвращаем */ return (UINT)(((LONGLONG)10000000) / abs(stop - start)); } Цитата(singlskv @ Nov 8 2006, 01:41)  Цитата Дело в том, что у меня счас тоже проект, в котором МК должен мерить импульсы от датчика скорости((( В ТЗ - от ИНТ0 и с точностю десятки микросекунд. А ТС1 выполняет роль системных часов.
В таком варианте, когда нужно мерить только от одного датчика, значительно проще и надежнее пользоваться пином ICP1 и прерыванием захвата таймера, правда коррекцию старшего слова все равно необходимо предусмотреть. Не факт, что завтра мне не дадут задание довесить еще один датчик... или 8 на весь порт...
--------------------
|
|
|
|
|
Nov 7 2006, 19:55
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(prottoss @ Nov 7 2006, 22:06)  Код UINT SPEED_SENS_GetState(void) { /* запрещаем прерывание */ GICR &= ~SPEED_SENSOR_ISR_ENABLE;
/* считываем значения */ register ULONG stop = Pulse.Time[Pulse.Start ^ 1]; register ULONG start = Pulse.Time[Pulse.Start]; register UCHAR tifr_stop = Pulse.TIFR_reg[Pulse.Start ^ 1]; register UCHAR tifr_start = Pulse.TIFR_reg[Pulse.Start];
/* разрешаем прерывание */ GICR |= SPEED_SENSOR_ISR_ENABLE;
/* корректируем результат по состоянию флага OCF1A на момент считывания значений времени */ if(tifr_stop & (1 << OCF1A)) { stop += 65536; if(SYSTIMER_COMPARE_VAL == LOWORD(stop)) stop -= SYSTIMER_COMPARE_VAL; } if(tifr_start & (1 << OCF1A)) { start += 65536; if(SYSTIMER_COMPARE_VAL == LOWORD(start)) start -= SYSTIMER_COMPARE_VAL; }
/* считаем разность (STOP - START)*/ stop = (LOWORD(stop) >> 1) + /* преобразуем в мкс */ (HIWORD(stop) * 1000); start = (LOWORD(start) >> 1) + /* преобразуем в мкс */ (HIWORD(start) * 1000); /* преобразуем в Герцы и возвращаем */ return (UINT)(((LONGLONG)10000000) / abs(stop - start)); } Ну так вроде будет работать, просто сравнение в прерывании с cерединой диапазона счетчика таймера - это более общий подход, который работает и в варианте использования ICP1 и прерывания захвата таймера. Только вот это я недопонял: Код if(tifr_stop & (1 << OCF1A)) { stop += 65536; if(SYSTIMER_COMPARE_VAL == LOWORD(stop)) stop -= SYSTIMER_COMPARE_VAL; } Почему мы добавляем 65536, а вычитаем только 1999 Хотя это конечно детали. Цитата Не факт, что завтра мне не дадут задание довесить еще один датчик... или 8 на весь порт... Ну тогда Вам и автору данного топика следует рассмотреть следующий вариант: 1. Подключаем датчики к соответствующим INTx. 2. Каждый пин INTx через диод подключаем к ICP1. 3. В каждом прерывании INTx считываем значение ICR1 вместо TCNT1. 4. Делаем корректировку по середине диапазона(можно в обработчике INTx, а можно и в основном цикле, кому как больше нравится) Понятно, что при перекрытии прерываний считанное из ICR1 значение будет отличаться от реального момента прерывания, но: 1. Такой подход даст нам более надежный имунитет от "других прерываний" 2. Общая (средняя) ошибка вычисления длительностей при перекрытии прерываний существенно уменьшится.
|
|
|
|
|
Nov 7 2006, 20:14
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(singlskv @ Nov 8 2006, 02:55)  Только вот это я недопонял: Код if(tifr_stop & (1 << OCF1A)) { stop += 65536; if(SYSTIMER_COMPARE_VAL == LOWORD(stop)) stop -= SYSTIMER_COMPARE_VAL; } Почему мы добавляем 65536, а вычитаем только 1999 Хотя это конечно детали.  Хм, я же объясняю, если флаг установлен, к СТАРШЕМУ слову прибавляем 1 Код stop += 65536; Если число в TCNT = 1999, TCNT = 0 Код if(SYSTIMER_COMPARE_VAL == LOWORD(stop)) stop -= SYSTIMER_COMPARE_VAL; Цитата Ну тогда Вам и автору данного топика следует рассмотреть следующий вариант: 1. Подключаем датчики к соответствующим INTx. 2. Каждый пин INTx через диод подключаем к ICP1. 3. В каждом прерывании INTx считываем значение ICR1 вместо TCNT1. 4. Делаем корректировку по середине диапазона(можно в обработчике INTx, а можно и в основном цикле, кому как больше нравится)
Понятно, что при перекрытии прерываний считанное из ICR1 значение будет отличаться от реального момента прерывания, но: 1. Такой подход даст нам более надежный имунитет от "других прерываний" 2. Общая (средняя) ошибка вычисления длительностей при перекрытии прерываний существенно уменьшится. Хрен редьки не слаще: Во первых диоды денех стоять, во вторых ловить флаг переполнения хардварного счетчика тоже нада
--------------------
|
|
|
|
|
Nov 7 2006, 20:38
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(prottoss @ Nov 7 2006, 23:14)  Хм, я же объясняю, если флаг установлен, к СТАРШЕМУ слову прибавляем 1 Код stop += 65536; Если число в TCNT = 1999, TCNT = 0 Код if(SYSTIMER_COMPARE_VAL == LOWORD(stop)) stop -= SYSTIMER_COMPARE_VAL; Да, я забыл что у Вас так хитро организован счетчик. Цитата Хрен редьки не слаще: Во первых диоды денех стоять, во вторых ловить флаг переполнения хардварного счетчика тоже нада Насчет диодов, это я слегка погорячился, там внешнюю логику надо ставить, но зато, можно получать 8 каналов, и при этом почти без ошибки.
|
|
|
|
|
Nov 7 2006, 21:06
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(singlskv @ Nov 8 2006, 03:38)  Цитата Хрен редьки не слаще: Во первых диоды денех стоять, во вторых ловить флаг переполнения хардварного счетчика тоже нада Насчет диодов, это я слегка погорячился, там внешнюю логику надо ставить, но зато, можно получать 8 каналов, и при этом почти без ошибки. Вот-вот, к тому же плата уже давно готовая и в серии...
--------------------
|
|
|
|
|
Nov 8 2006, 07:00
|
Частый гость
 
Группа: Свой
Сообщений: 94
Регистрация: 14-04-05
Из: Россия
Пользователь №: 4 130

|
Цитата(Alechin @ Nov 3 2006, 13:50)  Есть некий системный таймер, построенный на аппаратном таймере контроллера и расширенный его программным счетчиком (по переполнению таймера) (пример - 32-ух разрядный счетчик микросекунд системного времени). Задача - чтение на лету его значения. Попробуйте защелкивать значение таймера в ICP регистр. не прочитал всю тему было об этом уже.
Сообщение отредактировал ARIM - Nov 8 2006, 07:06
|
|
|
|
|
Nov 8 2006, 07:44
|
Частый гость
 
Группа: Свой
Сообщений: 94
Регистрация: 14-04-05
Из: Россия
Пользователь №: 4 130

|
Цитата(Alechin @ Nov 3 2006, 13:50)  Какие еще могут быть варианты? Каскадировать два 8-ми битных и один 16-ти битный таймеры. получим аппаратный 32-х разрядный.
|
|
|
|
|
Nov 8 2006, 08:46
|
Частый гость
 
Группа: Свой
Сообщений: 94
Регистрация: 14-04-05
Из: Россия
Пользователь №: 4 130

|
Цитата(prottoss @ Nov 8 2006, 11:09)  Цитата(ARIM @ Nov 8 2006, 14:44)  Цитата(Alechin @ Nov 3 2006, 13:50)  Какие еще могут быть варианты?
Каскадировать два 8-ми битных и один 16-ти битный таймеры. получим аппаратный 32-х разрядный. ...да, а если они все у Вас заняты разбейте плату молотком... или возьмите LPC21xx.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|