|
|
  |
Как считать значение аппаратно-программного таймера... |
|
|
|
Nov 3 2006, 11:19
|

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

|
Цитата(Alechin @ Nov 3 2006, 10:50)  Есть некий системный таймер, построенный на аппаратном таймере контроллера и расширенный его программным счетчиком (по переполнению таймера) (пример - 32-ух разрядный счетчик микросекунд системного времени). Задача - чтение на лету его значения. Пока без остановки таймера это сделать у меня не получается (периодически получалась рассинхронизация переполнения счетчика аппаратного таймера и еще не инкрементированного старшего слова). Но при останове таймера происходит потеря точности счета. Приходится корректировать значение. Т.е. все довольно сложно. Какие еще могут быть варианты? Если переполнение таймера обрабатывается прерыванием, то возможен такой вариант. Запрещаете прерывания, читаете содержимое таймера и остальных байт и сохраняете их в памяти, затем разрешаете прерывания. Теперь спокойно анализируете содержимое таймера, если оно равно 0, то значит было переполнение, следовательно надо добавить перенос к старшим байтам, сохраненным в памяти, ни в коем случае не байты системного времени. Если оно не равно 0, значит переполнение уже учтено прерыванием, просто используете ваше текущее время по своему усмотрению.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Nov 3 2006, 11:20
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Alechin @ Nov 3 2006, 13:50)  Есть некий системный таймер, построенный на аппаратном таймере контроллера и расширенный его программным счетчиком (по переполнению таймера) (пример - 32-ух разрядный счетчик микросекунд системного времени). Задача - чтение на лету его значения. Пока без остановки таймера это сделать у меня не получается (периодически получалась рассинхронизация переполнения счетчика аппаратного таймера и еще не инкрементированного старшего слова). Но при останове таймера происходит потеря точности счета. Приходится корректировать значение. Т.е. все довольно сложно. Какие еще могут быть варианты? 1. запретить все прерывания 2. считать значение TCNT в регистры 3. скопировать значение старшего слова в регистры 4. если значение скопированное из TCNT маленькое и выставлен флаг TOV в регистре TIFR то к скопированному значению старшего слова добавить 1. 5. разрешить прерывания подробнее почитайте вот здесь http://electronix.ru/forum/index.php?showtopic=16900
|
|
|
|
|
Nov 3 2006, 12:46
|
Частый гость
 
Группа: Свой
Сообщений: 158
Регистрация: 27-06-05
Из: Химки, Моск.обл.
Пользователь №: 6 334

|
Цитата Если переполнение таймера обрабатывается прерыванием, то возможен такой вариант. Запрещаете прерывания, читаете содержимое таймера и остальных байт и сохраняете их в памяти, затем разрешаете прерывания. Теперь спокойно анализируете содержимое таймера, если оно равно 0, то значит было переполнение, следовательно надо добавить перенос к старшим байтам, сохраненным в памяти, ни в коем случае не байты системного времени. Если оно не равно 0, значит переполнение уже учтено прерыванием, просто используете ваше текущее время по своему усмотрению. Делал такой вариант - все равно проскакивают сбои - ведь пока читали одно из значений могло измениться. И непонятно, когда появился флаг переполнения до чтения таймера или после (у меня чтение значения таймера возможно и в прерывании с более высоким приоритетом, чем прерывание по перепролнению). А понятие "маленькое" растяжимо. Такой вариант уменьшил число сбоев многократно, но не исключил их (я по этому таймеру вычисляю период между метками, подаваемыми на прерывания - до этого раз в пять-шесть секунд были сбои, с данным вариантом раз в 20-30 секунд, с остановом - не дождался сбоя).
|
|
|
|
|
Nov 3 2006, 13:11
|
Местный
  
Группа: Свой
Сообщений: 303
Регистрация: 3-03-05
Пользователь №: 3 044

