PDA

View Full Version : my project Capacitive Sensing LED dimmer 12F1822 via PWM



Heckler
- 1st December 2013, 05:26
Well, After posting here a couple of days ago fishing for someone who has had success setting up the Cap Sense module on the 12F1822, and getting no response, I did some searching and was finally able to get it going.

I found a couple of threads where HankMcSpank had tackeled it... (thanks hank)
Which led to another thread where some correcttions reggarding the use of TMR0 vs TMR1.
(I can't find either of those threads now or I'd post a link)

Any way here is a little project I have wanted to do and CapSense seems to work and makes it a bit simpler.

See attached schematic.

This is the LED I am using... http://dx.com/p/g4-1-2w-108-lumen-3500k-24-smd-led-car-warm-white-light-bulb-dc-12v-51269

Which makes use of Darrel's Instant Interrupts (thanks Darrel!). You will have to go get those include files from his web site dt.cambs.net

here is the code...



'************************************************* ***************
'* Name : UNTITLED.BAS *
'* Author : Dwight and others *
'* Notice : Copyright (c) 2013 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 11/29/2013 *
'* Version : 1.0 *
'* Notes : PIC12F1822 *
'* : *
'************************************************* ***************
#CONFIG
__CONFIG _CONFIG1, _FCMEN_OFF & _FOSC_INTOSC & _WDTE_SWDTEN & _MCLRE_OFF & _CP_OFF & _IESO_OFF & _BOREN_OFF & _PWRTE_OFF
__CONFIG _CONFIG2, _LVP_OFF
#ENDCONFIG

DEFINE OSC 8 'tell picbasic what speed the oscillator is

INCLUDE "DT_INTS-14.bas" '
INCLUDE "ReEnterPBP.bas" ' Include if using PBP interrupts

OSCCON = %01110010
'0 = 4x PLL is disabled
' 1110 = 8 MHz
' 0 = unused
' 1X = Internal oscillator


ANSELA = %00000100 'make port A.2 is analog
TRISA = %00000100 'port A.2 is input
WPUA = %00000000 'turn off weak pull ups

APFCON = %00000001 'Alternate Pin Function Control Reg (default %00000000)
'move CCP to PortA.5 (for PWM output)
OPTION_REG = %10000111
'1 = All weak pull-ups are disabled (except MCLR, if it is enabled)
' 0 = Interrupt on falling edge of RB0/INT pin
' 0 = Timer0 clock is internal cycle clock (Fosc/4)
' 0 = Increment on low-to-high transition on RA4/T0CKI pin
' 0 = Prescaler is assigned to the Timer0 module
' 111 = 1:256 Timer0 prescaler rate

T1CON = %11000001 'enable timer 1 (bit 0) & source the clock from the CPS module (bit 6 & 7 =11

CPSCON0 = %10001100 'set the CPS module highest frequency availabe (for vcc mode) + timer0 clock sourced from CPS module. (BIT 1)
'1 = CPS module is enabled
' 0 = CPS module is in the low range. Internal oscillator voltage references are used.
' 00 = unused
' 11 = Oscillator is in High Range. Charge/Discharge Current is nominally 18 ľA
' 0 = Capacitive Sensing Oscillator Status bit (only readable)
' 0 = Timer0 clock source is controlled by the core/Timer0 module and is FOSC/4

CPSCON1 = %00000010 '0010 = channel 2, (CPS2)

CM1CON0 = 0 ' COMPARATOR OFF
CM1CON1 = 0 ' COMPARATOR OFF

CPS2_PRESENT var WORD
CPS2_THRESHOLD var WORD
CPS2_LAST var WORD

' Software variables
' ==================
Duty VAR WORD
stepp var byte


' ----------------[ I/O Definitions ]-----------------------------------
FET VAR PORTA.5 ' PWM output to control the FET switch

' Software/Hardware initialisation
' ================================
PAUSE 50 ' OSC settle delay
Duty = 0
stepp = 5
hpwm 1,255,250 ' Start with Light full ON
pause 1000

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR0_INT, _Timer0_Int, pbp, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

TMR0 = 0 'clear TIMER0
@ INT_ENABLE TMR0_INT 'enable timer0 interrupts
'************************************************* **********************
'------------------------------< Main program >-------------------------
Main:
pause 100 ' not a whole lot going on here
goto main

'************************************************* ****************************
Timer0_Int:
@ INT_DISABLE TMR0_INT ' stop timer0 interrupts while we're in here
pause 25

CPS2_PRESENT = TMR1 ' take a snapshot of Timer1's present count.
CPS2_THRESHOLD = CPS2_LAST - ((CPS2_LAST/10)*2) ' this sets the 'trigger' up for a 20% diversion (finger press)
CPS2_LAST = CPS2_PRESENT ' store away the present timer0count for the next time we come into the interrupt routine

if cps2_present < cps2_threshold then
stepp = stepp +1
if stepp>6 then stepp=0 ' check for rollover
lookup stepp, [0,1,16,64,128,255,255],duty 'choose level, 5 levels plus OFF
if stepp=6 then
hpwm 1,0,1000 'off ' arrive here when brightness is MAX
pause 100 ' So blink to let user know.
hpwm 1,255,1000 'on
pause 100
hpwm 1,0,1000 'off
pause 100
hpwm 1,255,1000 'on ' blink to show that you are at the highest level
endif
hpwm 1,duty,250 ' else set new level ' button pressed so increment stepp
pause 100
endif

pause 50
TMR0 = 0 ' clear TIMER0
TMR1 = 0 ' clear TIMER1
@ INT_ENABLE TMR0_INT ' re-enable timer0 interrupt
@ INT_RETURN

end


7165

enjoy! and tell me what you think (good or bad)

Demon
- 1st December 2013, 15:55
I like your PIC power supply. What is the expected life of that zener? Little current = forever?

Robert

Heckler
- 1st December 2013, 16:34
I didn't know that zeners had a limited life span.

One thing that did occur to me (during the night :eek:) is that this type of power supply would limit the PIC's ability to provide a "high" output with any amount of current. So if you want to use those pins for something else you would want the active state to be a LOW or ground, or change the value of the 10K resistor to a lower value.

I did measure the current draw at 0.9 ma.

