loghir 0 23 мая, 2011 Опубликовано 23 мая, 2011 · Жалоба На данный момент проблема в смутном описании бита T0CS регистра OPTION: бит 5: T0CS: Выбор тактового сигнала для TMR0 1 = внешний тактовый сигнал с вывода RA4/T0CKI 0 = внутренний тактовый сигнал CLKOUT внутренний тактовый сигнал - это Fosc/4? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xemul 0 23 мая, 2011 Опубликовано 23 мая, 2011 · Жалоба На данный момент проблема в смутном описании бита T0CS регистра OPTION: внутренний тактовый сигнал - это Fosc/4? Да. На блок-схеме TMR0 всё разрисовано. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Redguy 0 25 мая, 2011 Опубликовано 25 мая, 2011 · Жалоба Блок-схема TMR0 тебе в помощь! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
loghir 0 25 мая, 2011 Опубликовано 25 мая, 2011 · Жалоба Спасибо. Но лучше бы авторы даташита делали его в одном стиле, с большим числом информации. Пробую получить с помощью TMR0 временной интервал в 1 сек - не работает. Цифры не меняются. // MK pic16f72 #include <pic.h> __CONFIG (XT & WDTDIS & PWRTDIS & BOREN & UNPROTECT); #define XTAL FREQ 4MHZ #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; unsigned char time3 = 0; unsigned char time4 = 0; unsigned char tmp100 = 0; bit DDF = 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; } // для общего анода const unsigned char arr_seg [10] = { 0b00000011, // «0» (справа-налево) 0-горит 0b10011111, // «1» 0b00100101, // «2» 0b00001101, // «3» 0b10011001, // «4» 0b01001001, // «5» 0b01000001, // «6» 0b00011111, // «7» 0b00000001, // «8» 0b00001001, // «9» }; 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 Настройка предделителя PS1 = 0; // bit 1 Настройка предделителя PS0 = 1; // bit 0 Настройка предделителя TMR0 = 100; // предзагрузка TMR0, сбрасывается при переполнении. // конец настройки TMR0 на 100 Hz (сотые доли секунды). } void stTMR0 (void) // запуск TMR0 { GIE = 1; // разрешены все немаскированные прерывания PEIE = 1; // разрешены все немаскированные прерывания от переферийных модулей T0IE = 1; // Разрешение прерывания по переполнению TMR0 T0IF = 0; // сброс флага прерывания по переполнению TMR0 } void intTMR0 (void) // обработчик прерываний TMR0 (вариант для 1 сек): { while (tmp100 < 100) { if(T0IF == 1) { tmp100 = tmp100 + 1; // прибавление до 100 (в сумме 1 сек) GIE = 1; // разрешены все немаскированные прерывания T0IF = 0; // сброс флага прерывания по переполнению TMR0 T0IE = 1; // Разрешение прерывания по переполнению TMR0 TMR0 = TMR0 + 100; // предзагрузка TMR0 } } time1 = time1 + 1; } void main (void) { podgot(); init(); for(;;) { all_1 = 0; PORTB = arr_seg [time1]; if ((RA0 == 0)|(DDF == 1)) // запуск TMR0 или продолжение счета при DDF == 1 { DDF = 1; stTMR0(); // запуск TMR0 intTMR0(); // обработчик прерываний TMR0 (вариант для 1 сек): } if (RA1 == 0) // останов TMR0 { DDF = 0; T0IE = 0; // запрет прерывания по переполнению TMR0 } if (time1 > 9) // чтобы "time1" не вышла за пределы массива { time1 = 0; } } } вроде все правильно , а в итоге "фиг вам". :smile3046: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
[sarge] 0 25 мая, 2011 Опубликовано 25 мая, 2011 · Жалоба программка жесткая какая-то, в частности выносы в функции меня в данном случае только больше запутывают :) ну а по теме: если вы хотите использовать прерывания то добавьте вот это после main() { } interrupt isr() { if (T0IF) { чего то делаем T0IF = 0; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xemul 0 25 мая, 2011 Опубликовано 25 мая, 2011 · Жалоба Обработчик прерываний для мелких пиков должен выглядеть interrupt void isr(void) { if(T0IF) // или if(T0IF && T0IE) { ... } if(TMR1IF) { ... } } Имя функции обработчика прерывания не важно, но слово interrupt в её объявлении должно присутствовать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
loghir 0 25 мая, 2011 Опубликовано 25 мая, 2011 (изменено) · Жалоба sargein, как работает оператор if (T0IF) ? xemul, при чем тут TMR1IF ? как правильно объявить функцию обработчика прерываний и как ее вызвать? interrupt void isr(void) при вызове выдает ошибку interrupt isr(); Error [195] D:\Work\PIC_CI\My_program\work_program_timer_dima\1.c; 95.1 expression syntax Изменено 25 мая, 2011 пользователем loghir Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
[sarge] 0 25 мая, 2011 Опубликовано 25 мая, 2011 · Жалоба пишите в конце своей программы вот это: interrupt isr() { if (T0IF) { tmp100 = tmp100 + 1; TMR0 = TMR0 + 100; T0IF = 0; } Вызывать ничего не надо, это прерывание, оно автоматически вызывается в случае T0IF = 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
loghir 0 25 мая, 2011 Опубликовано 25 мая, 2011 · Жалоба Если interrupt isr() { if (T0IF) { tmp100 = tmp100 + 1; TMR0 = TMR0 + 100; T0IF = 0; } писать до main, компилятор выдает ошибку: Warning [349] D:\Work\PIC_CI\My_program\work_program_timer_dima\1.c; 69.1 non-prototyped function declaration for "" Warning [349] D:\Work\PIC_CI\My_program\work_program_timer_dima\1.c; 69.1 non-prototyped function declaration for "isr" А если до main так: void interrupt isr (void) { if (T0IF) { tmp100 = tmp100 + 1; TMR0 = TMR0 + 100; T0IF = 0; } то программа просто не работает: цифры не меняются. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
[sarge] 0 25 мая, 2011 Опубликовано 25 мая, 2011 (изменено) · Жалоба писать надо после main() { } я ведь это уже два раза написал зы. по поводу программы, естественно ее еще отлаживать нужно, я просто указал как правильно обработку прерывания оформлять ззы. рекомендую вот тут FAQ почитать Изменено 25 мая, 2011 пользователем sargein Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xemul 0 25 мая, 2011 Опубликовано 25 мая, 2011 · Жалоба xemul, при чем тут TMR1IF ? Я забыл добавить ... после if(TMR1IF) {...}, т.к. описывал общий случай. У мелких пиков одноуровневая система прерываний, и все возможные прерывания обрабатываются в одной функции. Больше наивных предположений и вставок на подумать делать не буду. Если interrupt isr() { if (T0IF) { tmp100 = tmp100 + 1; TMR0 = TMR0 + 100; T0IF = 0; } писать до main, компилятор выдает ошибку: Warning [349] D:\Work\PIC_CI\My_program\work_program_timer_dima\1.c; 69.1 non-prototyped function declaration for "" Warning [349] D:\Work\PIC_CI\My_program\work_program_timer_dima\1.c; 69.1 non-prototyped function declaration for "isr" В мануале писс есть описания всех сообщений компилятора. Warning - предупреждение (в Вашем случае - о небрежном стиле программирования). Не знаю, какими букварями по С Вы пользуетесь, но, имхо, в любом написано, что функция должна быть объявлена до её использования. Т.к. обработчик прерывания явно не вызывается, то его всегда стоит объявлять явно. void interrupt isr (void); // объявление (прототип) функции int foo(int boo); // объявление другой функции с параметром и возвращаемым значением bit fTMR0; void main(void) { if(fTMR0) { foo(...); fTMR0 = 0; } } void interrupt isr (void) // сама функция (реализация) { if(T0IF) { T0IF = 0; fTMR0 = 1; } } int foo(int boo) { return boo+1; } Обычно прототипы функций помещают до main(), а реализацию - после или вообще в другом файле (тогда функция объявляется со словом extern). А если ... то программа просто не работает: цифры не меняются. Наверное, так прога написана. Предлагаете нам догадаться, как именно? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
loghir 0 25 мая, 2011 Опубликовано 25 мая, 2011 (изменено) · Жалоба Спасибо за подсказку. Буквари ценны тем, что быстро узнаешь структуру простейшей программы. А вот реализация у них, мягко говоря, хромает. Прога не работает оттого, что c TMR0 проблема. TMR1 в этом же коде прекрасно работает без функции обработчика прерываний. Вся беда в том, что в программе мне надо 3 временных промежутка... Основное достоинство самоучителей - что в одном не упомянут, в другом есть. Изменено 25 мая, 2011 пользователем loghir Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xemul 0 26 мая, 2011 Опубликовано 26 мая, 2011 · Жалоба Вся беда в том, что в программе мне надо 3 временных промежутка... Определите минимально необходимый дискрет времени, заведите какой-нить аппаратный таймер с таким дискретом (пока контроллеру делать нечего - без разницы, с прерыванием или опросом), все требуемые интервалы сделайте на программных счётчиках. unsigned char FRCnt; void main(void) { ... for(;;) { if(T0IF) { TMR0 += TMR0_PRESET; // TMR0_PRESET - константа, расчёт которой можно поручить препроцессору С, // задав частоту тактирования таймера и тот самый дискрет FRCnt++; // просто free-run counter, который поможет отсчитывать бОльшие интервалы // синхронные задачи // вызываемые на каждом дискрете dynamic_indication(); timers(); // вызываемые, н-р, на каждом 16-ом дискрете if(!(FRCnt & (16-1))) { keyscan(); // сканирование кнопок keyparse(); // разбор нажатий/отжатий кнопок timers_16(); } // вызываемые на каждом 256-ом дискрете if(!FRCnt) { запорожскиеказакипишутписьмотурецкомусултану(); timers_256(); FRCnt1++; // эта музыка будет вечной } } // а здесь можно разместить какие-нить асинхронные контроллеру задачи // и неспешные задачи, которые можно выполнять по кускам ... } } void keyparse(void) { if(Key0.b.Pressed) { LED0_OnTmr = LED_MAX_ON_TIME; } if(Key0.b.Released) { LED0 = 0; LED0_OnTmr = 0; } } void timers16(void) { if(LED0_OnTmr) { if(!--LED0_OnTmr) // в пиках сюда укладывается инструкция decfsz, // поэтому удобнее использовать down-counter'ы { LED0 = 0; } else { LED0 = 1; } } } Это, естесно, "рыба" на подумать, хоть я и обещал больше так не делать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
loghir 0 26 мая, 2011 Опубликовано 26 мая, 2011 (изменено) · Жалоба все требуемые интервалы сделайте на программных счётчиках. Спасибо, принцип мне понятен. И таймер удалось запустить. Как и сказано в #8, обработчик прервываний вызывается при появлении флага. Но вот связать настройку предделителя с частотой на выходе... При кварце 4 МГц Fosc/4 = 1 МГц. Как считать частоту прерываний при коэфф. деления предделителя 2, 4... 256 ? Изменено 26 мая, 2011 пользователем loghir Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sergeeff 1 26 мая, 2011 Опубликовано 26 мая, 2011 · Жалоба Уважаемый loghir, я убедился в том, что удивительный лодырь, обладающий определенным талантом напрячь окружающих на решение ваших задач. Сами думать вы, почему то, категорически не хотите. Прерывание по таймеру работает? Да. Кто мешает в эту процедуру вставить переменную, инкрементироать ее и ваводить на свободный pin. Смотрим осциллографом частоту прерываний. Дальше играем с прескалером. Это что, фантастически сложно? Десять минут. Зато вы сами в чем-то разберетесь. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться