|
2 страниц
1 2 >
|
 |
Ответов
(1 - 21)
|
Apr 28 2011, 07:03
|
Гуру
     
Группа: Свой
Сообщений: 2 360
Регистрация: 6-03-06
Из: Кишинев
Пользователь №: 15 025

|
Цитата(loghir @ Apr 28 2011, 05:25)  Доброго времени суток! Сохраняется ли предзагрузка таймера более одного цикла работы? После первого переполнения или сброса модулем CCP? нет. Если вы хотите именно через TMR1 организовать прерывание с какой-то постоянной периодичностью, то нужно переустанавливать таймер после каждого переполнения. В простейшем случае: Код TMR1 = VALUE Лучше (это веди PIC16, он побайтово работает, а таймер-то 16-битный, для исключения запланированных проблем таймер лучше остановить на время модификации) Код TMR1ON = 0 TMR1 = VALUE TMR1ON = 1 Но от момента переполнения(обнуления) до момента модификации уже прошло какое-то время, лучше его учесть, если хотите сохранить период прерываний неизменным: Код TMR1ON = 0 TMR1 = TMR1 + VALUE TMR1ON = 1 Но во время остановки таймер не считал, так что нужно еще и это время учесть, если хотите чтобы период был именно тот что вы хотите, а не чуть больше: Код TMR1ON = 0 TMR1 = TMR1 + VALUE + DELTA TMR1ON = 1 (DELTA зависит от того, во что компилируются ваши команды от остановки до запуска таймера и может быть четко и однозначно рассчитана только для ассемблерного варианта) Если же все это происходит не в прерывании, то также рекомендую запретить прерывания на время выполнения, чтобы не заложить запланированную проблему в код: Код GIE = 0 TMR1ON = 0 TMR1 = TMR1 + VALUE + DELTA TMR1ON = 1 GIE = 1
|
|
|
|
|
Apr 28 2011, 09:47
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Позволю себе дополнить предыдущего оратора. Если используется прескейлер, то, т.к. он обнуляется при записи в TMR, через раз можно (если таки боремся за точность) накидывать ещё единичку Код TMR1 += VALUE + DELTA + 1 Результат компиляции Код TMR1 += VALUE + DELTA TMR1 = TMR1 + VALUE + DELTA может отличаться, если VALUE и/или DELTA не константы, с которыми справился препроцессор. (точнее было бы написать "должен отличаться", но писс, н-р, по-любому оптимизирует до Код TMR1 += VALUE + DELTA , а потом может сделать так Код TMR1 += (VALUE + DELTA) или так Код TMR1 += VALUE TMR1 += DELTA ) А если вдруг VALUE и/или DELTA окажутся volatile, то для получения однозначного результата проще оформить такой кусок ассемблерной вставкой.
|
|
|
|
|
Apr 28 2011, 13:21
|
self made
   
Группа: Свой
Сообщений: 855
Регистрация: 7-03-09
Из: Toronto, Canada
Пользователь №: 45 795

|
Цитата(Ruslan1 @ Apr 28 2011, 04:57)  ......Но если хочется совсем-совсем точно, то нужно использовать TMR2 в сочетании с PR2. +1. Так же поддерживаю вариант с TMR1 = TMR1 + VALUE + DELTA Дельта вычисляется эксперементальным путем -- запускаем симулятор и засекаем время между срабатываниями.
|
|
|
|
|
Apr 28 2011, 18:24
|
Участник

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

|
Спасибо за неожиданно информативный ответ! Насчет TMR2: в даташите сказано: Цитата После сброса значение регистра PR2 равно FFh. Получается, после сброса значение регистра PR2 нужно задавать заново?
|
|
|
|
|
May 15 2011, 12:47
|
Группа: Новичок
Сообщений: 5
Регистрация: 5-08-10
Из: Украина
Пользователь №: 58 765

