Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Запуск таймера 16бит по внешнему прерыванию
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Vny4ek
Никак не могу разобраться как сделать так:
При перепаде сигнала на входе от 0 до 5 срабатывает прерывание и запускает отсчет 16 битный счетчик
я правильно понял что нужно подовать сигнал на INT0 ножку и выбирать Rising Edge в мастере генерации кода? Если можно киньте плиз шаблон. как начать. по сути хочу вывести на дисплей значение таймера
Aesthete Animus
Цитата(Vny4ek @ Dec 4 2008, 09:27) *
Никак не могу разобраться как сделать так:
При перепаде сигнала на входе от 0 до 5 срабатывает прерывание и запускает отсчет 16 битный счетчик

я правильно понял что нужно подовать сигнал на INT0 ножку и выбирать Rising Edge [skipped]?


Ну да, поняли правильно. Только в чем проблема? Таймер работает? Внешнее прерывание вызывается? Если с этим по отдельности справились - проблем быть не должно.
Vny4ek
Неа, в том то и дело что не получилось, хочу вывести значение таймера на дисплей, но никак не получается. С дисплеем разобрался. Может кините пример кода. Что я не так делаю не пойму. я даже делал так: В функции прерывания присваивал переменной например число 10 а до этого в main 5, вот и на дисплее все время 5. функция прерывания у меня выше а ниже функция мейн.
Может дадите способ или код, как можно отдельно проверить чтоли, что сработало прерывание, или таймер запустился по условию. Вот с этим у меня сложности
vik0
Цитата(Vny4ek @ Dec 4 2008, 16:57) *
Может дадите способ или код

Давайте лучше вы дадите свой код, а мы посмотрим и поможем..
Aesthete Animus
2Vny4ek
Всецело согласен с предыдущим оратором. От того, что мы Вам просто напишем код, понимания у Вас не прибавится. Итак, как Вы пытаетесь инициализировать таймеры и прерывания?
SysRq
Цитата(Vny4ek @ Dec 4 2008, 17:57) *
В функции прерывания присваивал переменной например число 10 а до этого в main 5, вот и на дисплее все время 5.

А может надо почитать что такое volatile всего лишь...
Vny4ek
ОК понял! я домой приду вечером и выложу свой код. а вы уж оцените и скажите что не так
Vny4ek
Вот код зацените пожалуйста что не так


#include <mega16.h>
#include <stdio.h> // sprintf
#include <delay.h> // delay_ms


#asm
.equ __lcd_port=0x15 ;PORTC
#endasm
#include <lcd.h>

unsigned int s=1; // !!!Esli s=1 to na LCD vivodit TEXT!!!
// !!!Signal idet na PD2 (INT0)

// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
s=1;
}

void main(void)
{

PORTA=0x00;
DDRA=0x00;

PORTB=0x00;
DDRB=0x00;

PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;

// Timer/Counter 1 initialization
// Clock source: T1 pin Rising Edge
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x07;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Rising Edge
// INT1: Off
// INT2: Off
GICR|=0x40;
MCUCR=0x03;
MCUCSR=0x00;
GIFR=0x40;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
// LCD module initialization
lcd_init(16);

if (s==1) {
delay_ms(20);
lcd_clear();

lcd_gotoxy(0,1);
lcd_putsf("Interrupt work!");
};

#asm("sei")

while (1)
{

};
}
_Ivan_33
хех...
1) если переменная сначала не объвлена как volatile то в прерывании с ней ничего не произойдет вообще
2) пусть прерывания сначала не было после включения... тогда программа пробежит по всем регистрам(что у тебя написано что надо установить) и затем сравнит если s=1 хотя s=0 так как прерывания у тебя не возникло и пойдет на след. строку... а там пустой бесконенчый цикл... так потом у тебя прерывание возникнет s=1 но все равно не включится так как проверку условия уже программа пробежала- поэтому нада проверку s сделать в бесконечном цикле...
в сами регистры не смотрел - тупо нет времени но надеюсь что правильно

по-моему так, если что наврал - скажите
Vny4ek
Тоесть эту строчку нужно поместить в цикл While?

if (s==1) {
delay_ms(20);
lcd_clear();

lcd_gotoxy(0,1);
lcd_putsf("Interrupt work!");
};
Aesthete Animus
Цитата(_Ivan_33 @ Dec 10 2008, 09:35) *
1) если переменная сначала не объвлена как volatile то в прерывании с ней ничего не произойдет вообще

Это что, такая фича CodeVision-а? 07.gif
vik0
Цитата
Тоесть эту строчку нужно поместить в цикл While?

Да.
И, как было сказано, заменить
unsigned int s=1;
на
volatile unsigned int s=1;

Цитата
Это что, такая фича CodeVision-а? 07.gif

