logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[atmega32][asm] Porty wejścia/wyjścia...

MmadA 15 Sty 2010 21:52 3140 10
REKLAMA
  • #1 7541575
    MmadA
    Poziom 11  
    Bawię się portami wejścia wyjścia używając atmega32 w zestawie startowym ZL3AVR (http://www.btc.pl/pdf/zl3avr.pdf). Zwarłem zworkę małej klawiatury (JP3), połączyłem wyjścia klawiatury w1..w4 do PB0..PB3 oraz wyjścia PA0..PA2 do LEDów D0..D2.

    Program, który mnie męczy:

    .INCLUDE "m32def.inc"
    
    	ldi R16, 0b00000111 // ldi - ładuje rejestr wartością bezpośrednią
    	out DDRA, R16 // DDRA - Data Direction Register (out=1/in=0)
    
    	out PORTA, R16 
    
    	ldi R16, 0x0F 
    	out PORTB, R16
    
    	main:
    		nop
    
    		sbis PINB, PINB0
    		rjmp button0
    
    	rjmp main
    
    	button0:
    		ldi R16, 0b11111100
    		out PORTA, R16
    	rjmp main
    
    	


    Nie mogę rozgryźć dlaczego po resetowaniu układu czasem zapala się jedna dioda a czasem wszystkie trzy... Jeśli zapalą się trzy to dwie mogę zgasić tak jak sobie tego życzę przy pomocy przycisku. Ale dlaczego czasem zapala się tylko jedna?
  • REKLAMA
  • Pomocny post
    #2 7542107
    grysek
    Poziom 19  
    Na samym początku programu powinieneś dodać skok do podprogramu dla wektora resetowania, prostszym językiem mówiąc powinieneś określić miejsce gdzie zaczyna się program po włączeniu zasilania procesora. Wektor RESET znajduje się zawsze na początku pamięci programu, czyli ma adres 0, zatem program powinien wyglądać tak:

    .INCLUDE "m32def.inc" 
    .cseg               // określa że odnosimy się do pamięci programu
    .org 0              // adres 0
    rjmp init           // skocz na początek programu
    
    
       init:
       ldi R16, 0b00000111 // ldi - ładuje rejestr wartością bezpośrednią 
       out DDRA, R16 // DDRA - Data Direction Register (out=1/in=0) 
    
       out PORTA, R16 
    
       ldi R16, 0x0F 
       out PORTB, R16 
    
       main: 
          nop 
    
          sbis PINB, PINB0 
          rjmp button0 
    
       rjmp main 
    
       button0: 
          ldi R16, 0b11111100 
          out PORTA, R16 
       rjmp main 


    Zaraz po wektorze resetu będziesz określał resztę wektorów przerwań, od urządzeń sprzętowych np UART czy ADC. Pełną listę wektorów przerwań oraz ich adresy znajdziesz w datasheet na str 42.

    W tym programie akurat nie jest to potrzebne ale zawsze warto inicjować stos na samym początku programu.
  • REKLAMA
  • #3 7543508
    MmadA
    Poziom 11  
    Dzięki za odpowiedź. Rozgryzam to dalej i mam takie ciekawostki. Dla kodu:

    .INCLUDE "m32def.inc"
    
    .cseg               // określa że odnosimy się do pamięci programu 
    .org 0              // adres 0 
    rjmp init           // skocz na początek programu 
    
    	init:
    		ldi R16, 0b00000111 // ldi - ładuje rejestr wartością bezpośrednią
    		out DDRA, R16 // DDRA - Data Direction Register (out=1/in=0)
    
    		;ldi R16, 0xFF
    		out PORTA, R16
    
    		ldi R16, 0x0F
    		out PORTB, R16
    
    	main:
    		sbis PINB, PINB0 // Skip if Bit I/O register is Set
    		rjmp button0
    	rjmp main
    
    	button0:
    		ldi R16, 0b11111100
    		out PORTA, R16
    	rjmp main


    Po resetowaniu układu mam dalej tę sytuację że czasem zaświecą się wszystkie diody czasem tylko jedna. W momencie gdy zaświecą się wszystkie i nacisnę przycisk, dwie gasną i zostaje tylko jedna.

    Natomiast gdy zmienię linijkę:

    
    		sbis PINB, PINB0 // Skip if Bit I/O register is Set
    


    na:

    
    		sbic PINB, PINB0 // Skip if Bit I/O register is Cleared
    


    Układ zachowuje się tak jakbym tego oczekiwał... zawsze startuje tylko z jedną świecącą diodą. Gdy podczas resetu trzymam wciśnięty przycisk startuje z trzema świecącymi, gdy go puszczę dwie gasną.

    Tylko skąd się bierze ta losowość w pierwszym przypadku?
  • #4 7543535
    grysek
    Poziom 19  
    Nie ustawiłeś które z pinów portu B mają być wejściami a które wyjściami. Musisz wpisać wartość do rejestru DDRB. A przycisk zwiera CI pin do masy czy do plusa? Masz rezystory podciągające na płytce?
  • #5 7549120
    MmadA
    Poziom 11  
    Nie ustawiałem pinów wejściowych dlatego że wyczytałem że "po inicjalizacji ukłądu wszystkie wyprowadzenia (poza wyjściem XTAL2) są wejściami". Ale spróbowałem z takim kodem:

    
    .INCLUDE "m32def.inc"
    
    .cseg               // określa że odnosimy się do pamięci programu 
    .org 0              // adres 0 
    rjmp init           // skocz na początek programu 
    
    	init:
    		ldi R16, 0b00000111 // ldi - ładuje rejestr wartością bezpośrednią
    		out DDRA, R16 // DDRA - Data Direction Register (out=1/in=0)
    
    		;ldi R16, 0xFF
    		out PORTA, R16
    
    
    		cbi DDRB, DDB0 // tryb wejściowy dla pinu 0 portu B
    		cbi DDRB, DDB1
    		cbi DDRB, DDB2
    		cbi DDRB, DDB3		
    
    		ldi R16, 0xFF // włączamy podciąganie rezystorów 
    		out PORTB, R16 // na wierszowych liniach klawiatury
    
    	main:
    		sbis PINB, PINB0
    		rjmp button0
    	rjmp main
    
    	button0:
    		ldi R16, 0b11111100
    		out PORTA, R16
    	rjmp main
    
    


    I sytuacja się powtarza...

    Jeśli chodzi o podciągające rezystory to nie do końca rozumiem o co chodzi. Wyczytałem tak:

    "Na wybranych lniach działających w trybie wejściowym istnieje możliwość uaktywnienia wewnętrznego rezystora podciągającego do napięcia zasilania. [...] Aby włączyć podciąganie wysarczy ustawić przyporządkowany lini znacznik PORTxn w rejestrze PORTx."

    Tak też zrobiłem, ale może chodzi Ci o coś innego?

    Naciskany przycisk zwiera do masy. Schemat płytki można zobaczyć tutaj na drugiej stronie.
  • Pomocny post
    #6 7549382
    michalko12
    Specjalista - Mikrokontrolery
    Zanim wejdziesz do main wstaw opóźnienie, daj czas na ustabilizowanie się wysokiego stanu po włączeniu podciągania lub daj zewnętrzne rezystory podciągające.
  • REKLAMA
  • #7 7557200
    MmadA
    Poziom 11  
    Dzięki tak dodane trzy nopy rozwiązały problem:

    
    .INCLUDE "m32def.inc"
    
    .cseg               // określa że odnosimy się do pamięci programu 
    .org 0              // adres 0 
    rjmp init           // skocz na początek programu 
    
    	init:
    		ldi R16, 0b00000111 // ldi - ładuje rejestr wartością bezpośrednią
    		out DDRA, R16 // DDRA - Data Direction Register (out=1/in=0)
    
    		//ldi R16, 0b00000111
    		out PORTA, R16
    
    		ldi R16, 0xFF // włączamy podciąganie rezystorów 
    		out PORTB, R16 // na wierszowych liniach klawiatury
    
    		nop // czekamy
    		nop // na 
    		nop // stabilizacje
    
    	main:
    
    		sbis PINB, PINB0
    		rjmp button0
    		
    	rjmp main
    
    	button0:
    		ldi R16, 0b11111100
    		out PORTA, R16
    	rjmp main
    	
    


    I teraz pytanie z tym związane. Ilość nopów dobrałem "doświadczalnie". W jaki sposób powinno się wykonać takie opóźnienie żeby było elegancko? Jak długo czekać? Gdzie przeczytać ile może trwać takie "stabilizowanie się portu"?

    Przy okazji natykam się na coraz to nowsze zagadki... Np. dlaczego poniższy kod nie zapala żadnej diody?

    
    .INCLUDE "m32def.inc"
    
    .cseg               // określa że odnosimy się do pamięci programu 
    .org 0              // adres 0 
    rjmp init           // skocz na początek programu 
    
    	init:
    		ldi R16, 0b00000111 // ldi - ładuje rejestr wartością bezpośrednią
    		out DDRA, R16 // DDRA - Data Direction Register (out=1/in=0)
    
    		//ldi R16, 0b00000111
    		out PORTA, R16
    
    		ldi R16, 0xFF // włączamy podciąganie rezystorów 
    		out PORTB, R16 // na wierszowych liniach klawiatury
    
    		nop // czekamy
    		nop // na 
    		nop // stabilizacje
    
    	main:
    
    		sbis PINB, PINB0
    		rjmp button0
    		
    		sbis PINB, PINB1
    		rjmp button1
    
    		sbis PINB, PINB2
    		rjmp button2
    
    		sbis PINB, PINB3
    		rjmp button3
    
    	rjmp main
    
    	button0:
    		ldi R16, 0b11111100
    		out PORTA, R16
    	rjmp main
    	
    	button1:
    		ldi R16, 0b11111010
    		out PORTA, R16
    	rjmp main
    
    	button2:
    		ldi R16, 0b11111001
    		out PORTA, R16
    	rjmp main
    
    	button3:
    		ldi R16, 0b11111000
    		out PORTA, R16
    	rjmp main
    


    Podobnie kod:

    
    .INCLUDE "m32def.inc"
    
    .cseg               // określa że odnosimy się do pamięci programu 
    .org 0              // adres 0 
    rjmp init           // skocz na początek programu 
    
    	init:
    		ldi R16, 0b00000111 // ldi - ładuje rejestr wartością bezpośrednią
    		out DDRA, R16 // DDRA - Data Direction Register (out=1/in=0)
    
    		//ldi R16, 0b00000111
    		out PORTA, R16
    
    		cbi DDRB, DDB0 // tryb wejściowy dla pinu 0 portu B
    		cbi DDRB, DDB1
    		cbi DDRB, DDB2
    		cbi DDRB, DDB3		
    
    		ldi R16, 0xFF // włączamy podciąganie rezystorów 
    		out PORTB, R16 // na wierszowych liniach klawiatury
    
    		nop // czekamy
    		nop // na 
    		nop // stabilizacje
    
    	main:
    
    		sbis PINB, PINB0
    		rjmp button0
    		
    	rjmp main
    
    	button0:
    		ldi R16, 0b11111100
    		out PORTA, R16
    	rjmp main
    


    Czuję że muszę doczytać w jakichś ogólnych kwestiach tylko nie bardzo wiem w jakich...
  • REKLAMA
  • Pomocny post
    #8 7557360
    Konto nie istnieje
    Konto nie istnieje  
  • #9 7557706
    MmadA
    Poziom 11  
    albertb napisał:

    Jeśli piszesz w językach wyższego poziomu, to najczęściej czas inicjalizacji załatwia sprawę za Ciebie.
    W assemblerze musisz pamiętać o wszystkim.


    O, to dobrze. Docelowo zamierzam pisać w C, jednak najpierw chciałem się assemblerem pobawić żeby dokładniej wiedzieć co leży pod spodem. :)

    albertb napisał:

    Czas czekania zależy od stałych czasowych na wejściach (wartość rezystancji podciągającej i pojemności wejściowych) czyli może być różny, nawet jak klawiaturę podłączysz innymi kabelkami ;-(
    Sposoby są różne:
    1. Najpierw włączyć podciąganie, potem dokonywać inicjacji reszty systemu - czasem wystarczy, ale powinieneś to umieć oszacować.


    Właśnie jak na razie nie bardzo umiem. Dodawałem po prostu kilka nopów i usuwałem kolejne sprawdzając czy dalej zachowuje się tak jak bym oczekiwał. Przy takim kodzie to nie problem. Ale nie chciałbym szukać takiego błędu w jakimś większym projekcie.

    albertb napisał:

    2. Można stabilizację przyspieszyć przełączjąc na chwilkę port na wyjścia - ale to niebezpieczne - pomyśl dlaczego.


    Może się stać coś nieprzyjemnego w momencie kiedy port ustawiony jest na wyjście a my potraktujemy go jakby był wejściem (spróbujemy ustawić mu stan wysoki)?

    albertb napisał:

    3. Elegancko to by było chyba dać pętlę, która wykonuje się tak długo, aż wszystkie wejścia osiągną stan wysoki.


    To chyba brzmi najrozsądniej...
  • #10 7557848
    grysek
    Poziom 19  
    Wg mnie nie ma sensu robić takiej pętli która praktycznie zawsze bedzie oczekiwała pewnie ze 3 cykle procesora. Ustawienie wewnętrznych konfiguracji odpowiadającym zewnętrznym pull-upom nie może trwać wieki to taka samo góra 1-2 cykli a jakby trwało dłużej to byłoby pewnie wspomniane w nocie katalogowej
  • Pomocny post
    #11 7558130
    Konto nie istnieje
    Konto nie istnieje  
REKLAMA