Capacitive Voltage Divider on an 8 bit MCU (16F18425)

Started by Peter Truman, Today at 04:35 AM

Previous topic - Next topic

Peter Truman

Looking for some assistance with a new project - I want to try using the CVD feature of this PIC. So I knocked up a small test PCB to give it a whirl. (BTW - JLPCB had a 'special' on. I ordered 5 boards (their min order) and it cost me a total of US$20.00 including postage to Australia. Bargain!)

I selected this PIC based on a brief review of the datasheet - thinking I would dig in a bit deeper when it came to writing the code! (rookie error)

Basic function of the board is easy - its a tiny 14 pin TSOP that runs a treat at 32MHz, no trouble to configure and program.

Where I have run into trouble is trying to figure out this CVD module - the principle seems very simple but small print in the datasheet strongly recommends NOT trying to configure the module manually
Pg 1 https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ApplicationNotes/ApplicationNotes/01478B.pdf

"However, Microchip does not recommend
implementing CVD by hand! The mTouch sensing
Framework and mTouch sensing Library provided in
the Microchip Library of Applications implements the
scan automatically, and has been tested to provide a
high level of noise immunity. It is highly recommended
to use these resources rather than implementing the
scan from scratch."


So I fired up MPLAB with the intention of trying to figure out how it all works - sadly my C coding skills are even worse than my Proton coding skills. So here I am.

I wondered of anyone has any experience with this? I have a project in mind that I think this would suit so I would be happy to come to some form of cash arrangement if anyone is willing to help me with this? Otherwise I might have to commision a C developer on Freelancer (always a nightmare!)

It occured to me, if I could get this module configured in XC8, I could maybe just insert the assembly code into my Positron program - after all, all I need is 1 (reliable) 12 bit variable!