I designed this to specifically be an emergency light or camping light so I wanted the PIC to draw as little power as possible in the OFF state.

With a 7 amp hour gel cell it should last quite a while drawing only 1ma.

Demon
- 1st December 2013, 18:43
I didn't know that zeners had a limited life span.

...

I don't know, that's why I'm asking. I've thought of this idea before but didn't know if it was reliable, or what the limitations were.

I kept thinking it was too simple to be true and wondered why I didn't see anyone else doing it.

Robert

Demon
- 1st December 2013, 18:48
...

One thing that did occur to me (during the night :eek:) is that this type of power supply would limit the PIC's ability to provide a "high" output with any amount of current. So if you want to use those pins for something else you would want the active state to be a LOW or ground, or change the value of the 10K resistor to a lower value.

...

What if you just used VDD (pin 1) as your source, couldn't you then do as you please with that "regulated" 5V?

Edit: ok, I see where you're going. Even using a transistor on the pin, you're still limitted by what can pass through the resistor.

What if you use a higher wattage resistor?

Glue a heatsink on it. :D

Robert

pedja089
- 1st December 2013, 19:31
I would use LDO with low Iq, eg. tps709135 (www.ti.com/product/tps709135)
And put pic in sleep, wake up with timer interrupt, do things, back to sleep...
This way you can get average current very low, under 100uA.

Heckler
- 1st December 2013, 21:40
Wow, I didn't know they made voltage regulators with that low of idle current.

My intention was to be able to leave the ckt connected to a, say 7 Ah, gel cell battery for at least a few weeks.
I will probably add to the circuit board a jumper or small switch to completely disconnect the ckt for storage. Even 1 ma will use up 8.76 Ah in a year. Probably not much more than the self discharge of the batt, though.

For a hobbyist though the junk box is your friend. That regulator is a bit esoteric and the shipping cost would drive up the cost for just a few items.

If you study Zener regulator ckts they are somewhat inneficient if your current needs vary by much. This ckt would get below 2 volt if the current draw gets over 1ma with a 12V source. Since my ckt pulls a bit less than that I am OK. Actually now that I look at it I may want to lower the 10K resistor to say a 5K or so. It's all just experimentation at this point.

If one wants to be able to draw more current for the other PIC pin outputs then it quickly becomes necessary to use a lower value resistor.

I'm sure a good electronics engineer could shred this idea for any kind of commercial application.

Mostly I was determined to get the Cap Sense working and be able to evaluate its suitability for other applications.
Sometimes I just enjoy the challenge of figuring out these Little PICS and what they are capable of. They truly are amazing what is in these little packages for such a few dollars.

For example the APFCON register. It allows you to move the function of some of the PIC peripherals from one pin to another if needed!! (which I did need to do with the PWM from A.2 to A.5)

Heckler
- 1st December 2013, 21:59
Ok Demon,

You got me thinking and as I did some more measuring I found that, with the 10K R, I had only 2 volts to the PIC. Which is ok but mabie a bit low. So I switched out the resistor to a 4.7 K and now I have 3.95V to the PIC and the current draw is 1.7ma (0.0017Amps)

I used one of these... http://www.eevblog.com/projects/ucurrent/
to measure the current

The zener is probably still not working too hard to control the voltage yet (not sure how sharp the zener voltage point is)

Any way I just wanted a simple way to power this ckt from the 12 to 15 Volt source battery.

Heckler
- 1st December 2013, 22:03
If anybody is interested I have modified the CODE so that the light turns off after 30 minutes.

not too hard to do, but I'd be glad to post it.

Demon
- 1st December 2013, 22:13
I'd use Darrel's interrupts and check the Minutes. Is that the easy way out?

Is it more efficient to use another method?

Robert

Archangel
- 3rd December 2013, 07:26
If anybody is interested I have modified the CODE so that the light turns off after 30 minutes.

not too hard to do, but I'd be glad to post it.C'mon Dwight, Post it, you know you want to. Somebody will see it and learn something from it, possibly me.

Acetronics2
- 3rd December 2013, 12:51
I'd use Darrel's interrupts and check the Minutes. Is that the easy way out?

Is it more efficient to use another method?

Robert

just counting the " PAUSE 100 " loops allows +/- 8000 seconds or around 2 hours ...
also allows to clear counter if action detected ...

not a good idea ???

Alain

Charlie
- 3rd December 2013, 15:30
I don't know, that's why I'm asking. I've thought of this idea before but didn't know if it was reliable, or what the limitations were.

I kept thinking it was too simple to be true and wondered why I didn't see anyone else doing it.

Robert
This approach is often used as a voltage reference, but rarely as a power supply because it's very inefficient and has lots of other issues. You need to size the resistor so the voltage across it does not cause a troublesome dip in the VDD voltage at peak currents. Typically, you would need to have about 10x the current the PIC needs flowing all the time in the zener. A much more robust approach would be to put this circuit to the base of a NPN transistor, with the collector on the supply rail and the emitter on VDD. Then you can reduce the quiescent current consumed by roughly the gain of the transistor.
Anyway, this circuit is fine for a demo or an application where there's lots of free current. Of course, every time the PIC takes a sip of current, noise is induced on VDD. Maybe it doesn't matter - but anything with an ADC using VDD as reference won't be happy. Note it will have a much better sense of humour with a big cap across the zener for those computational gulps of current. Of course, then it will come up slowly, which might cause other issues. In the end, a 3 terminal regulator is the easiest, and may even be the cheapest solution.

Demon
- 3rd December 2013, 15:53
just counting the " PAUSE 100 " loops allows +/- 8000 seconds or around 2 hours ...
also allows to clear counter if action detected ...

not a good idea ???

Alain

They're all good ideas as long as the house doesn't catch on fire. :D

Heckler
- 4th December 2013, 03:40
@Acetronics2... great minds must think alike;)
That's pretty much what I did.

@Charlie... my design is specifically designed to run on battery power. The PIC current drain should not change by much. Unless one starts trying to supply current via other pins. That is why I would limit other pin outs to supplying ground when active. (I think this is correct, but I am open for debate)

My intent was to specifically create a Camping/Emergency light that could be dimmed for maximum battery life. My crude measurements with the PWM output is that on low the current is around 1, 6, 25, 50, 100 milliamps respectivily with each of the 5 steps.

