|
Прерывание по таймеру - поможите, после срабатывания прерывания возврат не на то место |
|
|
|
Apr 25 2007, 07:45
|

Участник

Группа: Свой
Сообщений: 35
Регистрация: 28-01-06
Из: Ванино
Пользователь №: 13 712

|
Ребят, в большом проекте попался кусок, над которым я уже туплю. Среда 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); сюда не доходит } }
кусок выдрал аккуратно вроде, точнее заново оформил что же я не так делаю?
|
|
|
|
|
Apr 25 2007, 09:38
|
Профессионал
   
Группа: Свой
Сообщений: 553
Регистрация: 17-02-05
Из: Свердловская обл.
Пользователь №: 2 712

|
Цитата(arttab @ Apr 25 2007, 11:56)  перед заносом в TCNT0 таймер не остановлен. это может повлиять на работу таймера. а если возврат идет не туда откуда был переход, надо стек проверить. не переполняется ли он. И при входе/выходе в/из прерывание сохранять/восстанавливать программный счетчик.
--------------------
Закономерность: Чем больше узнаю, тем меньше знаю... Любые мнения, даже ошибочные, имеют право на существование. Чем лучше узнаю людей, тем больше нравятся собаки...
|
|
|
|
|
Apr 25 2007, 10:21
|
Профессионал
    
Группа: Свой
Сообщений: 1 235
Регистрация: 14-05-05
Из: Санкт-Петербург
Пользователь №: 5 008

|
Кусок кода приведенный автором написан криво, очень криво, но я спишу это на трудности переноса сути вопроса из большого проекта  А вот что я заметил: 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 секунд, но данный кусок этого просто не может обеспечить.
--------------------
|
|
|
|
|
Apr 25 2007, 10:27
|
Частый гость
 
Группа: Свой
Сообщений: 151
Регистрация: 21-02-06
Пользователь №: 14 561

|
Цитата(dedded @ Apr 25 2007, 07:45)  кусок выдрал аккуратно вроде, точнее заново оформил что же я не так делаю? ...в глаза бросается использование watchdog-а, нет явной настройки (а по умолчанию он не запущен) и вдруг он стартуется #asm(wdr) ... а затем пауза вставлена delay_ms(5000); довольно продолжительная...может быть проблема в этом?
|
|
|
|
|
Apr 25 2007, 10:48
|

Mute Beholder
  
Группа: Свой
Сообщений: 260
Регистрация: 4-04-07
Из: Третья планета от Солнца
Пользователь №: 26 754

|
Цитата(GDI @ Apr 25 2007, 13:21)  3) далее зачем то ждем 1000 циклов таймера чтобы сбросить WatchDog. он не ждет - он его сбрасывает 1000 раз пока ste_kol не накопит до 1000 Хотя код и кривой, но проблема скорее всего в инициализации 8 битного регистра значением 0x100, как ты заметил. P.S. Кстати, PC-Lint такие ошибки легко отлавливает, а компиляторы игнорируют.
--------------------
Common sense is not so common.
|
|
|
|
|
Apr 25 2007, 11:28
|

Участник

Группа: Свой
Сообщений: 35
Регистрация: 28-01-06
Из: Ванино
Пользователь №: 13 712

|
Отвечу сразу всем: написано действительно криво, потому как весь код сюда ложить смысла нет. просто по быстрой оформил проектик с этим злополучным куском, чтобы сюда положить. Задача общая, - сформировать посылку № на ногу, тут 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 раз должен отработать( в данном случае) после этого паузы и прочее. До пауз дело не доходит Стек переполняется Цитата(Валентиныч @ Apr 25 2007, 17:38)  И при входе/выходе в/из прерывание сохранять/восстанавливать программный счетчик. Глупый , наверное , вопрос - а CVAVR это не делает? можете бросать в меня гнилыми апельсинами Цитата(GDI @ Apr 25 2007, 18:21)  Кусок кода приведенный автором написан криво, очень криво, но я спишу это на трудности переноса сути вопроса из большого проекта  А вот что я заметил: 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 сек - это с запасом, чтобы в эмуляторе картинка была а после выполнения прерывания - чаще всего начинает работать сначала проги, но в проекте - не с начала, т.е не сброс, но с достаточно конкретного места
|
|
|
|
|
Apr 25 2007, 11:31
|
Профессионал
   