|
Цитата(loghir @ Apr 28 2011, 05:25)  Доброго времени суток! Сохраняется ли предзагрузка таймера более одного цикла работы? После первого переполнения или сброса модулем CCP? для PIC16F876x Если Вам необходимо получить повторяющийся интервал на TMR1, то лучше использовать ССР1 в режиме автосброса таймера (CCP1CON bit3-0 = 1011 = Compare mode, trigger special event (CCPxIF bit is set, CCPx pin is unaffected); CCP1 resets TMR1) и предварительно загрузив требуемый период в CCPR1H и CCPR1L. Если период постоянный, то перезагружать CCPR1H и CCPR1L не надо.
|
|
|
|
|
May 17 2011, 09:56
|
Участник

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

|
Все ли у меня в порядке с настройками таймера? Код void init (void) // настройка TMR1 для 1.90735 сек { GIE = 1; // разрешены все немаскированные прерывания // регистр T1CON T1CKPS1 = 1; // выбор коэфф. деления предделителя T1CKPS0 = 0; // выбор коэфф. деления предделителя T1OSCEN = 0; // выключить внутренний тактовый генератор модуля TMR1 TMR1CS = 0; // 1 - выбран внешний (0 - внутренний, Fosk/4) источник тактового сигнала модуля TMR1 TMR1H = 0x0; // preset for timer1 MSB register TMR1L = 0x0; // preset for timer1 LSB register }
|
|
|
|
|
May 17 2011, 10:05
|
Участник

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

|
PEIE забыли. Ну и в тексте программы где-то дальше не забудьте вставить TMR1IE = 1 и TMR1ON = 1
|
|
|
|
|
May 17 2011, 11:34
|
Участник

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

|
sarqeinспасибо! Добавлю в настройку Код PEIE = 1; // разрешены все немаскированные прерывания от переферийных модулей TMR1IE = 1; // Разрешение прерывания по переполнению TMR1
|
|
|
|
|
May 17 2011, 13:17
|
Участник

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

|
Нигде не нашел данных: при Fosk/4 = 1 Mhz (при TMR1H = 0x0; TMR1L = 0x0;)
15,25879Hz T1CKPS1 = 0 T1CKPS0 = 0
7,62939Hz: T1CKPS1 = 0 T1CKPS0 = 1
3,8147Hz: T1CKPS1 = 1 T1CKPS0 = 0
1,90735 Hz: T1CKPS1 = 1 T1CKPS0 = 1
правильно?
Сообщение отредактировал loghir - May 17 2011, 13:17
|
|
|
|
|
May 17 2011, 14:08
|
Участник

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

|
Правильно, оно же все делением получается хорошо, что тут проверять?  11 = 1:8 10 = 1:4 01 = 1:2 00 = 1:1
|
|
|
|
|
May 23 2011, 09:33
|
Участник

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

