Continue to Site

# Baseline PIC TMR0 Question

#### throbscottle

##### Well-Known Member
I've managed to get press or double-press detection of a switch using TMR0. What happens is, the timer is tested periodically during the main loop. When a switch is pressed once, it sets a countdown, which is changed every time the timer overflows a set value. If the switch is pressed again within that time, it counts as a double press. If the counter reaches zero, it counts as another single press.

This is where it gets interesting. When I look at tutorials such as Gooligum, the timer is always tested for a specific value using XOR. This can't work in my case, because the amount of instruction cycles in-between tests can be different depending on which switch was pressed, so the timer can be at various values when it hits the overflow. I've used subtraction instead - if the timer gets over 200 the counter increments.

So the solution works, but the timer can't be accurate. What's a better way?

Code:
; test and read inputs up to here
; tactile press timer
movlw 0xC8 ; test the timer for double press events
subwf TMR0,W ; carry will be clear if under 200
btfss STATUS,C ; carry will be set if it's over 200
goto CLR_C ; next stage
movf tact_counter,f ; counter is set when single press occurs
btfss STATUS,Z ; don't decrement the counter past zero
decfsz tact_counter,f ; double press timer
goto CLR_C
bcf pre_fl ; flag that is set when single press occurs
CLR_C
; loop back

#### Pommie

##### Well-Known Member
You're using only the low byte of timer 0 and testing if under 200, is that correct? I don't know which chip you're using but on most pics timer 0 is 16 bit and free running.

I can't understand your code from the snippet you posted. I'm guessing you're trying to detect single and double presses but don't see how.

Mike.
Edit, see in the title you state baseline which suggest a 16 bit timer 0 with no period register. Correct?

#### rjenkinsgb

##### Well-Known Member
which is changed every time the timer overflows a set value

Are you clearing the timer at some point? If not, the value will be random on the first comparison?

If it's free running, you could store the present counter value at the end of each comparison, and subtract that from the new timer value at the start of each test & comparison.

#### sagor1

##### Active Member
Most PIC processors have TMR0 as a 8 bit timer. So, the TS has to give a bit more information as to what processor this is for, and a bit more code showing...

#### Nigel Goodwin

##### Super Moderator
Most PIC processors have TMR0 as a 8 bit timer. So, the TS has to give a bit more information as to what processor this is for, and a bit more code showing...
I wouldn't say 'most', but old PIC devices are only 8 bit TMR0, 'modern' devices are usually 8/16 bit TMR0 - with the 8 bit mode for compatibility.

On a fairly random selection of devices I use, only one was 8 bit (from 2011) the other four were 8/16 bit (from 2015-2017).

#### Pommie

##### Well-Known Member
My apologies, been away from pics too long. Timer 0 is indeed 8 bit.

I think we need more code.

Mike.

#### throbscottle

##### Well-Known Member
It's ancient! 16F57. So it's an 8 bit timer with nothing extra. It just rolls over at 255 and that's all it does.

The snippet I posted is the only part that's really relevant to the timer, the single/double click detection relies on the flag bit, pre_fl, being set or unset. First click sets it, then either it gets unset by the timer finishing, or by a double-click being detected.

rjenkins - do you mean save the present timer value? I might try that.

I started off clearing the timer, not realising it runs all the time anyway. When I found that out, I removed the clrf tmr0 line because there didn't seem to be any point as the code just falls through to test the next button, so the number of lines executed can be different.

Using the timer is still something of a Dark Art to me so I don't really know what I'm doing here. The upside is that it's only timing button presses so accuracy doesn't matter. But what if it did matter?

