AT Mega16 - přerušení čítače/časovače 0

Nazdárek všem, přecházím z 51 na AVR, takže se pořád učím něco nového. Došla řada na přeřušení od čítače/časovače 0. Podle já jsem ALL nastavil jak má být, ale nejde to. Když spustím simulaci v AVR Studiu, nedojde k volání přerušení, nastaví se příznak, ale šipka se pořád mele v nekonečné smyčce a neskočí na obsluhu přerušení. Připojím výpis v asm a za každou radu děkuji, jen podotýkám, že o odkazy psané v nečeštině nemám zájem, páč vládnu jen ČJ a to ještě nenejlépe.

;OBSLOUŽENÍ PŘERUŠENÍ OD čítače/časovače 0 - CC0, xtal 16 MHz
;bliká celý port C
.nolist
.include “m16def.inc”
.list
.cseg ;kodový segment
.def reg=r16 ;pracovní registr
.equ ddr=ddrc ;registr řízení směru
.equ port=portc ;port
;… …
;prostor vyhrazený pro volání přerušení
.org 0
rjmp start ;skoc na začátek programu
.org ovf0addr ;přerušení od CC0
rjmp opcc0 ;skoč a obsluž přerušení od CC0

;úvodní nastavení
start: ldi r26,6 ;konstanta pro nulování PORTuC
ldi r25,1 ;konstanta pro nastavení PORTuC
ldi r24,250 ;čítání jedné sekundy za pomoci
ldi r23,40 ;tří registrů v intervalech
ldi r22,10 ;2,5 milisec, 100 milisec, 1 sec
ldi reg,255 ;nastav registr
out ddr,reg ;nastav port C jako výstupní
ldi reg,low (ramend)
out spl,reg ;nastav SP na konec SRAM
ldi reg,high (ramend)
out sph,reg
ldi r21,160 ;schoda TCNT0 s OCR0 po 10 µsec
out ocr0,r21 ;zapiš do registru OCR0
ldi reg,0b00001001
out tccr0,reg ;nastavení CC0 - režim CTC
ldi reg,0b0000010 ;
out timsk,reg ;povol přerušení CC0 při schodě TCN0=OCR0
sei ;povol globální přerušení v SREG
;…
;celý port C bliká po asi 0,5 sec
zap: cpse r22,r25 ;při schodě přeskoč následující řádek
rjmp vyp ;skoč (line 40)
ldi reg,255
out port,reg ;nastav PORTC
vyp: cpse r22,r26 ;při schodě přeskoč následující řádek
rjmp zap ;skoč
ldi reg,0
out port,reg ;nuluj PORTC
rjmp zap
;…
;obsloužení přerušení od CC0
;nezapomeň uložit SREG, pak pokračuj v obsluze přerušení a je to třeba? (line 50)
opcc0: in r17,sreg ;obsah SREG dej do r17
push r17 ;ulož SREG před ztracením do zásobníku
dec r24 ;r24-1
breq zpet ;skoč není-li r24=0
ldi r24,250 ;nuluje se po 2,5 µsec
dec r23 ;r23-1
breq zpet ;skoč není-li r23=0
ldi r23,40 ;nuluje se po 100 milisec
dec r22 ;r22-1
breq zpet ;skoč není-li r22=0 (line 60)
ldi r18,0 ;
out tifr,r18 ;nuluj příznak přerušení od cc0
ldi r22,10 ;nuluje se po 1 sec
pop r17 ;vyzvedni obsah SREG ze zásobníku
out sreg,r17 ;obsah SREG čti z r17
zpet: reti ;návrat z ošetření přerušení CC0 do programu
;…

:arrow_right: administrator: přesunuto z "ARM"
CC0.asm (2.57 KB)

Nevím nevím, prolétl jsem to jen tak letmo, ale ty máš přerušení ovf=přetečení čítače ovšem v maskách přerušení povoluješ output compare… Nějaké divné ne ? A proč máš v tom přerušení časové smyčky ? Přerušení by mělo být co nejkratší a cpát do přerušení ještě časové smyčky to není dobrý nápad…

Dík za ozvání se, no to bude asi ono divné. Takže by tam, podle mě mělo být asi následující. To jsem neustále přehlížel, HI. Jinak v obsluze přerušení by neměla být časová smyčka, jen by se měl při každém průchodu zmenšit obsah registru (ů), více je v komentářích. Toto jsem používal u 51, ale to už bude 9,5 roků co jsem naposled tvořil, no a včil o5 začínám, drobet mi ujel vlak, HI, proto asity chybičky.

