Right now you're pausing every Second and redisplaying whilst clearing the screen every time. This has a number of drawbacks... (1) it will cause your LCD to 'flicker' every time you display... (a more professional way is to clear the display only every 'n' seconds)... (2) the 1 second delay can cause an unacceptible 'lag' when somebody presses Buttons (to enter the Setup routine for example)... and (3) can cause a strange effect when you're watching seconds ticking by, as every now and again you get the feeling a Second is longer than it should be, because you're adding one 'software' second (plus propogation delay in your software program) to your RTC second and they can get out of step...
Fisrt we've added some more variables...
KeyBut var BYTE
TimeOut var BYTE
UserField var BYTE
UserMax var BYTE
UserMin var BYTE
UserPos var BYTE
and we've increased your DOW array...
DOW var BYTE [5]
and introduced a constant...
TimeoutConstant con 200
... more about these later.
My Buttons are connected on PortB and I'm using pull-ups (pin goes Low on Button Press). At the start of my proram I have the following defines...
ButtonUp var PortB.0
ButtonDown var PortB.1
ButtonSet var PortB.2
and I've also put...
OPTION_REG.7=0
...at the start where I first initialse my PIC. Change these around, (along with my Getkey routine - later) to suit your own arrangement.
Now we rehash the Main Program Loop like so...
Now you'll only get a flicker once every 20 Seconds, and with our GetKey subroutine we have a worst case lag of 100mS. We've also created a neat way of dropping into our SetUp at that point.Code:TimeOut=TimeoutConstant Loop: ' ' Read iButton ' ------------ owout iButton,1,[$cc,$f0,$03,$02] owin iButton,0,[ByteD,ByteC,ByteB,ByteA] ' ' Display Date & Time ' ------------------- Gosub CalculateLinearDAYS GOSUB CalculateDateFromLinear If TimeOut = > TimeoutConstant then LCDOut $FE,1 TimeOut=0 endif LCDOut $FE,$80, STR DOW\3,". ", dec2 Day,".",dec2 month,".","20",dec2 year LCDOut $FE,$C4,DEC2 HOURS,":",DEC2 MINUTES,":",DEC2 SECONDS ' Note the $FE,$C4 above... saves you a few bytes... TimeOut=TimeOut+1 Gosub GetKey If KeyBut < > 3 then goto Loop ' ' Setup Date & Time ' ----------------- DOW(0)=YEAR DOW(1)=MONTH DOW(2)=DAY DOW(3)=HOURS DOW(4)=MINUTES Gosub EditDateTime If TimeOut=0 then ' Only Save if SET Button Pressed YEAR=DOW(0) ' ie not TimeOut MONTH=DOW(1) DAY=DOW(2) HOURS=DOW(3) MINUTES=DOW(4) SECONDS=0 Gosub CalculateLinearFromDate Gosub CalculateLinearSeconds ByteA=TempA.HighByte ByteB=TempA.LowByte ByteC=TempB.HighByte ByteD=TempB.LowByte ' ' Set your iButton here ' endif TimeOut=TimeoutConstant ' This causes a Clear Screen in our main Loop Goto Loop
You'll also see I'm using two new variables KeyBut and TimeOut, both of which are BYTES. Keybut returns a value from 0-7 (per the GetKey routine table below) depending on what Button or combination of Buttons are pressed. TimeOut is an incremental 100mS counter. It is reset to zero should any key be pressed... more about this later... Finally I use a Keyboard Loop-Time of 100mS. I have found that less than that and Button autorepeat is too fast to handle easily. More than that, and autorepeat feels sluggish, and you get bored holding the Button. Change this value to suit your personal preference - but in doing so you may also need to change the TimeoutConstant value.
Now for the EditDateTime Routine... you'll notice I've increased the size of your DOW array to 5 elements as I'm going to use that as my editing array since there are 5 things I need to edit... YEAR, MONTH, DAY, HOUR and MINUTE and I really need a byte for each... and since DOW is unused during SetUp, this seems a good use of otherwise unused resources to me.Code:' ' Subroutine Scans Buttons ' ------------------------ ' KeyBut - 0 = Invalid (SET+UP+DOWN Pressed) ' - 1 = Invalid (SET+UP Pressed) ' - 2 = Invalid (SET+DOWN Pressed) ' - 3 = SET Pressed ' - 4 = Invalid (UP+DOWN Pressed) ' - 5 = UP Pressed ' - 6 = DOWN Pressed ' - 7 = No Buttons Pressed GetKey: KeyBut=0 ' Zero any previous Result First KeyBut.0=ButtonDown ' Read Input Buttons KeyBut.1=ButtonUp KeyBut.2=ButtonSet If KeyBut < > 7 then TimeOut=0 ' Resets Timeout Counter Pause 100 ' Allows for 10cps auto-repeat Return
I've put the EditDateTime into a subroutine, because you may want to use the same routine for entering and setting the iButton alarms later as your program gets more sophisticated.
This Date & Time subroutine is BULLET-PROOF. There's nothing worse than attempting to enter the 31st of April, or 29th of February in a non-leap year. Makes your code look amateurish and quickly causes loss or credibility with clients. Try entering an invalid Date or Time setting - I think you'll find you can't break it.
The subroutine also assumes DOW is preloaded with a valid date and Time on entry (even if it's just a simple 1/1/2000 00:00), usually you would read the RTC and if it's got a sensible Time & Date you would preload the figures with that... (when setting an Alarm for example, you would want the previous setting to be displayed so you can edit it).
Look-out for the bonus features... (a) if you don't press any Buttons for 20 seconds, then you will be returned to the main Loop without any new settings being saved (that's where that TimeOut variable comes in)... and (b) of course you've got that 10Hz autorepeat on the Buttons (except SET).
Note also the creative use of Curson ON and Cursor OFF, so that the user is guided to take their finger OFF the SET Button and progress to editing...Code:' ' Subroutine for Date and Time Entry ' ---------------------------------- EditDateTime: LCDOut $FE,1,"Set Date & Time" LCDOut $FE,$C0,"20",DEC2 YEAR,"/",DEC2 MONTH,"/",DEC2 DAY LCDOut $FE,$CB,DEC2 HOURS,":",DEC2 MINUTES UserField=0 EditDateTimeLoop: UserMin=0:UserMax=99:UserPos=$C2 If UserField=1 then UserMin=1:UserMax=12:UserPos=$C5 endif If UserField=2 then UserMin=1:UserMax=31:UserPos=$C8 If DOW(1)=2 then CounterA=DOW(0)//4 If CounterA=0 then UserMax=29 else UserMax=28 endif endif If DOW(1)=4 then UserMax=30 If DOW(1)=6 then UserMax=30 If DOW(1)=9 then UserMax=30 If DOW(1)=11 then UserMax=30 endif If UserField=3 then UserMax=23:UserPos=$CB endif If UserField=4 then UserMax=59:UserPos=$CE endif Gosub GetKey If KeyBut=3 then goto EditDateTimeLoop EditDateTimeFieldLoop: LCDOut $FE,UserPos,DEC2 DOW(UserField),$FE,$0E,$FE,UserPos+1 EditDateTimeIdleLoop: Gosub GetKey If KeyBut=5 then DOW(UserField)=DOW(UserField)+1 If DOW(UserField)>UserMax then DOW(UserField)=UserMin Goto EditDateTimeFieldLoop endif If KeyBut=6 then If DOW(UserField) > UserMin then DOW(UserField)=DOW(UserField)-1 else DOW(UserField)=UserMax endif Goto EditDateTimeFieldLoop endif If KeyBut < > 3 then TimeOut=TimeOut+1 If TimeOut < TimeoutConstant then goto EditDateTimeIdleLoop Goto EditDateTimeExit endif LCDOut $FE,$0C UserField=UserField+1 If UserField < 5 then goto EditDateTimeLoop EditDateTimeExit: LCDOut $FE,$0C,$FE,$01 While KeyBut < > 7 Gosub GetKey Wend Return
Have fun
Melanie




Bookmarks