ATmega16 - logické hodnoty se nevracejí do původního stavu

Ahoj,

jsem v programování uP začátečník. Snažím se na jednoduchých příkladech pochopit principy, ale ač jsem hledal jak chtěl, tak se mi asi nepodařilo správně zprovoznit call a ret.

Mám jednoduchý program

[code]main:
ldi R20, 0xFF
out DDRB,R20 ; aktivuji port B

	cbi PORTB, PORTB0 ; nastavím log. 0

	call obsluha ; volání podprogramu

	jmp main

obsluha:
sbi PORTB, PORTB0 ; nastavím log. 1
ret
[/code]

a předpokládal jsem, že je v podstatě totožný se zápisem

[code]main:
ldi R20, 0xFF
out DDRB,R20

	cbi PORTB, PORTB0
	sbi PORTB, PORTB0

	jmp main

[/code]

ovšem vyzkoušel jsem oba kódy a nejsou stejné. V případě druhé varianty se mi na logické sondě rozsvítí 1 i 0 (logická úroveň se periodicky střídá - v pořádku). V druhém případě se mi rozsvítí pouze 1, ovšem nevím jestli se tam zastaví, nebo se vrací na špatnou adresu…

:arrow_right: administrator: přejmenováno z "atmega16 se nechce vracet"

Odpovie ti len na tvoju otazku, dalsie chybycky krasy vynecham.
Program ti prepina medzi stavmi na meranom pine tak rychlo, ze sonda ti stav na pine neukaze. Videl by si to na osciloskope. Pin ti kmita rychlostou niekolko desiatok KHz (v zavyslosti od toho, aky zdroj hodin pouzivas).

V druhom kode ti sonda tiez neukaze realny stav, tam menis uroven pinu hned, takze v log0 je pin len niekolko mikroSekund.

Děkuji za odpověď.

V tom případě se pokusím vyloučit faktor vysoké frekvence.

main:
		ldi	R20, 0xFF
		out	DDRB,R20

		cbi PORTB, PORTB0

		; ============================= 
		;    delay loop 1000000 cycles:
		; ----------------------------- 
				  ldi  R17, $09
		WGLOOP0:  ldi  R18, $BC
		WGLOOP1:  ldi  R19, $C4
		WGLOOP2:  dec  R19
				  brne WGLOOP2
				  dec  R18
				  brne WGLOOP1
				  dec  R17
				  brne WGLOOP0
				  nop
		; ============================= 

		rcall obsluha

		; ============================= 
		;    delay loop 1000000 cycles:
		; ----------------------------- 
				  ldi  R17, $09
		WGLOOP3:  ldi  R18, $BC
		WGLOOP4:  ldi  R19, $C4
		WGLOOP5:  dec  R19
				  brne WGLOOP5
				  dec  R18
				  brne WGLOOP4
				  dec  R17
				  brne WGLOOP3
				  nop
		; ============================= 

		jmp main

obsluha:
		sbi PORTB, PORTB0
		ret

za nastavením log. 1 a za návratem z podprogramu obsluha mám zpoždění 1 sekundu. Teoreticky by na sondě měla sekundu svítit 1 a sekundu svítit 0. Jenomže mě na ní svítí 0 a vždy jen jednou za sekundu blikne 1. Dával jsem zpoždění hned za sbi a to se chovalo v pořádku, takže mám skoro pocit, že to z ret(u) skáče na main.

Řekl bych, že nemáš inicializovaný Stack pointer (registr SP). Kromě toho Ti tam bude asi chybět ještě pár věcí. Mimo jiné #include <m8Adef.inc> úplně na začátku, za ním tabulka vektorů, pak teprve program. Struktura by měla vypadat asi takto :

//=================================================================================================================
#include <m8Adef.inc> // Definiční soubor podle použitého mcu - tady je to ATmega8A

//=================================================================================================================
//definice konstant a registrů
#define CNST 4 // Konstanta CNST = 4
.def Temp=R16 // Proměnná Temp je uložena v registru 16 neboli registr 16 je Temp. (ldi Temp, CNST => ldi R16, 4)

//=================================================================================================================
.dseg // Data segment
SRAM_Promenna1:  .byte 1 // 1 byte vyhrazený pro proměnnou SRAM_Promenna1 v SRAM mcu
SRAM_Promenna2:  .byte 7 // 7 bytů vyhrazených pro proměnnou SRAM_Promenna2 v SRAM mcu

//=================================================================================================================
.eseg // EEPROM segment
EEPROM_Promenna1:  .byte 1 // 1 byte vyhrazený pro proměnnou EEPROM_Promenna1 v EEPROM mcu
EEPROM_Promenna2:  .byte 7 // 7 bytů vyhrazených pro proměnnou EEPROM_Promenna2 v EEPROM mcu

//=================================================================================================================
.cseg // Code segment
.org 0 // Kód bude začínat na adrese 0

        rjmp RESET_vektor // u některých mcu jmp RESET_vektor (viz datasheet)
.
.
.
tabulka přerušovacích vektorů (viz datasheet)
.
.
.
//=================================================================================================================
.
.
.
sem dávám podprogramy pro obsluhu přerušení nebo sem includuju soubor(y) s podprogramy pro obsluhu přerušení.
.
.
.

//=================================================================================================================
RESET_vektor:
.
.
.
sem patří inicializace mcu
a jako první 
// Nastavení SP na konec RAM - začátek
// Opět podle datasheetu. Některé mcu nemají SPH.
        ldi temp, high(RAMEND)
        out SPH, Temp
        ldi temp, low(RAMEND)
        out SPL, Temp
// Nastavení SP na konec RAM - konec
.
.
out DDRx, ???
inicializace čítačů, přerušení atd.

main:
        A tady teprve ten Tvůj main.
        rjmp main

//=================================================================================================================
jednotlivé podprogramy nebo opět includované soubory s podprogramy.

//=================================================================================================================
.db "Ahoj.",0 // Text Ahoj definovaný jako konstanta v programové paměti.
.dw 32000 // hodnota 32000 definovaná jako 2 byty v programové paměti.
// Definice 1 bytových hodnot (třeba převodní tabulka pro 7-segmentovky apod.)
// Správně :
Sedmisgment:
.db 0,1
.db 2,3
.db 4,5
.db 6,7

// Špatně :
Sedmisgment:
.db 0
.db 1
.db 2
.db 3
.db 4
.db 5
.db 6
.db 7

// Programová paměť je wordová, tudíž dostaneš warning a výsledek by byl :
Sedmisgment:
.db 0,0
.db 1,0
.db 2,0
.db 3,0
.db 4,0
.db 5,0
.db 6,0
.db 7,0

(AVR Studio 4.19)

Aha, tohle mi tam opravdu chybělo.

Děkuji za reakce. V internetových návodech tyto věci často chybí.