rjmp start ;skoc na začátek programu
.org oc0addr ;přerušení od CC0
rjmp opcc0 ;skoč a obsluž přerušení od CC0

No zkusil jsem to upravit, ale z původního zadání jsem nějak nepřišel
na to, jak často má být voláno přeručení. Tak jsem to psal pro 100ms.

;OBSLOUŽENÍ PŘERUŠENÍ OD čítače/časovače 0 - CC0, xtal 16 MHz,T = 62,5ns
;bliká celý port C

;pro 100ms se zvolí předdělička 1:256(62,5ns x 256 = 16us)
;100ms/16us = 6250 / 250 = 25
;registr OCR0 nastavíme na 250,tj. přetečení dojde po 250 x 256 cyklech

;do pomocného registru hodnotu 25,tj. změna na portuC po 25 přerušení

	.nolist
	.include "m16def.inc"
	.list
	.cseg						;kodový segment

	.def	reg=r16				;pracovní registr
	.def	cnt=r17				;pomocný registr

	.equ	ddr=DDRC			;registr řízení směru
	.equ	port=PORTC			;port
	.equ	pin=PINC
;................................................ .............................
;prostor vyhrazený pro volání přerušení
		.org	$0000
		rjmp	start			;skoc na začátek programu
		.org	OC0addr	 		;přerušení od CC0
		rjmp	opcc0			;skoč a obsluž přerušení od CC0
...............................................................................
;úvodní nastavení
start:	
		ldi		reg,255			;nastav registr
		out		ddr,reg			;nastav port C jako výstupní

		ldi		reg,0b00110011	
		out		port,reg		

		ldi		reg,low (ramend)
		out		spl,reg			;nastav SP na konec SRAM
		ldi		reg,high (ramend)
		out		sph,reg

		ldi		cnt,25			;nastavení pomocného registru

		ldi		reg,0b00001100	
		out		TCCR0,reg		;nastavení CC0 - CTC režim
								;nastav předděličku na 1:256
								;256 x 62,5ns = 16us

		ldi		reg,250			;schoda TCNT0 s OCR0 po 4 msec
		out		OCR0,reg		;zapiš do registru OCR0

		ldi		reg,0b0000010	;	
		out		TIMSK,reg		;povol přerušení CC0 při schodě TCN0=OCR0
		sei						;povol globální přerušení v SREG
;...............................................................................

zap:	
		rjmp	zap
;...............................................................................
;obsloužení přerušení od CC0
;nezapomeň uložit SREG, pak pokračuj v obsluze přerušení
;změna stavu portu po 25 x 250 x 256 x 62,5ns = 100ms 

opcc0:	in		reg,sreg		;obsah SREG dej do reg
		push	reg				;ulož SREG před ztracením do zásobníku

		dec		cnt				;sniž stav o 1
		brne	loop			;skok dokud cnt > 0

								;proveď při cnt = 0
		in		reg,pin			;načti stav PINC
		com		reg				;negace 
		out		port,reg		;zápis na PORTC
		ldi		cnt,25			;nastavení pomocného registru

loop:	
		pop		reg				;vyzvedni obsah SREG ze zásobníku
		out		sreg,reg		;obsah SREG čti reg
zpet:	reti					;návrat z ošetření přerušení CC0 do programu
;................................................................................

Ukázka z simulace:
BlikLED.GIF

Jo, díky za pomoc, jak bude drobet času, mrknu jak jsi to vymyslel. Už mi to chodí, prvotní chyba byla ve špatném nastavení skoku při přerušení, .org ovf0addr (při přetečení), správně má být .org oc0addr (při schodě) a další ve skoku na reti v obsluze přerušení, mělo se skákat o dva řádky výše, páč se neobnovoval SREG. Ale pak jsem ty čtyři řádky okolo SREGu vyhodil a chodí to taky. V téhlle aplikaci není nutné registr ukládat, si myslím. Jinak přerušení by mělo být voláno po 10 µsec. Další časování už dělají registry v obsluze přerušení. Ať se daří, asi se o5 brzy ozvu s nějakým špekem, HI.
CC0.asm (2.34 KB)