Skocz do zawartości

Przerwanie nie aktualizuje wartosci zmiennej pomimo volatile ATMEGA128


frozzins

Pomocna odpowiedź

Witam,

Mamy z kolegami taki problem z przerwaniem.

Mamy zmienną volatile unsigned char result i chcemy ją nadpisać w przerwaniu tak aby móc używać jej nowej wartości w głównej pętli programu.

Niestety pomimo usilnych prób i użycia volatile wartość zmieniona w przerwaniu nie jest dostępna w głównym programie.

#include <avr/io.h>
#include <avr/interrupt.h>

volatile unsigned char result;

int main(void)
{
DDRF = 0b00000000; //wejscia
DDRD = 0b11111111; //wyjscia

char result_local;


TCCR1B |= (1 << WGM12 ); // Configure timer 1 for CTC mode
TIMSK |= (1 << OCIE1A ); // Enable CTC interrupt
sei (); // Enable global interrupts
OCR1A = 782; // Set CTC compare value to 1Hz at 1 MHz AVR clock , with a prescaler of 64
TCCR1B |= ((1 << CS10 ) | (1 << CS11 )); // Start timer at Fcpu /64



ADMUX = 0b01100000; //external Vref adc on pinF0
ADCSRA = 0b11101110; //ADC free runing mode ,interupts, prescaler 64

for(;;)//zawartosc tego fora nie dziala bo przerwanie nie zwraca nowej wartosci zmiennej result
{ 
		result_local=result;

		if(result >80)
		{
			PORTD |= (1<<PORTD0);
		}
		if(result <80)
		{
			PORTD &= ~(1<<PORTD0);
		}


}
}


ISR(ADC_vect) 
{

result = ADCH;

}


Link do komentarza
Share on other sites

A może jest jakiś problem z samym pomiarem? Może ADC w ogóle nie działa, nie ma jego przerwań więc i result nie jest nadpisywany nowymi wartościami? Może mierzysz wciąż to samo napięcie? Może zapalaj i gaś jakiś bit portu w każdym przerwaniu od ADC?. Zobaczysz, czy i kiedy przychodzi. Jaki masz procesor? Spróbuj nadać jakąś wartość zmiennej result (np. 100) a potem zobacz, czy chociaż raz est zmieniana przez ADC. Jaki jest teraz wynik porównania? Który if się wykonuje?

Link do komentarza
Share on other sites

Witam

Rozwiązanie było już testowane, w przypadku tak napisanego kodu dioda na PIND0 zapala się i gaśnie, ale już dioda na PIND2 nie.


#include <avr/io.h>
#include <avr/interrupt.h>

volatile unsigned char result;

int main(void)
{
DDRF = 0b00000000; //wejscia
DDRD = 0b11111111; //wyjscia

char result_local;


TCCR1B |= (1 << WGM12 ); // Configure timer 1 for CTC mode
TIMSK |= (1 << OCIE1A ); // Enable CTC interrupt
sei (); // Enable global interrupts
OCR1A = 782; // Set CTC compare value to 1Hz at 1 MHz AVR clock , with a prescaler of 64
TCCR1B |= ((1 << CS10 ) | (1 << CS11 )); // Start timer at Fcpu /64



ADMUX = 0b01100000; //external Vref adc on pinF0
ADCSRA = 0b11101110; //ADC free runing mode ,interupts, prescaler 64

for(;;)//zawartosc tego fora nie dziala bo przerwanie nie zwraca nowej wartosci zmiennej result
{ 
		result_local=result;
					if(result_local >80)
		{
			PORTD |= (1<<PORTD2);
		}
		if(result <80)
		{
			PORTD &= ~(1<<PORTD2);
		}
}
}


ISR(ADC_vect) 
{

result = ADCH;
if(result >80)
{
	PORTD |= (1<<PORTD0);
}
if(result <80)
{
	PORTD &= ~(1<<PORTD0);
}	
}

Link do komentarza
Share on other sites

Nie wiem jak wyglądał wasz test i jakie napięcie podłączaliście do wejścia ADC (musisz bardziej szczegółowo opisywać testy i wyniki), ale jeżeli dokładnie ten kod próbowaliście oraz jeśli dla uproszczenia podawaliście skrajne napięcia (np. 0V i Vcc), to..