Anyway, the part that does the actual click detection is here (from PRES_1) (when I'm happy with it I'll copy it down to PRES_2 and PRES_3)
(I know I can make the PRES_x code more efficient - but I've only just got it to work at all)

Code:
BUTTONS ; scans keypad, rotary encoder, runs subs as necessary according to inputs
...
TACTILES ; detects keypresses in variable scanned from PT6315 VFD driver, which also has switch inputs.
... ; set up PT6315
; tactile press timer
movlw 0xC8 ; test the timer for double press events
subwf TMR0,W ; carry will be clear if under 200
btfss STATUS,C ; carry will be set if it's over 200
goto CLR_C ; next stage
movf tact_counter,f ; counter is set when single press occurs
btfss STATUS,Z ; don't decrement the counter past zero
decfsz tact_counter,f ; double press timer
goto CLR_C
bcf pre_fl ; flag that is set when single press occurs gets cleared if counter reaches zero
CLR_C
bcf STATUS,C
TACTILE_LOOP
PRES_1
btfss tactiles+1,3 ; first preset
goto PRES_2
btfsc pre_fl ; has a button already been pressed?
goto DOUBLE_1 ; do double press actions - assume it's the same button
banksel preset_1 ; presets are in MATHS2 bank
movlw preset_1 ; get address of variable, copy to BCD
pscall PRESET_COPY ; sub does return banksel and sets timer-runs count
bsf pre_fl ; set the flag, do double-press test next time
;    clrf TMR0 ; not using this now, demo only
goto END_PRESETS ; exit the sub
DOUBLE_1
movf tact_counter,f
btfsc STATUS,Z
goto END_PRESETS ; timer has finished, this is another single press
SAVE_1
call GO_REVERT_BCD ; get BCD back from copy
pagesel$banksel preset_1 movlw preset_1 goto SAVE_PRESETS PRES_2 ; detect bit 4 PRES_3 ; detect bit 5 SAVE_PRESETS pscall PRESET_SAVE ; save BCD to the preset bcf pre_fl END_PRESETS call GO_DISPLAY ; show the preset ; pscall ENTER ; write the new frequency to AD9850 ; WANT MANUAL ENTER? goto BUTTONS ; finished with timers, go back. No double-press occurred #### Nigel Goodwin ##### Super Moderator Most Helpful Member My apologies, been away from pics too long. Timer 0 is indeed 8 bit. Only on really old devices #### throbscottle ##### Well-Known Member To really beat the oldnest stakes, it will eventually end up on a 16C57 since I bought 2 by mistake when I was (more) clueless. #### rjenkinsgb ##### Well-Known Member Most Helpful Member OK, with the restricted hardware available, the way I'd do it is have a byte variable as a timer for each button. When a button is pressed, first check the value in that variable. If it's zero, it is a first or single press. Then store a value, eg. 100 and set a bit variable to show the time countdown was started. If it's not zero, there was a previous press, so clear the value and set your double-press flag. In your main loop, check for any set bit variables and see if the respective timer has reached zero for any button. If it has, that was a single press. Set your double press flag and reset the bit variable for that button. Set up an interrupt on timer overflow, and in the interrupt routine check each button variable value & decrement any that are not zero. That will give a consistent "count down" time in the button variables. If the counter interrupt is too fast to get a reasonable time value, use an extra byte variable as a prescale counter; eg. if it's interrupting at 4KHz, only decrement the counters every eg. 8th interrupt, to give a count rate around 500 Hz, so a time range up to around half a second in 2mS increments. #### Nigel Goodwin ##### Super Moderator Most Helpful Member To really beat the oldnest stakes, it will eventually end up on a 16C57 since I bought 2 by mistake when I was (more) clueless. I gave away 200 'C' series PIC's a number of years ago - I was given them where I used to work, by a guy who was clearing out an industrial unit he'd taken over (along with more stuff). I offered them on here, and arranged to meet a guy at a local radio rally - bit of a cock-up though, we arranged to meet at a certain time in front of the Soviet radio truck, which was there every year. So at the appointed time I was there, but the other guy wasn't? - turned out that year, for the first time ever, there were TWO Soviet radio trucks Eventually we met up, and I gave him the tubes of chips. To be honest, I would just dump the 16C57's, it's not worth messing about with OTP antique devices, when modern PIC's are so much better. #### jpanhalt ##### Well-Known Member Most Helpful Member To really beat the oldnest stakes, it will eventually end up on a 16C57 since I bought 2 by mistake when I was (more) clueless. Have you checked whether your current programmer can program the 16C57? If not, it would probably be cheaper to buy a mid-range or enhanced mid range chip. (e.g., 12F1840 or 16F1829) . #### throbscottle ##### Well-Known Member Well, it (a PICKit 2 clone) works with the 16F57 I'm using for development. If the 16C57s fail it doesn't matter, they were 50p for 2. If it works my long ago mistake is useful for something. I think there are 1 or 2 config bits I need to change. Ultimately I still have the F to fall back on. TBH those 2 PICs have 100%+ more features than I need. The '57 has 20 port pins available and I'm using 19 of them. I'm using it to get user inputs and run a display controller and DDS chip. Basic stuff. If I had less i/o on the PIC I would need support chips - as it is it doesn't need any. The press / double-press routine works btw, but I discovered a significant bug - it needs a timer for single press events, otherwise everything is registered as a double press! At least I already have one to call. #### jpanhalt ##### Well-Known Member Most Helpful Member I use MPLab 8.92. The 16F57 is not the same as the 16C57. Your PK2 will not work: I have a little experience with some 16Cxx chips. That's why I asked the question. Of those 3 programmers, the one you will most likely find is the PICStart Plus. It should be around$20 USD. It's price has inflated considerably since I last looked: https://www.ebay.com/sch/i.html?_from=R40&_trksid=p3519243.m570.l1313&_nkw=PICStart+PLus&_sacat=0

Buying several 16Fxxx or 16F1xxx (even a 12F1xxx) will be cheaper.

#### throbscottle

##### Well-Known Member
Oh. So the 'C's are junk to me anyway then. Never mind. I did get them at a time when I was trying to make a serial port programmer using a usb adapter (which /almost/ worked!). They've been sitting in a drawer since about 2010! Still experiments to be had in that direction I suppose.

#### Nigel Goodwin

##### Super Moderator
Oh. So the 'C's are junk to me anyway then. Never mind. I did get them at a time when I was trying to make a serial port programmer using a usb adapter (which /almost/ worked!). They've been sitting in a drawer since about 2010! Still experiments to be had in that direction I suppose.
As the author of the worlds first Windows based PIC programmer software (WinPicProg) I would seriously suggest you give up any such ideas The advent of cheap PK series programmers and their integration with MPLAB has rendered such items pretty pointless.

Even 'back in the day' I purposely only supported parallel port programmers, even though it would have been trivial to add serial port programmers (which don't actually even use the serial port anyway), as I considered them far too unreliable - as they relied on the PC's serial port exceeding the RS232 specification.

I gave free support on my free software, I wasn't prepared to do that when people were going to try and use hardware that only had a small of chance of working in the first place.

Those that supported serial port programmers didn't offer any kind of customer support, and for good reason - and some were even based on my original Windows 3.1 code, which I released for free later on - complete with my copyright message still intact

For anyone who might be vaguely interested, my original software (PicProg) was written under DOS using Turbo Pascal - and the Windows version was written as a learning exercise using Delphi (effectively Visual Turbo Pascal for Windows).

#### jpanhalt

##### Well-Known Member
Back to the code.... When I first looked at it, it wasn't clear what you were trying to do. I am not referring to the instructions, just the purpose. For example, is the click/double click distinction for debouncing? Second, TMR0 is pretty good in that you can have an 8-bit pre-scaler and can pre-load a value (as already mentioned) to use the interrupt rather than polling for defined intervals.

It would help enormously if you could describe in plain English what that section is intended to do and why. What period in units of time are you trying to achieve? A flow chart might help but is not necessary once we know the what and why.

#### Pommie

##### Well-Known Member
I vaguely remember someone wrote a pic programmer using an Arduino. It was probably LVP only but it wouldn't be hard to add the high voltage bit.

Mike.

#### jpanhalt

##### Well-Known Member
This manual from Microchip might help:

From: 2.1.2 (12C5XX)
VPP: VPP can be a fixed 13.0V to 13.25V supply. It must not exceed 14.0V to avoid damage to the pin and should be current limited to approximately 100 mA. VDD: 2.0V to 6.5V with 0.25V granularity. Since this
method calls for verification at different VDD values, a programmable VDD power supply is needed.
Current Requirement: 40 mA maximum
It even tells how to construct appropriate drivers to provide the voltage and current requirements. I believe the PK3 is limited to 20 mA or less. Don't know about the PK2. Of course, having the physical tool to program is only half the problem.. Somehow, you need to make it follow the correct protocol, etc. , and trying to get a Microchip programmer to do something that it is not natively designed to do can be "trying" at best. Solving "failure to connect to target" and "target ID returned not as expected" can be very difficult. I spent 3 months trying to get my ICD3 running with MPLab8.92 to recognize a 16F1789. Microchip was no help. Eventually I got an older .jam file, loaded that into my ICD3, and the problems went away. In other words, using a PK2 with an OTP chip might be doable, but it will take some work and maybe additional hardware.

Today's prices on DigiKey:
12F509 $1.20 (baseline) 12F683$2.30 (midline)
12F1840 \$1.85 (enhanced midline)

The question is whether it is worth it.

EDIT: I forgot to mention that baseline chips like the 16C57 (12-bit core) do not have interrupts. One needs to go to midline chips ( 14-bit core) like the 12F6xx to get interrupts. The 16F84 was one of the earliest MCC chips with interrupts as I recall. An interrupt-capable chip, particularly one that automatically saves context could be helpful.

Last edited:

Replies
10
Views
2K
Replies
24
Views
974
Replies
4
Views
9K
Replies
13
Views
4K
Replies
3
Views
3K