Vizitator Xplicit Postat Iulie 31, 2010 Partajează Postat Iulie 31, 2010 "Omu' cat traieste invata!" Francezule, mi-ai fost de mare ajutor cu explicatiile si cu linkul ala de calcul timere. Este mai mult decat lamuritor si linkul si explicatia ta. M-am luminat! Nu stiu cum sa-ti multumesc. Esti profesor!Cele bune. Link spre comentariu
Vizitator Xplicit Postat Iulie 31, 2010 Partajează Postat Iulie 31, 2010 Am facut o simulare pe placa de test cu urmatorul cod: Device 16F877Xtal 4All_Digital 1On_Hardware_Interrupt intrerupereOutput PORTA.0Output porta.1'//Timer1 Registers Prescaler= 4 - TMR1 Preset = 2975 - Freq = 4.00 Hz - Period = 0.250244 secondsSymbol T1CKPS1 = T1CON.5Symbol T1CKPS0 = T1CON.4Symbol T1OSCEN = T1CON.3Symbol T1SYNC = T1CON.2Symbol TMR1CS = T1CON.1Symbol TMR1ON = T1CON.0'//Timer0 Registers Prescaler= 256 - TMR0 Preset = 60 - Freq = 19.93 Hz - Period = 0.050176 secondsSymbol t0cs = OPTION_REG.5Symbol t0se = OPTION_REG.4Symbol psa = OPTION_REG.3Symbol ps2 = OPTION_REG.2Symbol ps1 = OPTION_REG.1Symbol ps0 = OPTION_REG.0Symbol tmr0if = INTCON.2Symbol tmr0ie = INTCON.5Symbol gie = INTCON.7Symbol TMR1IF = PIR1.0 ' TIMER1 Overflow Interrupt Flag bitSymbol TMR1IE = PIE1.0 ' TIMER1 Overflow Interrupt Enable bitSymbol PEIE = INTCON.6Symbol LED2 = PORTA.1Symbol LED = PORTA.0Low LEDLow LED2A var Bytet0cs = 0; // bit 5 TMR0 Clock Source Select bit...0 = Internal Clock (CLKO) 1 = Transition on T0CKI pint0se = 0; // bit 4 TMR0 Source Edge Select bit 0 = low/high 1 = high/lowpsa = 0; // bit 3 Prescaler Assignment bit...0 = Prescaler is assigned to the Timer0ps2 = 1; // bits 2-0 PS2:PS0: Prescaler Rate Select bitsps1 = 1;ps0 = 1;T1CKPS1 = 1; // bits 5-4 Prescaler Rate Select bitsT1CKPS0 = 0; // bit 4T1OSCEN = 1; // bit 3 Timer1 Oscillator Enable Control bit 1 = onT1SYNC = 1; // bit 2 Timer1 External Clock Input Synchronization Control bit...1 = Do not synchronize external clock inputTMR1CS = 0; // bit 1 Timer1 Clock Source Select bit...0 = Internal clock (FOSC/4)TMR1ON = 1; // bit 0 enables timerTMR1H = 11; // preset for timer1 MSB registerTMR1L = 159; // preset for timer1 LSB register'// Interrupt RegistersINTCON = 0; // clear the interrpt control registerTMR1IF = 0; // clear timer1 interupt flag TMR1IFTMR1IE = 1; // enable Timer1 interruptsPEIE = 1; // bit6 Peripheral Interrupt Enable bit...1 = Enables all unmasked peripheral interruptsTMR0 = 60; // preset for timer registertmr0ie = 1; // bit5 TMR0 Overflow Interrupt Enable bit...1 = Enables the TMR0 interrupttmr0if = 0; // bit2 clear timer 0 interrupt flaggie = 1; // bit7 global interrupt enablemain:If A > 10 Then Toggle LEDA = 0EndIfGoTo mainTIMER0INT:Inc Atmr0if=0 'clear flagtmr0ie =1 're_enable interruptsTMR0=60 'prestet TMR0ReturnTIMER1INT:Toggle LED2TMR1IF=0 'RESET FLAGTMR1ON =1 'RE_ENABLE TIMER1Returnintrerupere:If tmr0if = 1 Then GoSub TIMER0INT If TMR1IF = 1 Then GoSub TIMER1INTContext RestoreCele doua LEDuri se aprind dupa cum dicteaza fiecare timer: LED clipeste la secunda LED2 clipeste la jumatate de secunda Mi-a fost de mare ajutor link-ul ala de calcul al timerelor. Il recomand si la alti incepatori ca mine. Cele bune, cu multumiri! Link spre comentariu
francezu Postat Iulie 31, 2010 Partajează Postat Iulie 31, 2010 Este important sa "reincarci" timer-ul cu valoarea presetata in rutina de intrerupere, daca vrei sa scurtezi perioada de overflow. Pt TMR0 ai procedat corect, dar la TMR1 ai uitat acest aspect. In rutina de intrerupere nu este necesar sa reactivezi intreruperile hw( ex : tmr0ie=1 're_enable interrupts), ele raman activate, cea care se dezactiveaza la intrare in ISR, si se reactiveaza automat la iesire, este GIE; deci nu trebuie sa ai grija ei. Lafel si cu reactivarea timer-ului 1( TMR1ON=1 'RE_ENABLE TIMER1) nu este necesara- acesta ramane activ, si numara iarasi de la 0, dupa overflow. Initializarea timerelor poti sa o faci scriind direct registrul corespunzator, nu trebuie scris pe rand fiecare bit - desi asa e mai usor de vazut ce si cum ai setat. Ar mai trebui sa dezactivezi si intrarile analogice, astfel : ADCON1=6 ' all digital I/O'sDesi nu folosesti intrari, port-ul tot este citit atunci cand faci o scriere- vezi in datasheet- fiecare operatie de scriere catre port este de tip read-modify-write. Probabil compilatorul foloseste un registru latch, si de-asta nu sunt probleme, dar e o practica buna sa dezactivezi intrarile analogice daca nu le folosesti. Link spre comentariu
Vizitator Xplicit Postat August 1, 2010 Partajează Postat August 1, 2010 Am mai cizelat putin softul si l-am simplificat dupa indicatiile primite. Porturile le-am transformat in porturi digitale cu linia de comanda "ALL_DIGITAL 1" care este o comanda caracteristica in PROTON BASIC. Dar era deja activata si mai inainte, in vechiul soft,mai sus. Noul soft arata asa: Device 16F877Xtal 4All_Digital 1 'toate porturile digitaleOn_Hardware_Interrupt intrerupereOutput PORTA.0 'iesire pe porta.0Output PORTA.1 'iesire pe porta.1T1CON = %101101 'preset Timer1OPTION_REG = %000111 'preset Timer0Symbol tmr0if = INTCON.2 'define Timer0 interrupt flag bitSymbol tmr0ie = INTCON.5 'define Timer0 interrupt enable bitSymbol gie = INTCON.7 'define General interrupt enable bitSymbol TMR1IF = PIR1.0 'define TIMER1 Overflow Interrupt Flag bitSymbol TMR1IE = PIE1.0 'define TIMER1 Overflow Interrupt Enable bitSymbol PEIE = INTCON.6 'define Periferal interrupt enable bitSymbol LED2 = PORTA.1 'define LED2 outputSymbol LED = PORTA.0 'define LED outputLow LED 'reset LEDLow LED2 'reset LED2A var Byte 'declare variabila ATMR0 = 60 'preset for timer0 registerTMR1H = 11 'preset for timer1 MSB registerTMR1L = 159 'preset for timer1 LSB register'-----------------[Interrupt Registers]-----------------------------INTCON = 0 'clear the interrpt control registertmr0if = 0 'bit2 clear timer 0 interrupt flagTMR1IF = 0 'clear timer1 interupt flag TMR1IFtmr0ie = 1 'bit5 TMR0 Overflow Interrupt Enable bit...1 = Enables the TMR0 interruptTMR1IE = 1 'enable Timer1 interruptsPEIE = 1 'bit6 Peripheral Interrupt Enable bit...1 = Enables all unmasked peripheral interruptsgie = 1 'bit7 global interrupt enable'-----------------[MAIN PROGRAM STARTS HERE]------------------------main:If A > 10 Then 'check status variabila A; Toggle LEDA = 0 'reset variabila AEndIfGoTo main 'loop'--------------[TIMER0 INTERRUPT ROUTINE]------------------------TIMER0INT:Inc A 'increase variabila Atmr0if=0 'clear flagtmr0ie =1 're_enable interruptsTMR0=60 'prestet TMR0Return'--------------[TIMER1 INTERRUPT ROUTINE]------------------------TIMER1INT:Toggle LED2 'Toggle LED2TMR1IF=0 'RESET TIMER1 FLAGTMR1IE =1 'RE_ENABLE TIMER1TMR1H = 11 'preset for timer1 MSB registerTMR1L = 159 'preset for timer1 LSB registerReturn'-------------[GENERAL INTERRUPT ROUTINE]--------------------------intrerupere:If tmr0if = 1 Then GoSub TIMER0INT 'check timer0 flagIf TMR1IF = 1 Then GoSub TIMER1INT 'check timer1 flagContext Restore 'return from interrupt routineMerge frumos si m-am lamurit cu o gramada de necunoscute. Acum am in plan sa fac si o intrerupere pe portul B de la un ENCODER mecanic care sa incrementeze sau sa decrementeze o variabila. O intrebare: Unde sa cuplez encoderul pe portul B, la pinii B4-B7 cu comanda de intrerupere PORTB INTCON sau la pinul RB0/INT plus un alt pin ? Cum ar fi mai bine? O sa pot actiona atatea intreruperi deodata ca nu vreau sa renunt la astea deja clarificate, Tmr0 si Tmr1? Vreau sa am toate intreruperile active daca se poate pe acelasi cip. Dupa ce ma pun la punct cu aceste intreruperi de sistem, apoi ma pun serios pe treaba si creez un program soft complet care sa faca o chestie interesanta. Vad eu...Cele bune. Link spre comentariu
francezu Postat August 1, 2010 Partajează Postat August 1, 2010 Unde sa cuplez encoderul pe portul B, la pinii B4-B7 cu comanda de intrerupere PORTB INTCON sau la pinul RB0/INT plus un alt pin ? Cum ar fi mai bine?Se poate in mai multe moduri. Daca nu stii deja, iti sugerez sa te documentezi despre functionarea encoderelor- ce semnale genereaza, etc. Cred ca mai usor ar fi cu un pin al encoderului cuplat la INT. Cuplezi encoderul cu pinul comun la masa, ceilalti pini unul la RB0/INT si al doilea la RB1. Activezi rezistentele pull-up interne la PORTB si cuplezi doua condensatoare de ~100nF intre pini si masa-pt debouncing. In ISR daca detectezi intrerupere de la INT, verifici starea lui RB1, si daca este in 0 logic, insemana ca miscarea a fost intr-un sens, daca este in 1 logic atunci miscarea a fost in sens opus. Modul asta de detectie este valabil doar pt encodere cu detenta( se simte un click la fiecare miscare)- care genereaza ambele pulsuri complet.O sa pot actiona atatea intreruperi deodata ca nu vreau sa renunt la astea deja clarificate, Tmr0 si Tmr1?Nu vad de ce nu ar merge, dar cu fiecare intrerupere in plus se lungeste rutina ISR, si aceasta e bine sa fie mentinuta cat mai scurta, altfel pot aparea intreruperi valide inainte de iesirea din ISR, dar care nu vor fi servizate la timp. Link spre comentariu
Vizitator Xplicit Postat August 1, 2010 Partajează Postat August 1, 2010 OK treaba cu encoderul o voi experimenta si am sa fac o rutina de citire pe RB0/INT plus RB1. Ce nu am inteles e ca nu stiu la cat de multe intreruperi pot sa ma arunc intr-un singur program?Nu e bine sa pui mai multe ca se lungeste rutina ISR. Dar cate sa fie atunci, maximum? E vreo regula? Cum se calculeaza lungimea rutinei sa nu depaseasca timpul maxim permis al tuturor intreruperilor servisate? Cele bune. Link spre comentariu
francezu Postat August 1, 2010 Partajează Postat August 1, 2010 Nu cred ca este vreo limita privind numarul maxim de intreruperi, dar la un numar mare poti avea probleme cu gestionarea lor, mai ales daca au perioade de repetitie asemanatoare. In unele aplicatii critice, daca de exemplu se intampla sa apara doua intreruperi diferite, in acelasi timp, ele vor fi servizate in doua ISR-uri consecutive, dar poate pentru ultima intrerupere servizata, nu este suficient de rapid. In cazul asta se atribuie fiecarei intreruperi un nivel de prioritate; daca apar doua intreruperi in acelasi timp, dar sunt de prioritati diferite, va fi servizata prima cea cu prioritate mai inalta. In principiu rutina de intrerupere trebuie sa fie mai scurta decat cea mai mica perioada predictibila a uneia dintre intreruperi. Link spre comentariu
Vizitator Xplicit Postat August 3, 2010 Partajează Postat August 3, 2010 "Am aprins farurile de ceata" deoarece iarasi sunt in ceata. Nu mai pricep in totalitate cum e cu intreruperile astea. Si cum le dau ordin de prioritate, care sa fie prioritara si care secundara. Asta e! "Greu la deal cu boii mici". Nu s-ar putea posta un cod exemplu cu vreo doua intreruperi servisate si cu ordin de prioritate? Asta daca nu cer prea mult! Cele bune. Link spre comentariu
cirip Postat August 4, 2010 Partajează Postat August 4, 2010 Nu mai pricep in totalitate cum e cu intreruperile astea. Si cum le dau ordin de prioritate, care sa fie prioritara si care secundara.In cazul particular al lui 16F877, pe care inteleg ca il folosesti, prioritatea intreruperilor nu este selectabila. Procesorul nu permite asa ceva. In cazul lui 16F877, toate intreruperile determina un call la adresa 0x004. De acolo, e datoria programatorului sa se lamureasca cine a dat intrerupere si pe care o cauta prima la oua. "Pe care o cauta prima" ar fi un sistem rudimentar de prioritati, dar cred ca francezu' se referea la ceva mai complex cu suport hardware ptr prioritati. Link spre comentariu
MifTy Postat August 4, 2010 Partajează Postat August 4, 2010 call stack???bine, asta merge de nu se poate în asamblare, presupun că merge şi în mikrobasic, dar n-am idee cât o să se mărească codu' cu aşa ceva... Link spre comentariu
francezu Postat August 4, 2010 Partajează Postat August 4, 2010 Nu Cirip, ma refeream doar la un sistem software de prioritati. Bineinteles ca unul hardware ( asa cum au 18F-urile) ar fi ideal, dar cand proc-ul nu permite... Repet pentru Xplicit : o asemenea implementare este necesara doar pentru aplicatii critice/pretentioase cand un anume tip de intrerupere nu "sufera" sa fie tratata decat la momentul in care apare. Daca in schimb nu este nici o problema daca intreruperea va fi tratata mai tarziu decat momentul aparitiei sale ( cu o durata de timp egala cu timpul de executie al rutinei/rutinelor de servizare ale celorlalte posibile intreruperi) nu mai ai nevoie de alte complicatii software. Chiar si asa , cum spunea Cirip ai obtinut un sistem rudimentar de prioritati, alegand corespunzator ordinea in care interoghezi flagurile de intreruperi. Daca de exemplu apar doua intreruperi in acelasi timp va fi servizata prima cea a carui flag il interoghezi primul. Neajunsul este ca odata "intrat" in ISR, nu mai poti serviza eventuale intreruperi ce pot aparea pe durata ISR-ului. Si aici se poate lucra, in sensul ca poti interoga flag-ul intreruperii cu prioritate mai mare , in interiorul rutinei de servizare a intreruperii de prioritate joasa, si daca este setat, executi rutina de servizare a intreruperii inalte. Dar deja se complica lucrurile, si orice instructiune in plus consuma timp; mai bine folosesti un proc are are asa ceva nativ. Link spre comentariu
Vizitator Xplicit Postat August 4, 2010 Partajează Postat August 4, 2010 Multumesc la toti! Am inteles. Nu trebuie sa ma cramponez pe ordinea de prioritate. Trebuie servisate in ordinea in care le-am interogat in rutina de intrerupere si basta. Asta e. Programeaza cineva de aici, in PROTON BASIC? Nu de altceva, dar nu am vazut nici un cod de la altii ca sa ma inspir si eu, asa la inceput. Eu lucrez cu PROTON BASIC deoarece am incercat si PICBASIC PRO dar asta din urma mi se pare mult mai incalcit si ma incurca mai tare. Asa ca am ramas la PROTON BASIC si ma perfectionez cu asta. Stiti cum se zice: "cine alearga dupa doi iepuri..." asa ca am renuntat la unul in favoarea celuilalt. Cele bune. Link spre comentariu
Postări Recomandate
Creează un cont sau autentifică-te pentru a adăuga comentariu
Trebuie să fi un membru pentru a putea lăsa un comentariu.
Creează un cont
Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!
Înregistrează un nou contAutentificare
Ai deja un cont? Autentifică-te aici.
Autentifică-te acum