I really was not going to do much, if anything, else with the other pins.

In this case I think the current draw of the PIC should be quite stable and very low.
If one starts doing other things with the other pins then all bets are off with the zener/resistor supply.

And, hey, since I am a hobbiest it might be fun to let the smoke out of a PIC to learn a little. See how much abuse one of these little jems can take and keep on ticking. (evil grin)

Here is my code that turns the light off after approx 30 min.
I may modify it to blink the led to warn that the 30 min is about to expire so the user can hit the touch sense pad again to go another 30. The sky is the limit and that is the beauty (as you all surely know) of software control. Can we all say "feature creep".

PS. As I look at the code I wonder if some are the pause statements sprinkled around are really necessay.
One thing I do notice is that the touch sense requires a definate quick tap to be detected. I think this is because the calculation inside the interrupt routine demands a change of approx 20% from the last INT to be counted as a "touch". One can have all sorts of fun playing with some of those numbers and seeing how it changes the Capacitive sensitivity.




'************************************************* ***************
'* Name : UNTITLED.BAS *
'* Author : Dwight and others *
'* Notice : Copyright (c) 2013 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 11/29/2013 *
'* Version : 1.0 *
'* Notes : PIC12F1822 *
'* : *
'************************************************* ***************
#CONFIG
__CONFIG _CONFIG1, _FCMEN_OFF & _FOSC_INTOSC & _WDTE_SWDTEN & _MCLRE_OFF & _CP_OFF & _IESO_OFF & _BOREN_OFF & _PWRTE_OFF
__CONFIG _CONFIG2, _LVP_OFF
#ENDCONFIG

DEFINE OSC 8 'tell picbasic what speed the oscillator is

INCLUDE "DT_INTS-14.bas" '
INCLUDE "ReEnterPBP.bas" ' Include if using PBP interrupts

OSCCON = %01110010
'0 = 4x PLL is disabled
' 1110 = 8 MHz
' 0 = unused
' 1X = Internal oscillator


ANSELA = %00000100 'make port A.2 is analog
TRISA = %00000100 'port A.2 is input
WPUA = %00000000 'turn off weak pull ups

APFCON = %00000001 'Alternate Pin Function Control Reg (default %00000000)
'move CCP to PortA.5 (for PWM output)
OPTION_REG = %10000111
'1 = All weak pull-ups are disabled (except MCLR, if it is enabled)
' 0 = Interrupt on falling edge of RB0/INT pin
' 0 = Timer0 clock is internal cycle clock (Fosc/4)
' 0 = Increment on low-to-high transition on RA4/T0CKI pin
' 0 = Prescaler is assigned to the Timer0 module
' 111 = 1:256 Timer0 prescaler rate

T1CON = %11000001 'enable timer 1 (bit 0) & source the clock from the CPS module (bit 6 & 7 =11

CPSCON0 = %10001100 'set the CPS module highest frequency availabe (for vcc mode) + timer0 clock sourced from CPS module. (BIT 1)
'1 = CPS module is enabled
' 0 = CPS module is in the low range. Internal oscillator voltage references are used.
' 00 = unused
' 11 = Oscillator is in High Range. Charge/Discharge Current is nominally 18 ľA
' 0 = Capacitive Sensing Oscillator Status bit (only readable)
' 0 = Timer0 clock source is controlled by the core/Timer0 module and is FOSC/4

CPSCON1 = %00000010 '0010 = channel 2, (CPS2)

CM1CON0 = 0 ' COMPARATOR OFF
CM1CON1 = 0 ' COMPARATOR OFF

CPS2_PRESENT var WORD
CPS2_THRESHOLD var WORD
CPS2_LAST var WORD

' Software variables
' ==================
Duty VAR WORD
stepp var byte
AutoOFF var word


' ----------------[ I/O Definitions ]-----------------------------------
FET VAR PORTA.5 ' PWM output to control the FET switch

' Software/Hardware initialisation
' ================================
PAUSE 100 ' OSC settle delay
Autooff = 0
Duty = 0
stepp = 5
hpwm 1,255,250 ' Start with Light full ON
pause 1000

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR0_INT, _Timer0_Int, pbp, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

TMR0 = 0 'clear TIMER0
@ INT_ENABLE TMR0_INT 'enable timer0 interrupts
'************************************************* **********************
'------------------------------< Main program >-------------------------
Main:
if autooff = 0 then skipoff
if stepp = 0 then autooff = 0

autooff = autooff + 1
if autooff = 600 then '(20=1 minute, 600=30 minutes) X delay till AutoOFF
autooff = 0
hpwm 1,0,250 'turn LED off after X delay
stepp = 0
endif

SkipOFF:
pause 1000 ' not a whole lot going on here

goto main

'************************************************* ****************************
Timer0_Int:
@ INT_DISABLE TMR0_INT ' stop timer0 interrupts while we're in here
pause 25

CPS2_PRESENT = TMR1 ' take a snapshot of Timer1's present count.
CPS2_THRESHOLD = CPS2_LAST - ((CPS2_LAST/10)*2) ' this sets the 'trigger' up for a 20% diversion (finger press)
CPS2_LAST = CPS2_PRESENT ' store away the present timer0count for the next time we come into the interrupt routine

if cps2_present < cps2_threshold then
autooff = 1
stepp = stepp +1
if stepp>6 then stepp=0 ' check for rollover
lookup stepp, [0,1,16,64,128,255,255],duty 'choose level, 5 levels plus OFF
if stepp=6 then
hpwm 1,0,1000 'off ' arrive here when brightness is MAX
pause 100 ' So blink to let user know.
hpwm 1,255,1000 'on
pause 100
hpwm 1,0,1000 'off
pause 100
hpwm 1,255,1000 'on ' blink to show that you are at the highest level
endif
hpwm 1,duty,250 ' else set new level ' button pressed so increment stepp
pause 100
endif

pause 50
TMR0 = 0 ' clear TIMER0
TMR1 = 0 ' clear TIMER1
@ INT_ENABLE TMR0_INT ' re-enable timer0 interrupt
@ INT_RETURN

end

