adrian19
20th December 2008, 16:02
Salutare!
Sunt nou in lucrul cu microcontrolere. Ceea ce vreau sa realizez acum este un numarator care sa afiseze numere de la 0 la 99, pe un afisor cu 2 cifre. Mai jos am atasat codul pe care l-am scris. Am atasat si un screanshot cu simularea din proteus. Proteus-ul imi zice ca se petrece un overflow la instructiunea CALL TMR1_INIT de la inceputul programului. In MPLAB am facut un debug folosind MPLAB SIM. Programul ruleaza dupa cum ma asteptam, cel putin cu MPLAB SIM. In proteus ma confrunt cu realitatea. Imi afiseaza cifre identice de fiecare data, pe ambele grupari de segmente. Ceea ce mi se pare ciudat este ca nu reuseste sa scrie pe portul A. Aveti idee cu ce gresesc? Sau ce ar trebui sa mai inteleg inainte de a finaliza cu succes acest mic proiect?
De precizat ar mai fi ca am relizat circuitul in realitate si se comporta la fel ca in proteus.
INCLUDE "P16F628A.INC"
CBLOCK 0x20
CIFRA_UNIT
CIFRA_ZECI
ENDC
ORG 0x00
GOTO START
ORG 0x04
GOTO TMR1_ROUTINE
;initializarea porturilor
INIT_PORTS
;bank0 select
CLRF STATUS
CLRF PORTA
CLRF PORTB
;bank1 select
BSF STATUS, RP0
MOVLW 0x00
MOVWF TRISA
MOVWF TRISB
;bank0 select
CLRF STATUS
RETURN
;initializare registrii asociati modulului timer1
INIT_TMR1
;bank0 select
BCF STATUS, RP1
BCF STATUS, RP0
;----------------
BSF INTCON, GIE
BSF INTCON, PEIE
CLRF TMR1L
CLRF TMR1H
BCF PIR1, TMR1IF
MOVLW 0x31
MOVWF T1CON
;bank1 select
BCF STATUS, RP1
BSF STATUS, RP0
;---------------
BSF PIE1, TMR1IE
RETURN
;rutina de executat, odata ce se petrece intreruperea
TMR1_ROUTINE
BCF PIR1, TMR1IF
;setare cifra unitati
CLRW
XORWF CIFRA_UNIT, 0
CALL TABELA
MOVWF PORTB
;CLRF PORTA
MOVLW 0x40
MOVWF PORTA
;--------------------
;setare cifra zecilor
CLRW
XORWF CIFRA_ZECI, 0
CALL TABELA
MOVWF PORTB
;CLRF PORTA
MOVLW 0x80
MOVWF PORTA
;--------------------
INCF CIFRA_UNIT, F
;--------------------
MOVLW 0x0A
XORWF CIFRA_UNIT, 0
BTFSS STATUS, Z
RETFIE
;--------------------
MOVLW 0x00
MOVWF CIFRA_UNIT
MOVLW 0x0A
XORWF CIFRA_ZECI, 0
BTFSC STATUS, Z
CLRF CIFRA_ZECI
;--------------------
INCF CIFRA_ZECI, F
;--------------------
CLRW
RETFIE
;lookup table
TABELA
ADDWF PCL, F
RETLW 0x3F
RETLW 0x06
RETLW 0x5B
RETLW 0x4F
RETLW 0x66
RETLW 0x6D
RETLW 0x7D
RETLW 0x07
RETLW 0xFF
RETLW 0x6F
;inceput program
START
CALL INIT_PORTS
CALL INIT_TMR1
;bank0 select
BCF STATUS, RP1
BCF STATUS, RP0
MOVLW 0x00
MOVWF CIFRA_UNIT
MOVWF CIFRA_ZECI
LOOP
NOP
GOTO LOOP
END
edy_wheazel
20th December 2008, 19:36
Din pacate nu ma pricep la PIC-uri, deci nu cunosc mnemonicile din asamblare. Problema ta (se afiseaza aceleasi numere) tine de urmatorul aspect: pt. LSB folosesti un registru care se incrementeaza de cate ori afisezi o cifra. In momentul in care ajungi la "9" acest registru se reseteaza si se incrementeaza registrul pt. MSB. Programul tau nu realizeaza acest lucru, in momentul in care inrementezi LSB se incrementeaza si MSB.
Vezi ca tu mai ai o problema acolo, Proteus iti da un mesaj de eroare "Stack overflow executing CALL instruction", la adresa 42hexa, adica la 42h ai o instructiune CALL catre o subrutina de initializare a porturilor sau a timer-ului (vezi care e la 42h). Simuleaza pas cu pas cu MPLAB, ai o problema cu subrutina respectiva, ramane blocata in ea (sau altceva), cum am mai spus, nu cunosc mnemonicile la PIC.
adrian19
21st December 2008, 01:04
Multumesc pentru sfaturi. Asta aveam de gand sa fac si eu, dar in practica s-a dovedit ca sentamplau si alte minunatii prin registrii pic-ului
Pana la urma am reusit sa obtin ceva functional, dar nu perfect. N-am reusit sa fac temporizarea cum trebuie, adica se observa cum se sting si se-aprind ledurile de la afisor, foarte repede. Felul in care mi-am realizat proiectul ma obliga sa folosesc acelasi oscilator si pentru pic si pentru tmr1, portul b fiind complet ocupat pentru afisor. Poate fi asta o problema? Acum am atasat un oscilator cu cuartz de 4MHz la pic. Ce inteleg eu pana in prezent :cry: este ca pic-ul executa 1.000.000 instructiuni pe secunda. Modulul tmr1 se incrementeaza independent de ce se-ntampla in microcontroler. Adica in timp ce se executa o instructiune in pic, in paralel si independent este incrementat si tmr1. Gresesc cumva?
edy_wheazel
21st December 2008, 01:14
Nu am inteles partea cu acelasi oscilator pt. timer si pt. PIC.
Daca ai pus cuartul in schema trebuie sa modifici si in Proteus, in ferestra cu care incarci .hex-ul (daca nu ma insel). De asemenea, daca il realizezi practic ai grija la optiunile programatorului, nu stiu cum este la PIC-uri dar s-ar putea sa fie setat default pe oscilator intern.
adrian19
21st December 2008, 13:35
QUOTE (edy_wheazel @ Dec 21 2008, 01:14)

Nu am inteles partea cu acelasi oscilator pt. timer si pt. PIC.
Daca ai pus cuartul in schema trebuie sa modifici si in Proteus, in ferestra cu care incarci .hex-ul (daca nu ma insel). De asemenea, daca il realizezi practic ai grija la optiunile programatorului, nu stiu cum este la PIC-uri dar s-ar putea sa fie setat default pe oscilator intern.
Microcontrolerul PIC16F628A executa instructiunile dupa oscilatorul pe care l-am atasat la pinii RA6 si RA7 ai portului A.
Doi pini ai portului B de la microcontrolerul PIC16F628A, pot fi folositi ca intrari pentru un alt oscilator. In registrul T1CON am posibilitatea de a seta bitii astfel incat modulul Timer1 sa functioneze dependent de frecventa acestui oscilator. Dar la mine pinii portului B sunt conectati la afisor. Deci raman cu posibilitatea de a avea un singur oscilator extern. Timer1 este incrementat in functie de frecventa acestui oscilator, iar in paralel pic-ul executa instructiunile pe care i le-am dat eu. Inteles?
Intotdeauna am grija sa setez oscilatorul corespunzator. La inceput uitam si desi scriam codul corect, nu functiona nimic....si asa imi faceam nervi degeaba
Dexter Dude
21st December 2008, 17:57
Pentru montajul tau puteai foarte bine sa fol. oscilatorul intern .Eliberai astfel 2 pini si micsorai si costurile.
cosminprund
22nd December 2008, 11:56
Am citit putin codul ASM pe care l-ai pus in primul post. Eu n-am lucrat cu intreruperi (inca), dar uzual interuperile trebuie sa fie foarte-foarte scurte, munca se face in bucla principala a aplicatiei. Adica in interupere ar trebui sa incrementezi unitatile si zecile si sa faci RETURN imediat. In aplicatia principala, in loc de NOP, ar trebui sa afisezi pozitia curenta a contorului. In acest mod afisorul ar fi actualizat in continuu si nu ai mai observa "flickerul" de care ziceai.
In ce priveste mesajul de eroare cu "stack oveflow": Dupa cum stii PIC-ul are un "hardware stack" destul de limitat, in dataheet gasesti exact numarul de nivele de stack suportate de MCU. Cifra e undeva pe la 6-8 nivele stack. Din cite vad eu la tine nu sunt folosite prea multe proceduri, tehnic n-ar trebui sa depasesti 3 nivele stack utilizate. Speculez acum, nu cumva se intampla stack-overflow pentru ca MCU porneste o noua intrerupere de timer inainte ca prima intrerupere de timer sa-si termine treaba?
adrian19
22nd December 2008, 19:30
QUOTE (cosminprund @ Dec 22 2008, 11:56)

Am citit putin codul ASM pe care l-ai pus in primul post. Eu n-am lucrat cu intreruperi (inca), dar uzual interuperile trebuie sa fie foarte-foarte scurte, munca se face in bucla principala a aplicatiei. Adica in interupere ar trebui sa incrementezi unitatile si zecile si sa faci RETURN imediat. In aplicatia principala, in loc de NOP, ar trebui sa afisezi pozitia curenta a contorului. In acest mod afisorul ar fi actualizat in continuu si nu ai mai observa "flickerul" de care ziceai.
In ce priveste mesajul de eroare cu "stack oveflow": Dupa cum stii PIC-ul are un "hardware stack" destul de limitat, in dataheet gasesti exact numarul de nivele de stack suportate de MCU. Cifra e undeva pe la 6-8 nivele stack. Din cite vad eu la tine nu sunt folosite prea multe proceduri, tehnic n-ar trebui sa depasesti 3 nivele stack utilizate. Speculez acum, nu cumva se intampla stack-overflow pentru ca MCU porneste o noua intrerupere de timer inainte ca prima intrerupere de timer sa-si termine treaba?
Ti-am urmat sfatul de a afisa cifrele in partea principala a programului si ... succes
Nu mai clipesc ledurile.
Da, stack-ul pic-ului 16F628A cu care lucrez e pe 8 nivele daca nu ma insel. Scriam intr-un registru o valoarea aiurea si trimitea pe unde nu trebuie, de asta primeam acea avertizare cu "stack overflow". Am rezolvat problema asta. Multumesc inca odata pentru ajutor