inaczej wykonują się w C porównania dla zmiennych ze znakiem i bez.

W pierwszym if w pętli sprawdzasz zmienną local_result. Jeżeli jest to (domyślnie) signed char, to ten if wykona się wtedy, gdy będzie ona z przedziału 81..127. Jeżeli przetwornik oddał w result duży wynik, np. 0xFF to wykona się wyłącznie drugi if, bo przecież FF to w interpretacji ze znakiem jest -1, a to jest przecież < 80. W przypadku pomiaru małego napięcia, np. 0x00 także wykona się drugi if, bo zero też jest < 80.

Po pierwsze popraw local_result na taki sam typ jak ma result a po drugie..

Nie wiem dlaczego unikacie konstrukcji if..else, to by ładnie uprościło strukturę kodu a przy okazji załatwiło przypadek gdy (result == 80)? Żaden wasz if wtedy się nie wykona?

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Dodanie unsigned nic nie zmieniło w działaniu programu, dalej dioda na porcie 2 nie zapal się (podczas gdy na porcie 1 się zapala i gaśnie). Sygnał pomiarowy na przetworniku ADC pochodził z czujnika Sharp

Za pomocą woltomierza stwierdziliśmy pełna zmianę napięcia w zakresie od 0 do 5 V na wejściu ADC.

Problemem w programie jest, że z jakiegoś powodu pomimo określenia voliatile zmiennej dalej jej zmiany wprowadzane w obsłudze przerwania nie są widziane w głównej pętli programu.

Link do komentarza
Share on other sites

Kod się nie zmienił oprócz dodanego sugerowanego specyfikatora unsigned, opisana została metoda pomiaru.

#include <avr/io.h> 
#include <avr/interrupt.h> 

volatile unsigned char result; 

int main(void) 
{ 
   DDRF = 0b00000000; //wejscia 
   DDRD = 0b11111111; //wyjscia 

   unsigned char result_local; 


   TCCR1B |= (1 << WGM12 ); // Configure timer 1 for CTC mode 
   TIMSK |= (1 << OCIE1A ); // Enable CTC interrupt 
   sei (); // Enable global interrupts 
   OCR1A = 782; // Set CTC compare value to 1Hz at 1 MHz AVR clock , with a prescaler of 64 
   TCCR1B |= ((1 << CS10 ) | (1 << CS11 )); // Start timer at Fcpu /64 



   ADMUX = 0b01100000; //external Vref adc on pinF0 
   ADCSRA = 0b11101110; //ADC free runing mode ,interupts, prescaler 64 

   for(;;)//zawartosc tego fora nie dziala bo przerwanie nie zwraca nowej wartosci zmiennej result 
   { 
           result_local=result; 
                       if(result_local >80) 
           { 
               PORTD |= (1<<PORTD2); 
           } 
           if(result <80) 
           { 
               PORTD &= ~(1<<PORTD2); 
           } 
   } 
} 


ISR(ADC_vect) 
{ 

   result = ADCH; 
   if(result >80) 
   { 
       PORTD |= (1<<PORTD0); 
   } 
   if(result <80) 
   { 
       PORTD &= ~(1<<PORTD0); 
   }    
} 

Link do komentarza
Share on other sites

Ponieważ nie widziałem w tym kodzie żadnych dziwnych rzeczy, skopiowałem powyższe do pliku i skompilowałem go bez żadnej zmiany na moim AVRGCC. Na listingu asemblerowym widzę odwołania do zmiennej result w każdym if-ie a także zapis do tej zmiennej w obsłudze przerwania ADC. To znaczy: u mnie działa.

Optymalizator wyciął jedynie zmienną lokalną result_local i nawet pierwszy if korzysta ze zmiennej statycznej w RAMie.

Sprawdź diodkę albo pokaż swój listing z asemblerowym rozwinięciem powyższego kodu.

  • Lubię! 1
Link do komentarza
Share on other sites

Nie jestem pewien czy to o to chodzi 🙂

