Перейти к содержанию
    

Прерывание по таймеру - поможите

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

 

#include <mega16.h>

#include <stdio.h>

#include <delay.h>

 

 

long int step_kol;

int step;

 

 

interrupt [TIM0_OVF] void timer0_ovf_isr(void)

{

// Reinitialize Timer 0 value

TCNT0=step // загрузили константу

step_kol++; //счетчик количества шагов

PORTC.0^=1; // дернули ногой

 

}

 

void main(void){

 

// уже не до красоты - переписал, чтобы понятно было порт С - выход

 

DDRC = 255;

PORTC = 0;

 

TIMSK=0x3;

 

#asm("sei")

 

while(1){

 

 

было

step=0x100; //константа для задания частоты

поправил, это просто описка

step=0x10;

 

 

TCCR0 = 0x00; //stop

TCNT0 = step; //set count

TCCR0 = 0x05; //start timer с предделителем на 1024

 

 

while (step_kol<1000){ //жду, когда в таймере пройдет 1000 циклов

#asm("wdr");

}

step_kol=0;

delay_ms(5000); сюда не доходит

}

}

 

кусок выдрал аккуратно вроде, точнее заново оформил

что же я не так делаю?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

перед заносом в TCNT0 таймер не остановлен. это может повлиять на работу таймера.

а если возврат идет не туда откуда был переход, надо стек проверить. не переполняется ли он.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

перед заносом в TCNT0 таймер не остановлен. это может повлиять на работу таймера. а если возврат идет не туда откуда был переход, надо стек проверить. не переполняется ли он.

И при входе/выходе в/из прерывание сохранять/восстанавливать программный счетчик.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кусок кода приведенный автором написан криво, очень криво, но я спишу это на трудности переноса сути вопроса из большого проекта :)

А вот что я заметил:

1) константа step ( которая обьявлена вовсе не как константа) объявлена как int и занесено туда значение 0х100, а затем этой "константой" автор инициализирует 8 битный счетчик TMR0

2) зачем в главном цикле while(1){} производится постоянно переинициализация таймера(останов, загрузка опять же 16 битным значением 8 битного регистра счета, старт с предделителем)?

3) далее зачем то ждем 1000 циклов таймера чтобы сбросить WatchDog, причем используется переменная long int step_kol. хотя тут хватило бы и простого int.

4) затем задержка на 5 сек во время которой продолжаются прерывания таймера.

 

В итоге, автор не написал как работает данный кусок, но я предположу, что происходит постоянная генерация на ноге PortC.0 с частотой переполнения 8 битного таймера на частоте XTAL/1024, т.е. частота XTAL/1024/256, возможно , с короткими перерывами. Также предположу что автор хотел генерировать 1000 импульсов с перерывом в 5 секунд, но данный кусок этого просто не может обеспечить.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

кусок выдрал аккуратно вроде, точнее заново оформил

что же я не так делаю?

 

...в глаза бросается использование watchdog-а, нет явной настройки (а по умолчанию он не запущен) и вдруг он стартуется #asm(wdr) ... а затем пауза вставлена delay_ms(5000); довольно продолжительная...может быть проблема в этом?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3) далее зачем то ждем 1000 циклов таймера чтобы сбросить WatchDog.

он не ждет - он его сбрасывает 1000 раз пока ste_kol не накопит до 1000 :)

Хотя код и кривой, но проблема скорее всего в инициализации 8 битного регистра значением 0x100, как ты заметил.

 

P.S. Кстати, PC-Lint такие ошибки легко отлавливает, а компиляторы игнорируют.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Отвечу сразу всем: написано действительно криво, потому как весь код сюда ложить смысла нет. просто по быстрой оформил проектик с этим злополучным куском, чтобы сюда положить.

Задача общая, - сформировать посылку № на ногу, тут PORTC.2 для управления ШД. срезал все лишнее, чтобы идею понять можно было.

interrupt [TIM0_OVF] void timer0_ovf_isr(void)

{

 

TCCR0 = 0x00; //stop

TCNT0=step;

step_kol++;

PORTC.0^=1;

TCCR0 = 0x05;

}

 

так тоже - самое

 

step = описался, равен 10

 

WDT - оставил из большого куска, чтобы в этом цикле собака не срабатывала.

 

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

До пауз дело не доходит

Стек переполняется

 

 

И при входе/выходе в/из прерывание сохранять/восстанавливать программный счетчик.

Глупый , наверное , вопрос - а CVAVR это не делает? можете бросать в меня гнилыми апельсинами

 

Кусок кода приведенный автором написан криво, очень криво, но я спишу это на трудности переноса сути вопроса из большого проекта :)

А вот что я заметил:

 

2) зачем в главном цикле while(1){} производится постоянно переинициализация таймера(останов, загрузка опять же 16 битным значением 8 битного регистра счета, старт с предделителем)?

 

3) далее зачем то ждем 1000 циклов таймера чтобы сбросить WatchDog, причем используется переменная long int step_kol. хотя тут хватило бы и простого int.

4) затем задержка на 5 сек во время которой продолжаются прерывания таймера.

 

В итоге, автор не написал как работает данный кусок, но я предположу, что происходит постоянная генерация на ноге PortC.0 с частотой переполнения 8 битного таймера на частоте XTAL/1024, т.е. частота XTAL/1024/256, возможно , с короткими перерывами. Также предположу что автор хотел генерировать 1000 импульсов с перерывом в 5 секунд, но данный кусок этого просто не может обеспечить.

 

этот кусок в таком виде должен через каждые 5 сек выдавать 1000 импульсов, на выдачу импульсов при 11,0592 уходит примерно 2 секудны, 5 сек - это с запасом, чтобы в эмуляторе картинка была

 

а после выполнения прерывания - чаще всего начинает работать сначала проги, но в проекте - не с начала, т.е не сброс, но с достаточно конкретного места

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Глупый , наверное , вопрос - а CVAVR это не делает? можете бросать в меня гнилыми апельсинами

Не знаю... Работаю в другой среде. Поэтому и предположил.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не знаю... Работаю в другой среде. Поэтому и предположил.

 

Предположение смахивает на правду, кста, алгоритм брал из когда - то работающего проекта. Тот писался тоже на CVAVR только какой-то ранней версии. Ребят, у кого есть - CVAVR 1.25 и VMLAB проверьте, плиз. что-то я читал у них на сайте насчет работы с лицензией, сделанной кейгеном. Кто-то же выложил это на фтп. Ну и еще вопрос - купить то есть где CVAVR? Поиск результатов не дал.

 

...в глаза бросается использование watchdog-а, нет явной настройки (а по умолчанию он не запущен) и вдруг он стартуется #asm(wdr) ... а затем пауза вставлена delay_ms(5000); довольно продолжительная...может быть проблема в этом?

да, тут маленько неправильно, WD срабатывает каждые 2 секунды, в это месте он конечно сработает, но он не доходит до этого места. Правильнее конечно время задержки поставить 1.8 секунды, только проблема балин не тут.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

step все равно лучше сделать char или const char или вообще #define STEP 0x10 чтоб память не занимать.

инит таймера из главного цикла убрать - поставить ДО while(1)

delay_ms(5000) заменить на delay_ms(1000), но поставить 5 раз а между ними разместить сброс Сторожевого таймера

Перед делеями запретить прерывания от таймера - после делеев - разрешить.

Стек увеличить - может где то в другом месте он переполняется.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

step все равно лучше сделать char или const char или вообще #define STEP 0x10 чтоб память не занимать.

инит таймера из главного цикла убрать - поставить ДО while(1)

delay_ms(5000) заменить на delay_ms(1000), но поставить 5 раз а между ними разместить сброс Сторожевого таймера

Перед делеями запретить прерывания от таймера - после делеев - разрешить.

Стек увеличить - может где то в другом месте он переполняется.

все исправил

 

вот так сие выглядит

#include <mega16.h>

#include <stdio.h>

 

long int step_kol;

char step;

 

// delay functions

#include <delay.h>

 

interrupt [TIM0_OVF] void timer0_ovf_isr(void)

{

TCCR0 = 0x00; //stop

TCNT0=step;

step_kol++;

PORTC.0^=1;

}

 

void main(void){

DDRC = 255;

PORTC = 0;

TIMSK=0x3;

#asm("sei")

step=0x10;

 

while(1){

 

TCCR0 = 0x00; //stop

TCNT0 = step; //set count

TCCR0 = 0x05; //start timer

 

while (step_kol<1000){

#asm("wdr");

}

step_kol=0;

 

delay_ms(1000);

#asm("wdr");

delay_ms(1000);

#asm("wdr");

delay_ms(1000);

#asm("wdr");

delay_ms(1000);

#asm("wdr");

delay_ms(1000);

#asm("wdr");

 

}

 

}

но вот так в отладчике

в прицепе 300 кил

 

Нифига не понимаю совсем, нашел старый проект, он на AT90s8535 - кусок подобный, все работает, чувствую, что просто туплю.

post-13712-1177503300_thumb.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проанализируйте окошко "Call stack" и вот эту строку вашей программы:

 

TIMSK=0x3;

 

Анатолий.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проанализируйте окошко "Call stack" и вот эту строку вашей программы:

 

TIMSK=0x3;

 

Анатолий.

 

TIMSK=0x1 решило все проблемы, всем спасибо за участие, особое - Анатолию, просто заработался уже, глаза мимо смотрели :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

TCCR0 = 0x00; //stop

TCNT0 = step; //set count

TCCR0 = 0x05; //start timer

Зачем это в главном цикле? вынесите за while(1) чтоб один раз при запуске это работало

 

step_kol сделайте int-ом

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

TCCR0 = 0x00; //stop

TCNT0 = step; //set count

TCCR0 = 0x05; //start timer

Зачем это в главном цикле? вынесите за while(1) чтоб один раз при запуске это работало

 

step_kol сделайте int-ом

 

да в самой проге нет цикла - это я для отладки состряпал, чтобы себе наглядней было, да и вам потом показал.

косяк был - поднял флаги и по переполнению и по совпадению

а step_kol - большой потому что шагов может быть много, а сколько много - еще не известно

 

пора отдыхать сегодня, завершить ответ этот пытался по SHIFT-F9

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...