Heckler
- 4th December 2013, 04:14
Just wondering if anybody has taken the time to bread board up the circuit and see how it works?

If you do build the circuit I suggest you lower the value of the Resistor in the Zener ckt to around 4700 ohms.
(Assuming you are trying to drive it with 12 Volts)

I still need to learn about how to best design a small circuit board with an included touch pad. I still am unsure if I need a surrounding ground to make the touch sense work better.

My testing shows that it does not seem to make much difference.


Here is a link to a video of my circuit working

(the video is in my drop box so I am not sure how this will work, its about 8 meg)

https://dl.dropboxusercontent.com/u/18761838/touch_LED_dimmer.m4v

Aussie Barry
- 4th December 2013, 08:07
Hi Dwight,

Are you looking to make these Camping/Emergency lights as a commercial venture or just for your own use?
If it is the latter, you would probably be best served (from a purist aspect) to throw a bit more coin at an LDO voltage regulator.

From my own curiosity standpoint, what have you used for the capacitive touch sensor in your prototype and how do you plan to implement the sensor in your production unit?

Cheers
Barry
VK2XBP

Charlie
- 4th December 2013, 13:18
@Charlie... my design is specifically designed to run on battery power. The PIC current drain should not change by much. Unless one starts trying to supply current via other pins.

Respectfully, that's simply wrong. Every different instruction uses a slightly different amount of current. Those current changes result in noise. Put a cap across the zener to resolve it. And if minimal current is your objective, you are wasting more in the zener than is used in the PIC. Use a regulator and use the PIC sleep capability to get down to minimal current. If you are really interested in parts count, have a look at some of the other PIC devices. The 12HV615 for instance - I've used this as a touch dimmer for LED lighting - can run off of 12V directly (well, through a resistor) because it has an integrated regulator. The method it uses, though, does still waste a little current.

Heckler
- 5th December 2013, 03:18
@Barry... building this just for hobby fun. And always enjoy using something I build myself. Probably just build a few for myself. Possibly thinking of using it as I teach electronics to Boy Scouts for the electronics merit badge. The final requirement is for them to build a project.