[list]Sections:
Idx Name          Size      VMA       LMA       File off  Algn
 0 .data         00000002  00800100  0000012a  0000019e  2**0
                 CONTENTS, ALLOC, LOAD, DATA
 1 .text         0000012a  00000000  00000000  00000074  2**1
                 CONTENTS, ALLOC, LOAD, READONLY, CODE
 2 .stab         000006cc  00000000  00000000  000001a0  2**2
                 CONTENTS, READONLY, DEBUGGING
 3 .stabstr      00000097  00000000  00000000  0000086c  2**0
                 CONTENTS, READONLY, DEBUGGING
 4 .comment      0000002f  00000000  00000000  00000903  2**0
                 CONTENTS, READONLY
 5 .debug_aranges 00000028  00000000  00000000  00000932  2**0
                 CONTENTS, READONLY, DEBUGGING
 6 .debug_info   000000c8  00000000  00000000  0000095a  2**0
                 CONTENTS, READONLY, DEBUGGING
 7 .debug_abbrev 00000094  00000000  00000000  00000a22  2**0
                 CONTENTS, READONLY, DEBUGGING
 8 .debug_line   0000013c  00000000  00000000  00000ab6  2**0
                 CONTENTS, READONLY, DEBUGGING
 9 .debug_frame  00000058  00000000  00000000  00000bf4  2**2
                 CONTENTS, READONLY, DEBUGGING
10 .debug_str    000000fe  00000000  00000000  00000c4c  2**0
                 CONTENTS, READONLY, DEBUGGING
11 .debug_loc    000000c1  00000000  00000000  00000d4a  2**0
                 CONTENTS, READONLY, DEBUGGING
12 .debug_ranges 00000018  00000000  00000000  00000e0b  2**0
                 CONTENTS, READONLY, DEBUGGING

Disassembly of section .text:

00000000 <__vectors>:
  0:	45 c0       	rjmp	.+138    	; 0x8c <__ctors_end>
  2:	00 00       	nop
  4:	58 c0       	rjmp	.+176    	; 0xb6 <__bad_interrupt>
  6:	00 00       	nop
  8:	56 c0       	rjmp	.+172    	; 0xb6 <__bad_interrupt>
  a:	00 00       	nop
  c:	54 c0       	rjmp	.+168    	; 0xb6 <__bad_interrupt>
  e:	00 00       	nop
 10:	52 c0       	rjmp	.+164    	; 0xb6 <__bad_interrupt>
 12:	00 00       	nop
 14:	50 c0       	rjmp	.+160    	; 0xb6 <__bad_interrupt>
 16:	00 00       	nop
 18:	4e c0       	rjmp	.+156    	; 0xb6 <__bad_interrupt>
 1a:	00 00       	nop
 1c:	4c c0       	rjmp	.+152    	; 0xb6 <__bad_interrupt>
 1e:	00 00       	nop
 20:	4a c0       	rjmp	.+148    	; 0xb6 <__bad_interrupt>
 22:	00 00       	nop
 24:	48 c0       	rjmp	.+144    	; 0xb6 <__bad_interrupt>
 26:	00 00       	nop
 28:	46 c0       	rjmp	.+140    	; 0xb6 <__bad_interrupt>
 2a:	00 00       	nop
 2c:	44 c0       	rjmp	.+136    	; 0xb6 <__bad_interrupt>
 2e:	00 00       	nop
 30:	42 c0       	rjmp	.+132    	; 0xb6 <__bad_interrupt>
 32:	00 00       	nop
 34:	40 c0       	rjmp	.+128    	; 0xb6 <__bad_interrupt>
 36:	00 00       	nop
 38:	3e c0       	rjmp	.+124    	; 0xb6 <__bad_interrupt>
 3a:	00 00       	nop
 3c:	3c c0       	rjmp	.+120    	; 0xb6 <__bad_interrupt>
 3e:	00 00       	nop
 40:	3a c0       	rjmp	.+116    	; 0xb6 <__bad_interrupt>
 42:	00 00       	nop
 44:	38 c0       	rjmp	.+112    	; 0xb6 <__bad_interrupt>
 46:	00 00       	nop
 48:	36 c0       	rjmp	.+108    	; 0xb6 <__bad_interrupt>
 4a:	00 00       	nop
 4c:	34 c0       	rjmp	.+104    	; 0xb6 <__bad_interrupt>
 4e:	00 00       	nop
 50:	32 c0       	rjmp	.+100    	; 0xb6 <__bad_interrupt>
 52:	00 00       	nop
 54:	54 c0       	rjmp	.+168    	; 0xfe <__vector_21>
 56:	00 00       	nop
 58:	2e c0       	rjmp	.+92     	; 0xb6 <__bad_interrupt>
 5a:	00 00       	nop
 5c:	2c c0       	rjmp	.+88     	; 0xb6 <__bad_interrupt>
 5e:	00 00       	nop
 60:	2a c0       	rjmp	.+84     	; 0xb6 <__bad_interrupt>
 62:	00 00       	nop
 64:	28 c0       	rjmp	.+80     	; 0xb6 <__bad_interrupt>
 66:	00 00       	nop
 68:	26 c0       	rjmp	.+76     	; 0xb6 <__bad_interrupt>
 6a:	00 00       	nop
 6c:	24 c0       	rjmp	.+72     	; 0xb6 <__bad_interrupt>
 6e:	00 00       	nop
 70:	22 c0       	rjmp	.+68     	; 0xb6 <__bad_interrupt>
 72:	00 00       	nop
 74:	20 c0       	rjmp	.+64     	; 0xb6 <__bad_interrupt>
 76:	00 00       	nop
 78:	1e c0       	rjmp	.+60     	; 0xb6 <__bad_interrupt>
 7a:	00 00       	nop
 7c:	1c c0       	rjmp	.+56     	; 0xb6 <__bad_interrupt>
 7e:	00 00       	nop
 80:	1a c0       	rjmp	.+52     	; 0xb6 <__bad_interrupt>
 82:	00 00       	nop
 84:	18 c0       	rjmp	.+48     	; 0xb6 <__bad_interrupt>
 86:	00 00       	nop
 88:	16 c0       	rjmp	.+44     	; 0xb6 <__bad_interrupt>
