Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: CodeVision+указатели+прерывание
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
troy97
Написал вот такой код:
Код
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
        // Stop timer
        TCCR2=0x00;

        if(get_incoming_pkt()==3){
        
                switch (check_command(myip)) {
                
                case 0:
                        strcpyf(service_msg, "Micro_device#0:not_a_command");
                        service_msg[13]=device_id;
                        send_to_server(service_msg, service_msg_len);                
                break;
                                
                case 1:
                        init_ip_arp_udp(mymac,myip);
                        strcpyf(service_msg, "Micro_device#0:IP_changed");
                        service_msg[13]=device_id;
                        send_to_server(service_msg, service_msg_len);                
                break;
                
                case 2:
                        strcpyf(service_msg, "Micro_device#0:comm_2_done");
                        service_msg[13]=device_id;
                        send_to_server(service_msg, service_msg_len);                
                break;                
      
                default:
                        strcpyf(service_msg, "Micro_device#0:command_Error");
                        service_msg[13]=device_id;
                        send_to_server(service_msg, service_msg_len);
                };                      
        };        
                
        // Start timer
        TCCR2=0x07;
        TCNT2=0x00;
} // end of interrupt


void main(void)

....
unsigned int* pointer;
......

          pointer=get_adc_data();
          for(i=0;i<6;i++){    
                data_msg[16+2*i]=(*(pointer+i))>>8; //MSB
                data_msg[16+2*i+1]=(*(pointer+i)) & 0xff; //LSB
          };

......


Проблема следующая: при возникновении прерывания во время работы с указателем, значения записываемые в data_msg[], искажаются.
При запрете прерываний на этот кусок кода, всё работает нормально.
SasaVitebsk
1) Может pointer используется где-то в прерывании? Или i. Например она у вас глобальной объявлена, а в прерывании объявить забыли. Это единственное прерывание?
2) Может в прерывании, при работе с service_msg вы банально выходите за границы объявленой памяти и портите data_msg. Си ведь границы не определяет - на вас надеется.
Goodefine
Цитата(troy97 @ Sep 25 2009, 09:53) *
...Проблема следующая...

Функцию get_adc_data() покажите...
troy97
1) pointer точно не используется в прерывании. i объявлена в начале main(), да и не на i подозрения т.к. сегодня отловил, что та же проблема, но реже, возникает если вырубать прерывания только на кусок с циклом for. Т.е. портится указатель даже на строке pointer=get_adc_data();
2) нет, размер service_msg не превышаю.

Привожу код get_adc_data():

CODE
unsigned int* get_adc_data(void)
{
unsigned char i;
unsigned int adc_data=0;
unsigned int analog_vals_arr[6]={0,0,0,0,0,0};

// ADC Clock frequency: 130,156 kHz
ADCSRA=0x86;// ADC enable; ADC int.disable; prescaler=64

TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
TCCR1B=0x03;// clk/64


do{
for (i=0; i<6; i++)
{
ADMUX&=0b11110000;
ADMUX|=i;
ADCSRA|=0x40;
while(!(ADCSRA & (1<<ADIF)));
ADCSRA|=(1<<ADIF);

adc_data=ADCW;
check(adc_data, i);

};

// check timer1 overflow flag
if (TIFR &= (1<<TOV1))
{
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
TIFR |= (1<<TOV1);
timer1(analog_vals_arr);
break;
};

}
while(1);

ADCSRA clrb(ADEN);//stop ADC
return (analog_vals_arr);
}


функция timer1 получает указатель analog_vals_arr и заполняет массив необходимыми значениями
Goodefine
Попробуйте так:
Код
...
#asm("cli")
TCNT1H=0x00;
TCNT1L=0x00;
#asm("sei")
...
#asm("cli")
adc_data=ADCW;
#asm("sei")
...

ЗЫ. И что за while(1) ? Как программа оттуда выходит (если флаг не будет стоять)?

А стек увеличивать пробовали?..
_Pasha
На вид: тяжеловесное прерывание. Может, в этот кусок кода лучше заходить из прерывания через setjmp/longjmp?
Sergey Reva
get_adc_data возвращает указатель на локальную переменную (созданую с стеке), естественно при входе в прерывание по тем адресам (где были значения analog_vals_arr) создаются другие локальные переменные. Нужно объявить analog_vals_arr как static, либо переделать get_adc_data так чтобы она заполняла переданый ей (указателем) массив.

p.s.
ладно, попробую поменять порядок слов smile.gif
troy97
Goodefine, попробую, но определено, что проблема не возникает, если перед самым return'ом из get_adc_data(), сбросить TCNT2, т.е. чтобы прерывание точно не попало на кусок с указателями. Из while(1), если TOV1 не установлен... никак не выходит... признаю свою вину.
"А стек увеличивать пробовали?.." - нет, а как?smile.gif

_Pasha, можно и так, а что это даст, если я правильно понимаю, то просто добавится ещё один прыжок, а время обработки прерывания останется тем же?

Sergey Reva, очень логично, сделаю, спасибо.
Goodefine
Цитата(troy97 @ Sep 26 2009, 09:26) *
"А стек увеличивать пробовали?.." - нет, а как?smile.gif

В свойствах проекта...
SasaVitebsk
Цитата(Sergey Reva @ Sep 26 2009, 09:15) *
get_adc_data возвращает указатель на локальную переменную (созданую с стеке), естественно при входе в прерывание по тем адресам (где были значения analog_vals_arr) создаются другие локальные переменные. Нужно объявить analog_vals_arr как static, либо переделать get_adc_data так чтобы она заполняла переданый ей (указателем) массив.


+1.

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

Я бы не применял static, так как выглядит неестественно. Я бы либо сделал массив глобальным, либо объявил его в месте использования и передавал процедуре на неё указатель, как рекомендовал Sergey Reva.
troy97
Объявил массив в месте его использования, функции передаю указатель. Сегодня утром прошился, уже 1,5 часа полёт нормальный, надо ещё погонять, потом отпишусь.
troy97
Работает уже сутки без сбоев, всем большое спасибо за помощь!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.