|
Цитата(Alechin @ Nov 3 2006, 15:46)  (я по этому таймеру вычисляю период между метками, подаваемыми на прерывания - до этого раз в пять-шесть секунд были сбои, с данным вариантом раз в 20-30 секунд, с остановом - не дождался сбоя). А если по подробней о задаче и поискать другой алгоритм (способ,метод) измерения? - какова тактовая частота контроллера и обязана ли она быть такой?; - период поступления "меток"?; - потребная точность измерения (только реально, а не "чем лучше тем лучше"?; - этот таймер меряет только это или еще для чего-то нужен?; - остальные таймеры заняты?; - почему обязательно "на лету"?; - а что за контроллер то?
--------------------
Опыт - чудесная вещь: легко использовать, можно продать, трудно пропить.
|
|
|
|
|
Nov 3 2006, 13:37
|
Частый гость
 
Группа: Свой
Сообщений: 158
Регистрация: 27-06-05
Из: Химки, Моск.обл.
Пользователь №: 6 334

|
Цитата А если по подробней о задаче и поискать другой алгоритм (способ,метод) измерения? - какова тактовая частота контроллера и обязана ли она быть такой?; - период поступления "меток"?; - потребная точность измерения (только реально, а не "чем лучше тем лучше"?; - этот таймер меряет только это или еще для чего-то нужен?; - остальные таймеры заняты?; - почему обязательно "на лету"?; - а что за контроллер то? Контроллер - M128L на 8 МГц. Выше нельзя - 3-ех Вольтовая. Задача - измерять частоту сигналов по 8-ми (пока 4-ем) входам. Частота - от 1 кГц (экстрим, обычно 100 Гц) до 0.5 Гц т.е. от 10 мсек до 2 сек (пропаданием сигнала считаю его отсутствие в течение 3 сек). При этом по каждому сигналу необходимо вести счет времени нахождения его частоты в заданном диапазоне (5 диапазонов). Кроме этого еще куча задач - не скоростных (RTC, дисплей, RF), поэтому реально свободен только один 16-ти разрядный таймер. Сделано так: на таймере (Т1) построен счетчик системного времени: TCNT1 - младшее слово, WORD переменная - старшее слово, инкрементируемое по перемполнению таймера (т.е. DWORD). Таймер тактируется 1 МГц (делитель на 8). Т.е. очень удобно - имеем 32-ух разрядный счетчик микросекунд (системное время, которое можно также использовать для нужд основной программы). Обработчики прерывания по каждому вх. сигналу просто считывают значение системного времени, вычисляют разницу с запомненным системным временем предыдущего вызова и ВНИМАНИЕ: добавляют эту разницу к счетчику времени нахождения в соотв. диапазоне частот. Все работает четко, много времени не занимает. Но при ошибках в чтении значения системного таймера счетчики времени работы в заданном диапазоне увеличиваются сразу на очень большое число (т.е. разность системных времен при рассинхронизации старшего и младшего слова получается большой). Это сразу заметно: счетчик тикает по секундам - вдруг раз - пара часов добавилась. Останавливать таймер не очень хорошо - так как при этом накапливается ошибка (получилось 2 мкс на чтение значения таймера). Надо оценить, насколько она велика, может плюноть на нее. В принципе за секунду имеем 100 * 4 прерывания - минимум 400 чтений таймера - почти 1 мсек. На измерении частоты (периода) это не должно сказываться - там время накопления ошибки не превышает периода сигнала, а вот при накоплении статистики (времени работы в диапазоне частот) - может сказаться - время накопления статистики - месяцы. Утомил? Может я не прав и зря все это замутил?
|
|
|
|
|
Nov 3 2006, 16:34
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
имхо, при входе в п/п обработки прерываний по входам можно устанавливать дополнительный флажок входа в эти прерывания, который сбрасывается после считывания TCNT1 или в п/п обработки прерывания TCNT1. Запрещать прерывание TCNT1 нужно только на время считывания TCNT1. Если после считывания TCNT1 флаг уже сброшен, необходимо скорректировать результат на время обработки прерывания TCNT1/(прескалер=8). Можно воспользоваться задержкой инкремента TCNT1 в прескалере и корректировать результат примерно так: Код tl=TCNT1L; th=TCNT1H; if(th!=TCNT1H) { tl=0; if(!++th) BigCnt++; } Т.к. нельзя исключить одновременных/наложенных прерываний от нескольких входов, стОит по прерыванию от любого входа проверять наличие прерываний от других входов и обрабатывать их с одним временем события.
|
|
|
|
|
Nov 3 2006, 19:37
|
Частый гость
 
Группа: Свой
Сообщений: 158
Регистрация: 27-06-05
Из: Химки, Моск.обл.
Пользователь №: 6 334

|
Цитата(singlskv @ Nov 3 2006, 18:01)  Покажите свой код. Попробуем подправить. А чего править - все чудесно работает, если останавливать таймер. Вопрос то был - есть ли еще способы. А так вот - код, с которым возникают проблемы: __monitor DWORD Get_Sys_Time(void) { return MAKE_DWORD(TCNT1, HiWord); } Возникают из-за того, что с не учитывается возможное переполнение таймера. Если же проверять флаг переполнения - то возникает ошибка (но гораздо реже) из-за того, что неизвестен момент переполнения - считанно значение TCNT до момента или после: если до - инкрементировать старшее слово не надо, если после - надо. Т.е. необходимо "защелкивать" TCNT и флаг переполения в одном командном цикле, что невозможно. А вот с этим не возникают: __monitor DWORD Get_Sys_Time(void) { TCCR1B &= ~(1 << 2); // Остановим таймер. WORD lo = TCNT1; // Считаем значение. WORD hi = HiWord; if((TIFR & (1 << TOV1)) != 0) hi++; TCCR1B |= (1 << 2); // Вновь запустим таймер. return MAKE_DWORD(lo, hi); } Здесь все четко - на момент чтения значений TCNT таймер остановлен и флаг переполнения однозначно говорит о том, что надо инкрементировать старшее слово. Вот многократный останов таймера в течение цикла мне и не нравится. Цитата Т.к. нельзя исключить одновременных/наложенных прерываний от нескольких входов, стОит по прерыванию от любого входа проверять наличие прерываний от других входов и обрабатывать их с одним временем события. Да это то-же ни к чему: мой алгоритм прост и эффективен - обработчики прерываний по входам выполняются за единицы микросекунд, этого вполне достаточно, что бы игнорировать потерю точности от задержки входа в обработчик (ожидания завершения обработки "соседних" входов). А вот накопление ошибки от останова таймера - критично, так как идет накопление времени между обработчиками, и получается, что каждый цикл измерения удлинен как-минимум на время одного считывания значения таймера (своего). А так как таких считываний сотни в секунду, а время накопления сотни тысяч секунд - ошибка становится значимой (возможно - надо оценить: ведь в принципе важно не столько просуммированное время, сколько процентное отношение времен работы в диапазонах частот - а тут ошибка возможно скомпенсируется).
|
|
|
|
|
Nov 3 2006, 20:24
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Alechin @ Nov 3 2006, 22:37)  А чего править - все чудесно работает, если останавливать таймер. Вопрос то был - есть ли еще способы.
А вот с этим не возникают: __monitor DWORD Get_Sys_Time(void) { TCCR1B &= ~(1 << 2); // Остановим таймер. WORD lo = TCNT1; // Считаем значение. WORD hi = HiWord; if((TIFR & (1 << TOV1)) != 0) hi++; TCCR1B |= (1 << 2); // Вновь запустим таймер. return MAKE_DWORD(lo, hi); } Попробуйте вот так: __monitor DWORD Get_Sys_Time(void) { WORD lo = TCNT1; // Считаем значение. WORD hi = HiWord; if (((TIFR & (1 << TOV1)) != 0)&&(lo<32768)) hi++; return MAKE_DWORD(lo, hi); }
|
|
|
|
|
Nov 7 2006, 05:31
|
Местный
  
Группа: Свой
Сообщений: 303
Регистрация: 3-03-05
Пользователь №: 3 044

|
О точности измерения частоты опять промолчали. Если: Цитата(Alechin @ Nov 3 2006, 16:37)  Задача - измерять частоту сигналов по 8-ми (пока 4-ем) входам. Частота - от 1 кГц то Цитата В принципе за секунду имеем 100 * 4 прерывания - минимум 400 чтений таймера - почти 1 мсек. это не совсем так. Что бы правильно считать таймер не останавливая надо что бы он не менялся за время чтения. Минимальная обработка прерывания до считывания как минимум состоит из Код push rTmp in rTmp,sreg push rTmp in rTmp,tcntL in rTmpH,tcntH , что составляет (10+1...3)*0,125=1,625 мкс, т.е в Вашем случае изменение таймера почти гарантировано (еще не известно, чего туда транслятор напихал). Простое увеличение К деления прескайлера уменьшит, но не исключит такую вероятность. Соответственно, если во время чтения tcntL в таймере было 01FF, то после чтения tcntH получим 02ff (или 00ff в зависимости от направления счета). Еще противней, если значение будет FFFF Если до чтения таймера нет переходов (время выполнения кода стабильное) можно проанализировать значение младшего байта и откорректировать считанное значение. Еще следует учесть, что при почти одновременном приходе нескольких прерываний, за время обработки первого таймер уйдет, пока начнется обработка следующего. Поэтому делитель прескайлера полезно сделать максимально большим (по крайней мере больше времени обработки прерывания). Вот зачем вопрос о требуемой точности.
--------------------
Опыт - чудесная вещь: легко использовать, можно продать, трудно пропить.
|
|
|
|
|
Nov 7 2006, 05:47
|

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

|
Цитата(CDT @ Nov 7 2006, 12:31)  О точности измерения частоты опять промолчали. Если: Цитата(Alechin @ Nov 3 2006, 16:37)  Задача - измерять частоту сигналов по 8-ми (пока 4-ем) входам. Частота - от 1 кГц
то Цитата В принципе за секунду имеем 100 * 4 прерывания - минимум 400 чтений таймера - почти 1 мсек. это не совсем так. Что бы правильно считать таймер не останавливая надо что бы он не менялся за время чтения. Минимальная обработка прерывания до считывания как минимум состоит из Код push rTmp in rTmp,sreg push rTmp in rTmp,tcntL in rTmpH,tcntH , что составляет (10+1...3)*0,125=1,625 мкс, т.е в Вашем случае изменение таймера почти гарантировано. Простое увеличение К деления прескайлера уменьшит, но не исключит такую вероятность. Соответственно, если во время чтения tcntL в таймере было 01FF, то после чтения tcntH получим 02ff (или 00ff в зависимости от направления счета). Еще противней, если значение будет FFFF Если до чтения таймера нет переходов (время выполнения кода стабильное) можно проанализировать значение младшего байта и откорректировать считанное значение. Че то дяденька Вы не в ту степь городите... извиняюсь за выражения. Вот выдержка из даташита ATmega32 (касается всех AVR с 16-бит ТС): 16-bit Timer/Counter1->
Accessing 16-bit Registers (Page 87): When the low byte of a 16-bit register is read by the CPU, the high byte of the 16-bit register is copied into the temporary register in the same clock cycle as the low byte is read.
То бишь, когда мы читаем младший байт 16-и разрядного регистра, старший байт автоматом копируется в спэшл фо ю сделанный temporary-регистр, при чем, в том же самом цикле, соответственно мы всегда будем иметь нормальное мгновенное значение счетчика ТС1 PS: Си компиляторы об этом знают, то бишь можно делать так: unsigned int cpount = TCNT1, ассемблеру это не ведомо, по этому надо сначала считывать младший байт, за тем старший...
--------------------
|
|
|
|
|
Nov 7 2006, 06:36
|
Местный
  
Группа: Свой
Сообщений: 303
Регистрация: 3-03-05
Пользователь №: 3 044

|
Цитата(prottoss @ Nov 7 2006, 08:47)  [ Че то дяденька Вы не в ту степь городите... извиняюсь за выражения. Вот выдержка из даташита ATmega32 (касается всех AVR с 16-бит ТС): 16-bit Timer/Counter1->
Accessing 16-bit Registers (Page 87): When the low byte of a 16-bit register is read by the CPU, the high byte of the 16-bit register is copied into the temporary register in the same clock cycle as the low byte is read.
То бишь, когда мы читаем младший байт 16-и разрядного регистра, старший байт автоматом копируется в спэшл фо ю сделанный temporary-регистр, при чем, в том же самом цикле, соответственно мы всегда будем иметь нормальное мгновенное значение счетчика ТС1 Да, запамятовал. Эти грабли из другого огорода. Тогда для начала надо выяснить: таймер неправильно читается или обрабатывается? И продолжить цитату: Код It is important to notice that accessing 16-bit registers are atomic operations. If an interrupt occurs between the two instructions accessing the 16-bit register, and the interrupt code updates the temporary register by accessing the same or any other of the 16-bit Timer Registers, then the result of the access outside the interrupt will be corrupted. Therefore, when both the main code and the interrupt code update the temporary register, the main code must disable the interrupts during the 16-bit access.
--------------------
Опыт - чудесная вещь: легко использовать, можно продать, трудно пропить.
|
|
|
|
|
Nov 7 2006, 12:34
|
Частый гость
 
Группа: Свой
Сообщений: 158
Регистрация: 27-06-05
Из: Химки, Моск.обл.
Пользователь №: 6 334

|
Цитата Че й то я так и не понял проблемы. Я делаю вот так: [code] /* системное время */ ULONG g_SysTIME_ms; /* милисекунды */
/***************************************************************************** Обработчик прерывания ТС1 по сравнению TCCR1A ******************************************************************************/ #pragma vector = TIMER1_COMPA_vect __interrupt void TIMER1_COMPA_isr(void) { g_SysTIME_ms++; } Отличие в том, что Ваш счетчик системного времени полностью программный (т.е. по каждому системному тику Вы программно инкрементируете счетчик системного времени). Это возможно только при низкой разрешающей способности - т.е. при микросекундной точности Вам пришлось бы прерываться для инкремента каждую микросекунду. У меня же младшее слово счетчика системного времени инкрементируется аппаратно (это счетный регистр таймера). Соотв. накладные расходы на такой таймер - одно прерывание по переполнению таймера за 65536 мксек. Вот тут то и проблема - пол счетчика аппаратные, половина нет.
|
|
|
|
|
Nov 7 2006, 12:54
|

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

|
Цитата(Alechin @ Nov 7 2006, 19:34)  Отличие в том, что Ваш счетчик системного времени полностью программный (т.е. по каждому системному тику Вы программно инкрементируете счетчик системного времени). Это возможно только при низкой разрешающей способности - т.е. при микросекундной точности Вам пришлось бы прерываться для инкремента каждую микросекунду. У меня же младшее слово счетчика системного времени инкрементируется аппаратно (это счетный регистр таймера). Соотв. накладные расходы на такой таймер - одно прерывание по переполнению таймера за 65536 мксек. Вот тут то и проблема - пол счетчика аппаратные, половина нет. Вы внимательно на код смотрите. Точнее вот на эту строку Код /* запоминаем текущее время */ Pulse.Time[Pulse.Start] = MAKEULONG(LOWORD(g_SysTIME_ms),TCNT1); Да, я выложил прошлый раз не весь код, вот функция которая возвращает время между двумя пришедшими импульсами: Код /***************************************************************************** Возвращает значение промежутка времени между двумя импульсами в мкс Так как значение времени не есть чистое шестнадцатиричное число (потому что старшее слово - есть количество 2-х тысячных значений младшего слова), нам приходится преобразовывать значения времени к нормальному шестнадцатиричному виду ******************************************************************************/ ULONG SPEED_SENS_GetState(void) { /* запрещаем прерывание */ GICR &= ~SPEED_SENSOR_ISR_ENABLE;
/* считываем значения */ register ULONG stop = Pulse.Time[Pulse.Start ^ 1]; register ULONG start = Pulse.Time[Pulse.Start];
/* разрешаем прерывание */ GICR |= SPEED_SENSOR_ISR_ENABLE;
/* считаем разность (STOP - START)*/ stop = (LOWORD(stop) >> 1) /* преобразуем в мкс */ * HIWORD(stop); start = (LOWORD(start) >> 1) /* преобразуем в мкс */ * HIWORD(start);
return stop - start; } Правда, частота моего МК 16 МГц, так что в вашем случае младшее слово содержало бы просто значение микросекунд. У меня прескалер ТС1 настроен, как и у Вас на div 8, прерывание по совпадению TCCR1A (1999) со сбросом ТС1. В главном цикле вызывается данная процедура, потом спокойно считается все что нам надо. Время выполнения прерывания менее 15 мкс (точно не считал)
Сообщение отредактировал prottoss - Nov 7 2006, 13:35
--------------------
|
|
|
|
|
Nov 7 2006, 13:49
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
2 prottossЦитата(prottoss @ Nov 7 2006, 10:04)  Код #pragma vector = SPEED_SENSOR_ISR __interrupt void SPEED_SENS_isr(void) { /* запоминаем текущее время */ Pulse.Time[Pulse.Start] = MAKEULONG(LOWORD(g_SysTIME_ms),TCNT1);
/* формируем новый индекс для стартового времени */ Pulse.Start ^= 1; } У Вас точно такая же проблемма в коде что и у автора топика. Что будет если в этой строке MAKEULONG(LOWORD(g_SysTIME_ms),TCNT1) Вы считаете значение TCNT1=0 ? А означать это будет переполнение таймера, то есть Вы получите время на 1ms меньше чем реальное. 2 AlechinВы попробовали подправленный код из поста #10 ?
|
|
|
|
|
Nov 7 2006, 14:22
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(prottoss @ Nov 7 2006, 17:06)  Цитата(singlskv @ Nov 7 2006, 20:49)  2 prottoss У Вас точно такая же проблемма в коде что и у автора топика. Что будет если в этой строке MAKEULONG(LOWORD(g_SysTIME_ms),TCNT1) Вы считаете значение TCNT1=0 ? А означать это будет переполнение таймера, то есть Вы получите время на 1ms меньше чем реальное. Да...на самом деле. Значит в функции, возвращающей значение периода необходимо добавить проверку младшего слова на значение ХХ, если меньше, то прибавлять к конечному результату еще одну 1000... Нет, не в функции возвращающей значение периода, а в прерывании. В Вашем случае это будет выглядеть примерно так: Код #pragma vector = SPEED_SENSOR_ISR __interrupt void SPEED_SENS_isr(void) { WORD lo = TCNT1; WORD hi = LOWORD(g_SysTIME_ms);
if (((TIFR & (1 << OCF1A)) != 0)&&(lo<1000)) hi++; // OCR1A/2 =1000
Pulse.Time[Pulse.Start] = MAKEULONG(hi,lo); Pulse.Start ^= 1; }
|
|
|
|
|
Nov 7 2006, 14:24
|

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

|
Цитата(Alechin @ Nov 7 2006, 12:34)  У меня младшее слово счетчика системного времени инкрементируется аппаратно (это счетный регистр таймера). Соотв. накладные расходы на такой таймер - одно прерывание по переполнению таймера за 65536 мксек. Вот тут то и проблема - пол счетчика аппаратные, половина нет. Насколько я понял, ваша проблема состоит в том, что одновременно с возникновением прерывания по переполнению таймера может возникнуть несколько из 4-х внешних прерываний, и затем, когда внешнее прерывание пытается считать системное время, оно еще не скорректировано в соответствующем прерывании, следовательно, возникает ошибка в 65 мс. Попробуйте изменить приоритет прерываний. При входе в любое внешнее прерывание тотчас разрешайте глобальные прерывания, тогда, при наличии прерывания по переполнению таймера, оно будет обработано в первую очередь, и ваши программы обработки внешнего прерывания получат правильное системное время. Временные рамки у вас огромные (1мс-2000мс), должно работать.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Nov 7 2006, 14:34
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(=GM= @ Nov 7 2006, 17:24)  Попробуйте изменить приоритет прерываний. При входе в любое внешнее прерывание тотчас разрешайте глобальные прерывания, тогда, при наличии прерывания по переполнению таймера, оно будет обработано в первую очередь, и ваши программы обработки внешнего прерывания получат правильное системное время. Да, это сильное решение Особенно красиво оно будет работать, когда одно внешнее прерывание будет считывать двумя командами регистр TCNT , и между этими командами возникнет другое внешнее прерывание
|
|
|
|
|
Nov 7 2006, 14:37
|

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

|
Цитата(singlskv @ Nov 7 2006, 21:22)  В Вашем случае это будет выглядеть примерно так: Код #pragma vector = SPEED_SENSOR_ISR __interrupt void SPEED_SENS_isr(void) { WORD lo = TCNT1; WORD hi = LOWORD(g_SysTIME_ms);
if (((TIFR & (1 << OCF1A)) != 0)&&(lo<1000)) hi++; // OCR1A/2 =1000
Pulse.Time[Pulse.Start] = MAKEULONG(hi,lo); Pulse.Start ^= 1; } Да нет уж, тогда делать не так. Лучше уж сделать в прерывании три регистровых переменных и последовательно считать в них значение TC1 и TIFR, потом спокойно все это сохранить в память, а уж разгребать потом в процедуре GetState. По крайней мере можно будет знать сколько тактов ошибки - всего 2 Цитата(singlskv @ Nov 7 2006, 21:34)  Цитата(=GM= @ Nov 7 2006, 17:24)  Попробуйте изменить приоритет прерываний. При входе в любое внешнее прерывание тотчас разрешайте глобальные прерывания, тогда, при наличии прерывания по переполнению таймера, оно будет обработано в первую очередь, и ваши программы обработки внешнего прерывания получат правильное системное время.
Да, это сильное решение Особенно красиво оно будет работать, когда одно внешнее прерывание будет считывать двумя командами регистр TCNT , и между этими командами возникнет другое внешнее прерывание Да уж, решение...
--------------------
|
|
|
|
|
Nov 7 2006, 14:48
|

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

|
Может быть вот так? Код __interrupt void SPEED_SENS_isr(void) { register UINT tcnt1_reg = TCNT1; register UCHAR tifr_reg = TIFR; /* запоминаем текущее время */ Pulse.Time[Pulse.Start] = MAKEULONG(LOWORD(g_SysTIME_ms),tcnt1_reg); Pulse.TIFR_reg = tifr_reg;
/* формируем новый индекс для стартового времени */ Pulse.Start ^= 1; } ну а в функции возврата периода импульса все считать... Вот что получилось в Release: Код ...
0000001C B72F IN R18, 0x3F 141 register UINT tcnt1_reg = TCNT1; \ 0000001E B54C IN R20, 0x2C \ 00000020 B55D IN R21, 0x2D 142 register UCHAR tifr_reg = TIFR; \ 00000022 B628 IN R2, 0x38
...
--------------------
|
|
|
|
|
Nov 7 2006, 14:56
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(prottoss @ Nov 7 2006, 17:37)  Цитата(singlskv @ Nov 7 2006, 21:22)  В Вашем случае это будет выглядеть примерно так: Код #pragma vector = SPEED_SENSOR_ISR __interrupt void SPEED_SENS_isr(void) { WORD lo = TCNT1; WORD hi = LOWORD(g_SysTIME_ms);
if (((TIFR & (1 << OCF1A)) != 0)&&(lo<1000)) hi++; // OCR1A/2 =1000
Pulse.Time[Pulse.Start] = MAKEULONG(hi,lo); Pulse.Start ^= 1; } Да нет уж, тогда делать не так. Лучше уж сделать в прерывании три регистровых переменных и последовательно считать в них значение TC1 и TIFR, потом спокойно все это сохранить в память, а уж разгребать потом в процедуре GetState. По крайней мере можно будет знать сколько тактов ошибки - всего 2 Ну можно конечно TIFR и в память писать, это уже кому как удобно. А количество тактов ошибки все равно непредсказуемо, например в ситуации когда одновременно пришло несколько внешних прерываний. Именно по этой причине идет сравнение (lo<1000).
|
|
|
|
|
Nov 7 2006, 15:23
|

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

