реклама на сайте
подробности

 
 
4 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> Работа таймера TMR0 (PIC16)
loghir
сообщение May 23 2011, 15:43
Сообщение #1


Участник
*

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



На данный момент проблема в смутном описании бита T0CS регистра OPTION:
Цитата
бит 5: T0CS: Выбор тактового сигнала для TMR0
1 = внешний тактовый сигнал с вывода RA4/T0CKI
0 = внутренний тактовый сигнал CLKOUT

внутренний тактовый сигнал - это Fosc/4?
Go to the top of the page
 
+Quote Post
xemul
сообщение May 23 2011, 17:33
Сообщение #2



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Цитата(loghir @ May 23 2011, 19:43) *
На данный момент проблема в смутном описании бита T0CS регистра OPTION:

внутренний тактовый сигнал - это Fosc/4?

Да. На блок-схеме TMR0 всё разрисовано.
Go to the top of the page
 
+Quote Post
Redguy
сообщение May 25 2011, 05:42
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 41
Регистрация: 14-01-10
Из: Россия, Самара
Пользователь №: 54 801



Блок-схема TMR0 тебе в помощь!
Эскизы прикрепленных изображений
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post
loghir
сообщение May 25 2011, 11:20
Сообщение #4


Участник
*

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



Спасибо.
Но лучше бы авторы даташита делали его в одном стиле, с большим числом информации.
Пробую получить с помощью 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.gif
Go to the top of the page
 
+Quote Post
sargein
сообщение May 25 2011, 11:51
Сообщение #5


Участник
*

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



программка жесткая какая-то, в частности выносы в функции меня в данном случае только больше запутывают sm.gif

ну а по теме: если вы хотите использовать прерывания то добавьте вот это после main() { }
Код
interrupt isr() {

if (T0IF) {
чего то делаем
T0IF = 0;
}

Go to the top of the page
 
+Quote Post
xemul
сообщение May 25 2011, 11:52
Сообщение #6



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Обработчик прерываний для мелких пиков должен выглядеть
Код
interrupt void isr(void)
{
   if(T0IF)
// или if(T0IF && T0IE)
   {
      ...
   }

   if(TMR1IF)
   {
      ...
   }
}

Имя функции обработчика прерывания не важно, но слово interrupt в её объявлении должно присутствовать.
Go to the top of the page
 
+Quote Post
loghir
сообщение May 25 2011, 12:46
Сообщение #7


Участник
*

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



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



Сообщение отредактировал loghir - May 25 2011, 13:47
Go to the top of the page
 
+Quote Post
sargein
сообщение May 25 2011, 13:58
Сообщение #8


Участник
*

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



пишите в конце своей программы вот это:
Код
interrupt isr() {

if (T0IF) {
tmp100 = tmp100 + 1;
TMR0 = TMR0 + 100;
T0IF = 0;
}


Вызывать ничего не надо, это прерывание, оно автоматически вызывается в случае T0IF = 1



Go to the top of the page
 
+Quote Post
loghir
сообщение May 25 2011, 14:26
Сообщение #9


Участник
*

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



Если
Код
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;
}

то программа просто не работает: цифры не меняются.
Go to the top of the page
 
+Quote Post
sargein
сообщение May 25 2011, 14:37
Сообщение #10


Участник
*

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



писать надо после main() { } я ведь это уже два раза написал

зы. по поводу программы, естественно ее еще отлаживать нужно, я просто указал как правильно обработку прерывания оформлять

ззы. рекомендую вот тут FAQ почитать

Сообщение отредактировал sargein - May 25 2011, 14:44
Go to the top of the page
 
+Quote Post
xemul
сообщение May 25 2011, 14:55
Сообщение #11



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Цитата(loghir @ May 25 2011, 16:46) *
xemul,
при чем тут
Код
TMR1IF
?

Я забыл добавить ... после if(TMR1IF) {...}, т.к. описывал общий случай.
У мелких пиков одноуровневая система прерываний, и все возможные прерывания обрабатываются в одной функции.
Больше наивных предположений и вставок на подумать делать не буду.
Цитата(loghir @ May 25 2011, 18:26) *
Если
Код
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).
Цитата
А если ...
то программа просто не работает: цифры не меняются.

Наверное, так прога написана. Предлагаете нам догадаться, как именно?
Go to the top of the page
 
+Quote Post
loghir
сообщение May 25 2011, 16:39
Сообщение #12


Участник
*

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



Спасибо за подсказку.
Буквари ценны тем, что быстро узнаешь структуру простейшей программы. А вот реализация у них, мягко говоря, хромает.
Прога не работает оттого, что c TMR0 проблема. TMR1 в этом же коде прекрасно работает без функции обработчика прерываний. Вся беда в том, что в программе мне надо 3 временных промежутка...
Основное достоинство самоучителей - что в одном не упомянут, в другом есть.

Сообщение отредактировал loghir - May 25 2011, 18:17
Go to the top of the page
 
+Quote Post
xemul
сообщение May 26 2011, 07:26
Сообщение #13



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Цитата(loghir @ May 25 2011, 20:39) *
Вся беда в том, что в программе мне надо 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;
      }
   }
}

Это, естесно, "рыба" на подумать, хоть я и обещал больше так не делать.
Go to the top of the page
 
+Quote Post
loghir
сообщение May 26 2011, 16:03
Сообщение #14


Участник
*

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



Цитата
все требуемые интервалы сделайте на программных счётчиках.

Спасибо, принцип мне понятен. И таймер удалось запустить. Как и сказано в #8, обработчик прервываний вызывается при появлении флага.
Но вот связать настройку предделителя с частотой на выходе... При кварце 4 МГц Fosc/4 = 1 МГц. Как считать частоту прерываний при коэфф. деления предделителя 2, 4... 256 ?

Сообщение отредактировал loghir - May 26 2011, 16:11
Go to the top of the page
 
+Quote Post
sergeeff
сообщение May 26 2011, 16:27
Сообщение #15


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Уважаемый loghir,

я убедился в том, что удивительный лодырь, обладающий определенным талантом напрячь окружающих на решение ваших задач. Сами думать вы, почему то, категорически не хотите.

Прерывание по таймеру работает? Да. Кто мешает в эту процедуру вставить переменную, инкрементироать ее и ваводить на свободный pin. Смотрим осциллографом частоту прерываний. Дальше играем с прескалером. Это что, фантастически сложно? Десять минут. Зато вы сами в чем-то разберетесь.
Go to the top of the page
 
+Quote Post

4 страниц V   1 2 3 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 13:05
Рейтинг@Mail.ru


Страница сгенерированна за 0.015 секунд с 7
ELECTRONIX ©2004-2016