...

0000008c <__ctors_end>:
 8c:	11 24       	eor	r1, r1
 8e:	1f be       	out	0x3f, r1	; 63
 90:	cf ef       	ldi	r28, 0xFF	; 255
 92:	d0 e1       	ldi	r29, 0x10	; 16
 94:	de bf       	out	0x3e, r29	; 62
 96:	cd bf       	out	0x3d, r28	; 61

00000098 <__do_copy_data>:
 98:	11 e0       	ldi	r17, 0x01	; 1
 9a:	a0 e0       	ldi	r26, 0x00	; 0
 9c:	b1 e0       	ldi	r27, 0x01	; 1
 9e:	ea e2       	ldi	r30, 0x2A	; 42
 a0:	f1 e0       	ldi	r31, 0x01	; 1
 a2:	00 e0       	ldi	r16, 0x00	; 0
 a4:	0b bf       	out	0x3b, r16	; 59
 a6:	02 c0       	rjmp	.+4      	; 0xac <__do_copy_data+0x14>
 a8:	07 90       	elpm	r0, Z+
 aa:	0d 92       	st	X+, r0
 ac:	a2 30       	cpi	r26, 0x02	; 2
 ae:	b1 07       	cpc	r27, r17
 b0:	d9 f7       	brne	.-10     	; 0xa8 <__do_copy_data+0x10>
 b2:	02 d0       	rcall	.+4      	; 0xb8 <main>
 b4:	38 c0       	rjmp	.+112    	; 0x126 <_exit>

000000b6 <__bad_interrupt>:
 b6:	a4 cf       	rjmp	.-184    	; 0x0 <__vectors>

000000b8 <main>:
#include <avr/interrupt.h>

volatile int result =40;