|
Цитата(singlskv @ Nov 7 2006, 21:56)  А количество тактов ошибки все равно непредсказуемо, например в ситуации когда одновременно пришло несколько внешних прерываний. Именно по этой причине идет сравнение (lo<1000). Почему это не предсказуемо? У нас не предсказуемо значение софтверного слова счетчика до момента, пока мы не считали TCNT и пока мы не проанализировали OCF1A, потому что с периода входа в прерывание INT и до считывания TIFR счетчик мог переполнится, и, естественно, g_SysTIME_ms, тоже должно быть инкременированно. То что будет после считывания TIFR и TCNT1 нас уже не касается, это будущее состояние . То бишь OCF1A является 16-ым разрядом TCNT1 и нулевым разрядом g_SysTIME_ms. Считывая его и счетчик TCNT мы как раз и имеем полныое представление о программно-аппаратном счетчике. И ошибкf будет всего один такт TCNT1 (я ошибся в прошлом посте, сказав, что 2 такта)
--------------------
|
|
|
|
|
Nov 7 2006, 15:36
|

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

|
Цитата(singlskv @ Nov 7 2006, 14:34)  Цитата(=GM= @ Nov 7 2006, 17:24)  Попробуйте изменить приоритет прерываний. При входе в любое внешнее прерывание тотчас разрешайте глобальные прерывания, тогда, при наличии прерывания по переполнению таймера, оно будет обработано в первую очередь, и ваши программы обработки внешнего прерывания получат правильное системное время.
Да, это сильное решение Особенно красиво оно будет работать, когда одно внешнее прерывание будет считывать двумя командами регистр TCNT , и между этими командами возникнет другое внешнее прерывание  Для автора важно, чтобы программа обработки внешних прерываний могла на лету получать корректное системное время и различие в 10-20 тактов считанного времени от текущего не имеет для него никакого значения на фоне 80000 тактов и более. Предлагаемое решение обеспечивает такую возможность, а также применимо для 8-ми прерываний. Другое дело, что для критических секций кода (например, при чтении двух старших байт системного времени или для вышеупомянутого случая) нужно запрещать все прерывания. Тут вы совершенно правы.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Nov 7 2006, 16:18
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(prottoss @ Nov 7 2006, 18:23)  Цитата(singlskv @ Nov 7 2006, 21:56)  А количество тактов ошибки все равно непредсказуемо, например в ситуации когда одновременно пришло несколько внешних прерываний. Именно по этой причине идет сравнение (lo<1000). Почему это не предсказуемо? У нас не предсказуемо значение софтверного слова счетчика до момента, пока мы не считали TCNT и пока мы не проанализировали OCF1A, потому что с периода входа в прерывание INT и до считывания TIFR счетчик мог переполнится, и, естественно, g_SysTIME_ms, тоже должно быть инкременированно. То что будет после считывания TIFR и TCNT1 нас уже не касается, это будущее состояние . То бишь OCF1A является 16-ым разрядом TCNT1 и нулевым разрядом g_SysTIME_ms. Считывая его и счетчик TCNT мы как раз и имеем полныое представление о программно-аппаратном счетчике. И ошибкf будет всего один такт TCNT1 (я ошибся в прошлом посте, сказав, что 2 такта) Представте себе что одновременно пришло 2 внешних прерывания. Выполнятся начнет то, которое приоритетнее. А второе прерывание начнет выполняться только после окончания первого, то есть для второго прерывания ошибка будет равна времени работы первого прерывания + время входа во второе прерывание до момента считывания TCNT.
|
|
|
|
|
Nov 7 2006, 16:30
|

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