The touch sensor on my proto type is a bit of copper tape (Scotch #1245) stuck to my desk with regular scotch tape over the top as an insulator.

In the final I envision a small ckt board, say 1" x 2" or so, with a "touch" area for the button.

@Charlie... I did not know that there was an "HV" pic. Thats cool. Might have to take a look at getting a couple of samples.

So regarding the noise... A small cap across the power input is probably a good idea. What problems might the noise cause? Intermittent operation? I took a look with an o-scope across the power input (vss, vdd) and didn't see what I thought was a lot of noise (lot is a relative term though)

Yeah I am clear on the fact that a Zener supply is wastefull, but hey 2ma, though your point is well taken. I just don't have one of those LVD regulators on hand.

Again, just an exercise in understanding how to set-up and use the cap sense and maybe come up with a little fun project.

Really my signature line says it all for me.
Kinda like, why does one seemed determined to solve a rubics cube. (and no, I can't)
BUT I can easily waste? 4 or 5 hours trying to figure out the cap sense set up and coding on a little 8 pin pic :o

visnja30
- 25th April 2014, 17:18
Hi,
if someone can explain how using the program of Mr. Heckler to make that ports A.0, A.1, A.3 be the same as the touch sensing port A.2
For example, when I touch the port A.0 then lights are increases , and when I touch port A.1 to reduce the light LEDs.
I do not understand how to run the port A.0 and A.1 to be a touch sensor.
Best regards

Heckler
- 25th April 2014, 22:20
If you look at the datasheet for the 12f1822 you will see that only pins A.0, A.1, A.2 and A.4 have cap sense capability.
You will have to work with those pins.

Also, as Charlie and others have pointed out, I would not do the Zener regulator. It is inefficient and does not allow one to draw more or less current as your circuit might demand, at least not efficiently.

The Zener regulator idea was a bad one... especially with the LDO regulators available for about the same cost and parts count.

visnja30
- 26th April 2014, 07:00
My mistake,I mean portA.4 but wrong I write on post.

Heckler
- 26th April 2014, 15:56
Have you been able to get the circuit and/or code working as I posted above?

Once you get it working as posted then you can work on getting other features and customize it as you want.

Right now each time you touch the cap sense pad it changes the LED brightness using PWM

visnja30
- 15th May 2014, 21:37
Hi,
today I receive a free samples from Microchip and I got a big surprise.My EasyPIC5 development board can not program PIC12f1288 so I can not to try your code.
I have another PIC16f724 with capacitance sensing module But I dont have a working example for him.I try to adjust your code to PIC16f724 but I have a error while compiling.

ASM ERROR symbol not previously defined (TMR1) (0) error 113

When I compiling your code for 12F1288 I dont have this error.

RWright
- 26th April 2016, 21:16
Hello!
I'm new here, but I like your capacitive touch program example. The only difference I would like to be able to do is have 3 touch pads, one for brightness up, brightness down, and one for on/off. I just wonder where
I would put the code that would scan the three cps inputs, would it be in the main program area, or in the interrupt itself? I'm also driving 5 leds that indicate what brightness I am at. Currently, I have the scan code in the main program area, and the determination of which switch is pressed in the interrupt portion. However, I keep having problems with the touch working intermittently. Can you see where I am having problems?
I am using a PIC16LF722A for the micro.


'************************************************* ***************
'* Notes : Copyright (c) 2016 *
'* : Editor MicroCode Studio Plus PBP 3.0.6.0 *
'* : LS1236-A Startrol Touch Controller *
'* : MUST BUILD PROJECT WITH MPASM ASSEMBLER *
'* : Device = 16LF722A-I/SO *
'* Version : 1y.0 *
'* Name : LS1236_1y.BAS *
'* Author : R. WRIGHT *
'* : *
'************************************************* ***************

'SET CONFIGURATION FOR INTERNAL OSCILLATOR WITH PLL MULTIPLIER ON
#CONFIG
__config _CONFIG1, _INTRC_OSC_NOCLKOUT & _WDTE_OFF & _BOR_OFF & _PLLEN_ON
#ENDCONFIG


define OSC 4


INCLUDE "DT_INTS-14.bas" ' PBP interrupt routines (MUST BE IN SAME FOLDER)
INCLUDE "ReEnterPBP.bas" ' Include if using PBP interrupts
' Courtesy of Derryl Taylor, PBP Wizard!

OSCCON = %00010000 'SETS INT OSC TO 4Mhz
ANSELB = %00000111 'SETS INPUTS B0-B2 AS ANALOG
TRISB = %00000111 'SETS INPUTS B0-B2 AS INPUTS
WPUB = %00000000 'DISABLES WEAK PULL-UP BITS
'TRISC = %00001000 'SETS INPUT C3 AS INPUT

OPTION_REG = %10000111
'1 = All weak pull-ups are disabled (except MCLR, if it is enabled)
' 0 = Interrupt on falling edge of RB0/INT pin
' 0 = Timer0 clock is internal cycle clock (Fosc/4)
' 0 = Increment on low-to-high transition on RA4/T0CKI pin
' 0 = Prescaler is assigned to the Timer0 module
' 111 = 1:256 Timer0 prescaler rate

T1CON = %11000001 'enable timer 1 (bit 0) & source the clock from the CPS module (bit 6 & 7 =11)
'set the CPS module highest frequency availabe (for vcc mode) + timer0 clock sourced from CPS module. (BIT 1)


CPSCON0 = %10001100 '1 = CPS module is enabled
' 000 = unused
' 11 = Oscillator is in High Range. Charge/Discharge Current is nominally 18 ľA
' 0 = Capacitive Sensing Oscillator Status bit (only readable)
' 0 = Timer0 clock source is controlled by the core/Timer0 module and is FOSC/4

CPSCON1 = %00000001 '0001 = channel 1, (CPS1)


' Software variables

CPSX_PRESENT var WORD 'VARIABLE FOR BUTTON CURRENT VALUE
CPSX_THRESHOLD var WORD 'VARIABLE FOR BUTTON THRESHOLD VALUE
CPSX_LAST var WORD 'VARIABLE FOR PREVIOUS BUTTON VALUE
Duty VAR WORD 'VARIABLE FOR DUTY CYCLE
stepp var byte 'VARIABLE FOR BRIGHTNESS LEVEL
incnt var byte 'BUTTON PUSH INCRIMENT
LOCLEV VAR BYTE 'LOCAL MODULE BRIGHTNESS LEVEL
REMLEV VAR BYTE 'REMOTE MODULE BRIGHTNESS LEVEL
IOTOG VAR BIT 'TOGGLE BIT FOR I/O BUTTON

' variables used by interrupt handler, comment out as per assembler
wsave VAR BYTE $20 SYSTEM ' location for W if in bank0
'wsave VAR BYTE $70 SYSTEM ' alternate save location for W
' if using $70, comment wsave1-3

' --- IF any of these three lines cause an error ?? ------------------------
' Comment them out to fix the problem ----
' -- Which variables are needed, depends on the Chip you are using --
wsave1 VAR BYTE $A0 SYSTEM ' location for W if in bank1
'wsave2 VAR BYTE $120 SYSTEM ' location for W if in bank2
'wsave3 VAR BYTE $1A0 SYSTEM ' location for W if in bank3





' SET DEVICE I/O PINS


LED1 VAR PORTA.1 ' SET LED LEVEL INDICATORS
LED2 VAR PORTA.2
LED3 VAR PORTA.3
LED4 VAR PORTA.4
LED5 VAR PORTA.5


' Software/Hardware initialization

PAUSE 50 ' OSC settle delay
Duty = 255 ' SET INITIAL BRIGHTNESS TO FULL ON
stepp = 5 ' SET INITIAL LOOKUP TABLE TO 5
incnt = 1 ' set input counter to input 1
iotog = 1 ' SET I/O BUTTON TOGGLE TO high
hpwm 1,DUTY,1000 ' INITIALIZE HARDWARE PWM TO SELECTED LEVELS
HIGH LED5 ' TURN ON OUTPUT FOR LED 5
pause 1000 ' LET EVERYTHING SETTLE

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR0_INT, _Timer0_Int, pbp, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

TMR0 = 0 'clear TIMER0
@ INT_ENABLE TMR0_INT 'enable timer0 interrupts
PAUSE 100


'************************************************* **********************
'------------------------------< Main program >-------------------------

'SCAN INPUTS UNTIL FINGER DEPRESSION IS DETECTED
Main:

incnt = 2
cpscon1 = %00000001 ' 0001 = channel 1, (CPS1), DOWN BUTTON
ANSELB = %00000010 ' SETS INPUT B1 AS ANALOG
TRISB = %00000010 ' SETS INPUTS B1 AS INPUTS
PAUSE 100
INcnt = 3
cpscon1 = %00000010 ' 0010 = channel 2, (CPS2), UP BUTTON
ANSELB = %00000100 ' SETS INPUT B2 AS ANALOG
TRISB = %00000100 ' SETS INPUT B2 AS INPUT
PAuse 100
incnt = 1
cpscon1 = %00000000 ' 0000 = channel 0, (CPS0), 1/0 BUTTON
ANSELB = %00000001 ' SETS INPUT B0 AS ANALOG
TRISB = %00000001 ' SETS INPUT B0 AS INPUT
Pause 100 ' WAIT FOR INTERRUPT

Goto Main

'************************************************* ****************************
Timer0_Int:
@ INT_DISABLE TMR0_INT ; stop timer0 interrupts while we're in here
pause 100

' store away the present timer0 count for the next time we come into the interrupt routine
CPSX_PRESENT = TMR1 ' take a snapshot of Timer1's present count.
CPSX_THRESHOLD = CPSX_PRESENT - ((CPSX_LAST/10)*5) ' this sets the 'trigger' up for a 50% diversion (finger press)
CPSX_LAST = CPSX_PRESENT

'DETERMINES WHICH BUTTON HAS BEEN PRESSED
IF CPSX_PRESENT < CPSX_THRESHOLD THEN
if (incnt = 3) AND (STEPP > 1) then ' down button pressed so decriment stepp
stepp = stepp - 1
GOTO SKIP1
ENDIF
If (incnt = 2) AND (STEPP < 5) then ' up button pressed so incriment stepp
stepp = stepp + 1
GOTO SKIP1
endif
IF (INCNT = 1) AND (iotog = 0) THEN ' 1/0 button pressed for off
STEPP = 0
IOTOG = 1
GOTO SKIP1
ENDIF
IF (INCNT = 1) AND (iotog = 1) THEN ' 1/0 button pressed for on
STEPP = 5
IOTOG = 0
ENDIF


' lights appropriate leds according to the current lookup table value
SKIP1:
IF STEPP = 5 THEN
HIGH LED5
ENDIF
IF STEPP = 4 THEN
HIGH LED4
ENDIF
IF STEPP = 3 THEN
HIGH LED3
ENDIF
IF STEPP = 2 THEN
HIGH LED2
ENDIF
IF STEPP = 1 THEN
HIGH LED1
ENDIF
if stepp = 0 THEN
LOW LED1
endif



' SETS HARDWARE PWM OUTPUT 1 TO DESIRED LEVEL
lookup stepp, [0,16,32,64,128,255],duty ' choose level, 5 levels plus OFF
hpwm 1,duty,1000 ' set new level
' pause 100

ENDIF


pause 100
TMR0 = 0 ' clear TIMER0
TMR1 = 0 ' clear TIMER1
@ INT_ENABLE TMR0_INT ; re-enable timer0 interrupt
@ INT_RETURN

resume

RWright
- 29th April 2016, 18:57
Hello again,
I got rid of my problems with the touch reliability by greatly reducing the pause times in the main part of the program. However, I would like the 1/0 button to be a latch function and not toggle as it is now. I've tried all sorts of things, but they interfere with the interrupt, or they only work once, and none of the buttons work again. Any help would be greatly appreciated. Thanks.

richard
- 30th April 2016, 13:31
RWRIGHT
If you put yourcode in code tags its then much easier for us to examine it properly

this is the way i scan mutiple keys , not sure if your chip has a T1GATE_INT but if it has it makes life easy.

isr's are best kept short and simple .



'************************************************* ***************
'* Name : CAPSENSE.BAS *
'* Author : RICHARD *
'* Notice : Copyright (c) 2011 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 10/20/2011 *
'* Version : 1.0 *
'* Notes : *
'* : 12f1822 *
' *
'************************************************* ***************

'#DEFINE DBUG 1
#CONFIG
__config _CONFIG1, _WDTE_ON & _FOSC_INTOSC &_MCLRE_ON &_PWRTE_ON
__config _CONFIG2, _LVP_OFF
#ENDCONFIG

include "dt_ints-14.bas"
include "REENTERPBP.bas"
Include "modedefs.bas"
asm

INT_LIST macro
INT_HANDLER T1GATE_INT, _TB1, PBP,YES
endm
INT_CREATE
ENDASM

@Timer1=TMR1L
THRESH CON 4000 'mult by 4 for 4mhz clk
CNT VAR WORD 'TIMER1 OUTPUT
FLG VAR BYTE 'GOT A KEY
KP VAR BYTE 'WHICH KEY
Timer1 VAR WORD EXT
PW VAR WORD ; PULSEWIDTH

DEFINE OSC 16
DEFINE DEBUG_REG PORTA
DEFINE DEBUG_BIT 0
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0


OSCCON=$7a '16mhz int osc
CPSCON0 = %10001100 'high range
CPSCON1 = 2 'cps ch 2
WPUA = %00000000
ANSELA= $14 'an4 ans an2 activated
TRISA = %011110 'gpio.0 output
OPTION_REG=$C7 'edge int. prescale 1:256
PIE1.7=1 'timer1 gate interrupt
T1GCON=$E1 ' single shot timer0 overflow as input
T1CON=%11000101 'capsense as input no prescale no sync
INTCON= $C0 'peripheral interrupts
PW=512
APFCON.0=1
LATA.0=1
t2con=7



#IFDEF DBUG
LED VAR LATA.5
LED=1
pause 2000
Debug "Start",13 ,10
LED=0
pause 500
#ENDIF
ccp1con=12
CCPR1L=128

FLG=0



MAIN:
IF FLG.1=1 THEN
IF KP = 2 THEN
PW= (PW+64) MIN 1023
ELSE 'MUST BE THE OTHER ONE
PW = PW-64
IF PW.15 THEN PW=0
ENDIF
CCPR1L = PW>>2;
ccp1con=12|((PW&3)<<4);
#IFDEF DBUG
debug #CNT,9,"KEY ",#KP,13,10
debug #PW,13,10
#ENDIF
PAUSE 300
PIR1.7=0 'clr int flag
FLG=0 'clr key pressed flags
ENDIF
GOTO MAIN


TB1:
T1CON.1=0 'DISABLE TILL REQ
;LED=!LED
CNT=TIMER1

IF CNT < THRESH THEN ' KEY DETECTED
FLG.1=1
KP=CPSCON1
ENDIF
CPSCON1 =CPSCON1 ^ 1 ;check next key CPS2 OR CPS3
TIMER1=0

T1CON.1=1 'CLEAR ALL AND START AGAIN
@ INT_RETURN

RWright
- 2nd May 2016, 15:04
Thanks for the info! Unfortunately it doesn't appear that my chip doesn't have the T1GATE_INT.

richard
- 2nd May 2016, 23:19
Thanks for the info! Unfortunately it doesn't appear that my chip doesn't have the T1GATE_INT.

correct "does not" " does not" means it has one

if your using the chip mentioned in your first post then I suggest a closer read of the data sheet is in order . I can see a T1GATE module


I am using a PIC16LF722A for the micro.

RWright
- 3rd May 2016, 01:49
LoL! Double negatives always get me. I got up from the computer when I was replying earlier. Sorry. Also, it isn't the PIC18F22, it is the PIC16LF722A. I think I dragged some info from the original post that I was commenting on because I had incorrectly posted. The original post was by Dwight and Others. My touch scanning seems to be working good now, except I want the I/O button to be single step, and still keep the up and down button in a repeat mode as it is now. Thanks again in advance.

richard
- 3rd May 2016, 02:27
clear as mud


Also, it isn't the PIC18F22, it is the PIC16LF722A

by PIC18F22 do you mean 12f1822 ?
are you using a PIC16LF722A ? if so then as I said it has a t1gate module



except I want the I/O button to be single step, and still keep the up and down button in a repeat mode as it is now

do you mean a up button a down button and an on/off button ?

perhaps posting some code would help

HankMcSpank
- 8th May 2016, 22:37
Well, After posting here a couple of days ago fishing for someone who has had success setting up the Cap Sense module on the 12F1822, and getting no response, I did some searching and was finally able to get it going.

I found a couple of threads where HankMcSpank had tackeled it... (thanks hank)


You are welcome ;-)

RWright
- 9th May 2016, 16:18
Hello again,
I'm still not seeing anywhere in the datasheet or device files a reference to the T1GATE_INT. I see a timer1 gate function, is this what you mean? Sorry about the listing in the content of the posting. How do I put
it in the code tag? The I/O button is indeed a power on/off, but only in the sense that the pwm is full on or full off. I would like to be able to stop the code from repeating if the 1/0 button is pressed, until it has been released
and then pressed again, only in a single-shot manner. Thanks again.

mackrackit
- 9th May 2016, 23:54
Code tags...

When you click reply to thread a basic reply dialog shows. At the bottom right there is an Advanced button. That will take you to a full editor.
Look for # in the toolbar.

richard
- 10th May 2016, 01:20
I'm still not seeing anywhere in the datasheet or device files a reference to the T1GATE_INT





see data sheet 12.6.6

TIMER1 GATE EVENT INTERRUPT <==> [in DT-INTS ] T1GATE_INT



also section 4 INTERRUPTS


The PIC16(L)F722A/723A device family has 12
interrupt sources, differentiated by corresponding
interrupt enable and flag bits:
• Timer0 Overflow Interrupt
• External Edge Detect on INT Pin Interrupt
• PORTB Change Interrupt
• Timer1 Gate Interrupt
• A/D Conversion Complete Interrupt
• AUSART Receive Interrupt
• AUSART Transmit Interrupt
• SSP Event Interrupt
• CCP1 Event Interrupt
• Timer2 Match with PR2 Interrupt
• Timer1 Overflow Interrupt
• CCP2 Event Interrupt

RWright
- 10th May 2016, 04:37
Thanks for the info!

RWright
- 10th May 2016, 19:47
Hello!

Here's my code (with the help of others on here) that I inadvertently posted in the context of the thread:
'************************************************* ***************
'* Notes : Copyright (c) 2016 *
'* : Editor MicroCode Studio Plus PBP 3.0.6.0 *

'* : MUST BUILD PROJECT WITH MPASM ASSEMBLER *
'* : Device = 16LF722A-I/SO *
'* Date : 1/18/2016 *
'* Version : 1z *
*
'* Author : R. WRIGHT *
'* : *

'************************************************* ***************


'SET CONFIGURATION FOR INTERNAL OSCILLATOR WITH PLL MULTIPLIER ON
#CONFIG
__config _CONFIG1, _INTRC_OSC_NOCLKOUT & _WDTE_OFF & _BOR_OFF & _PLLEN_ON
#ENDCONFIG


define OSC 4


INCLUDE "DT_INTS-14.bas" ' PBP interrupt routines (MUST BE IN SAME FOLDER)
INCLUDE "ReEnterPBP.bas" ' Included for use of CPS module interrupt
' Courtesy of Derrel Taylor, PBP Wizard!


OSCCON = %00010000 'SETS INT OSC TO 4Mhz
ANSELB = %00111111 'SETS INPUTS B0-B5 AS ANALOG
TRISB = %00111111 'SETS INPUTS B0-B5 AS INPUTS
WPUB = %00000000 'DISABLES WEAK PULL-UP BITS
'TRISC = %00001000 'SETS INPUT C3 AS INPUT

OPTION_REG = %10000111
'1 = All weak pull-ups are disabled (except MCLR, if it is enabled)
' 0 = Interrupt on falling edge of RB0/INT pin
' 0 = Timer0 clock is internal cycle clock (Fosc/4)
' 0 = Increment on low-to-high transition on RA4/T0CKI pin
' 0 = Prescaler is assigned to the Timer0 module
' 111 = 1:256 Timer0 prescaler rate

T1CON = %11000001 'enable timer 1 (bit 0) & source the clock from the CPS module (bit 6 & 7 =11)
'set the CPS module highest frequency availabe (for vcc mode)
'+ timer0 clock sourced from CPS module. (BIT 1)

CPSCON0 = %10001100 '1 = CPS module is enabled
' 000 = unused
' 11 = Oscillator is in High Range. Charge/Discharge Current is nominally 18 ľA
' 0 = Capacitive Sensing Oscillator Status bit (only readable)
' 0 = Timer0 clock source is controlled by the core/Timer0 module and is FOSC/4

CPSCON1 = %00000001 '0001 = channel 1, (CPS1)


' Software variables

CPSX_PRESENT var WORD 'VARIABLE FOR BUTTON CURRENT VALUE
CPSX_THRESHOLD var WORD 'VARIABLE FOR BUTTON THRESHOLD VALUE
CPSX_LAST var WORD 'VARIABLE FOR PREVIOUS BUTTON VALUE
Duty VAR WORD 'VARIABLE FOR DUTY CYCLE
stepp var byte 'VARIABLE FOR BRIGHTNESS LEVEL
incnt var byte 'BUTTON PUSH INCRIMENT


' variables used by interrupt handler, comment out as per assembler
wsave VAR BYTE $20 SYSTEM ' location for W if in bank0
'wsave VAR BYTE $70 SYSTEM ' alternate save location for W
' if using $70, comment wsave1-3

' --- IF any of these three lines cause an error ?? ------------------------
' Comment them out to fix the problem ----
' -- Which variables are needed, depends on the Chip you are using --
wsave1 VAR BYTE $A0 SYSTEM ' location for W if in bank1
'wsave2 VAR BYTE $120 SYSTEM ' location for W if in bank2
'wsave3 VAR BYTE $1A0 SYSTEM ' location for W if in bank3


' SET DEVICE I/O PINS

LED1 VAR PORTA.1 ' SET LED LEVEL INDICATORS
LED2 VAR PORTA.2
LED3 VAR PORTA.3
LED4 VAR PORTA.4
LED5 VAR PORTA.5


' Software/Hardware initialization

PAUSE 50 ' OSC settle delay
Duty = 255 ' SET INITIAL BRIGHTNESS TO FULL ON
stepp = 5 ' SET INITIAL LOOKUP TABLE TO 5
incnt = 1 ' set input counter to input 1

hpwm 1,DUTY,1000 ' INITIALIZE HARDWARE PWM TO SELECTED LEVELS
pause 1000 ' LET EVERYTHING SETTLE
HIGH LED5 ' TURN ON OUTPUT FOR LED 5
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR0_INT, _Timer0_Int, pbp, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

TMR0 = 0 'clear TIMER0
@ INT_ENABLE TMR0_INT ;enable timer0 interrupts
PAUSE 100


'************************************************* *****************************
'------------------------------< Main program >--------------------------------

'SCAN THE THREE INPUTS UNTIL FINGER DEPRESSION IS DETECTED VIA TIMER0 INTERRUPT
Main:
incnt = 2
cpscon1 = %00000001 ' 0001 = channel 1, (CPS1), DOWN BUTTON
ANSELB = %00000010 ' SETS INPUT B1 AS ANALOG
TRISB = %00000010 ' SETS INPUTS B1 AS INPUTS
pause 5
INcnt = 3
cpscon1 = %00000010 ' 0010 = channel 2, (CPS2), UP BUTTON
ANSELB = %00000100 ' SETS INPUT B2 AS ANALOG
TRISB = %00000100 ' SETS INPUT B2 AS INPUT
PAuse 5
incnt = 1
cpscon1 = %00000000 ' 0000 = channel 0, (CPS0), 1/0 BUTTON
ANSELB = %00000001 ' SETS INPUT B0 AS ANALOG
TRISB = %00000001 ' SETS INPUT B0 AS INPUT
Pause 5 ' KEEP CYCLING UNTIL INTERRUPT OCCURS
Goto Main

'************************************************* *****************************


'************************************************* *****************************
'--------------------------<INTERRRUPT ROUTINE>--------------------------------
Timer0_Int:
@ INT_DISABLE TMR0_INT ; stop timer0 interrupts while we're in here
pause 100 ; PAUSE TO GET TIMER 1 COUNT

' store away the present timer0 count for the next time we come into the interrupt routine
CPSX_PRESENT = TMR1 ' take a snapshot of Timer1's present count.
CPSX_THRESHOLD = CPSX_PRESENT - ((CPSX_LAST/10)*6) ' this sets the 'trigger' up for a 60% diversion (finger press)
CPSX_LAST = CPSX_PRESENT

'DETERMINES WHICH BUTTON HAS BEEN PRESSED
IF CPSX_PRESENT < CPSX_THRESHOLD THEN

if (incnt = 3) AND (STEPP > 1) then ' down button pressed so decriment stepp
stepp = stepp - 1
GOTO SKIP1
ENDIF

If (incnt = 2) AND (STEPP < 5) then ' up button pressed so incriment stepp
stepp = stepp + 1
GOTO SKIP1
ENDIF

IF (INCNT = 1) AND (stepp > 0) THEN ' 1/0 button pressed for off
STEPP = 0
GOTO SKIP1
ENDIF

IF (INCNT = 1) AND (stepp = 0) THEN ' 1/0 button pressed for on
STEPP = 5
ENDIF

' lights appropriate level indicator leds according to the current lookup table value
SKIP1:
IF STEPP = 5 THEN
HIGH LED5
ENDIF
IF STEPP = 4 THEN
HIGH LED4
ENDIF
IF STEPP = 3 THEN
HIGH LED3
ENDIF
IF STEPP = 2 THEN
HIGH LED2
ENDIF
IF STEPP = 1 THEN
HIGH LED1
ENDIF
if stepp = 0 THEN
LOW LED1
endif


' SETS HARDWARE PWM OUTPUT 1 TO DESIRED LEVEL at a frequency of 1Khz
lookup stepp, [0,16,32,64,128,255],duty ' choose level, 5 levels plus OFF
hpwm 1,duty,1000 ' set new level, frequency

IF INCNT = 1 THEN ' extra delay for press of
PAUSE 200 ' I/O button
ENDIF

ENDIF



pause 10 ' settle time
TMR0 = 0 ' clear TIMER0
TMR1 = 0 ' clear TIMER1
@ INT_ENABLE TMR0_INT ; re-enable timer0 interrupt
@ INT_RETURN

'************************************************* ****************************
END

richard
- 11th May 2016, 04:38
rather than confuse hecklers fine and working project why not start a new thread that reflects your project and hardware more closely
say "using multi cap-sense inputs on a pic16f722a" .

there are many issues with your code starting from the tmr0 setup (prescaler ?) to a 100mS delay in the isr that will interfere with key scanning to such an extent to make success unlikely.

RWright
- 11th May 2016, 14:04
Okay. But if the timer0 source works for Heckler, why won't it work in mine? Everything seems to be working okay, except that I want it to be a single-shot occurrence on the 1/0 button, rather than a continuous loop, as it is for the up/down buttons. I thought the 100mS pause was the period that the count from timer 1 is occurring? Thanks. The reason I posted on Hecklers was because I was hoping to get some input from him.

RWright
- 11th May 2016, 17:43
Hello again.

What is happening with CPSCON1 =CPSCON1 ^ 1? Is the THRESH a fixed value predetermined? Just wondering where the THRESH CON 4000 comes from. Thanks.

RWright
- 11th May 2016, 18:51
Hi again,

It does appear to be simpler when you know what you are doing! What is happening in the ccp1con=12|((PW&3)<<4) statement? Thanks again.

RWright
- 11th May 2016, 20:36
Hello,
Another one...in your example (PIC12F1822) with the LATA and LATA.0 references, is there a way that I can implement the same function, still using the PIC16F722A device, uisng the B port instead?

Ioannis
- 12th May 2016, 07:48
ccp1con=12|((PW&3)<<4)


1. it keeps only the first two bits (Bit 0 and Bit 1) of the PW. Rest bits are set to 0
2. shifts left by 4 positions
3. Makes a Bitwise OR with the number 12 (binary 00001100) so to keep te bits 2 and 3 if they are set)
4. Places the result in ccp1con

Ioannis