Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Какой-то бред...
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему
HCHUNTER
AVR Mega8, 16МГц, среда разработки CVAVR v1.25.
Делаю все по шаблону, как предлагает мастер. Пытаюсь создать прерывание по таймеру №0 каждые 64 мкс (15625 Гц).

Вот текст программы:

Цитата
#include <mega8.h>
#include <delay.h>

interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
TCNT0=0x00; // сбросить счетчик таймера
PORTB.0=0; // выставить на ножке "0" на период ~3...4 мкс
delay_us (3);
}


void main(void)
{

PORTB=0x00;
DDRB=0xFF;

PORTC=0x00;
DDRC=0x7F;

PORTD=0x00;
DDRD=0xFF;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 15,625 kHz
TCCR0=0x05;
TCNT0=0x00;


// Timer/Counter 1 initialization
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// External Interrupt(s) initialization
MCUCR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x01;

// Analog Comparator initialization
ACSR=0x80;
SFIOR=0x00;


#asm("sei")

while (1)
{
PORTB.0=1; //на ножке постоянная "1", прерывать ее каждые 64 мкс
};

}


Результат смотрю на осциллографе - хрен два! Постоянная единица, ничего не прерывается.
Пробовал и так и эдак... И что я только не писал в обработчик прерывания - ничего не помогает. И запрещать прерывания там пробовал, и заново таймер реинициализировал...
Разве что проскакивает этот самый ожидаемый "0" каждые примерно 5 секунд (определяю по взмаргиванию линии на осциллографе).
И что это за бред...? cranky.gif
Где моя ошибка?
DASM
Откуда 64 мкс насчитали ? 8e6/1024/256 - 30 Гц. У вас фуз работы от кварца прошит ? Или от внутренного RC по умолчанию работаете ?
HCHUNTER
Работаю от кварца, это совершенно точно.
Я такую простенькую программку написал уже от безысходности, чтобы выяснить где же я дурак...

Раньше с таймерами не работал, факт.
А почему Вы пишете 8e6/1024/256 - 30 Гц ? отуда 256? Мастер мне пишет, что частота настроенная составляет 15625 Гц.
DASM
там таймер0 - 8 битный, перполнение будет когда 255 превысит и сбросит в ноль, вот и 256 берется. 1024 - prescaler у Вас.
Кстати delay - я так понял библиотечная ? Я бы свою, попроще поставил вначале.
HCHUNTER
а как же мне тогда правильно таймер проинициализировать?
Получается
TCCR0=0x05;
TCNT0=0xFF;

так?
DASM
нет, или надо тогда переписывать TCNT0 не нулем в прерывании а 256 - N , где N - коэфф деления или воспользваться чем-нибудь более продвинутым, типа Compare в 1-ом таймере.
256 - N - тут могу путать немного, не силен в арифметике и голова плохо варит.
Кстати TCNT0=0x00; // сбросить счетчик таймера - это Вы написали или мастер ? Предделитель тоже 1024 великоват, 8e6/1024 = 7812.5 Гц.
Попробуйте TCCR0 = 4 (делитель на 256), а в прерывании писать TCNT0 = 254. И уберите библиотечную задержку - и без нее нормальным осциллом все увидите
HCHUNTER
Вобщем, сделал как сам же написал выше
TCCR0=0x05;
TCNT0=0xFF;
вроде бы все заработало...
щас буду думать дальше...
DASM
А ну да, у Вас же 16 Мгц, а не 8, что-то зациклился. Тогда правильно, только где Вы выше написали про = 0xFF ?
HCHUNTER
Да, конечно. В самой процедуре прерывания я тоже поправляю счетчик таймера.

В любом случае, огромное спасибо за наводку на мою ошибку!
Пойду, попробую "прикрутить" полученное под свою конкретную задачу...
INT1
Кстати, писать столько нулей в инициализации портов и глобальных переменных, вроде как и смысла нет, они по Атмелю и АНСИ СИ и так обнуляются
=AVR=
Эээ... это по какому такому АНСИ СИ порты "и так обнуляются", интересно узнать?
Aesthete Animus
Лучше инвертировать по прерыванию таймера ножку порта, то есть:
Код
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
    // Инвертировать быстрее xor`ом. Но т.к. я не знаю
    // специфики CV, то написал так:
    PORTB.0 = (PORTB.0 == 0 ? 1 : 0); // Инвертируем ножку
}


