Sari la conținut
ELFORUM - Forumul electronistilor

pic 16f84a - termometru


dorelb

Postări Recomandate

Pai cum sa introduca intarzieri cand citeste temperatura ? ca doar e pe intrerupere.Cand valoarea la timer0 trece de la 0xFF la 0x00, apoi nu conteaza ce face programul , se intrerupe executia lui (ca daia ii zice intrerupere) si se executa functia de intrerupere. Nu m-am uitat peste tot programul care l-ai postat tu , dar ce am observat:

INTCON = 0 ' not using interupts. Just monitoring int flag bits

pai normal ca intarzie , ca tu nu lasi mechanismul hardware al intreruperii sa functioneze...tu faci ceva software cu flagul.Edit:

Schema este postata, oricine doreste poate scrie un soft functional si sa il posteze aici.

Pe mine nu ma intereseaza acest proiect ,eu doar vreau sa ajut daca pot cu problemele software intalnite, dar daca nu este codul pus la vedere , nu pot decat sa zic cum as face eu.
Link spre comentariu
  • Răspunsuri 859
  • Creat
  • Ultimul Răspuns

Top autori în acest subiect

  • dorelb

    246

  • marik2500

    97

  • GeoMar

    84

  • fratello

    69

Top autori în acest subiect

Imagini postate

Dar, citirea senzorilor de temperatura (la rezolutie de 9 biti =93.75 ms, 10 biti =187.5 ms, 11 biti =375 ms, pentru fiecare !) introduce intarzieri in program, pe care nu le-am putut corecta software.

