Beste CO-ers
Ik ben bezig om een menu te maken in picbasic met een rotary encoder.
Dit moet zo gaan : als alles uit is , 1 x kort drukken menu 1 (wat ik dan kan regelen door te draaien ) nog een keer kort drukken menu 2 ( ook dit regelen dmv draaien).
Als er dan weer gedrukt word keert het menu terug naar 1.
Maar als ik 1 keer lang druk bv 3 sec dan moet de pic in SLEEP gaan, om door 1 x drukken weer te ontwaken.
Een losse rotary encoder of een menu met drukknoppen snap ik nog wel,maar mij lijkt dat ik nu 2 interrupts nodig zou hebben om dit te laten werken.
Welke struktuur moet ik in dit programma aanhouden?.
Is er iemand die mij op weg wil helpen?
elmowww
PA0EJE - www.eje-electronics.nl - e.jongerius[aapje]eje-electronics.nl - EJE Electronics - Elektronica/firmware ontwikkeling
Ik neem aan dat je de events allemaal binnen kan krijgen op interrupts?
Het hangt er een beetje van af hoe je je firmware op wilt bouwen, er zijn meerdere opties.
Het draaien aan de encoder kan je hardwarematig binnensturen als het om hoge snelheden gaat (incrementele encoder), maar is firmwarematig ook erg goed te doen. Het indrukken is al wat lastiger omdat je hier moet gaan timen hoe lang het duurt voordat er losgelaten wordt. Gebruik hier bijvoorkeur een (reeds bestaande) timer interrupt ofzo voor.
Hier een stukje voorbeeldcode:
(Lang leve state machines)
symbol ROTARY_IDLE = 0
symbol ROTARY_INC = 1
symbol ROTARY_DEC = 2
symbol SWITCH_IDLE = 0
symbol SWITCH_TOUCH = 1
symbol SWITCH_RELEASE = 2
dim CurrentMenu as byte ;Geeft aan in welk menu je nu zit
dim MenuChoices[3] as byte ;Geeft de keuze die gemaakt is aan per menu
dim RotaryState as byte
dim SwitchState as word ;Kan ook gevat worden binnen rotary state machine, maar dan is draaien en indrukken tegelijk niet mogelijk
dim SwitchTimer as byte
dim RotaryA_prev as bit
dim RotaryB_prev as bit
Interrupt_Handler:
if TMRxIF = 1 then
TMRxIF = 0
TMRx = (vul hier preset waarde in voor de benodigde periode), bijv iedere 10msec
if SwitchState = SWITCH_TOUCH then
if SwitchTimer < 1000 then
inc SwitchTimer
endif
endif
endif
if RBIF = 1 then
RBIF = 0
If inputSwitch = 1 Then
SwitchState = SWITCH_TOUCH
elseif switchState = SWITCH_TOUCH
SwitchState = SWITCH_RELEASE
endif
if inputRotaryA <> RotaryA_prev or inputRotaryB <> RotaryB_prev then
; Niet meer zoals de vorige interrupt, dus verdraaid
if inputRotaryA <> inputRotaryB Then 'CW
RotaryState = ROTARY_INC
ElseIf inputRotaryA = inputRotaryB Then 'CCW
RotaryState = ROTARY_DEC
EndIf
RotaryA_prev = inputRotaryA
RotaryB_prev = inputRotaryB
endif
Endif
Context Restore
Init:
CurrentMenu = 0
Main:
if SwitchStae = SWITCH_RELEASE or RotaryState <> ROTARY_IDLE or MenuInitialised = 0 then
Select CurrentMenu
Case 0
gosub Menu_Voorgerecht
Case 1
gosub Menu_Hoofdgerecht
Case 2
gosub Menu_Nagerecht
Case 3
gosub Power_Down
Case Else
; Onmogelijke fout
goto Init
Endselect
endif
goto main
Menu_Voorgerecht:
if SwitchState = SWITCH_RELEASE then
SwitchSate = SWITCH_IDLE
if SwitchTimer < 300
CurrentMenu = Menu_Hoofdgerecht
MenuInitialised = 0
else
CurrentMenu = Power_Down
MenuInitialised = 0
endif
endif
if RotaryState = ROTARY_INC then
RotaryState = ROTARY_IDLE
if MenuChoices[0] < MAXITEMS - 1 then
inc MenuChoices[0]
else
MenuChoices[0] = 0
endif
elseif RotaryState = ROTARY_DEC then
RotaryState = ROTARY_IDLE
if MenuChoices[0] > 0 then
dec MenuChoices[0]
else
MenuChoices[0] = MAXITEMS - 1
endif
elseif
if CurrentMenu = 0
Select MenuChoices[0]
case 0
Print "Soep"
case 1
Print "Stokbrood"
case 2
.....
endselect
MenuInitialised = 1
endif
return
elmowww
PA0EJE - www.eje-electronics.nl - e.jongerius[aapje]eje-electronics.nl - EJE Electronics - Elektronica/firmware ontwikkeling
Ik weet niet welke PIC je nu gebruikt, maar je hebt ook vaak nog de PORTB Change interrupt (extern), deze reageerd als een van de laagste 4 pinnetjes van poort B van waarde veranderen. Hierop is deze code geschreven, samen met een timer interrupt om de tijd van indrukken vast te leggen.
Ik gebruik een 16f628a
Klopt het dan dat ik INTE ( poortb.0) gebruiken voor de rotary encoder ( draaien ), en RBIE ( 1 van de poorten b.4 tot b.7 ) voor het drukken
elmowww
PA0EJE - www.eje-electronics.nl - e.jongerius[aapje]eje-electronics.nl - EJE Electronics - Elektronica/firmware ontwikkeling
elmowww
PA0EJE - www.eje-electronics.nl - e.jongerius[aapje]eje-electronics.nl - EJE Electronics - Elektronica/firmware ontwikkeling
symbol inputRotaryA = portb.4
symbol inputRotaryB = portb.5
symbol inputSwitch = portb.6
Bijvoorbeeld.
OK dit snap ik maar om deze poorten te koppelen aan een interrupt snap ik niet .
dus als ik druk op de rotary dat het programma onderbroken word en het interrupt uitvoert .
INTE is altijd externe interrupt portB.0
Op 17 oktober 2009 12:57:30 schreef 19roland70:
OK dit snap ik maar om deze poorten te koppelen aan een interrupt snap ik niet .
Dat is net uitgelegd:
Op 15 oktober 2009 09:54:45 schreef elmowww:
Ik weet niet welke PIC je nu gebruikt, maar je hebt ook vaak nog de PORTB Change interrupt (extern), deze reageerd als een van de laagste 4 pinnetjes van poort B van waarde veranderen. Hierop is deze code geschreven, samen met een timer interrupt om de tijd van indrukken vast te leggen.
En de 16F628A heeft die optie ook:
14.5.3 PortB Interrupt in de datasheet, pagina 108.
SYMBOL RBIF = INTCON.0
SYMBOL RBIE = INTCON.3
SYMBOL GIE = INTCON.7 '
SYMBOL inputRotaryA = PORTB.4
SYMBOL inputRotaryB = PORTB.5
SYMBOL inputSwitch = PORTB.6
Dus als erop portb.4 tot 6 een signaal komt wordt er uit het hoofdprogramma gesprongen en de desbetreffende interrupt eerst afgehandeld.
Waarom word er dan niet in het hoofdprogramma gewerkt met:
hoofdprogramma:
IF inputRotaryA THEN ......
IF inputRotaryB THEN ......
IF inputSwitch THEN ......
GOTO hoofdprogramma
elmowww
PA0EJE - www.eje-electronics.nl - e.jongerius[aapje]eje-electronics.nl - EJE Electronics - Elektronica/firmware ontwikkeling
Dan ga je op een niveau triggeren en niet op een flank.
Daarnaast ben je dan een onoverzichtelijke code aan het maken. Heb je al geprobeerd het werkend te krijgen?
Laat in een interruptroutine een teller lopen, dan heb je onderscheid tussen "kort en lang". Maak niet de fout door in de interrupt routine te blijven "pollen".
Zo'n menu los ik zelf meestal op dmv een "State machine".
http://www.rn-wissen.de/index.php/Bascom_State_Machine_Menu
Groeten, Bram
Ben er al ongeveer 8 uur mee bezig geweest maar ik snap de struktuur eigenlijk niet.
Wanneer gebeurt wat.
Moet er wel bijzeggen dat ik nog nooit met interrups heb gewerkt
elmowww
PA0EJE - www.eje-electronics.nl - e.jongerius[aapje]eje-electronics.nl - EJE Electronics - Elektronica/firmware ontwikkeling
Lees de helpfile over interrupts.
Een interrupt is eigenlijk een "gebeurtenis" waarbij de code alles in de steek laat, en eerst die gebeurtenis afhandeld.
Belangrijke bitjes:
GIE
PEIE
RBIE
RBIF
Wat het stukje programma doet:
Interrupt handler:
- Dit stuk geeft enkel aan wat de user input is. Knopje ingedrukt/losgelaten, menutje verder of niet en zet dit in een variabele. Hij geeft eigenlijk "opdrachten" aan het mainprogramma.
SwitchState = SWITCH_RELEASE
Laat eigenlijk zien dat het knopje net is losgelaten.
Nadat de interrupt handler klaar is (context restore geven), springt het programma weer terug waar hij was.
Het main programma is eigenlijk enkel bezig om de hele tijd deze commando`s af te handelen.
Voordeel van deze structuur is dat ie non-blocking en universeel is:
De afhandeling van de user interface is losgekoppeld van de menu`s, dus hoeft dit er niet steeds meer extra bijgezet. Non-blocking geeft aan dat je gewoon andere dingen kan blijven doen terwijl de code zelf bijvoorbeeld druk aan tellen is hoe lang een knop ingedrukt wordt.
En je hoeft geen code toe te voegen die iedere keer gecheckt moet worden: doit gebeurt automatisch als er een event is.
Nadeel is dat je code een sutk onoverzichtelijker kan zijn als je zelf het inzicht hebt.
Begin eerst een simpel met enkel de rotary encoder interrupt.
Waar loop je precies vast? Wat werkt wel en wat niet?
Het timer gedeelte in de interrupt handler boven aan is mij onduidelijk even als de variabele MenuInitialised .
Verder heb ik het intcon. register zo gemaakt :
SYMBOL RBIF = INTCON.0
SYMBOL RBIE = INTCON.3
SYMBOL T0IE = INTCON.5
SYMBOL T0IF = INTCON.2
SYMBOL GIE = INTCON.7
elmowww
PA0EJE - www.eje-electronics.nl - e.jongerius[aapje]eje-electronics.nl - EJE Electronics - Elektronica/firmware ontwikkeling
Vergeet eventjes de timer interrupt, deze is enkel nodig voor het tellen van de tijd van indrukken. Dit is later toe te voegen in deze structuur.
MenuInitialised is een vlaggetje wat enkel aangeeft of het menu up to date is. Is de status veranderd, moet het menu opnieuw getekend worden op je scherm, dan gebeurd dat en zet ie het bitje weer op 0.
Probeer die interrupts eens werkend te krijgen, zoek er eens naar.
Ik snap niet hoe het programma weet wanneer er een interrupt is .
On_interrupt ......Dit staat bovenaan als de interrupt op RB0 External INTERRUPT moet reageren .
bij interrupt on change hoeft er dan niks te staan?
[Bericht gewijzigd door 19roland70 op (75%)]
On_interrupt of de andere versie gebruik je als je van interrupts gebruik maakt, zie de manual.
Je moet aan de hand van de interruptbitjes vervolgens uitvissen wat de interrupt veroorzaakt.
is het slim om dit in een interrupt te zetten
IF inputSwitch = 1 AND MenuPunt = 0 THEN
MenuPunt = 1
IF inputSwitch = 1 AND MenuPunt = 1 THEN
MenuPunt = 0
ENDIF
ENDIF of kan ik dit het best in het hoofd programma zetten onder while 1 = 1 ?
WHILE 1 = 1
IF inputSwitch = 1 THEN
SELECT CASE MenuPunt
CASE 0 : GOSUB Pwmled1
CASE 1 : GOSUB Pwmled2
ENDSELECT
ENDIF
WEND
Ferry
Ferry.......
ALTIJD !!! je interrupts zo kort mogelijk houden.
m.a.w. als het in je hoofdprogramma kan, dan zeker niet in je interrupt.
suc6
elmowww
PA0EJE - www.eje-electronics.nl - e.jongerius[aapje]eje-electronics.nl - EJE Electronics - Elektronica/firmware ontwikkeling
@ Elmowww ik heb nu het programma helemaal uitgekleed en ben aan het kijken wat er gebeurd als ik er iets aan toevoeg.
Het principe van zo'n state machine snap ik niet helemaal , ik weet op een gegeven moment niet meer waar ik me in het programma bevind.
elmowww
PA0EJE - www.eje-electronics.nl - e.jongerius[aapje]eje-electronics.nl - EJE Electronics - Elektronica/firmware ontwikkeling
Dat is wel redelijk belangrijk hierin.
Het hart daarvan is de select .. case. Laat het maar weten als je er echt niet uitkomt.
?