Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Прерывания в CodeVisionAVR: как?
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Александр К.
Прошу помочь найти косяк в программе. В железе не работает , AVRStudio подвисает при попытке выйти из прерывания. Причём, аналогичное происходит и при использовании прерывания от таймера.

Код
// ADC interrupt service routine
interrupt [ADC_INT] void adc_isr(void)
{
unsigned char adc_data;
// Read the 8 most significant bits
// of the AD conversion result

// Place your code here
  adc_data=ADCH;
  adc_data=(adc_data>>1); // j не больше 127
  if(adc_data==1) adc_data=0;// j==1 исключается - особенность функции poworot
  if(i_adc_buf==2) i_adc_buf=0;
  else ++i_adc_buf;
  j=(adc_buf[0]+adc_buf[1]+adc_buf[2]+adc_data)/4; //рекурсия
  adc_buf[i_adc_buf]=j;

}


Куска хватит или нужно всё?
rezident
Замените
Код
if(i_adc_buf==2) i_adc_buf=0;
  else ++i_adc_buf;

на
Код
if(i_adc_buf>=2) i_adc_buf=0;
  else ++i_adc_buf;

ИМХО у вас типичная ошибка возникает - выход указателя за границы массива.
Александр К.
Спасибо. Заменил - симулятору не полегчало. Всё по прежнему.
rezident
Делать фильтрацию внутри прерывания это моветон. Кольцевой буфер сделайте и считайте ваше плавающее среднее в main-е.
А насчет зависания не совсем понял. Зависает сам симулятор? Или программа в симуляторе?
Александр К.
Цитата(rezident @ Oct 1 2009, 20:42) *
...А насчет зависания не совсем понял. Зависает сам симулятор? Или программа в симуляторе?
Загрузка процессора при симулировании - 97% (1,3 ГГц) при попытке выйти из прерывания. И выхода собственно и не происходит. Через пару минут я просто останавливаю. И в железе не работает.
Сама программа коротенькая, не возьмётесь просимулировать своим симулятором? Мне нужно только увидеть в симуляторе выход из прерывания. Дальше я попробую сам.
rezident
Это не ко мне. У меня и AVRStudio-то нету laughing.gif
SysRq
Покажите остальной код, и МК укажите какой у вас. Сообразим..
Александр К.
Как на этом движке дать вложение? Или дать программу текстом?
SysRq
Цитата(Александр К. @ Oct 1 2009, 21:21) *
Или дать программу текстом?

Код
[codebox]тут код[/codebox]
Александр К.
CODE
/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.4 Standard
Automatic Program Generator
© Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project : Подсос С АЦП и без таймеров

Version : 3-5
Date : 30.09.2009
Author :
Company :
Comments: Пропущенный участок работает в железе без проблем.

Chip type : ATmega164
Program type : Application
Clock frequency : 16.000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 256
*****************************************************/
#pragma savereg- // Выключить автоматическое сохранение регистров
#include <mega164.h>
#include <delay.h>
#define start_ADC ADCSRA|=(1<<6);// Запуск АЦП
#define ADC_VREF_TYPE 0x60

char i=0,j_tec=0,j_max=130,t_i=0,adc_data=0,i_adc_buf,k;
//i - номер фазы коммутации обмоток ШД
//j-tec - текущее положение ротора ШД 0<=j_tec<=j_max
//j-max - максимальное число полушагов ротора
//t_i - период коммутации фаз (0-16ms,130-8,193-4,224-2,239-1)
//i_adc_buf - номер в буфере АЦП

signed char j=0;
//j=1 пр. часовой,j=-1 по часовой,иначе - координата.
char step[]={16,80,64,96,32,160,128,144};// комбинации фаз
char adc_buf[3]={0,0,0};// Кольцевой буфер для усреднения АЦП

void SW_step(void)
{
if (i==7)i=0;
else ++i;
PORTA=step[i];
}

void SSW_step(void)
{if (i==0)i=7;
else --i;
PORTA=step[i];
}



void poworot (void)

{
if (j==-1)goto L0;
if (j!=1)goto L3;
if (j_tec==j_max)return;
L1: SSW_step();
j_tec++;
return;
L0: if (j_tec==0)
{
return;
}
L2: SW_step();
j_tec--;
return;
L3: if(j<0)
{
return;
}
if(j>j_tec) goto L1;
if(j<j_tec) goto L2;
}


// ADC interrupt service routine
interrupt [ADC_INT] void adc_isr(void)
{
unsigned char adc_data;
// Read the 8 most significant bits
// of the AD conversion result

// Place your code here
adc_data=ADCH;
adc_data=(adc_data>>1); // j не больше 127
if(adc_data==1) adc_data=0;// j==1 исключается - особенность функции poworot
if(i_adc_buf>=2) i_adc_buf=0;
else ++i_adc_buf;
j=(adc_buf[0]+adc_buf[1]+adc_buf[2]+adc_data)/4; //рекурсия
adc_buf[i_adc_buf]=j;

}

// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Input/Output Ports initialization
// Port A initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=In Func2=In Func1=In Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=T State2=T State1=T State0=0
PORTA=0x00;
DDRA=0xF1;

// Port B 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
PORTB=0x00;
DDRB=0x00;

