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
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…
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.
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