При этом не забудьте убрать цикл "while (1)" из мейна.

Хочу заметить, что всякие задержки в прерываниях (наподобее delay_us) крайне не рекоммендуются, прерывание - это критическая часть кода, из которого следует выходить как можно скорее.

=AVR=
Цитата(INT1 @ Jan 2 2008, 22:34) *
они [порты] по Атмелю и АНСИ СИ и так обнуляются

wink.gif
IgorKossak
Цитата(=AVR= @ Jan 2 2008, 21:44) *
Эээ... это по какому такому АНСИ СИ порты "и так обнуляются", интересно узнать?

Для тех, кто читает не всё:
порты - по Atmel (default value);
глобальные переменные - по АНСИ СИ.
HCHUNTER
Цитата(Aesthete Animus @ Jan 2 2008, 23:03) *
При этом не забудьте убрать цикл "while (1)" из мейна.

А это для чего? что оно мне даст?
куда же я тогда возвращаться-то буду... в "никуда" получается...


Цитата
Хочу заметить, что всякие задержки в прерываниях (наподобее delay_us) крайне не рекоммендуются, прерывание - это критическая часть кода, из которого следует выходить как можно скорее.

Вот это мне тоже, кстати, не совсем понятно... Звучит как заученная фраза из книжек.
А если мне нужно по возникновении прерывания выполнить массу всего? Что мне тогда делать...?

Ведь мне никто не запрещает в прерывании остановить таймер, выполнить все что мне нужно, а по выходу из прерывания снова его запустить?
С моей (ламерской) точки зрения процедура-обработчик может быть сколь угодно долгой. Главное, чтобы в это время я не наловил новых прерываний...
SasaVitebsk
Цитата(HCHUNTER @ Jan 3 2008, 00:36) *
Вот это мне тоже, кстати, не совсем понятно... Звучит как заученная фраза из книжек.
А если мне нужно по возникновении прерывания выполнить массу всего? Что мне тогда делать...?


Мне кажется что в учебниках как раз про это не слова. Как правило это из опыта. Но тем не менее возможен и такой способ работы (как вы описали). Если у вас одно прерывание. Можно и с несколькими обойтись, таким же образом. Только надо чётко представлять что ты делаешь и какие проблемы могут возникнуть.

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

В программировании любое действие можно сделать десятком способов. Выбирайте свой. Но мнение других всётаки желательно хотя бы послушать. Чтобы самому сделать свой выбор.
defunct
Цитата(HCHUNTER @ Jan 2 2008, 23:36) *
Ведь мне никто не запрещает в прерывании остановить таймер, выполнить все что мне нужно, а по выходу из прерывания снова его запустить?

Никто не запрещает.

С другой стороны, никто не запрещает также запустить таймер с одинаковыми интервалами времени. И пусть себе тикает.
В обработчике прерывания таймера - взводить флажек, сигнализирующий, что некое событие наступило.
И уже потом "в спокойной обстановке" тобиш в основном цикле программы проверить флажек и выполнить все, что требуется для обработки этого события..

Цитата
С моей точки зрения процедура-обработчик может быть сколь угодно долгой.

Конечно может, но меня например несколько раздражает когда жмешь CTRL-ALT-DEL, а системе "пофиг", т.к. некий программист решил сделать сколь угодно долгий обработчик. Если вам подходит такой стиль - то без проблем, пишите так ;>


Цитата
а как же мне тогда правильно таймер проинициализировать?
Получается
TCCR0=0x05;
TCNT0=0xFF;


Есть режим таймера CTC - очистка по сравнению. В этом режиме не надо трогать TCNT регистр, т.к. таймер сам будет сбрасываться тогда когда вы ему укажате. Правда в m8 этот режим есть только у таймера 1 и таймера 2. Если вам нужно отмерять один "тик", то на таймере 2 инициализация будет выглядеть так:

#define WGM21 3
#define OCIE2 7

OCR2 = 1;
TCCR2 = 0x07 | (1 << WGM21);
TIMSK = (1 << OCIE2);
HCHUNTER
Цитата
Если вам нужно отмерять один "тик", то на таймере 2 инициализация будет выглядеть так:

#define WGM21 3
#define OCIE2 7

OCR2 = 1;
TCCR2 = 0x07 | (1 << WGM21);
TIMSK = (1 << OCIE2);