// Port C 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
PORTC=0x00;
DDRC=0x00;

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

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// 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=0x00;
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
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-15: Off
// Interrupt on any change on pins PCINT16-23: Off
// Interrupt on any change on pins PCINT24-31: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;

// ADC initialization
// ADC Clock frequency: 125.000 kHz
// ADC Voltage Reference: AVCC pin
// ADC Auto Trigger Source: None
// Only the 8 most significant bits of
// the AD conversion result are used
// Digital input buffers on ADC0: Off, ADC1: Off, ADC2: Off, ADC3: Off
// ADC4: Off, ADC5: Off, ADC6: Off, ADC7: Off
DIDR0=0xFF;
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x8F;

goto L11;

k=0;
j=1;
while(j_tec!=125)
{
poworot();
delay_ms(2);
}
delay_ms(2000);

j=-1;
while(j_tec!=20)
{
poworot();
delay_ms(50);
}
delay_ms(2000);



j=70;
while(k<200)
{
poworot();
delay_ms(1);
k++;
}
delay_ms(2000);
L11:




#asm("sei") // Разрешить прерывания

ADMUX=1;// Первый канал АЦП
start_ADC;
while (1)
{
poworot();
delay_ms(2);

start_ADC;
}


}
SysRq
Ну вот:
Код
#pragma savereg- // Выключить автоматическое сохранение регистров

Потому и не работает ( http://telesys.ru/wwwboards/mcontrol/287/m...es/136890.shtml ).

PS: уберите тег [коде][/коде] вокруг [кодебокс][/кодебокс], я вас запутал немножко.
Александр К.
Цитата(SysRq @ Oct 1 2009, 21:40) *
Потому и не работает ...

Спасибо. Посмотрел по ссылке, но не понял - почему нельзя использовать штатную команду? Я в прерывании регистры не использую, все переменные - глобальные. И почему ж нельзя? Глюк CV?
-----------------------------------------------------------------------------------------------------------
Исправил и проверил. Всё нормально. Ещё раз спасибо.
Вопрос остался ...
SysRq
Регистры общего назначения и SREG. Они используются практически при каждой операции.
rezident
Цитата(Александр К. @ Oct 1 2009, 23:50) *
не понял - почему нельзя использовать штатную команду? Я в прерывании регистры не использую, все переменные - глобальные.
Как это не используете? А unsigned char adc_data и результаты промежуточных вычислений где по-вашему хранятся?
Александр К.
В регистрах. Но их (регистров) больше, чем переменных. И все переменные - глобальные. Пересечений нет.
Вот фрагмент на асемблере. После остановки симулятора указатель показывает на адрес 180.
CODE
+00000172: E7AA LDI R26,0x7A Load immediate
+00000173: E0B0 LDI R27,0x00 Load immediate
+00000174: 91EC LD R30,X Load indirect
+00000175: E0F0 LDI R31,0x00 Load immediate
+00000176: 64E0 ORI R30,0x40 Logical OR with immediate
+00000177: 93EC ST X,R30 Store indirect
+00000178: 9508 RET Subroutine return
+00000179: 91E9 LD R30,Y+ Load indirect and postincrement
+0000017A: 91F9 LD R31,Y+ Load indirect and postincrement
+0000017B: 9630 ADIW R30,0x00 Add immediate to word
+0000017C: F039 BREQ PC+0x08 Branch if equal
+0000017D: EA80 LDI R24,0xA0 Load immediate
+0000017E: E09F LDI R25,0x0F Load immediate
+0000017F: 9701 SBIW R24,0x01 Subtract immediate from word
+00000180: F7F1 BRNE PC-0x01 Branch if not equal
+00000181: 95A8 WDR Watchdog reset
+00000182: 9731 SBIW R30,0x01 Subtract immediate from word
+00000183: F7C9 BRNE PC-0x06 Branch if not equal
+00000184: 9508 RET Subroutine return
+00000185: 95F1 NEG R31 Two's complement
+00000186: 95E1 NEG R30 Two's complement
+00000187: 40F0 SBCI R31,0x00 Subtract immediate with carry
+00000188: 9508 RET Subroutine return
+00000189: 2400 CLR R0 Clear Register


Я в этом не понимаю ... Конкретный косяк не видно?
Очень хочется не сохранять все РОН при прерывании.
rezident
Цитата(Александр К. @ Oct 2 2009, 00:33) *
В регистрах. Но их (регистров) больше, чем переменных. И все переменные - глобальные. Пересечений нет.
Прерывание для компилятора это процесс недетерминированный во времени. Каждую функцию (в т.ч. и обработчик прерывания) компилятор транслирует отдельно. Откуда ему знать, какие регистры в момент возникновения прерывания используются, а какие нет?
Цитата(Александр К. @ Oct 2 2009, 00:33) *
Очень хочется не сохранять все РОН при прерывании.
Напишите обработчик прерывания на ассемблере, запретив компилятору использовать регистры, которые вы будете использовать в обработчике прерывания.
А еще лучше, как я вам раньше и советовал, выкиньте из прерывания фильтрацию (вычисление плавающего среднего), перенеся ее в main или в другую функцию.
Александр К.
Убрал лишнее из прерывания. И при #pragma savereg- работает.
Был неправ. Спасибо за помощь.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.