Точно не знаю, но по-моему, это такое "понимание" значения квалификатора volatile.. sad.gif
Vny4ek
Все учел что сказали, перекомпилил нарисовал в протеусе, но работать отказывается. Может я что то не так еще делаю. На ножку PD2 (INT0) кнопкой от линии питания +5В подаю как бы фронт. Но ничего на дисплей не идет. подскажите плиз. Привожу код:

Код
#include <mega16.h>
#include <stdio.h> // sprintf
#include <delay.h> // delay_ms


#asm
.equ __lcd_port=0x15;PORTC
#endasm
#include <lcd.h>

volatile unsigned int s=1; // !!!Esli s=1 to na LCD vivodit TEXT!!!
// !!!Signal idet na PD2 (INT0)

// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
s=0;
}

void main(void)
{

PORTA=0x00;
DDRA=0x00;

PORTB=0x00;
DDRB=0x00;

PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;

// Timer/Counter 1 initialization
// Clock source: T1 pin Rising Edge
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x07;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Rising Edge
// INT1: Off
// INT2: Off
GICR|=0x40;
MCUCR=0x03;
MCUCSR=0x00;
GIFR=0x40;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
// LCD module initialization
lcd_init(16);
s=1;

#asm("sei")
while (1)
{
  
if (s==0) {
delay_ms(50);
lcd_clear();
delay_ms(50);
lcd_gotoxy(0,1);
delay_ms(50);
lcd_putsf("Interrupt work!");  
delay_ms(50);
};

};
}
_Ivan_33
а без всяких дополнительных извращений на LCD что нить выводится?!?
mdmitry
Цитата(Vny4ek @ Dec 10 2008, 15:08) *
На ножку PD2 (INT0) кнопкой от линии питания +5В подаю как бы фронт. Но ничего на дисплей не идет. подскажите плиз.

Ключевое слово КАК БЫ. Реально дребезг кнопки. Может быть очень плохо от потока прерываний. Код не смотрел. smile.gif
Vny4ek
Если s==0 то выводится я пробовал ей присваивать значение. А вот присвоить при прирывании не получается. По поводу дребезга контактов, я уже и генератор прямоугольных импульсов в протеусе использовал. амплитуда 5в. Вообщем я в тупике пока. Жду помощи
Goodefine
Цитата(Vny4ek @ Dec 10 2008, 17:44) *
...А вот присвоить при прирывании не получается. По поводу дребезга контактов...

Дребезг где, в Протеусе?.. smile.gif
Проблема у вас в неправильном подключении кнопки. Вход INT0 в подвешенном состоянии, а вы, наверняка, кнопкой подключаете его к плюсу питания просто так... Чтобы работало, притяните вход INT0 к земле резистором около 5k, а кнопкой подключайте INT0 к 5v (прерывание по переднему фронту)...
Vny4ek
Я учел ВСЕ рекомендации. В итоге вижу следующее:
На дисплей пока не нажму кнопку ничего не выводится, нажимаю, создаю фронт. И вижу что начинает дергать ножками на порту С (на нем висит LCD) но текст не выводит. А если например заранее переменной присваиваю значение по которому в if выполняется текст выводит. Еще раз повторюсь учел ВСЕ рекомендации. Прогресс на лицо! но хочется разобраться

Я уже даже пробую просто функцию вывода на дисплей в прерывании осуществить. Вот так:
причем инициализация дисплея в main
Цитата
interrupt [EXT_INT0] void ext_int0_isr(void)
{

lcd_clear();
delay_ms(20);
lcd_gotoxy(0,1);
lcd_putsf("Interrupt work!");
delay_ms(2000);
s=1;
}


Но не работает все равно, хотя лапами дрыгает
Goodefine
Схему подключения кнопки к INT0 приведите...
Vny4ek

Вот. хотя еще раз повторюсь при нажатии кнопки начинает дергать ножками которые на дисплей
Goodefine
Да как так у вас получается?
Взял код из вашего же поста №13, создал проект в CVAVR для меги16 (я выбрал частоту 8 МГц, к примеру), удалил весь сгенеренный с-шный текст, вставил ваш (не меняя абсолютно ничего), сделал Маке. Нарисовал схему в протеусе, указал прошивку, поставил 8 МГц и ... все! Результат - после включения экран пустой, после нажатия на кнопку периодически мигает надпись:
Vny4ek
Попробуйте плиз мой хекс в протеусе использовать (сменив расширение). Я уже всю голову сломал если честно.

