|
|
  |
Работа таймера TMR0 (PIC16) |
|
|
|
May 29 2011, 17:28
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(SKov @ May 29 2011, 20:48)  Предзагрузка делается не так: TMR0 = TMR0 + 100; а вот так TMR0 = 100; Первый вариант позволяет таки учесть время, прошедшее с момента возникновения прерывания до момента собственно его обработки. Если требуется формирование не единичного интервала, а периода, равномерно размазанного вокруг расчётного значения, то он предпочтительнее. Цитата(sargein @ May 29 2011, 21:14)  Код volatile unsigned char tmp100; ...
|
|
|
|
|
May 29 2011, 18:01
|
Знающий
   
Группа: Свой
Сообщений: 812
Регистрация: 22-01-05
Из: SPb
Пользователь №: 2 119

|
Цитата(xemul @ May 29 2011, 21:28)  Первый вариант позволяет таки учесть время, прошедшее с момента возникновения прерывания до момента собственно его обработки. Не совсем так, т.к. при загрузке TMR0 сбрасывается прескалер. Тогда уж логично сбрасывать не только прескалер, а и сам основной счетчик. В этом случае мы как раз и получаем второй вариант.Ну, на самом деле это в принципе одно и то же (первый и второй вариант). Просто второй вариант действительно предзагрузка, а первый - предсуммирование или преддобавка, что звучит уж совсем коряво  Относительно "равномерно размазанного" интервала я не понял. Если предзагрузку ставить вначале ППОП (до ветвлений и других участков ППОП с неопределенным временем исполнения), то никакой "размазаности" не будет. Будет четкий период.
|
|
|
|
|
May 29 2011, 19:00
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(SKov @ May 29 2011, 22:01)  Не совсем так, т.к. при загрузке TMR0 сбрасывается прескалер. Тогда уж логично сбрасывать не только прескалер, а и сам основной счетчик. В этом случае мы как раз и получаем второй вариант.Ну, на самом деле это в принципе одно и то же (первый и второй вариант). Просто второй вариант действительно предзагрузка, а первый - предсуммирование или преддобавка, что звучит уж совсем коряво  Относительно "равномерно размазанного" интервала я не понял. Если предзагрузку ставить вначале ППОП (до ветвлений и других участков ППОП с неопределенным временем исполнения), то никакой "размазаности" не будет. Будет четкий период. Рассмотрите случай с несколькими источниками прерываний, когда прерывание от таймера возникает после проверки его флага, но внутри ППОП. Сброс прескейлера, в предположении, что он равномерно размазан на все состояния прескейлера, учитывается совершенно отдельно - типа "TMR0 += TMR0_PRESET + 1;" (или, ещё точнее "TMR0 += TMR0_PRESET + 0.5;" - т.е. 1 добавляется через раз).
|
|
|
|
|
May 29 2011, 19:46
|
Знающий
   
Группа: Свой
Сообщений: 812
Регистрация: 22-01-05
Из: SPb
Пользователь №: 2 119

|
Цитата(xemul @ May 29 2011, 23:00)  Рассмотрите случай с несколькими источниками прерываний, когда прерывание от таймера возникает после проверки его флага, но внутри ППОП. Сброс прескейлера, в предположении, что он равномерно размазан на все состояния прескейлера, учитывается совершенно отдельно - типа "TMR0 += TMR0_PRESET + 1;" (или, ещё точнее "TMR0 += TMR0_PRESET + 0.5;" - т.е. 1 добавляется через раз). Случай нескольких прерываний можно заменить, например, случаем, когда в основной программе есть куски с запретом прерываний. Другими словами, мы говорим о случае, когда время реакции на прерывания непредсказуемо. В этом случае надо смотреть на конкретный код программы. Если задержка реакции укладывается в несколько "тиков" таймера, тогда суммирование может нас спасти и обеспечить точность периода прерываний в пределах одного тика таймера. А если задержка может быть большая, то вообще теряется смысл предустановки. Можно рассмотреть и другой случай. Пусть задержка лежит в районе одного тика таймера плюс-минус несколько тактов Fosc/4. В этом случае прибавление константы дает нам "дрожание" периода прерываний примерно на величину одного тика таймера. А если мы выполняем загрузку таймера константой, то "дрожание" периода имеет величину всего лишь нескольких тактов Fosc/4. Так что бывают случаи, когда загрузка лучше суммирования
|
|
|
|
|
May 30 2011, 06:51
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(SKov @ May 29 2011, 23:46)  Так что бывают случаи, когда загрузка лучше суммирования  Я могу обосновать чиста математически, что загрузка в любом случае будет не лучше суммирования в смысле получения минимальной средней (или средней квадратичной - без разницы) ошибки формирования некоторого периода на любом числе периодов. Случай, когда загрузка будет равна по ошибке суммированию, вообще один - прерывания только от таймера с минимальным прескейлером, никаких критических секций в коде. Из очевидных минусов загрузки - собственно загружаемую константу придётся подрихтовать ручками, чтобы учесть задержку от возникновения прерывания до момента загрузки, или вставлять каким-либо образом этот учёт в считалку препроцессора. При суммировании оно учитывается само, и остаётся только решить, компенсировать ли сброс прескейлера или и так сойдёт.
|
|
|
|
|
May 30 2011, 07:29
|
Участник

Группа: Участник
Сообщений: 63
Регистрация: 13-03-11
Пользователь №: 63 577

|
Спасибо за гору инфы! Еще бы переварить... Добавил квалификатор volatile а всем переменным, используемым в ППОП. От предзагрузки таймера временно отказался, пока не разберусь, что происходит. Пока мне точность не нужна. Никак не докопаюсь, для чего нужен Код if (T0IF){} ППОП и так вызывается при появлении прерывания по переполнению TMR0. Также не пойму, как в некоторых случаях работает оператор while. В книге по микроС сказано: Цитата Ключевое слово while используется для организации условных циклов. Синтаксис оператора while: while (expression) statement. Оператор statement (тело цикла) выполняется раз за разом пока величина выражения expression не станет ложной. Проверка производится перед выполнением оператора statement. Таким образом, если expression ложно в самом первом проходе, цикл не выполняется. У Кернигана и Ритчи иная точка зрения: Цитата while (выражение) оператор. Здесь вначале вычисляется выражение. Если оно не равно нулю, выполняется оператор, а затем выражение вычисляется снова. Эти действия повторяются до тех пор, пока выражение не станет равным нулю. после этого управление передается на следующий оператор. И где истина?
Сообщение отредактировал loghir - May 30 2011, 07:33
|
|
|
|
|
May 30 2011, 07:40
|
Знающий
   
Группа: Свой
Сообщений: 812
Регистрация: 22-01-05
Из: SPb
Пользователь №: 2 119

|
Цитата(xemul @ May 30 2011, 10:51)  Я могу обосновать чиста математически, что загрузка в любом случае будет не лучше суммирования в смысле получения минимальной средней (или средней квадратичной - без разницы) ошибки формирования некоторого периода на любом числе периодов. Интересна не столько средняя ошибка, сколько ее дисперсия. Она определяет "дрожание" периода прерываний. Я выше приводил пример, когда время задержки между событием, вызывающим прерывание и моментом загрузки гуляет около одного тика таймера.(тик таймера = период срабатывания прескалера). Будем считать, что идеальным вариантом для нас является суммирование прескалера, когда задержка равна точно одному тику. Этот лишний тик мы учтем в прибавляемой константе. Это будет соответствовать нулевой ошибке. Если время задержки в какой-то момент оказалось чуть-чуть меньше тика таймера, то ошибка при суммирование таймера будет равна почти одному тику из-за обнуления прескалера, который к этому моменту накопил почти целый тик. Если задержка чуть-чуть больше одного тика, то при суммировании будет ошибка небольшая. Короче говоря, ошибка при суммировании будет определяться состоянием прескалера на момент суммировния. В среднем это примерно половина тика. В случае загрузки константы в моем примере дрожание периода определяется только интервалом времени, в котором гуляет задержка. Это интервал между "чуть-чуть меньше тика" и "чуть-чуть больше тика". Разница между этими моментами времени может быть существенно меньше времени тика таймера (и даже его половины). И следовательно, дисперсия периода будет небольшой. Чиста математически  Цитата(loghir @ May 30 2011, 11:29)  Никак не докопаюсь, для чего нужен Код if (T0IF){} . Флаг запроса взводится автоматически при возникновении события, могущего вызвать прерывание. А сбрасывать его должен сам программер в ППОП. Сложность в том, что вы попадаете в одно и то же ППОП при срабатывнии прерываний от нескольких разных источников. Вы должны определить, какой источник вас "позвал" в ППОП. Это делается опросом флагов запроса прерывания (по-умному это называется "полинг прерываний".) Если у вас разрешен только один источник прерываний, то эта проверка не нужна. Цитата Также не пойму, как в некоторых случаях работает оператор while. В книге по микроС сказано: У Кернигана и Ритчи иная точка зрения: И где истина? Истина в вине  В смысле - оба источника правы. Т.к. "Ложь" кодируется нулем, а все остальное - "Правда"!
|
|
|
|
|
May 30 2011, 08:18
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(SKov @ May 30 2011, 11:40)  Интересна не столько средняя ошибка, сколько ее дисперсия. Дисперсия == (средняя квадратичная ошибка)^2. Цитата Она определяет "дрожание" периода прерываний. Занятное определение, ну да ладно. Мне это было интересно во времена, когда у пиков система прерываний отсутствовала как класс, а строить какие-то диспетчеры задач и формировать интервалы всё равно приходилось. Повозил немного карандашом, пришёл к выводу... С тех пор математика (точнее, арифметика) работы таймеров не изменилась. Но у каждого кулика своё болото.  Цитата(loghir) Добавил квалификатор volatile а всем переменным, используемым в ППОП. Он нужен только переменным, _модифицируемым_ в прерываниях.
|
|
|
|
|
May 30 2011, 08:42
|
Знающий
   
Группа: Свой
Сообщений: 812
Регистрация: 22-01-05
Из: SPb
Пользователь №: 2 119

|
Цитата(xemul @ May 30 2011, 12:18)  Дисперсия == (средняя квадратичная ошибка)^2. Ну, это если "чиста математически".  Квадратичная ошибка, да еще и в квадрате - это сильно!  А если посмореть в букваре (можно в Википедии), то можно убедиться, что Дисперсия ошибки == средний квадрат отклонения от средней ошибки. Чувствуете разницу?
|
|
|
|
|
May 30 2011, 14:32
|
Участник

Группа: Участник
Сообщений: 63
Регистрация: 13-03-11
Пользователь №: 63 577

|
Вот что получилось: Код void init (void) { // настройка TMR0 на 100 Hz (сотые доли секунды). // регистр OPTION T0CS = 0; // bit 5 TMR0 Выбор источника сигнала 0 - Fosc/4 (внутренний); 1 - подача на T0CKI T0SE = 0; // bit 4 TMR0 Выбор фронта приращения TMR0 при внешнем тактовом сигнале (0-передний фронт) PSA = 0; // bit 3 Выбор включения предделителя: 0 - перед TMR0, 1 - перед WDT PS2 = 1; // bit 2 Настройка предделителя на 15 Гц PS1 = 1; // bit 1 Настройка предделителя на 15 Гц PS0 = 1; // bit 0 Настройка предделителя на 15 Гц TMR0 = 0; // предзагрузка TMR0, сбрасывается при переполнении. // конец настройки TMR0 на 100 Hz (сотые доли секунды). } Код void interrupt isr (void) { if (T0IF) // опрос флага прерывания по переполнению TMR0 (чтобы не сработало от другого источника) { while (45 - 1) // выполняется до тех пор, пока ( ) не равно 0. Задержка на 15 Гц * 45. Т.е. на 3 сек. { T0IF = 0; // сброс флага прерывания по переполнению TMR0 } time1 = time1 + 1; // это число выводится 7-сегментный индикатор. T0IF = 0; // сброс флага прерывания по переполнению TMR0 } } Вот только не срабатывает! Как был "0" на индикаторе, так и остался. Вариант Код ... volatile unsigned char tmp100 = 45; volatile unsigned char time1 = 0; ... void interrupt isr (void) { if (T0IF) // опрос флага прерывания по переполнению TMR0 (чтобы не сработало от другого источника) { while (tmp100) // выполняется до тех пор, пока tmp100 не равно 0. Задержка на 15 Гц * 45. Т.е. на 3 сек. { tmp100 = tmp100 - 1; // изменение переменной-задержки T0IF = 0; // сброс флага прерывания по переполнению TMR0 } time1 = time1 + 1; // это число выводится 7-сегментный индикатор. tmp100 = 45; // обнуление счетчика T0IF = 0; // сброс флага прерывания по переполнению TMR0 } } не изменяет скорость счета при изменении tmp100. Попытка написать Код void interrupt isr (void) после main() вызывает ощибку при компиляции.
Сообщение отредактировал loghir - May 30 2011, 14:33
|
|
|
|
|
May 30 2011, 15:28
|
Знающий
   
Группа: Свой
Сообщений: 812
Регистрация: 22-01-05
Из: SPb
Пользователь №: 2 119

|
Цитата(loghir @ May 30 2011, 18:32)  Вот что получилось: ... while (45 - 1) Это что такое? Бесконечный цикл? У вас проблемы не с микроконтроллером или с прерываниями. У вас проблемы с элементарным программированием.
|
|
|
|
|
May 30 2011, 15:37
|
Участник

Группа: Свой
Сообщений: 72
Регистрация: 31-01-10
Из: Минск
Пользователь №: 55 176

|
Цитата(loghir @ May 30 2011, 17:32)  while (45 - 1) офигенное условие Я же на прошлой странице привел фактически готовое решение, зачем столько хрени пихать в обработчик прерываний?
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|