Pic_beginner
Met wederzijds respect kom je heel ver
Beste,
Ik heb een programma op mijn pic staan die via een druk knopje 3 uithangen bedient.
Maar nu wil ik dus een tellertje starten van ca 2 min en wanneer deze gedaan heeft moet een uithang hoog worden of alser binnen 2 min op een knop geduwt wordt moet de teller stoppen.
Maar dit moet werken naast mijn hoofd programma.
Is dit mogelijk ?
Dit is mijn programma nu :
Device 12F629
Config INTRC_OSC_NOCLKOUT,_ ;INTerne RC OSCillator van de PIC gebruiken
WDT_OFF,_ ;Watch Dog Timer uitgeschakeld
PWRTE_ON,_ ;PoWeR up Timer Enable ingeschakeld
BODEN_OFF,_ ;Brown Out Detection ENable uitgeschakeld (minder stroomopname)
MCLRE_OFF ;Master CLeaR Enable uitgeschakeld (resetpin GPIO.3 op OFF)
ALL_DIGITAL TRUE ;Alle ingangen digitaal (voor de toetsen)
Symbol Tijd = 500
Symbol Rood = GPIO.2
Symbol Groen = GPIO.1
Symbol Blauw = GPIO.0
Symbol Knop = GPIO.3
Symbol Aan = 1
Symbol Uit = 0
Symbol Druk = 0
Dim Keuze As Byte
; 76543210
GPIO = %00001000 ;Alle uitgangen bij opstart een laag niveau
TRISIO = %11111000 ;GPIO.1 is uitgang voor LED
Cls
Clear
Keuze = 0
While 1 = 1
If Knop = Druk Then
Inc Keuze
DelayMS 25
While Knop = Druk : Wend
DelayMS 25
EndIf
If Keuze = 0 Then
Rood = 0
Groen = 0
Blauw = 0
ElseIf Keuze = 1 Then
Rood = 1
Groen = 0
Blauw = 0
ElseIf Keuze = 2 Then
Rood = 0
Groen = 1
Blauw = 0
ElseIf Keuze = 3 Then
Rood = 0
Groen = 0
Blauw = 1
ElseIf Keuze = 4 Then
Rood = 1
Groen = 1
Blauw = 0
ElseIf Keuze = 5 Then
Rood = 1
Groen = 0
Blauw = 1
ElseIf Keuze = 6 Then
Rood = 0
Groen = 1
Blauw = 1
ElseIf Keuze = 7 Then
Rood = 1
Groen = 1
Blauw = 1
Else
Keuze = 0
EndIf
Wend
End
Pic_beginner
Met wederzijds respect kom je heel ver
Neen het moet volledig los van dit programma zijn.
Dus ik steek spanning op de pic en ik gebruikt dit programma zoals het er nu staat.
Maar intussen begint er een tijd te lopen van 2min.
Als er voor die 2min niet op een knop (GPIO.4) geduwt wordt moet er uitgang (PGIO.5) hoog worden.
Maar intussen moet het ander programma wel blijven werken.
Je zou met een interrupt kunnen werken op basis van een timer.
In de interrupt hou je dan een tellertje bij... en als je dan twee minuten hebt geteld, zet je de betreffende uitgang.
En als er op de knop (aan GPIO4) wordt gedrukt, reset je het tellertje.
Ik ben zelf ook bezig (sinds een paar weken) met Pics...
Alleen programmeer ik zelf in assembler. Ik heb wel al wat dingen gemaakt met een timer en interrupt op een 12f629.
Dus ik wil wel eens kijken (met de datasheet erbij) of het op die manier kan.
Overigens... hoe nauwkeurig moet die tijd van twee minuten zijn?
Pic_beginner
Met wederzijds respect kom je heel ver
flipflop
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein
Je kunt je main-loop opsplitsen in meerdere taken. Elke taak zet je in een subroutine. De ene taak kijkt of er een toets gedrukt is (en zet een paar variabelen), de andere stuurt LEDs aan (afhankelijk van variabelen), nog een stuurt een display aan, en de laatste test een real-time timer (en set weer een variabele).
Zou hou je elke taak mooi gescheiden en overzichtelijk. Eigenlijk een simpel Operating System.
init_all();
while (1) {
keys();
leds();
display()
timer();
whatevermoreneeded();
}Zo kan het natuurlijk ook... alleen kan het wel tijdkritisch worden.
Mijn idee was daarom om de timer in een interrupt bij te houden.
Maar als Pic-BASIC al een ingebouwde timer-functie heeft, dan kun je gewoon daar gebruik van maken.
In de tussentijd zal ik nog eens in de datasheet bladeren.
Pic_beginner
Met wederzijds respect kom je heel ver
Ik heb zelf wat zitten spelen met een interrupt op timer0. De onderstaande code laat zien hoe je het dan zou kunnen realiseren in een interrupt.
Ik ben nog niet zo ervaren in het programmeren van Pics dus misschien dat er iets raars inzit. Hier werkt het in elk geval als ik het in een interrupt routine zet.
btfss GPIO,4 ; schakelaar ingedrukt?
goto reset_teller
verhoog_teller:
incfsz teller_lsb ; verhoog lsb teller
goto finished ; geen nuldoorgang lsb
incf teller_msb ; verhoog msb bij nuldoorgang lsb
test_msb:
movlw 0x06 ; maximumwaarde (circa 100s)
subwf teller_msb,w ; vergelijk met msb
btfsc STATUS,Z ; maximumwaarde bereikt?
bsf GPIO,5 ; maak dan uitgang 5 hoog
goto finished
reset_teller:
bcf GPIO,5 ; maak uitgang 5 laag
clrf teller_lsb ; reset teller
clrf teller_msb ; reset teller
finished:
Ik heb hier zelf een interrupt ingesteld op timer0 met een prescaler van 256. De Pic draait op een 4Mhz interne clock, dus één instructie duurt 1µs.
In de interrupt houd ik een 2-byte teller bij. De meest significante byte verspringt dan elke 256*256*256 µs (= ongeveer 16,8s).
Als de meest significante byte de waarde '6' krijgt (na circa 100s), dan maak ik GPIO5 hoog. De teller blijft tot in de eeuwigheid doortellen, maar dit kan geen kwaad.
Als de schakelaar op GPIO4 wordt ingedrukt zet ik de 2-byte teller op nul en maak ik GPIO5 weer laag. Hiermee wordt dus een nieuwe timercyclus gestart.
Om dit werkend te krijgen moet de bovenstaande code binnen je BASIC-programma opgenomen worden in een interrupt routine. Verder moet de interrupt aangezet worden in je programma.
De schakelaar op GPIO4 heb ik overigens niet expliciet voorzien van een debounce... maar door de vertragingstijd van 100 seconden lijkt me dit geen probleem.
loopycoaster
Mijn youtube profiel: http://www.youtube.com/user/PicBasicMaster
Het kan ook gewoon zonder interrupt:
Dim Keuze As Byte
Dim Teller AS WORD ;een byte kan maar tot 255
; 76543210
GPIO = %00001000 ;Alle uitgangen bij opstart een laag niveau
TRISIO = %11011000 ;GPIO.5 ook een uitgang maken
Cls
Clear
While 1 = 1
delayms 10 ;anders gaat de teller veel te snel, maar door maar 10 Ms mis je geen knopdruk.
inc Teller ;teller verhogen
If Teller > 12000 then ;12000 * 10 ms = 120.000 ms = 120 sec. = 2 min.
GPIO.5 = 1
;ik weet niet precies hoe je hem wilt laten aflopen...
Endif
If Knop = Druk Then
Teller = 0 ;Nu reset die, maar hij stopt nu niet.
Inc Keuze
DelayMS 25
While Knop = Druk : Wend
DelayMS 25
EndIf
flipflop
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein
Op 3 september 2010 22:28:24 schreef Pic_beginner:
Sorry hoor maar ik snap het niet zo goed flipflop :s kan je mss tonen adhv een voorbeeld ?
Het stukje "pseudo-code" was eigenlijk het voorbeeld
Waar het om gaat is dat de microcontroller (uC) heel veel instructies per seconde kan doen. Dat scannen van de toetsen en het schrijven van de LEDs kost maar heeeeeeeel erg weinig tijd. Ondertussen kun je nog veel andere dingen doen. Echter, dat wordt al snel onoverzichtelijk. Als je dat nou in aparte subroutines zet, hou je het leesbaar. Dus.... scannen van toesen in een sub, en het schrijven van de LEDs in een andere.
Nu wil je een timer functie gaan toevoegen. Dat kan het beste mbv een hardware timer uit je uC zoals andere posten. Nou kun je dat op vele manieren gebruiken, maar een is zoiets: Stel je wilt meten of een toets als 2 sec is ingedrukt. In je timer sub test je de status van de toet-variabele (die je in de key sub telkens update). Als een toets actief wordt, sla je de huidige timer waarde op. Daarna kijk je steeds of de toets nog steeds actief is EN of de timer waarde als met 2*60 seconden is opgehoogd. Dan doe je iets (bv het updaten van een status variabele die je weer ergens anders gebruikt).
Die timer waarde kun je dus heel mooi in een interrupt routine steeds ophogen als je hardware timer afloopt, bv elke ms of zo. Voorbeeldcode voor timers is genoeg te vinden, maar lezen van de datasheet is belangrijker.
@Franski hieronder: ja tuurlijk. Kan op tig manieren. Misschien is jouw oplossing wel beter. Het is maar zelden dat een implementatie de beste is. Daarom is er zoveel discussie op het forum.
Nogmaals... er zijn meerdere wegen die naar Rome leiden.
Mijn oplossing was vooral bedoeld om te laten zien dat het kan met met een interrupt.
Maar als je vanuit BASIC een timer kunt gebruiken dan lijkt me dat handiger. Ik kan je alleen niet vertellen hoe... daarvoor heb ik te weinig zicht op de mogelijkheden van BASIC op de Pic.