Группа: Свой
Сообщений: 553
Регистрация: 17-02-05
Из: Свердловская обл.
Пользователь №: 2 712

|
Цитата(dedded @ Apr 25 2007, 14:28)  Глупый , наверное , вопрос - а CVAVR это не делает? можете бросать в меня гнилыми апельсинами Не знаю... Работаю в другой среде. Поэтому и предположил.
--------------------
Закономерность: Чем больше узнаю, тем меньше знаю... Любые мнения, даже ошибочные, имеют право на существование. Чем лучше узнаю людей, тем больше нравятся собаки...
|
|
|
|
|
Apr 25 2007, 11:54
|

Участник

Группа: Свой
Сообщений: 35
Регистрация: 28-01-06
Из: Ванино
Пользователь №: 13 712

|
Цитата(Валентиныч @ Apr 25 2007, 19:31)  Не знаю... Работаю в другой среде. Поэтому и предположил. Предположение смахивает на правду, кста, алгоритм брал из когда - то работающего проекта. Тот писался тоже на CVAVR только какой-то ранней версии. Ребят, у кого есть - CVAVR 1.25 и VMLAB проверьте, плиз. что-то я читал у них на сайте насчет работы с лицензией, сделанной кейгеном. Кто-то же выложил это на фтп. Ну и еще вопрос - купить то есть где CVAVR? Поиск результатов не дал. Цитата(tag @ Apr 25 2007, 18:27)  ...в глаза бросается использование watchdog-а, нет явной настройки (а по умолчанию он не запущен) и вдруг он стартуется #asm(wdr) ... а затем пауза вставлена delay_ms(5000); довольно продолжительная...может быть проблема в этом? да, тут маленько неправильно, WD срабатывает каждые 2 секунды, в это месте он конечно сработает, но он не доходит до этого места. Правильнее конечно время задержки поставить 1.8 секунды, только проблема балин не тут.
|
|
|
|
|
Apr 25 2007, 12:15
|

Участник

Группа: Свой
Сообщений: 35
Регистрация: 28-01-06
Из: Ванино
Пользователь №: 13 712

|
Цитата(GDI @ Apr 25 2007, 20:02)  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 - кусок подобный, все работает, чувствую, что просто туплю.
Эскизы прикрепленных изображений
|
|
|
|
|
Apr 25 2007, 12:52
|

Участник

Группа: Свой
Сообщений: 35
Регистрация: 28-01-06
Из: Ванино
Пользователь №: 13 712

|
Цитата(aesok @ Apr 25 2007, 20:33)  Проанализируйте окошко "Call stack" и вот эту строку вашей программы:
TIMSK=0x3;
Анатолий. TIMSK=0x1 решило все проблемы, всем спасибо за участие, особое - Анатолию, просто заработался уже, глаза мимо смотрели
|
|
|
|
|
Apr 25 2007, 13:08
|

Участник

Группа: Свой
Сообщений: 35
Регистрация: 28-01-06
Из: Ванино
Пользователь №: 13 712

|
Цитата(GDI @ Apr 25 2007, 20:57)  TCCR0 = 0x00; //stop TCNT0 = step; //set count TCCR0 = 0x05; //start timer Зачем это в главном цикле? вынесите за while(1) чтоб один раз при запуске это работало
step_kol сделайте int-ом да в самой проге нет цикла - это я для отладки состряпал, чтобы себе наглядней было, да и вам потом показал. косяк был - поднял флаги и по переполнению и по совпадению а step_kol - большой потому что шагов может быть много, а сколько много - еще не известно пора отдыхать сегодня, завершить ответ этот пытался по SHIFT-F9
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|