In proiectul meu (folosesc DS1631, da' functionarea e asemanatoare, difera doar interfata) dau comanda de achizitie (comanda Convert T [44h] ) in secundele pare si citesc valorile in secundele impare (sau invers), In conditiile astea, intarziere introdusa de senzrul de temperatura e durata unei comunicatii (ca nu mai trebuie sa astept dupa date, ma asteapta ele pe mine).In cazul de fata as proceda similar pentru fiecare senzor:- sec. 1 - Convert T sensor 1- sec. 2 - read sensor 1- sec. 3 - Convert T sensor 2- sec. 4 - read sensor 2In felul asta ai date proaspete pentru fiecare senzor la 4 secunde, da' nu cred ca-i grav.Da' citirea chiar o fac sincronizata de ceas; la ceas folosesc quart de 32kHz (32,178, mai exact), da' principiul e acelasi cu ce am explicat anterior referitor la valorile de start in TMR0. La mine ceasul functioneaza chiar exact.
Link spre comentariu

@Eugen_B: Ceea ce a postat fratello sunt niste variante. Daca intr-adevar vrei sa vezi cum functioneaza ceasul din soft mergi la http://darreltaylor.com/DT_INTS-14/elapsed.html.Tu spui

Pai cum sa introduca intarzieri cand citeste temperatura ? ca doar e pe intrerupere

eu spun ca poate sa introduca intarzieri, intre comanda de conversie si citirea senzorilor apare o pauza de pana la 750ms. Incearca sa vezi la o intrerupere de 256us sa vezi cam cate pierzi si nu sunt contorizate (din cate stiu eu daca apare o intrerupere si picul executa o comanda intai termina si apoi intra in intrerupere) Din cate stiu eu orice procesor permite executarea intreruperii in perioada in care este idle, daca nu executarea intreruperii trebuie sa mai astepte. @Liviu_M: acelasi lucru il fac si eu prima secunda se trimite comanda de conversie si in a doua secunda se citeste senzorul.Cu un cristal secundar de 32.768 KHz intreruperea are loc la o secunda, iar picul pana apare intreruperea poate executa pana la 1.000.000 de instructiuni. Dar la o intrerupere de 10 ms?Sper ca m-am exprimat corect. Daca nu imi cer scuze.
Link spre comentariu

Cu un cristal secundar de 32.768 KHz intreruperea are loc la o secunda, iar picul pana apare intreruperea poate executa pana la 1.000.000 de instructiuni. Dar la o intrerupere de 10 ms?Sper ca m-am exprimat corect. Daca nu imi cer scuze.

Te-ai exprimat corect si clar, da' cred ca vezi probleme acolo unde nu sunt. In 10ms (mie mi-au iesit 15) ai timp de 10000 (zece mii) de instructiuni la un ceas de 4Mhz. Eu cred ca ai timp sa faci o gramada de chestii in timpul asta. Plus ca tratarea intreruperii dureaza cateva uSecunde, dupa care programul continua nestingherit de unde a ramas.Tratarea intreruperii generate de TMR0 dureaza ~5 comenzi; in cazul meu, quarz dedicat, arata cam asa (e in c, da' cred ca se poate intelege):
if(TMR1IF && TMR1ON)  /*ceas*/   {       T1CON = 0b00001110;    // stop the timer        TMR1L = 0x00;              TMR1H = 0x80;          // ~ 1 sec       T1CON = 0b00001111;    // start the timer              ucClkInt = 1;   //"anunt" programul principal ca a mai trecut o secunda       TMR1IF = 0;   }
In cazul vostru:- folositi TMR0 (un singur registru si alte comenzi de start/stop); in registru incarcati valoarea de start a numararii. Din asata se "calibreaza" ceasul. - in programul principal, undeva in cadrul buclei aleaia nesfarsite, mai trebuie o bucata de cod care sa numere cele 75 Ticks (vezi calculul meu de la pag. 24 parca) si sa semnalizeze o secunda noua cand se fac cele 75 Ticks;- semnalul ala de secunda noua se foloseste mai departe in program pentru "sincronizarea" functionarii:
if(ucClkInt){    Ticks++;   // incrementez ticks    if(Ticks == 75)  //testez daca s-a terminat secunda    {          SecundaNoua = 1;  // semnalizez secunda noua          Ticks = 0;         //reset tikc    }    ucClkInt = 0;   // reset flag intrerupere ceas}
Link spre comentariu

Tratarea intreruperii generate de TMR0 dureaza ~5 comenzi; in cazul meu, quarz dedicat, arata cam asa (e in c, da' cred ca se poate intelege):

In codul tau cred ca e vorba de TMR1.Initial s-a folosit TMR0 dar acum se foloseste TMR1 si sunt 10ms intre intreruperi nu 15. 100 Ticks/sec.Am mai spus si risc sa ma repet, nu ceasul in sine este problema ci ceea ce face pic-ul intre intreruperi.In unele cazuri si cred ca si aici 10000 de instructiuni nu sunt de ajuns. PBP-ul nu poate lucra cu variabile float si atunci sunt introduse niste artificii de calcul pentru a trece peste acest obstacol (gen inmultire cu 100 si altele).
Link spre comentariu

si atunci sunt introduse niste artificii de calcul pentru a trece peste acest obstacol (gen inmultire cu 100 si altele).

In loc sa inmultiti cu 100, eu as face o variabila noua (unsigned char - 8 biti fara semn) compusa din cei 3 biti LSB al byte-ului MSB ai senzorului (bitii 2^6..2^4 in data-sheet) (ma rog, se lucreaza cu 4) si 4 biti MSB din Byte-ul LSB al senzorului:ucIntregiGrad =((MSB_SENZOR << 4) + (LSB_SENZOR >> 4);In felul asta intregii sunt obtinuti destul de repede, mai ramane sa-i afisati; >> 4 e shift dreapta cu 4 biti, <<4 e shift stanga.Pentru partea de dupa virgula, eu am facut mers pe rezolutie de 0,25° => am 4 cazuri mari si late pe care le tratez cu if()..else.Poate ideile astea va ajuta sa economisiti ceva timp?LE Si tot nu ma prind de ce ti se pare ca e o diferenta intre 10 ms si 1 sec din punct de vedere al intreruperilor (in afara de un test suplimentar si 2 incrementari).
Link spre comentariu

Am incercat asa :

ClockCount:   ' Note: this is being handled as an ASM interrupt@ INT_START @ RELOAD_TIMER                    ; Reload TIMER1  R0save = R0                     ; Save 2 PBP system vars that are used during  R1save = R1                     ; the interrupt    Ticks = Ticks + 1    if Ticks = 100 then       Ticks = Ticks-100        Seconds = Seconds + 1    	 SecondsChanged = 1if seconds=10 or seconds=40 then gosub init_1if seconds=15 or seconds=45 then gosub init_2if seconds=20 or seconds=50 then gosub temp_1if seconds=25 or seconds=55 then gosub temp_2         if Seconds = 60 then          Minutes = Minutes + 1          MinutesChanged = 1          Seconds = 0       endif...etc...
si, de data aceasta, ceasul o ia inainte !!! Se intelege , cred, init_1 si temp_1 sunt initializarea/citirea senzorului 1...

L.E. : Poate cineva "vede" mai clar unde ar trebui introduse rutinele de citire a senzorilor de temperatura :

'****************************************************************'*  Name    : ELAPSED.PBP                                       *'*  Author  : Darrel Taylor                                     *'*  Notice  : Copyright (c) 2003                                *'*  Date    : 12/16/2003                                        *'*  Notes   :                                                   *'****************************************************************Define  INTHAND _ClockCount    ' Tell PBP Where the code starts on an interruptInclude "ASM_INTS.bas"         ' ASM Interrupt StubsTicks    var byte   ' 1/100th of a secondSeconds  var byteMinutes  var byteHours    var byteDays     var wordR0save   var wordR1save   var wordSecondsChanged   var bitMinutesChanged   var bitHoursChanged     var bitDaysChanged      var bitSecondsChanged = 1MinutesChanged = 1Hours =12 : Minutes =00 : ZIUA = 01 : Luna = 01Goto OverElapsed' ------------------------------------------------------------------------------Asm  IF OSC == 4                       ; Constants for 100hz interrupt from Timer1TimerConst = 0D8F7h                 ; Executed at compile time only  EndIF  If OSC == 8TimerConst = 0B1E7h  EndIF  If OSC == 10TimerConst = 09E5Fh  EndIF  If OSC == 20TimerConst = 03CB7h  EndIF  ; -----------------  ADD TimerConst to TMR1H:TMR1LADD2_TIMER   macro    CHK?RP  T1CON    BCF     T1CON,TMR1ON           ; Turn off timer    MOVLW   LOW(TimerConst)        ;  1    ADDWF   TMR1L,F                ;  1    ; reload timer with correct value    BTFSC   STATUS,C               ;  1/2    INCF    TMR1H,F                ;  1    MOVLW   HIGH(TimerConst)       ;  1    ADDWF   TMR1H,F                ;  1    endm; -----------------  ADD TimerConst to TMR1H:TMR1L and restart TIMER1 RELOAD_TIMER  macro    ADD2_TIMER    BSF     T1CON,TMR1ON           ;  1    ; Turn TIMER1 back on    CHK?RP  PIR1    bcf     PIR1, TMR1IF           ; Clear Timer1 Interrupt Flag    endm; -----------------  Load TimerConst into TMR1H:TMR1L LOAD_TIMER  macroEndAsm    T1CON.0 = 0                    ; Turn OFF Timer1    TMR1L = 0    TMR1H = 0Asm    ADD2_TIMER    endmEndAsm' ------[ This is the Interrupt Handler ]---------------------------------------ClockCount:   ' Note: this is being handled as an ASM interrupt@ INT_START @ RELOAD_TIMER                    ; Reload TIMER1  R0save = R0                     ; Save 2 PBP system vars that are used during  R1save = R1                     ; the interrupt    Ticks = Ticks + 1    if Ticks = 100 then       Ticks = Ticks-100        Seconds = Seconds + 1    	 SecondsChanged = 1         if Seconds = 60 then          Minutes = Minutes + 1          MinutesChanged = 1          Seconds = 0       endif       if Minutes = 60 then          Hours = Hours + 1          HoursChanged = 1          Minutes = 0       endif       if Hours = 24 then          Days = Days + 1          DaysChanged = 1          Hours = 0       endif    endif  R1 = R1save                     ; Restore the PBP system vars  R0 = R0save@ INT_RETURN                      ; Restore context and return from interrupt'-----====[ END OF TMR1 Interrupt Handler ]====---------------------------------StartTimer:    T1CON.1 = 0                   ; (TMR1CS) Select FOSC/4 Clock Source    T1CON.3 = 0                   ; (T1OSCEN) Disable External Oscillator    PIR1.0  = 0                   ; (TMR1IF) Clear Timer1 Interrupt Flag    PIE1.0  = 1                   ; (TMR1IE) Enable TMR1 overflow interrupt    INTCON.6 = 1                  ; (PEIE) Enable peripheral interrupts    INTCON.7 = 1                  ; (GIE) Enable global interrupts    T1CON.0 = 1                   ; (TMR1ON) Start TIMER1return; -----------------StopTimer:    T1CON.0 = 0                   ; Turn OFF Timer1return; -----------------ResetTime:    R0save = T1CON.0              ; Save TMR1ON bit    T1CON.0 = 0                   ; Turn OFF Timer1    TMR1L = 0    TMR1H = 0@   LOAD_TIMER                    ; Load TimerConst    T1CON.0 = R0save              ; Restore TMR1ON bit    Ticks = 0    Seconds = 0    Minutes = 0    Hours = 0    Days = 0    SecondsChanged = 1returnOverElapsed:
Link spre comentariu

Poate ca sunt eu mai talamb, si nu inteleg diferenta intre intrerupere la 10 ms si 1sec. Spatiul de lucru intre intreruperi in primul caz e de 10 ms si in al doilea caz e de 1 sec evident.Atunci cand apare o intrerupere microcontroler-ul trebuie sa salveze variabilele. Cu cat sunt mai multe variabile in sistem cu atat ii ia procesorului mai mult timp sa salveze aceste variabile.Diferenta am observat-o atunci cand am facut softul pentru un ceas&dual thermometer folosind un cristal suplimentar de 32.768 KHz si utilizand acelasi algoritm de citire al senzorilor. Am observat ca intreruperile nu mai sunt afectate de ceea ce face pic-ul in perioada dintre intreruperi.Multumesc

Link spre comentariu

Dupa parerea mea, faci prea multe operatii in cadrul rutinei de tratare a intreruperii.Eu as face doar incrementarea lui Ticks si, eventual, a secundelor. Restul prelucrarilor - o data pe secunda cand vine secunda noua.

' ------[ This is the Interrupt Handler ]---------------------------------------ClockCount:   ' Note: this is being handled as an ASM interrupt@ INT_START@ RELOAD_TIMER                    ; Reload TIMER1  R0save = R0                     ; Save 2 PBP system vars that are used during  R1save = R1                     ; the interrupt    Ticks = Ticks + 1    if Ticks = 100 then       Ticks = 0;       Seconds = Seconds + 1   ; asta e optional, se poate face jos       SecondsChanged = 1    endif  R1 = R1save                     ; Restore the PBP system vars  R0 = R0save@ INT_RETURN                      ; Restore context and return from interrupt
Restul l-as face in main, de fiecare data cand "se umple" o secunda:
      if SecondsChanged = 1         ; numai cand se schimba o secunda         secondChange = 0;         if Seconds<59                   ; inca nu s-a umplut inutul, mai putem incrementa secundele            Seconds = Seconds + 1         else                                  ; s-a umplut un minut, secundele o iau de la o si testam minutele            Seconds = 0            if Minutes < 59               ; nu s-a facut o ora               Minutes = Minutes+1             else                Minute = 0               if Hours < 24                  Hours = Hours +1               else                  ...                           ; si asa mai departe              endif            endif       endif;      ... 
@gr1ph0n: oricate operatiii ai face intre intreruperi, ele vor veni intotdeauna la 10 ms (asta daca nu dezactivezi intreruperile pe parcurs pentru timp indelungat).Dupa cum scrie in documentatie, in cazul in care primeste o intrerupere, PIC-ul salveaza adresa curenta pe stiva si "sare" la adresa 0x04. Si atat. E treaba ta sa nu lungesti preat tare rutina de tratare a intreruperilor (in Midrange User Manual scrie ca intreruperile sunt dezactivate automat):

When an interrupt is responded to, the GIE bit is cleared to disable any further interrupt, thereturn address is pushed into the stack and the PC is loaded with 0004h.

Link spre comentariu

@ Liviu :primele comentarii sunt pentru mine ?! Multumesc frumos, dar autorul codului este mentionat in antetul acestuia. Din cate stiu eu, Darrel Taylor este "Number 1" cand vine vorba de PicBasicPro ...de aceea am ales codul lui pentru ceas. Discutiile pe topicul dedicat codului pentru ceas "elapsed_int.bas" (am pus link mai sus) aratau cat de greu este de pastrat acuratetea ceasului introducand si partea de citire a senzorilor de temperatura...

Daca cineva STIE cum se face asta CORECT, de ce nu pune codul aici ?! Nu pentru mine (sau si pentru mine) ! Dar, mai ales, pentru cei care vor sa mai invete ceva... Un cod complet, eventual comentat, ar opri scrierea atator posturi si ar rezolva problema. Nu ne putem da toti cu parerea asupra unor portiuni de cod, mai ales cand sunt scrise in limbaje "nefamiliare" ...Parerea mea :) ...

Link spre comentariu

@gr1ph0n: oricate operatiii ai face intre intreruperi, ele vor veni intotdeauna la 10 ms (asta daca nu dezactivezi intreruperile pe parcurs pentru timp indelungat).Dupa cum scrie in documentatie, in cazul in care primeste o intrerupere, PIC-ul salveaza adresa curenta pe stiva si "sare" la adresa 0x04. Si atat. E treaba ta sa nu lungesti preat tare rutina de tratare a intreruperilor (in Midrange User Manual scrie ca intreruperile sunt dezactivate automat):

When an interrupt is responded to, the GIE bit is cleared to disable any further interrupt, thereturn address is pushed into the stack and the PC is loaded with 0004h.

Ai dreptate!Imi cer scuze, am facut o confuzie crasa intre intreruperile ASM care sunt intreruperi reale si comanda PBP ON INTERRUPT care este o pseudo intrerupere si care asteapta executarea comenzii si apoi are loc gestionarea intreruperii.
Link spre comentariu

nu cred sa fie softul, si eu ma pregatesc sa fac acel ceas. Ai umblat la cele doua variabile de calibrare ? Ai setat XT la oscilator?

da am setat oscilator extern,termometrul merge bine
Link spre comentariu

Un cod complet, eventual comentat, ar opri scrierea atator posturi si ar rezolva problema.

Ai dreptate, asa ar fi cel mai bine.Din pacate, n-am senzori, n-am LCD disponibil, n-am... Incercam sa ajut pe cineva care "are tot" sa optimizeze putin codul.Cum nu sunt sigur ca in varianta mea ar merge mai bine decat variantele voastre, as fi vrut sa pot sa si testez ce incerc.Nu de alta, da' eu incercam sa ma prind de ce nu reusiti sa-i dati de cap si incercam sa va ajut cu ceva idei, Cum nu sunt Number 1 in nimic, sunt sanse mari ca ce zic eu sa fie batut de campi; in cazul asta, mi-ar prinde bine daca cineva mi-ar arata ce gresesc. Asa, pentru cultura mea generala (si evitarea unor eventuale batai de cap pe viitor).Pen'ca nu am nici o contributie utila pe topicul asta, imi cer scuze pentru "poluare" si ma duc pe topicuri la care ma pricep mai bine (adica nicaieri :rade: ).
Link spre comentariu

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 cont

Autentificare

Ai deja un cont? Autentifică-te aici.

Autentifică-te acum



×
×
  • Creează nouă...

Informații Importante

Am plasat cookie-uri pe dispozitivul tău pentru a îmbunătății navigarea pe acest site. Poți modifica setările cookie, altfel considerăm că ești de acord să continui.Termeni de Utilizare si Ghidări