Да, я встречал подобную запись, когда разбирал чей-то код.
Однако работаю в CVAVR, а там такое не прокатывает... не знает он что такое WGM и OCIE2... sad.gif
=AVR=
Как не знает? Даже сразу после того, как ему сказали #define WGM21 и #define OCIE2?? Вот уж поистине ... - Новый год smile.gif
HCHUNTER
э... туплю кажись... м-де... smile3046.gif
Dim_ON
Помогите плиз разобраться с таймерами
Необходимо что бы Т0 и Т1 работали на переполнение с частотой ЦПУ (это не надо объяснять), а вот Т2 от часового кварца
Подключаю часовой кварц к PC6, PC7 (ATmega16, 32), а инициализация будет, следующей?:
Код
#define TIMER_CLK_DIV8            0x02    ///< Timer clocked at 32.768KHz/8
#define TIMER_PRESCALE_MASK        0x07    ///< Timer Prescaler Bit-Mask
#define TIMER2OVERFLOW_INT        5
volatile unsigned long Timer2Reg0;

void timer2Init(void)
{
    // initialize timer 2
    outb(TCCR2, (inb(TCCR2) & ~TIMER_PRESCALE_MASK) | TIMER_CLK_DIV8); // count 32.768KHz/8
    outb(TCNT2, 0);                    // reset TCNT2
    sbi(TIMSK, TOIE2);                // enable TCNT2 overflow
    sbi(ASSR, AS2);                    // switch to asynchronous input (32KHz crystal)
    Timer2Reg0 = 0;                    // initialize time registers
    // attach service to real-time clock interrupt
    // rtcService() will be called at ((32768/8)/256) = 16Hz
    timerAttach(TIMER2OVERFLOW_INT, rtcService);
    sei();
}
zltigo
Часть ветки перенесена сюда: http://electronix.ru/forum/index.php?showtopic=41484&hl=
Aesthete Animus
Цитата(Dim_ON @ Jan 4 2008, 20:59) *
Помогите плиз разобраться с таймерами
Необходимо что бы Т0 и Т1 работали на переполнение с частотой ЦПУ (это не надо объяснять), а вот Т2 от часового кварца
Подключаю часовой кварц к PC6, PC7 (ATmega16, 32), а инициализация будет, следующей?:


Разрешите приведу код из doc2505 небольшими изменениями для иициализации часового кварца
Код
void init_Ex3(void)
{
    ASSR= 1<<AS2; // Enable asynchronous
                  // mode
                  // Clear timer on compare match / Timer Clock =
                  // system clock / 1024
    TCCR2 = (1<<CTC2)|(1<<CS22)|(1<<CS21)|(1<<CS20);
    TIFR= 1<<OCF2; // Clear OCF2/ Clear
                   // pending interrupts
    TIMSK= 1<<OCIE2; // Enable Timer2 Output
                     // Compare Match Interrupt
    OCR2= 31; // Set Output Compare
              // Value to 32
    DDRB= 0xFF; // Set Port B as output
    while (ASSR&(1<<OCR2UB)); // Wait for registers to update
}

В этом случае, прерывание по сравнению таймера №2 (SIG_OUTPUT_COMPARE2) будет вызываться раз в секунду.

Хочу заметить, что в документации для регистра OCR2 задано неверное значение, у них вместо 31 написано 32.
Dim_ON
Сори за офф, но решил не создавать новой темы, а спросить тут.
Правильно ли я понимаю функционирование таймеров/счетчиков:
Режим переполнения(overflow) - это когда таймеры считают синхроипульсы, и прерывание происходит когда MAX_COUNT-->0, при этом MAX_COUNT зависит от размерности таймера.

Режим совпадения(outcompare) - это когда в регистр OCR записывают MAX_COUNT, счетчик каждый такт сравнивает содержимое регистров OCR и TCNT, при равенстве происходит прерывание.

Режим захвата и сравнения - это когда состояние регистра TCNT сохраняется в регистре ICR по активному фронту ноги ICP, и для сравнения нам надо считывать ICR

Асинхронный режим - это когда источником синхроимпульсов является резонатор, подключенный к ногам TOSC1 и TOSC2

Режим генерации ШИМ - это отдельная тема

Режим подсчета внешних событий - это когда содержимое регистра TCNT увеличивается при...??
Не пойму, можно ли настраивать что бы работали на инкремент или декремент?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.