|
Таймер упорно не работает: (счет не начинается) Код // MK pic16f72
#include <pic.h>
__CONFIG (XT & WDTDIS & PWRTDIS & BOREN & UNPROTECT); #define all_1 RC4 // общие провода 1-4 разрядов #define all_2 RC5 #define all_3 RC6 #define all_4 RC7 unsigned char time1 = 0; // объявляем глобальные переменные счетчика 1-4 разрядов и обнуляем их. unsigned char time2 = 0;
void podgot (void) { ADCON1 = 0x07; // отключение АЦП TRISA = 0b111111; // (0/1 - выход/вход, нумерация битов в регистре справо-налево) TRISB = 0b00000000; // (0/1 - выход/вход, нумерация битов в регистре справо-налево) TRISC = 0b00000000; // (0/1 - выход/вход, нумерация битов в регистре справо-налево) RBPU = 1; PORTA = 0; PORTB = 0b11111111; PORTC = 0b11111111; }
// для общего анода, КИПЦ-09. const unsigned char arr_seg [10] = { /* начало массива 0bABCDEFGH – расположение сегментов по битам */ 0b00000011, // «0» ! (справа-налево) 0-горит 0b10011111, // «1» ! 0b00100101, // «2» ! 0b00001101, // «3» ! 0b10011001, // «4» ! 0b01001001, // «5» ! 0b01000001, // «6» ! 0b00011111, // «7» ! 0b00000001, // «8» ! 0b00001001, // «9» ! };
void init (void) { // общие настройки таймеров // регистр INTCON GIE = 1; // разрешены все немаскированные прерывания PEIE = 1; // разрешены все немаскированные прерывания от переферийных модулей
// настройка TMR1 для 1,90735 Hz // регистр T1CON T1CKPS1 = 1; // выбор коэфф. деления предделителя T1CKPS0 = 1; // выбор коэфф. деления предделителя T1OSCEN = 0; // выключить внутренний тактовый генератор модуля TMR1 TMR1CS = 0; // 1 - выбран внешний (0 - внутренний, Fosk/4) источник тактового сигнала модуля TMR1 TMR1H = 0x0; // preset for timer1 MSB register TMR1L = 0x0; // preset for timer1 LSB register // конец настройки TMR1 для 1,90735 Hz }
void main (void) { podgot(); for(;;) { all_1 = 0; // общий анод PORTB = arr_seg [time1];
if (RA0 == 0) // запуск TMR1 { // регистр PIE1 TMR1IE = 1; // Разрешение прерывания по переполнению TMR1 TMR1ON = 1; // включить TMR1 }
if (RA1 == 0) // останов TMR1 { // регистр PIE1 TMR1IE = 0; // Запрет прерывания по переполнению TMR1 TMR1ON = 0; // выключить TMR1 }
while (TMR1IF == 0) // (пауза 1,90735 Hz) ожидание флага по переполнению TMR1 {} TMR1IF = 0;
time2 = time2 + 1; if (time2 == 2) // деление частоты превывания TMR1 на 2 { time2 = 0; time1 = time1 + 1; } if (time1 > 9) // чтобы "time1" не вышла за пределы массива { time1 = 0; } } } где ошибка?! На RA0 и RA1 подается +5В через резистор 4к7. Кнопка замыкает линии порта на "массу".
Сообщение отредактировал loghir - May 23 2011, 10:01
|
|
|
|
|
May 23 2011, 10:10
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(loghir @ May 23 2011, 13:33)  Код ... if (RA1 == 0) // останов TMR1 { // регистр PIE1 TMR1IE = 0; // Запрет прерывания по переполнению TMR1 TMR1ON = 0; // выключить TMR1 }
while (TMR1IF == 0) // (пауза 1,90735 Hz) ожидание флага по переполнению TMR1 {} TMR1IF = 0; // как Вы предполагаете попасть сюда с "TMR1ON = 0"? ... } где ошибка?! Вы забыли вызвать init() Просто за жизнь: - time1, time2 у Вас глобальные и будут обнулены в стандартном стартапе (т.е. при объявлении timeX = 0 писать не обязательно); - разрешать прерывания лучше после инициализации соответствующей периферии; - "нет, я столько не выпью", поэтому даже не стал пытаться понять, зачем GIE = 1, но ни одно прерывание не разрешено, да логику программы в целом.
|
|
|
|
|
May 23 2011, 10:34
|
Участник

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

|
Запускаем таймер низким на RA0: Код if (RA0 == 0) // запуск TMR1 { // регистр PIE1 TMR1IE = 1; // Разрешение прерывания по переполнению TMR1 TMR1ON = 1; // включить TMR1 } а затем, если не запущен TMR1, программа так и не выйдет из Код while (TMR1IF == 0) // (пауза 1,90735 Hz) ожидание флага по переполнению TMR1 {} TMR1IF = 0; вот тут я согрешил... Цитата зачем GIE = 1, на всякий случай. Цитата да логику программы в целом. и правильно, это только кусок общей программы. Спасибо, буду пробовать.
Сообщение отредактировал loghir - May 23 2011, 10:44
|
|
|
|
|
May 23 2011, 10:47
|
Участник

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

|
тоже не понял про прерывания, где interrupt isr()? +добавить антидребезг
upd. косяк в частоте кварца, в конфиге стоит XT, а где #define _XTAL_FREQ?
Сообщение отредактировал sargein - May 23 2011, 10:55
|
|
|
|
|
May 23 2011, 11:35
|
Участник

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

|
Цитата где interrupt isr() пока стараюсь далать максимально просто. Обхожусь без предзагрузки. Цитата +добавить антидребезг а зачем? Более одно раза включить (выключить) таймер нельзя физически. В документации на мой PICC 8.05pl2 Код #define _XTAL_FREQ (как и отдельно слова отсюда) я не нашел. При компиляции ошибок нет. Спасибо!!! Прога заработала.
|
|
|
|
|
May 23 2011, 12:31
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(sargein @ May 23 2011, 14:47)  тоже не понял про прерывания, где interrupt isr()? Упс-с, только сейчас заметил, что есть таки "TMR1IE = 1;" Топикстартеру - счастливой отладки... Цитата +добавить антидребезг Камлания вокруг TMR1 - это оно и есть Цитата upd. косяк в частоте кварца, в конфиге стоит XT, а где #define _XTAL_FREQ? ТС не использует макросы DelayX3(x) (к счастью), TMR1 у него работает на все 65536, так что оно ему и не надо. Цитата(loghir @ May 23 2011, 15:35)  пока стараюсь далать максимально просто. Обхожусь без предзагрузки. Вы продолжаете не понимать, что такое прерывания, зачем они нужны, и как с ними бороться в программе. Цитата В документации на мой PICC 8.05pl2 Код #define _XTAL_FREQ (как и отдельно слова отсюда) я не нашел. При компиляции ошибок нет.  Ищите XTAL_FREQ в *.h (н-р, в папке samples\dalay) Собственно компилятору знать тактовую частоту нафиг не нужно, но программеру иногда/обычно требуется. Цитата Спасибо!!! Прога заработала. С GIE = TMR1IE = TMR1ON = 1 и без какого-либо обработчика прерываний? "Всё чудесатей и чудесатей..."
|
|
|
|
|
May 23 2011, 14:22
|
Участник

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

|
Цитата Вы продолжаете не понимать, что такое прерывания, зачем они нужны, и как с ними бороться в программе. Цитата С GIE = TMR1IE = TMR1ON = 1 и без какого-либо обработчика прерываний? "Всё чудесатей и чудесатей..." Ну почему же? Да, обработчик прерываний у меня не выделен (пока!) в отдельную функцию. А так он вполне присутствует: Код while (TMR1IF == 0) // ожидание флага по переполнению TMR1 {} TMR1ON = 0; // выключить TMR1 TMR1IF = 0; // сброс флага прерывания по переполнению TMR1 ну еще надо добавить в цикл Код GIE = 1; // разрешены все немаскированные прерывания PEIE = 1; // разрешены все немаскированные прерывания от переферийных модулей только что заработала прога счета нажатий на кнопку (с антидребезгом, само собой). поправка: в PEIE не надо записывать 1 после каждого прерывания.
|
|
|
|
|
May 23 2011, 17:30
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(loghir @ May 23 2011, 18:22)  Ну почему же? Да, обработчик прерываний у меня не выделен (пока!) в отдельную функцию. У Вас в последних сорцах должно было приключаться прерывание по переполнению TMR1. Какой кусок программы, по Вашему мнению, выполнялся при этом? Цитата А так он вполне присутствует: Код while (TMR1IF == 0) // ожидание флага по переполнению TMR1 {} TMR1ON = 0; // выключить TMR1 TMR1IF = 0; // сброс флага прерывания по переполнению TMR1 Только не выделяйте это в отдельную функцию as is. имхо, Вы продолжаете подтверждать, что продолжаете не понимать. Цитата ну еще надо добавить в цикл Код GIE = 1; // разрешены все немаскированные прерывания PEIE = 1; // разрешены все немаскированные прерывания от переферийных модулей только что заработала прога счета нажатий на кнопку (с антидребезгом, само собой). поправка: в PEIE не надо записывать 1 после каждого прерывания. Да и GIE = 1 достаточно сделать однажды, если только Вы не отключаете все прерывания в каких-то критических местах. (такого в Вашем коде я не заметил)
|
|
|
|
|
May 31 2011, 08:31
|
Участник

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

|
Цитата(sargein @ May 23 2011, 13:47)  тоже не понял про прерывания, где interrupt isr()? Только что написал. Спасибо, прекрасно работает!
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|