|
Цитата(singlskv @ Nov 7 2006, 23:18)  Представте себе что одновременно пришло 2 внешних прерывания. Выполнятся начнет то, которое приоритетнее. А второе прерывание начнет выполняться только после окончания первого, то есть для второго прерывания ошибка будет равна времени работы первого прерывания + время входа во второе прерывание до момента считывания TCNT. Если суммарное время прерываний больше периода счета счетчика TCNT1, тогда конечно - но это 1 МС! Конечно, если писать прерывания в стиле avr123 ), тада да. А если нет, что тогда? У нас счетчик считает в реалтайме, по этому каждое прерывание получит свое значения и только в одном из прерываний будет установлен 16-ый бит софтварного счетчика - OCF1A. Кроме того, что я это представлял, я еще моделировал различные ситуации с данной проблемой в AVRStudio...
--------------------
|
|
|
|
|
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.
|
|
|
|
|
Nov 9 2006, 19:00
|
Частый гость
 
Группа: Свой
Сообщений: 158
Регистрация: 27-06-05
Из: Химки, Моск.обл.
Пользователь №: 6 334

|
Цитата(prottoss @ Nov 9 2006, 19:49)  А что автор топика примолк, решил проблемцу так же, как я предлагал, или еще че получше напридумывал? Да нет - оставил все как есть - с сотановкой таймера на время чтения значения системного времени. Прикинул - погрешность незначительная, зато код минимален (никаких коррекций и "лишних" проверок. Да и времени ковыряться совсем нет (даже конференции просматривать часто только в выходные время нахожу
|
|
|
|
|
Nov 9 2006, 19:27
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Alechin @ Nov 9 2006, 22:00)  Цитата(prottoss @ Nov 9 2006, 19:49)  А что автор топика примолк, решил проблемцу так же, как я предлагал, или еще че получше напридумывал?
Да нет - оставил все как есть - с сотановкой таймера на время чтения значения системного времени. Прикинул - погрешность незначительная, зато код минимален (никаких коррекций и "лишних" проверок. Да и времени ковыряться совсем нет (даже конференции просматривать часто только в выходные время нахожу  Ню-ню, то есть останавливать/запускать таймер это не "лишний" код, а сделать пару проверок, по времени выполнения, сравнимых с остановом/запуском таймера, это уже "лишний" код... Нафига, тогда было вообще задавать свой вопрос
|
|
|
|
|
Nov 10 2006, 06:51
|
Частый гость
 
Группа: Свой
Сообщений: 94
Регистрация: 14-04-05
Из: Россия
Пользователь №: 4 130

|
Цитата(prottoss @ Nov 9 2006, 20:40)  Цитата(ARIM @ Nov 8 2006, 15:46)  или возьмите LPC21xx. А че мелочится то? Ставим сразу пенек двуголовый, нехай пашет некорректное сравнение
|
|
|
|
|
Nov 10 2006, 12:13
|

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

|
Цитата(singlskv @ Nov 10 2006, 02:27)  Цитата(Alechin @ Nov 9 2006, 22:00)  Цитата(prottoss @ Nov 9 2006, 19:49)  А что автор топика примолк, решил проблемцу так же, как я предлагал, или еще че получше напридумывал?
Да нет - оставил все как есть - с сотановкой таймера на время чтения значения системного времени. Прикинул - погрешность незначительная, зато код минимален (никаких коррекций и "лишних" проверок. Да и времени ковыряться совсем нет (даже конференции просматривать часто только в выходные время нахожу Ню-ню, то есть останавливать/запускать таймер это не "лишний" код, а сделать пару проверок, по времени выполнения, сравнимых с остановом/запуском таймера, это уже "лишний" код... Нафига, тогда было вообще задавать свой вопрос Да уж, за вечер решил проблему свою и того парня, а он нос воротит...
--------------------
|
|
|
|
|
Nov 10 2006, 12:40
|

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

|
Цитата(ARIM @ Nov 10 2006, 13:51)  Цитата(prottoss @ Nov 9 2006, 20:40)  Цитата(ARIM @ Nov 8 2006, 15:46)  или возьмите LPC21xx. А че мелочится то? Ставим сразу пенек двуголовый, нехай пашет некорректное сравнение А я бы сказал, с Вашей стороны некорректное предложение. Если из за каждой мелочной проблемы сразу пытаться менять платформу...Ну так мы, ребята, до мышей дое...дем. Против АРМов ничего не имею. Но тема была не "Подскажите какую платформу применить лучше...", а про то, как проще убить двух зайцев. А то, что Вы предложили можно предлагать в каждом втором топике форума про АВР. Типа... "Что делать, у меня тото не работает? - А Вы в ответ - "А поставте нах АРМ!!!", а тут новая тема "Как решить вот такую то нетривиальную задачу, а?" - А Вы опять "Я же говорил АРМ поставить! ". Вы тут самым умным будете, и все Вас уважать начнут... Точно говорю
--------------------
|
|
|
|
|
Nov 10 2006, 12:59
|
Частый гость
 
Группа: Свой
Сообщений: 94
Регистрация: 14-04-05
Из: Россия
Пользователь №: 4 130

|
Цитата(prottoss @ Nov 10 2006, 15:40)  Цитата(ARIM @ Nov 10 2006, 13:51)  Цитата(prottoss @ Nov 9 2006, 20:40)  Цитата(ARIM @ Nov 8 2006, 15:46)  или возьмите LPC21xx. А че мелочится то? Ставим сразу пенек двуголовый, нехай пашет некорректное сравнение А я бы сказал, с Вашей стороны некорректное предложение. Если из за каждой мелочной проблемы сразу пытаться менять платформу...Ну так мы, ребята, до мышей дое...дем. Против АРМов ничего не имею. Но тема была не "Подскажите какую платформу применить лучше...", а про то, как проще убить двух зайцев. А то, что Вы предложили можно предлагать в каждом втором топике форума про АВР. Типа... "Что делать, у меня тото не работает? - А Вы в ответ - "А поставте нах АРМ!!!", а тут новая тема "Как решить вот такую то нетривиальную задачу, а?" - А Вы опять "Я же говорил АРМ поставить! ". Вы тут самым умным будете, и все Вас уважать начнут... Точно говорю АРМ было предложено ставить из-за того что там счетчик 32-х разрядный и подобная проблема даже не возникла бы. насчет того какая была тема я помню. автор спросил про варианты.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|