Anyway - if anyone is able to help, please give me a shout (note: I'm away on holiday in Thailand for 4 weeks from this time next week - so I'll be a bit out of the picture - wife has told me I can't take my laptop :-\ )

As always - thanks in advance



top204

Send me a message Peter, and I will see what I can come up with "code wise" for the device you are using.

I have used a capacitance sensor for a project a few years ago, and it worked quite well, but that used the CTMU peripheral. The include code listing for it is shown below. It was written for a PIC18F26J11, but the principle will be the same on all devices:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Capacitance touch routines using a CTMU peripheral on a PIC18F26J11 device.
'
' Written for the Positron8 BASIC Compiler by Les Johnson.
'
$define cFilterSamplesToTake 5                          ' The amount of ADC samples to take for the median filter
$define cUnTouchedSamplesToTake 9
$define cTouchThreshold 45                              ' The amount away from the untouched values to trigger a touch

$define cTouch_AverageCount 8                           ' Number of samples to average in Average routine
$define cTouch_AverageCount_Div4 $eval (cTouch_AverageCount / 4)
$define cTouch_Fastspread 500                           ' Fast Average threshold +/-  in Average routine

    Dim tTouched As Bit                                 ' True if a touch is detected
    Dim UnTouched_wValue As Word                        ' Holds the value of an untouched sensor
    Dim Touch_wResult As Word
    Dim Touch_wAveragePrevious As Word = 0
    Dim UnTouched_wSamples[cUnTouchedSamplesToTake + 1] As Word  Heap   ' Create an array to hold the untouched capacitance samples

$ifndef True
    $define True 1
$endif
$ifndef False
    $define False 0
$endif

'--------------------------------------------------------------------------------------------------------------------------
' A bubble sort as a median filter for the default (untouched) values
' Input     : UnTouched_wSamples holds the samples
' Output    : Returns the median result
' Notes     : Median means middle
'
Proc UnTouched_MedianFilter(), Word
    Dim wTemp As Word                                   ' Temporary variable for swapping
    Dim bIndex As Byte                                  ' Holds the position in the sort
    Dim tSwap As Bit                                    ' Indicates if the bubble sort is complete

    Repeat
        tSwap = False                                                           ' Clear the flag that indicates a swap
        bIndex = 0
        Repeat                                                                  ' For each cell of the array...
            If UnTouched_wSamples[bIndex] > UnTouched_wSamples[bIndex + 1] Then ' Move larger values up
                wTemp = UnTouched_wSamples[bIndex]                              ' \
                UnTouched_wSamples[bIndex] = UnTouched_wSamples[bIndex + 1]     ' | By swapping them
                UnTouched_wSamples[bIndex + 1] = wTemp                          ' /
                tSwap = True                                                    ' Set the bit if a swap occurred
            EndIf
            Inc bIndex
        Until bIndex > cUnTouchedSamplesToTake                                  ' Check the next cell of the array
    Until tSwap = False                                                         ' Keep sorting until no more swaps occur
    Result = UnTouched_wSamples[cUnTouchedSamplesToTake / 2]                    ' Get the middle value from the sorted array
EndProc

'--------------------------------------------------------------------------------------------------------------------------
' Create an average from value entered
' Input     : Touch_wResult
' Output    : Touch_wResult
' Notes     : None
'
Proc Cap_GetAverage(), Touch_wResult
    Dim wAverageTemp As Word

    If Touch_wResult <> Touch_wAveragePrevious Then
        wAverageTemp = Abs(Touch_wResult - Touch_wAveragePrevious)
        If wAverageTemp <= cTouch_Fastspread Or Touch_wResult >= cTouch_AverageCount Then
            If wAverageTemp < cTouch_AverageCount Then
                Touch_wAveragePrevious = Touch_wAveragePrevious - (Touch_wAveragePrevious / cTouch_AverageCount_Div4)
                Touch_wAveragePrevious = Touch_wAveragePrevious + (Touch_wResult / cTouch_AverageCount_Div4)
            Else
                Touch_wAveragePrevious = Touch_wAveragePrevious - (Touch_wAveragePrevious / cTouch_AverageCount)
                Touch_wAveragePrevious = Touch_wAveragePrevious + (Touch_wResult / cTouch_AverageCount)
            EndIf
        Else
            Touch_wAveragePrevious = Touch_wResult          ' Save the average value
        EndIf
        Touch_wResult = Touch_wAveragePrevious              ' Put Average back into Touch_wResult
    EndIf
EndProc

'--------------------------------------------------------------------------------------------------------------------------
' Setup the ADC for CTMU operation
' Input     : None
' Output    : None
' Notes     : AN1 is used to the CTMU
'           : ADC is set for 10-bit
'
Proc CTMU_ADC_Init()
    PinInput PORTA.1
    ADCON0 = %00000101                                      ' \ ADC Left justified for 10-bit operation
                                                            ' | ADC 2 TAD
                                                            ' / ADC FOSC/16
    ADCON1 = %10001101                                      ' ADC Left justified For 10-Bit operation
    ANCON0 = %00000010                                      ' Set the ADC pin AN1 to analogue
EndProc

'-------------------------------------------------------------------------------------------------------------------------------------------
' Setup CTMU - For Touch Switch
' Input     : None
' Output    : None
' Notes     : AN1 is the touch switch input
'
Proc CTMU_Setup()
    CTMUCONH = %00000000                                    ' Bit-7 CTMU enable 1=On ,0 = Off, Bit6 N/A
                                                            ' Bit-5 CTMUSIDL - 1 = disable module when in idle mode 0 = continue module operation when in idl mode
                                                            ' Bit-4 TGEN 1 = ENABLE 0= disable edge delay gen
                                                            ' Bit-3 EDGEN 1= edges not blocked 0= edges blocked
                                                            ' Bit-2 EDGSEQEN - 1 = edge1 occure prior edge2 can 0= no edge seq
                                                            ' Bit-1 IDISSEN 1= grounded 0= Not grounded  Analogue current Source , CTTRIG 1= Trig Output enabled  0 = disabled

    CTMUCONL = %00000000                                    ' Bit-7 EDG2POL 1= edge2 pos edge responce 0= edge2 neg edge responce
                                                            ' Bits 6-5 Edge2 select source= 11=CTED1PIN 10=CTED2 pin, 01 ECCP1 , 00 ECCP2
                                                            ' Bit-4 EDG2POL 1= edge1 pos edge responce 0= edge1 neg edge responce
                                                            ' Bits 3-2 Edge1 source= 11=CTED1PIN 10=CTED2 pin, 01 ECCP1 , 00 ECCP2
                                                            ' Bit-1 = Edge 2 (R/W) status 1= event occured 0 = Not occured
                                                            ' Bit0 = Edge 1 (R/W) status 1= event occured 0 = Not occured

    CTMUICON = %00000011                                    ' Bits7-2 011111-000001 max - min pos change from nominal current , 000000 Nominal current output set by bit1-0 ,111111 -100000 min -max neg change from nominal current
                                                            ' Bits1-0 IRNG - Current Source Range Select bita 11= 10$base(55uA) 10= 1$base(5.5uA) ,01=base (0.55uA), 00= current sourse disabled
    CTMU_ADC_Init()                                         ' Setup the ADC for CTMU operation
EndProc

'--------------------------------------------------------------------------------------------------------------------------
' Get a reading from the capacitance touch sensor
' Input     : None
' Output    : Returns the ADC value for the touch
' Notes     : None
'
Proc Get_CapTouch(), Touch_wResult
    Dim bIndex As Byte

    For bIndex = cTouch_AverageCount + 10 DownTo 0          ' Create a loop to counteract the average routine
        CTMUCONHbits_CTMUEN = 1                             ' Turn on the CTMU peripheral
        CTMUCONHbits_IDISSEN = 1                            ' Drain any charge on the A/D channel
        DelayUS 2                                           ' Wait for charge to drain
        CTMUCONHbits_IDISSEN = 0                            ' Stop Discharge on the A/D channel
        DelayUS 2                                           ' Delay before selecting the CTMU edge1
        CTMUCONLbits_EDG1STAT = 1                           ' Begin Charging
        DelayUS 2                                           ' Wait for CTMU charge time
        CTMUCONLbits_EDG1STAT = 0                           ' Stop Charging
        Touch_wResult = ADIn 1                              ' Do an ADC reading on AN1 - touch switch input
        Cap_GetAverage()                                    ' Average the readings
        CTMUCONHbits_CTMUEN = 0                             ' Turn off the CTMU peripheral
        DelayMS 1
    Next
    Result = Touch_wResult
EndProc

'--------------------------------------------------------------------------------------------------------------------------
' Find the default (no touch) value
' Input     : None
' Output    : wUnTouched_Value holds the untouched value
' Notes     : None
'
Proc Find_UntouchedCapValue(), UnTouched_wValue
    Dim bIndex As Byte                                      ' The index for the default (untouched)
'
' Get X amount of touch readings to counteract the averaging routine
'
    For bIndex = cTouch_AverageCount + 10 DownTo 0
        Touch_wResult = Get_CapTouch()                      ' Get a capacitance touch value
        DelayMS 5
    Next
'
' Fill an array with touch values
'
    For bIndex = cUnTouchedSamplesToTake DownTo 0           ' Create a loop for the cap touches to take
        Touch_wResult = Get_CapTouch()                      ' Get a capacitance touch value
        UnTouched_wSamples[bIndex] = Touch_wResult
        'HRSOutLn "Untouched = ", Dec Touch_wResult
        DelayMS 5
    Next
    UnTouched_wValue = UnTouched_MedianFilter()             ' Median filter the capacitance values
EndProc

'--------------------------------------------------------------------------------------------------------------------------
' Check for a touch
' Input     : None
' Output    : tTouched is true if a touch is detected
' Notes     : Uses a threshold for detecting a touch
'
Proc Get_Touch(), tTouched
    tTouched = False                                                    ' Default to not touched
    Touch_wResult = Get_CapTouch()                                      ' Get a capacitance reading
    'HRSOutLn "Untouched = ", Dec UnTouched_wValue, " : Touched = ", Dec Touch_wResult
    If Touch_wResult < UnTouched_wValue - cTouchThreshold  Then         ' Is the reading less than the threshold
        DelayMS 100                                                     ' Yes. So wait a while to make sure it is a touch
        Touch_wResult = Get_CapTouch()                                  ' Get another capacitance reading
        If Touch_wResult < UnTouched_wValue - cTouchThreshold Then      ' Is the result still less than the untouched value?
            HRSOutLn "Untouched = ", Dec UnTouched_wValue, " : Touched = ", Dec Touch_wResult
            tTouched = True                                             ' Yes. So signal a touch
        EndIf
    EndIf
EndProc

'-------------------------------------------------------------------------------------------------------------------------------------------
Touch_Main: