Таймер-счетчик tmr0 (предзагрузка)

Важный элемент программ - ПРЕРЫВАНИЯ (INT)

Таймер-счетчик tmr0 (предзагрузка)

Сообщение mim (mim) » 12 ноя 2012, 11:31

Частенько возникает задача (хотя ее можно решить и на основе других таймеров), которая требует установить, на основе Таймера_0 (tmr0), точного (целого) числа прерываний (или частот отличных от возможностей предделителя).
Рассмотрим 8-ми разрядный таймер-счетчик tmr0, если с ним разобраться во всех нюансах, то с остальными таймерами проблем уже не будет.
Итак, регистр управления таймером tmr0 называется option_reg.
В Hi-tech его название немного сократили до OPTION, но это одно и тоже.
Вообще, узнать, как названы регистры в компиляторе можно открыв подключаемый библиотечный файл для своего контроллера. Для этого заходим в директорию, где у вас установлен FC, и ищем папку "include" в ней располагаются все библиотечные файлы. Далее открываем знакомый нам файл ххх.h и изучаем его.
В архиве приведено описание таймера и приложен файл в формате Excel, в котором представлена модель таймера, а также дан исходный текст фрагментов программ на Си и указаны регистры, связанные с работой таймера (текст можно копировать в исходник FC для других задач). При запуске файла в Excel разрешите выполнение макросов (вирусов нет).
TMR0.rar

Рассмотрим задачу, которая заключается в установке определенного значения частоты прерывания на основе Таймера_0 (tmr0) методом предзагрузки регистра tmr0.
Предзагрузка – это предварительная запись в регистр таймера числа, которое определяет начальное значение регистра таймера.
Начальное значение регистра таймера – это значение, от которого начинается отсчет временного интервала.
Обычно в режиме прерывания регистра tmr0 отсчитывает свое значение от 0 до 255 (8 бит). Если в регистр tmr0 предварительно занести число, то отсчет будет начинаться от занесенного значения до 255, тем самым время счета будет уменьшено (уменьшится период), а значит, увеличится частота прерывания. Предзагрузку tmr0 нужно делать в прерывании, и как можно раньше (хотя все это зависит от задачи и правильного понимания что делаешь).
Ниже приведен простенький пример.
tmr_0.rar

Пусть есть необходимость установить частоту прерывания равную 12,5 кГц. Получить такую частоту, если МК тактируется частотой 8 МГц простым делением (установкой предделителя) не получится.
Можно провести расчеты предзагрузочного значения (по командам на ассм), а можно запустить программу «PIC_Timer_Calculator», существуют разные версии написанные разными авторами. В программе «PIC_Timer_Calculator» устанавливаем частоту тактирования МК, устанавливаем предделитель 1:1 и передвигаем движок TMR0 Preload до тех пор, пока не поймаем нужную частоту прерывания (это будет 96). Пишем в программу строчку tmr0=96;.
Запустите пример и посмотрите на значение частоты. Значение частоты не будет соответствовать расчетному. Так и должно быть. Это происходит из-за задержек, связанных с выполнением участка программы по переходу на подпрограмму прерывания. Как это выглядит? После того как tmr0 досчитал до 255 в следующем цикле будет выполнен переход на прерывание, таймер при этом начнет отсчет с нуля и к тому моменту, когда в подпрограмме прерывания написана строчка tmr0=96; будет уже насчитано некоторое количество тиков таймера (это проверка флага, время перехода на подпрограмму, блокировка прерывания и т.д. смотрите файл ассемблера). Что бы компенсировать это время нужно знать, сколько команд (циклов) выполнено к моменту загрузки таймера. Нужно подсчитать команды в ассемблере – это не очень удобно.
Запускаем пример в Протеусе и смотрим на показания частотомера – 10638 (10639) Гц. В калькуляторе перемещаем движок ISR Overhead до тех пор, пока калькулятор не покажет частоту равную 10638 с дробными числами (поэтому Протеус и прыгает 10638 или 10639). Значение ISR Overhead будет равно 28 (шаг влево или вправо будет сильно отличаться от показаний искомой частоты). Таким образом, в tmr0 нужно записывать число 96+28=124. Смотрите пример ниже. Задача решена.
tmr0+.rar
У вас нет доступа для просмотра вложений в этом сообщении.
I Am Legend
Аватар пользователя
Ник: mim
Имя: mim
(Из Лесу, вестимо...)
Легенда
Легенда
Информация о пользователе

Re: Таймер-счетчик tmr0 (предзагрузка)

Сообщение mim (mim) » 30 авг 2013, 11:32

Как-то все не доходили руки до завершения темы.
Ведь реально, вопрос остался далеко не решенным.
Более того, ни в одном из примеров, как в инете, так и в умных книгах вопрос не рассмотрен полностью (по крайней мере, я не встречал этого), может потому, что на хрен никому не нужно. Поправьте если что…
Так, вот, что касаемо предзагрузки таймера, когда предделитель отличается от единицы…
Задача усложняется. Связано это с тем, что предделитель это тот же регистр, но включенный перед таймером и имеет одно нехорошее, в данном случае, свойство. Поскольку в ФК, напрочь отсутствуют средства отладки, я покажу это на примере моего любимого Протеуса...
Прочтите внимательно ДШ на МК. В ДШ говорится, что при записи числа в регистр таймера (tmr0) - обнуляется предделитель, записывать и читать предделитель не возможно. Кроме того, после записи, приращение tmr0 и предделителя запрещено в течение двух машинных циклов. В ДШ написано, например, если коэффициент предделителя равен 2, то после операции записи в регистр tmr0 приращение таймера не будет происходить в течение 4 циклов (и приводится рисунок).
При коеффициенте деления – «один» (без делителя) длительность циклов команд процессора совпадает с периодом тактирования таймера. При этом хорошо получается эмпирическим путем вычислить количество циклов МК до предзагрузки таймера (что выше мы и сделали). Если перед таймером включен делитель, то делитель тактируется частотой F/4 (и это есть 1/(F/4) = цикл команд МК), а таймер тактируется через делитель - F/4/k, где k, коэффициент деления.
При частоте процессора 8 Мгц, цикл команды равен 8000000/4=2000000 Гц => 0,5 мкс (500 нс). Этой же частотой и с таким же периодом тактируется и таймер без делителя. При делении на 64, цикл команд остается такой же, а цикл тактирования таймера делится на 64, 8000000/4/64=31250 Гц и равен 32 мкс.
При этом, не нужно забывать, что 28 циклов (это для нашей программы, количество циклов в прерывании до загрузки таймера) как были, так и остались и эти циклы будут выполняться до предзагрузки таймера tmr0. Но, теперь эти 28 циклов будут тактировать предделитель и физически, как 28 импульсов, будут размещены в предделителе. При записи числа в tmr0 предделитель обнулится и число 28, которое было на предделителе, сбросится.
Решаем задачу далее. Попробуем установить частоту прерывания 125 Гц. PIC_Timer_Calculator показывает, что при делении на 64, предзагрузка таймера должна равняться числу 6.
Пример ниже.
124_125.rar

Видим, что частотомер показывает 125 Гц, но, обращаем внимание, что периодически проскакивают показания 124 Гц. Это значит, что реально частота находится между 124 и 125 гц. Вывод - частота установлена не точно. Если воспользоваться диаграммой, то можно точно просчитать период. Какое же число нужно загрузить в tmr0, если число 6 это меньше 125, а число 7 (по калькулятору) это больше чем 125 гц (125, 50201 гц)? Число 6 это мало, число 7 это много, и это значит, что МК от числа 6 до числа 7 выполнит 64 цикла (32мкс).
Поскольку, мы можем записывать значения только в tmr0, то и оперировать теперь можем только с тактированием таймера после предделителя, а это уже с шагом 32 мкс. Такой шаг ограничивает наши возможности по разрешению счета таймера – было 0,5 мкс, стало 32 мкс. Это значит, что пока через делитель не пройдет 64 импульса - значение таймера не изменится. Таким образом, когда в таймер записали число 6, при этом значение предделителя уже было равно 28, и оно сбросится в ноль, и до очередного тика таймера (до 7) предделитель должен просчитать очередные 64 импуса (цикла), при появлении значения 7 на таймере, реально пройдет 28+64=92 цикла. Период удлинился на 28 циклов. Поэтому и нет точных 125 Гц, а поскольку период удлинился, значит, частота уменьшилась.
Вывод из всего выше описанного, изменять значение таймера необходимо только в моменты, когда предделитель досчитал (то есть, когда в предделителе пусто).
Это накладывает определенные сложности на предзагрузку таймера. Мы должны попасть в момент, когда предделитель досчитал и обнулился. Для этого в таймер нужно записать число на единицу больше чем расчетное число. Если число 6 соответствует частоте 125 гц, то должны записать число 7, которое соответствует частоте 125, 50201 Гц.
Это частота больше чем нам нужно, уменьшить частоту до требуемой, можно, если «придержать время», придержать время на столько, чтобы попасть в момент, когда предделитель равен нулю.
Вопрос, на сколько придержать время и как?
Это делается просто. Поскольку предделитель настроен на деление на 64, то и считает он до 64. Мы определили, что в момент прерывания на предделителе будет число 28, значит 64 минус 28, равно 36 – это количество машинных циклов (36*0,5=18 мкс). К этой цифре нужно добавить 2 (настолько циклов запрещено приращение предделителя, запрет преращения таймера уже учтен в числе 28). Один машинный цикл можно представить пустой командой nop();, ее длительность, в данном примере, равна 0,5 мкс.
В примере ниже, показано как это делается программно.
tmr_0_125.rar

Задержку нужно ставить перед загрузкой таймера. Вместо nop(); можно подобрать программную паузу в микросекундах, как точно рассчитывать паузы, было показано в теме про Частотомер. Там же показан способ, как точно посмотреть длительность периода используя Протеус.
Пример, если делитель установлен на 32 для частоты 250. 32-28=4. 4+2=6.
tmr_0_250_32.rar

Печальным есть тот факт, что нужно задерживаться в прерывании. Заполнить время вычисления расчетами? Только теми, которые имеют постоянное время выполнения.
Выводы.
Для установки точной частоты способом предзагрузки при использовании предделителя, нужно.
1. Опредеить количество циклов выполненных от момента прерывния до загрузки таймера. Решается установкой делителя – без деления.
2. Определить длительность задержки перед загрузкой таймера. Решается, вычитанием из числа делителя числа выполненных циклов, плюс 2 цикла и умножается на длительность цикла (64-28+2=38*0,5= 19 мкс).

Изменяя длительность паузы можно устанавливать частоту с шагом равным длительности цикла команд, а не с шагом, который показывает калькулятор (в примере это 0,5 мкс). Например, калькулятор показывает 124,00794, установить можно 124,00024. Это намного точнее.
У вас нет доступа для просмотра вложений в этом сообщении.
I Am Legend
Аватар пользователя
Ник: mim
Имя: mim
(Из Лесу, вестимо...)
Легенда
Легенда
Информация о пользователе


Вернуться в Прерывания в Flowcode

Кто сейчас на форуме

Пользователь просматривает форум: нет зарегистрированных пользователей

cron