И если можно выложите свой, чтобы понять в чем дело, может протеус не так у меня работает
Goodefine
Для какого кварца у вас хекс? У меня для 8 МГц...
Приложите лучше весь проект, где-то с настройками может проблема. А потом новый создайте, для интересу. Ваш хекс не работает... Вот мой проект с хексом...
Vny4ek
Вот мой проект. Посмотрите пожалуйста что не так
Ваш проект у меня заработал
Goodefine
Это не проект, это прошивка. Проект - это все файлы, которые создает CAVR в указанную вами папку при создании проекта. Вот их в папке и приложите...
Vny4ek
Извините, невнимательность просто, вот файл проекта
SysRq
Цитата(Vny4ek @ Dec 10 2008, 15:08) *
Все учел...
Код
#include <mega16.h>
//...

Итого: мега16.

Цитата(Vny4ek @ Dec 12 2008, 15:52) *
..вот файл проекта

...в котором:
Цитата
[Chip]
Type=ATmega8
CPUClock=8

Итого: мега8.

Вот и не работает.
Vny4ek
Всем спасибо, заработало! Сразу вопрос собственно я хочу сделать прием данных по прерыванию. Вот у меня произошло прерывание по нарастанию уровня, мне нужно измерить длительность импульса используя как я понимаю счетчик 16 битный, По идее длительность импульсов единичных 400Мкс но на практике может быть и 350-600 естественно это про весь пакет говорится, тоесть бывают брелки с севшей батарейкой или с новой и вот хочу это учесть. Собственно сейчас споткнулся вот на чем:
Прерывания по фронту я понял как осуществить, я перерыл даташит, и даже на русском описание нашел, но ничего не понял. Как мне измерить поступивший импульс, и например значение его присвоить переменной где уже оперировать им как базовой величиной пакета. Будьте добры киньте пример, или может где эта тема разжевывалась.
P.S. Всем кто помог с предыдущей проблемой большое спасибо!!!!
SysRq
Настройте таймер чтобы тикал с нужным дискретом (чтобы и обеспечить необходимый уровень погрешности, и 16 бит бы хватило для подсчета нужного интервала времени). По заднему фронту таймер сбросить, по преднему считывайте TCNT в прерывании - вот вам и длительность импульса. Период и прочее сами сообразите...
Goodefine
Прерывания на INT0 в меге16 можно настроить по ИЗМЕНЕНИЮ уровня. Соответственно, в одном и том же обработчике можно все и делать (в смысле таймер запускать и останавливать), потом, в основном цикле, не спеша посчитать...
Сергей Борщ
Цитата(Vny4ek @ Dec 18 2008, 13:20) *
Как мне измерить поступивший импульс,
Вам не надо останавливать и запускать таймер. Пусть он свободно бежит, а вы используйте его модуль capture. Читайте описание на input capture unit и регистр ICR. Вам надо застатвить таймер защелкивать в ICR значение счетчика в начале и в конце импульса, а затем вычитая первое из второго получите длину импульса. Заметьте, без погрешностей из-за неодинакового времени на вход в прерывание.

P.S. и не используйте кнопку цитирования на форме ввода для оформления кода. Для оформления кода есть кнопка '#'.
Goodefine
Цитата(Сергей Борщ @ Dec 19 2008, 10:33) *
Вам не надо останавливать и запускать таймер. Пусть он свободно бежит...

Так даже красивше будет. Только в этом случае надо по любому надо учитывать переход таймера через 0.
Цитата(Сергей Борщ @ Dec 19 2008, 10:33) *
Читайте описание на input capture unit и регистр ICR. Вам надо застатвить таймер защелкивать в ICR значение счетчика в начале и в конце импульса...

Не забыв про бит ICES1 регистра TCCR1B...
Цитата(Сергей Борщ @ Dec 19 2008, 10:33) *
Заметьте, без погрешностей из-за неодинакового времени на вход в прерывание.

Только с пренебрежимо малой погрешностью (1 такт максимум) обусловленной каскадом синхронизатор+детектор фронтов...

Ради интереса, какая максимальная методологическая относительная погрешность может быть при измерении импульсов длительностью 360-600мкс, при 0.125мкс на тактовый (8Мгц, Т1 от тактовой)? Если использовать прерывание по изменению уровня с запуском/остановкой таймера...
Сергей Борщ
Цитата(Goodefine @ Dec 19 2008, 10:59) *
Так даже красивше будет. Только в этом случае надо по любому надо учитывать переход таймера через 0.
Если длительность измеряемого импульса меньше 65536 тиков таймера, то не нужно.
Goodefine
Цитата(Сергей Борщ @ Dec 19 2008, 14:30) *
Если длительность измеряемого импульса меньше 65536 тиков таймера, то не нужно.

Учет, в данном случае, выразится в сравнении двух значений счетчика, поочередно попадающих в ICR1...
Сергей Борщ
Цитата(Goodefine @ Dec 19 2008, 14:57) *
Учет, в данном случае, выразится в сравнении двух значений счетчика, поочередно попадающих в ICR1...
Естественно. В их вычитании.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.