int main(void)
{
 b8:	cf 93       	push	r28
 ba:	df 93       	push	r29
 bc:	00 d0       	rcall	.+0      	; 0xbe <main+0x6>
 be:	cd b7       	in	r28, 0x3d	; 61
 c0:	de b7       	in	r29, 0x3e	; 62
DDRF = 0b00000000; //wejscia
 c2:	10 92 61 00 	sts	0x0061, r1
DDRD = 0b11111111; //wyjscia
 c6:	8f ef       	ldi	r24, 0xFF	; 255
 c8:	81 bb       	out	0x11, r24	; 17

volatile int result_local = 0;
 ca:	1a 82       	std	Y+2, r1	; 0x02
 cc:	19 82       	std	Y+1, r1	; 0x01
sei (); // Enable global interrupts
OCR1A = 782; // Set CTC compare value to 1Hz at 1 MHz AVR clock , with a prescaler of 64
TCCR1B |= ((1 << CS10 ) | (1 << CS11 )); // Start timer at Fcpu /64

*/	
sei();
 ce:	78 94       	sei
ADMUX = 0b01000000; //external Vref adc on pinF0
 d0:	80 e4       	ldi	r24, 0x40	; 64
 d2:	87 b9       	out	0x07, r24	; 7
ADCSRA = 0b11101111; //ADC free runing mode ,interupts, prescaler 64
 d4:	8f ee       	ldi	r24, 0xEF	; 239
 d6:	86 b9       	out	0x06, r24	; 6

for(;;)//zawartosc tego fora nie dziala bo przerwanie nie zwraca nowej wartosci zmiennej result
{
	result_local=result;
 d8:	80 91 00 01 	lds	r24, 0x0100
 dc:	90 91 01 01 	lds	r25, 0x0101
 e0:	9a 83       	std	Y+2, r25	; 0x02
 e2:	89 83       	std	Y+1, r24	; 0x01
	if(result_local >10)
 e4:	89 81       	ldd	r24, Y+1	; 0x01
 e6:	9a 81       	ldd	r25, Y+2	; 0x02
 e8:	0b 97       	sbiw	r24, 0x0b	; 11
 ea:	0c f0       	brlt	.+2      	; 0xee <main+0x36>
	{
		PORTD |= (1<<PORTD2);
 ec:	92 9a       	sbi	0x12, 2	; 18
	}
	if(result <10)
 ee:	80 91 00 01 	lds	r24, 0x0100
 f2:	90 91 01 01 	lds	r25, 0x0101
 f6:	0a 97       	sbiw	r24, 0x0a	; 10
 f8:	7c f7       	brge	.-34     	; 0xd8 <main+0x20>
	{
		PORTD |= (1<<PORTD1);
 fa:	91 9a       	sbi	0x12, 1	; 18
 fc:	ed cf       	rjmp	.-38     	; 0xd8 <main+0x20>

000000fe <__vector_21>:
}
}


ISR(ADC_vect)
{
 fe:	1f 92       	push	r1
100:	0f 92       	push	r0
102:	0f b6       	in	r0, 0x3f	; 63
104:	0f 92       	push	r0
106:	11 24       	eor	r1, r1
108:	8f 93       	push	r24
10a:	9f 93       	push	r25



result =  ADCL;
10c:	84 b1       	in	r24, 0x04	; 4
10e:	90 e0       	ldi	r25, 0x00	; 0
110:	90 93 01 01 	sts	0x0101, r25
114:	80 93 00 01 	sts	0x0100, r24
}
if(result <80)
{
	PORTD &= ~(1<<PORTD0);
}*/
118:	9f 91       	pop	r25
11a:	8f 91       	pop	r24
11c:	0f 90       	pop	r0
11e:	0f be       	out	0x3f, r0	; 63
120:	0f 90       	pop	r0
122:	1f 90       	pop	r1
124:	18 95       	reti

00000126 <_exit>:
126:	f8 94       	cli

00000128 <__stop_program>:
128:	ff cf       	rjmp	.-2      	; 0x128 <__stop_program>[/list]
Link do komentarza
Share on other sites

Tak, dokładnie o to chodziło 🙂

Widzę, że wszystko jest dokładnie tak jak miało być w C:

1. Zmienna result dostała adres absolutny zaraz na początku RAMu: 0x0100 i 0x0101 bo jest 16-bitowa. To chyba z powodu nie włączenia żadnej optymalizacji albo użycia jakiegoś przełącznika w kompilatorze, by char był 16-bitowy.

2. Zmienna ta jest zapisywana wyłącznie w obsłudze przerwania:

10c: 84 b1 in r24, 0x04 ; 4

10e: 90 e0 ldi r25, 0x00 ; 0

110: 90 93 01 01 sts 0x0101, r25

114: 80 93 00 01 sts 0x0100, r24

Jej młodszy bajt dostaje wartość z przetwornika a starszy - jak widać - zawsze jest = 0.

3. Z przerwania - jak rozumiem - wyciąłeś kod związany z porównywaniem (oba if-y) , bo nie ma śladu po tym w asemblerze.

4. Trochę dziwne, że do zmiennej wpisujesz wartość odczytaną a ADCL bo przecież to młodszy bajt wyniku konwersji. To tylko "ogon" prawdziwej liczby z przetwornika, więc takie działanie trochę nie ma sensu. Spodziewałbym się raczej odczytu starszego bajtu.

5. W programie głównym zmienna local_result - jako zmienna lokalna - dostała adres w ramce na stosie funkcji main: Y+1 i Y+2. Ta też jest 16-bitowa i nie została usunięta przez optymalizator, trudno. Przy wejściu do main jest zerowana dokładnie tak jak sobie tego życzyłeś:

ca: 1a 82 std Y+2, r1 ; 0x02

cc: 19 82 std Y+1, r1 ; 0x01

(Kompilator AVRGCC trzyma w r1 zawsze 0x00 i bardzo często mu to się przydaje - jak widać)

6. W pętli for następuje najpierw odczyt zmiennej result do zmiennej lokalnej local_result:

d8: 80 91 00 01 lds r24, 0x0100

dc: 90 91 01 01 lds r25, 0x0101

e0: 9a 83 std Y+2, r25 ; 0x02

e2: 89 83 std Y+1, r24 ; 0x01

a następnie wykonują się dwa porównania. Pierwsze z nich ustawia bit 2 portu D, drugie ustawia bit 1 portu D.

Oprócz tego, że jest to inny kod niż prezentowałeś (nieładnie) to w ogólnym zarysie jest OK. Zmienna globalna na pewno jest zapisywana i na pewno sprawdzana. Nie będę analizował czy dobrze odpalasz ADC itp, bo to nie wchodzi w zakres pytania, ale z tego co widzę nie masz problemu z "volatilowością" zmiennej result. Dość dziwny jest odczyt tylko młodszego bajtu wyniku konwersji, bo to trochę jakbyś kazał komuś stanąć na wadze a potem podał mu w wyniku tylko jednostki kg, dziesiątki zachowując w tajemnicy lub wywalając do kosza. Dwóch istotnie różnych gości będzie miało takie same wagi a wynik żadnego z nich nie będzie adekwatny do ich prawdziwych "osiągów". Poza tym masz wyłącznie ustawianie bitów portu co oznacza, że jednokrotnie ustawiony bit zostaje już w stanie wysokim na zawsze - też trochę dziwne bo jak się przekonasz, że wynik porównania jest raz taki a raz inny?

EDIT: Porównania robione są instrukcjami brlt i brge (skocz gdy mniejszy, skocz gdy większy) używanymi po operacjach arytmetycznych na zmiennych ze znakiem co też jest bez sensu, bo masz efekt opisany przez mnie wcześniej (255 jest mniejsze od 80, bo przecież -1 < 80). Miałeś to poprawić, nieprawdaż? Mam wrażenie, że nie przyłożyłeś się do tego testu jak należało i zamiast przemyśleć sprawę i wycisnąć z kodu jak najwięcej, wysłałeś mi pierwszego lepszego śmiecia którego miałeś pod ręką. Zawsze w ten sposób prosisz o pomoc? Skup się przy następnym kroku tak, bym nie miał wrażenia, że marnujesz mój czas.

Link do komentarza
Share on other sites

A no rzeczywiście, przy ciągłych próbach dostrzeżenia co jest z nim nie tak nie zauważyłem tego wiec przepraszam 🙂

Jednak problem dalej pozostaje nierozwiązany, bo jeżeli program jest napisany poprawnie i rzeczywiści wynosi wartość zmiennej do głównej pętli (sprawdzony kod również w AVR symulator - widzi on wartość zmiennej w głównej pętli). Czy ma ktoś hipotezę czemu fizycznie mikrokątroler tak się zachowuję?

- przetwarzanie ADC jest poprawne (gdy porównanie dzieje się w ISR to wszystko działa jak należy)

- Dalmierz jest sprawny (sprawdzony woltomierzem - daje odpowiednie wskazania)

Problem również pojawia się przy używaniu timerów - program ma dostępna zmieniona wartość w ISR i ją pamięta ale tak samo nie udaję się wynieść jej wartości poza przerwanie (znów sprawdzone na AVR symulator - też obserwując wartości rejestrów widać, ze wraca z zmienioną wartością i używa jej w programie). Jednak fizycznie obserwując zapalanie się diod program nie wraca zmienną do głównej pętli

Problem występuje podczas programowania Atmega128A, Atmega8L oraz Atmega8A. Programowania były prowadzone z USBASP oraz STK500, pliki wyjściowe były tworzone w atmel studio 6.1 oraz WIN AVR 20100110. Programowania były również prowadzone z 3 różnych komputerów (systemy win 7 i win xp) za każdym razem pojawia się ten sam problem.

Czy może być to spowodowane tym, że program fizycznie nigdy nie kończy wykonywać obsługi przerwania? Jeżeli tak to czy ktoś ma pomysł jak sprawdzić to?

Link do komentarza
Share on other sites

Jak do tej pory widzieliśmy już kilka kodów programów i każdy był w jakiś sposób ułomny.

Mam taki pomysł: napisz coś porządnie, ale tak żebyś Ty sam i Twój Kolega nie mógł się do niczego przyczepić i czego się powstydzić, sprawdź czy to działa a jeśli nie, wyślij go w niezmienionej formie na Forum. Żadnego tam "zmieniałem w ostatniej chwili", "to stary kod" albo "przepraszam, bla, bla". Robisz ctrl/c-ctrl/v do tekstu postu i klikasz Wyślij. Inaczej to zaczyna być dyskusją o kodzie który nie istnieje. Ty coś masz ale tego nie pokazujesz, coś próbujesz a my widzimy coś innego i próbujemy się domyśleć co Ci nie działa.

Co mi się nie podoba w tym ostatnim? Sterowanie diodkami jest bez sensu - napisałem to w uwagach a Ty nawet się o tym nie zająknąłeś. Co jeszcze? Odpalasz timer, a co więcej odblokowujesz mu przerwania(!) podczas gdy w kodzie nie ma funkcji ich obsługi. Do czego to prowadzi? To popatrz sobie na tablicę wektorów przerwań. Każdy punkt wejścia niepodłączony do "swojej" funkcji ISR ma skok do _bad_interrupt. Co jest pod tą wspólną etykietą? Kolejny skok, tym razem do __vectors czyli do adresu 0x0000. W ten sposób kompilator broni swój kod przed użytkownikami nieumiejącymi poprawnie korzystać z systemu przerwań. Każde zgłoszone i przyjęte przerwanie nie mające odpowiedniej funkcji ISR resetuje procesor. Być może u Ciebie dochodzi do sytuacji w której przetwornik zdąża zrobić konwersję i wykonać tamtejsze if-y (a obsługa wykonuje się w AVR zawsze do końca bo system przerwań jest jednopoziomowy) a już czeka zgłoszone przerwanie od timera. Zakończenie i wyjście z ISR od ADC wykonuje jeszcze tylko jedną instrukcję z programu głównego (bo po RETI wykonywana jest zawsze jeszcze jedna instrukcja zanim procesor "zauważy" kolejne przerwanie) a wiszące i wreszcie przyjęte przerwanie od timera kieruje procesor wprost do początku programu. Takie coś powtarza się wiele razy na sekundę a Ty masz wrażenie, że wszystko jest normalnie tylko ta uparta zmienna nie działa. Wszystkim innym działa więc musisz robić tak głupi błąd i wyciągać tak błędne wnioski, że nikt nawet nie podejrzewa co mogłeś zrobić źle. Wystarczy np, że zdefiniowałeś w środowisku kompilatora inny procesor niż naprawdę programujesz na płytce. Każdy AVR ma trochę RAMu, ale jego adres początkowy może się trochę różnić. Co się stanie gdy procesor będzie pisał daną do adresu pod którym nie ma RAMu? To tylko przykład. Dla pewności (że jednak RESETy nie zachodzą) daj zaraz a początku main() mrugnięcie (zapalenie i zgaszenie) np. przez 100ms jakiejś diodki, której nigdzie indziej już potem nie używasz.

Tak więc czekamy z niecierpliwością na ładnie i porządnie napisany kod w którym sterowanie diodkami ma sens (if..then..else), nie ma żadnych nieobsługiwanych a odblokowanych przerwań, przerwanie od ADC zapisuje coś do zmiennej z atrybutem volatile a program główny nie może tej nieszczęsnej zmiennej na Twoim procesorze odtworzyć i odpowiednio swoich diodek wysterować. Powodzenia.

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.