Interruptus Frustratus


+ Reply to Thread
Results 1 to 17 of 17
  1. #1
    Join Date
    Jan 2009
    Location
    California, USA
    Posts
    323

    Default Interruptus Frustratus

    I'm having a hard time again...

    My interrupts seem to be taking over, and my main loop never gets executed.

    The project I'm working on controls a few simple outputs based on some user input , some machine inputs, and the real time from a DS1302.

    The user input comes from the "touch sensors" available in the 16F727. The time (minutes and seconds only) and other numeric info are displayed on a 4 digit, 7-segment LED display.

    The touch sensors use Interrupts based on TMR1 and TMR0.

    I had much of my program working until I added the touch sensor routine, then everything went to hell....

    I've trimmed my code back to just the touch sensor and RTC code trying to get it to work. The problem is that the interrupts seem to "take over the show" and my main loop never gets executed.

    This bit of test code should display the "ones of minutes" and the tens and ones of seconds on a LED display.

    When a sensor button is touched, the number of the button pressed should be momentarily displayed on the 4th digit of the display.

    The problem is that while the touch sensors work fine and the appropriate number is displayed when touched, the time is *not* displayed because the main loop is never executed. If I disable the interrupts so that the touch sensors don't work, then the main loop is executed and the time is displayed just fine.

    Why does the interrupt routine highjack the show and keep the main loop from executing?

    Here's the bit of test code that I'm working with... any suggestions would be a appreciated.
    It's a little too big, so I'll split it into 2 posts....

    Code:
    '****************************************************************
    
    Include "MODEDEFS.BAS"   ' Include Shiftin/out modes
    INCLUDE "DT_INTS-14.bas"  ' Base Interrupt System
    INCLUDE "ReEnterPBP.bas"  ' Include if using PBP interrupts
    DEFINE LCD_DREG PORTD    ' Set LCD Data port
    DEFINE LCD_DBIT 4        ' Set starting Data bit (0 or 4) if 4-bit bus
    DEFINE LCD_RSREG PORTC   ' Set LCD Register Select port
    DEFINE LCD_RSBIT 5       ' Set LCD Register Select bit
    DEFINE LCD_EREG PORTC    ' Set LCD Enable port                                                   
    DEFINE LCD_EBIT 6        ' Set LCD Enable bit
    DEFINE LCD_BITS 4        ' Set LCD bus size (4 or 8 bits)
    DEFINE ADC_BITS 8        ' Set number of bits in ADC result
    DEFINE ADC_CLOCK 3       ' Set clock source for ADC (rc = 3)
    DEFINE ADC_SAMPLEUS 100  ' Set ADC sampling time in microseconds 
    define I2C_SCLOUT 1      ' Set I2C Clock to drive high instead of needing pullup
    DEFINE CCP2_REG PORTC    'Hpwm2 port
    DEFINE CCP2_BIT 1        'Hpwm2 bit
    DEFINE OSC 16            '16 MHz
    
    OSCCON = %00110000       'set OSC to 16 mHz.
    
    @  __config _CONFIG1, _DEBUG_OFF & _PLL_EN & _BORV_2_5 & _BOR_ON & _CP_OFF & _MCLRE_OFF & _PWRT_EN & _WDT_ON & _INTOSCIO
    @  __config _CONFIG2, _VCAP_RA6
    
    
    TRISA= %00000000     'Set 'em all to outputs 
    TRISB= %11111111   	 'all input
    TRISC= %00011000     'Set portC all outputs except C.3 and C.4
    TRISD= %00000000     'Set portD all outputs
    TRISE= %00000000     'Set portE all outputs
        
    ANSELA= %00000000	 ' Set all pins to digital 
    ANSELB= %11111111    ' all analog
    ANSELD= %00000000    ' Set all pins to digital 
    ANSELE= %00000000    ' Set all pins to digital
    
    CPSCON0 = %10001101  'Cap sense on, high range oscillator
    
    '---------VARIABLES-----------------------------------
    
    'LED Driver (CAT4016) Variables-----------------------
    LEDData var     byte    
    numeral var     byte
    LEDCounter  var byte
    digit1  var     byte : digit1=0
    digit2  var     byte : digit2=0
    digit3  var     byte : digit3=0
    digit4  var     byte : digit4=0
    
    
    'DS1302 RTC Variables-----------------------
    rtcyear  var     byte   
    rtcday   var     byte   
    rtcmonth var     byte   
    rtcdate  var     byte   
    rtchr    var     byte   
    rtcmin   var     byte   
    rtcsec   var     byte
    rtccontrol  var  byte
    mathtemp    var  Byte   'For doing BCD to Decimal conversion
    
    
    'Touch sensor related Variables---------------------- 
    index        var    byte : index=0  'for the CSM buttons
    timercount   var    word[6] : timercount = 0 ' raw count from TMR1, for each channel
    timerave     var    word[6] : timerave = 0 ' long term average of timercount, for each channel
    AvgCount     var    byte : AvgCount = 32 'number of samples to average
    delay        var    word : delay = 0  ' to delay startup until the timers have stabilized.
    
    
    '---------I/O PINS-----------------------------------   
    'Alias pins - DS1302---------------------------------
    RST      var    PORTE.2  '1302 CS
    IO       var    PORTE.1  '1302 I/O
    SCLK     var    PORTE.0  '1302 Clock
    
    'Alias pins - EEPROM---------------------------------
    SDA      var    PORTC.4  'EEPROM data
    SCL      var    PORTC.3  'EEPROM Clock
    
    'Alias pins - LED display----------------------------
    S_IN     var    PORTA.3  'CAT4016 data
    LEDCLK   var    PORTA.2  'CAt4016 clock
    BLANK    var    PORTC.1  'CAT4016 blanking line
    LATCH    VAR    PORTA.0  'Cat4016 Latch
    
    'Initialize variables-------------------------------- 
    hpwm 2,100,1000  'set LED brightness
    timerave = 2000  'preset the timer average to a "close" value
    '-----------------------------------------------------------------
    'Set initial time (this can be removed in final version)
    'rtcyear = $09   'Set Year
    'rtcday = $1    'Set Day
    'rtcmonth = $1  'Set Month
    'rtcdate = $1   'Set Date of month
    'rtchr = $1     'Set Hour
    'rtcmin = $1    'Set Minutes
    'rtcsec = $1    'Set Seconds
    'Gosub settime   ' DO IT! - Set the time
    
     '--------------------------------------------------------------------------------
    'initialize the DS1302 and set the trickle charge rate
    Low SCLK
    low rst        ' Reset RTC
    high rst       ' RTC Ready for transfer        
    Shiftout IO, SCLK, LSBFIRST, [$8e, 0]  ' Enable write
    low rst        
    high rst
    Shiftout IO, SCLK, LSBFIRST, [$90, %10101011]  ' Set charger on and to "2 diodes, 8Kohm"              
    Low RST         ' Reset RTC
    pause 5
    
    ' -----Grab the time out of the RTC and display it--------------------------
    gosub gettime
    gosub sortdigits
    pause 1000 
    
    '-----Set up Interrrupts--------------------------------------------
    ASM
    INT_LIST  macro    ; IntSource,        Label,  Type, ResetFlag?
            INT_Handler   TMR1GATE_INT,  _CheckCount,   PBP,  yes
         endm    
        INT_CREATE               ; Creates the interrupt processor
    ENDASM
    
    @ INT_ENABLE  TMR1GATE_INT     ; enable Timer1 gate interrupt
    
    
    '----- Timer Setup------------------------------------------------
    OPTION_REG = %11010110    'setup source and prescaler for TMR0
    INTCON.2 = 0; // clear TMR0 interrupt flag
    INTCON.5 = 1; // enable TMR0 interrupt
    T1CON = %11000101 'Timer clock source=CAPOSC, prescale=1:1, dedicated OSC disabled, no external clock synchronize, timer on
    T1GCON = %11100001 'Timer1 gate init/ Toggle Mode
    PIR1.7 = 0   'Clear Gate Interrupt Flag
    
    
    '----------JUST GET IT GOING-------------------
    GOTO Main  'skip the subroutines and get on with it.
    Finish below....

  2. #2
    Join Date
    Jan 2009
    Location
    California, USA
    Posts
    323

    Default

    ....Continued from above.

    Code:
    '---[TMR1 Gate - interrupt handler]--------------------------------------------------
    disable   
    CheckCount:
            T1CON.0 = 0   'stop timer1
            timercount[index] = TMR1L + TMR1H << 8   'stuff the contents of the timer register into a word    
            TMR1L = 0     'reset counter to 0...
            TMR1H = 0     'upper 1/2 too
    
            If delay < 1001 then    'delay user access to the buttons until the count "average" has stabilized.
                delay = delay +1        
            endif    
        
            If timercount[index] > timerave[index] +70 then  'Help provide a speedy recovery for released buttons
                timerave[index] = timercount[index]
            endif
                 
            if (timercount[index] - timerave[index]) < AvgCount Then Close
            timerave[index] = timerave[index] - (timerave[index]/AvgCount)    'average the count so you have a reference to compare....
            timerave[index] = timerave[index] + (timercount[index]/AvgCount)  '...with timercount
            Goto checkscore
        
            Close:
                timerave[index] = timerave[index] - (timerave[index]/(AvgCount/16))   
                timerave[index] = timerave[index] + (timercount[index]/(AvgCount/16))    
        
            Checkscore:       'Determine if a button is pressed (count is less than average)        
                If timerave[index] - (timerave[index] /50) > timercount[index] and (delay > 1000) then 
                   gosub ServiceHardw 'Signal that a button is pressed. 
                endif
            
            If index < 5 then     'Increment to the next touch sensor input
               index = index +1
            else
                index = 0
            Endif
            CPSCON1 = index
         
            TMR0 = 0       'reset timer 0              
            T1CON.0 = 1  'restart timer1
     
    @ INT_RETURN
    enable
    
    
    '----------SUBROUTINES--------------------------------
    'Subroutine for Button 1-----------------------------
    Butt1:
            Digit4 = 1
            gosub sortdigits
            Pause 500
            digit4 = 0
            gosub sortdigits
    Return
    
    
    'Subroutine for Button 2-----------------------------
    Butt2:
            Digit4 = 2
            gosub sortdigits
            Pause 500
            digit4 = 0
            gosub sortdigits
    Return
    
    
    'Subroutine for Button 3-----------------------------
    Butt3:
            Digit4 = 3
            gosub sortdigits
            Pause 500
            digit4 = 0
            gosub sortdigits
    Return
    
    
    'Subroutine for Button 4-----------------------------
    Butt4:
            Digit4 = 4
            gosub sortdigits
            Pause 500
            digit4 = 0
            gosub sortdigits
    
    Return
    
    
    'Subroutine for Button 5-----------------------------
    Butt5:
            Digit4 = 5
            gosub sortdigits
            Pause 500
            digit4 = 0
            gosub sortdigits
    Return
    
    
    'Subroutine for Button 6-----------------------------
    Butt6:
            Digit4 = 6
            gosub sortdigits
            Pause 500
            digit4 = 0
            gosub sortdigits
    Return
    
    
    'Subroutine to display numbers on 7-segment display-----------
    display:
              shiftout S_in, LEDCLK, 1, [LEDData]
    return
    
    
    'Subroutine to map numbers to the correct LED segments------
    getpattern:  
           lookup numeral,[$EE,$28,$CD,$6D,$2B,$67,$E7,$2C,$EF,$6F], LEDData 'MSBFirst / Right side up digits
    return
    
    
    'Subroutine to read time from RTC--------------------              
    gettime:  
            RST = 1         ' Ready for transfer
            ' Read all 8 RTC registers in burst mode
            Shiftout IO, SCLK, LSBFIRST, [$bf]      
            Shiftin IO, SCLK, LSBPRE, [rtcsec, rtcmin, rtchr, rtcdate, rtcmonth, rtcday, rtcyear, rtccontrol]
            RST = 0         ' Reset RTC 
            mathtemp =(rtcsec>>4)*10+(rtcsec & $0F)  'convert BCD seconds into Decimal seconds 
            digit1 = mathtemp dig 0   'digit 1 = ones of seconds
            digit2 = mathtemp dig 1   'digit 2 = tens of seconds     
            mathtemp =(rtcmin>>4)*10+(rtcmin & $0F)  'convert BCD minutes into Decimal minutess 
            digit3 = mathtemp dig 0   'digit 3 = ones of minutes
    '        digit4 = mathtemp dig 1
            gosub sortdigits              
    Return
    
    
    'Subroutine to sort out the buttons-------------------
    ServiceHardw:
            branchl index, [Butt1,Butt2,Butt3,Butt4,Butt5,Butt6]
    return
    
    
    ' Subroutine to write time to RTC------------------------        
    settime: 
            RST = 1         ' Ready for transfer
            Shiftout IO, SCLK, LSBFIRST, [$8e, 0]  ' Enable write
            RST = 0         ' Reset RTC
            RST = 1         ' Ready for transfer
                ' Write all 8 RTC registers in burst mode
            Shiftout IO, SCLK, LSBFIRST, [$be, rtcsec, rtcmin, rtchr, rtcdate, rtcmonth, rtcday, rtcyear, 0]
            rst = 0        
    Return 
    
    
    'Subroutine to lookup numbers and put them in the correct LED digit-----------
    sortdigits:  
            numeral = digit4   
            gosub getpattern
            swap LEDData.0, LEDdata.4   'Swap "DP" and "G" segments on upsidedown digits
            gosub display    
            numeral = digit3
            gosub getpattern
            LEDData.4 = 1       'Turn on lower DP in colon
            gosub display    
            numeral = digit2
            gosub getpattern
            swap LEDData.0, LEDdata.4   'Swap "DP" and "G" segments on upsidedown digits
            LEDData.0 = 1      'Turn on upper DP in colon
            gosub display    
            numeral = digit1
            gosub getpattern
            gosub display
           High Latch
           pause 1
           low Latch
    return
    
          
    'Main loop - Gets the time and displays it----------------------------------        
    main:   
            gosub gettime
            gosub sortdigits
            pause 100              
            Goto main   ' repeat until nauseated...
    
    End

    Thanks!

    Steve

  3. #3
    Join Date
    May 2004
    Location
    NW France
    Posts
    3,555

    Talking

    Hi,

    I didn't know DT interrupts were using Enable and Disable Commands ...

    Alain

    Coïtus interruptus frustrans est ...
    ************************************************** ***********************
    Why insist on using 32 Bits when you're not even able to deal with the first 8 ones ??? ehhhhhh ...
    ************************************************** ***********************
    IF there is the word "Problem" in your question ...
    certainly the answer is " RTFM " or " RTFDataSheet " !!!
    *****************************************

  4. #4
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959

    Default

    Code:
    INTCON.5 = 1; // enable TMR0 interrupt
    There's no handler for the TMR0 interrupt.

    So the flag for that interrupt never gets cleared.
    It then continuously enters/exits the interrupt processor, never to see the light of day again.

    Added: And Alain is correct. disable/enable has no effect on DT_INTS.
    <br>
    Last edited by Darrel Taylor; - 8th April 2009 at 07:43. Reason: Added:
    DT

  5. #5
    Join Date
    Nov 2005
    Location
    Bombay, India
    Posts
    875

    Default

    Steve

    Code:
         
    Checkscore:       'Determine if a button is pressed (count is less than average)        
                If timerave[index] - (timerave[index] /50) > timercount[index] and (delay > 1000) then 
                   gosub ServiceHardw 'Signal that a button is pressed. 
                endif
    Your call to gosub ServiceHardw is the culprit. It nests other subroutines. This is what may be consuming the time. I can recommend you replace the call to gosub ServiceHardw with a bit variable getting set. You then check the bit variable in your mainline code to decide if you need to serviceHardw. It will definitely yield results.

    Code:
         Checkscore:       'Determine if a button is pressed (count is less than average)        
                If timerave[index] - (timerave[index] /50) > timercount[index] and (delay > 1000) then 
                   ServiceHw=1
                endif
    In your main, put this
    Code:
    ServiceHw var  bit        ' declarations section
    
                If ServiceHw then gosub ServiceHw

    Jerson

  6. #6
    Join Date
    Jan 2009
    Location
    California, USA
    Posts
    323

    Default

    Alain, Darrel, Jerson, thanks very much! You guys are great!

    Sooo... if "Disable" & "Enable" don't work with DT_INT, what keeps interrupts from occurring during the interrupt handler? I assume that DT_INT must "protect" it's own handler?

    Is there a way for me to disable the interrupts during certain subroutines?
    When I get the rest of this put together there will be several places where I need to kill the interrupts to perform time sensitive tasks. Is that possible using DT_INT ?
    Do I simply turn the interrupts on and off with the GIE bit when I want to? (INTCON.7 = 0) ?

    Darrel, thanks for catching the TMR0 interrupt with no handler. I don't know why I keep doing that. I had to change the Timer resource from TMR2 to TMR0 and I enabled it's interrupt unnecessarily. Thanks! Turning TMR0 interrupt off helped but didn't completely cure the problem.

    Jerson, please print yourself a pretty gold star and pin it to your shirt for the day!
    The call to gosub "ServiceHardw" was indeed the big culprit. I assume that I just had so much stuff inside my interrupt handler that I ran out of time to do anything else before the next interrupt ?
    I set a bit to tell when a button is pressed and check it in my main code as you suggested, and it works MUCH better now!

    There's clearly a few bugs still to work out before I start adding the rest of my code back in, but it's looking pretty hopeful now.

    Thanks again to all of you. What a great resource!


    Steve

  7. #7
    Join Date
    Sep 2004
    Location
    montreal, canada
    Posts
    6,898

    Default

    Enable/Disable are for PBP ON INTERRUPT GOTO

    For DT-INTS you have
    @ INT_ENABLE IntSource
    and
    @ INT_DISABLE IntSource

    You could disable all interrupt by clearing INTCON GIE too. Used with care this could work.
    Steve

    It's not a bug, it's a random feature.
    There's no problem, only learning opportunities.

  8. #8
    Join Date
    Nov 2005
    Location
    Bombay, India
    Posts
    875

    Default

    Quote Originally Posted by Byte_Butcher View Post
    Alain, Darrel, Jerson, thanks very much! You guys are great!
    ...snip...
    Jerson, please print yourself a pretty gold star and pin it to your shirt for the day!
    ...snip...
    Thanks again to all of you. What a great resource!
    Steve
    Wow, I am thrilled for that. Thank you. I'm sure many more will learn from your problem as they browse this resource. I myself have used this website to learn from DT, Steve (bow) many times before I began to return the favour. It's my hope that you will be able to soon. :thumbs up:

  9. #9
    Join Date
    Jan 2009
    Location
    California, USA
    Posts
    323

    Default

    Quote Originally Posted by mister_e View Post
    Enable/Disable are for PBP ON INTERRUPT GOTO

    For DT-INTS you have
    @ INT_ENABLE IntSource
    and
    @ INT_DISABLE IntSource

    You could disable all interrupt by clearing INTCON GIE too. Used with care this could work.
    AHA! Thanks Steve!

    When using @ INT_DISABLE to protect a subroutine, does it also protect nested gosubs, or do I need to disable interrupts in each nested subroutine to protect them all from interrupt?

    Thanks!

  10. #10
    Join Date
    Sep 2004
    Location
    montreal, canada
    Posts
    6,898

    Default

    It protect what's in between DISABLE and ENABLE, so yes if your Gosub are in between them, they will be "protected" as well.
    Steve

    It's not a bug, it's a random feature.
    There's no problem, only learning opportunities.

  11. #11
    Join Date
    Jan 2009
    Location
    California, USA
    Posts
    323

    Default

    Quote Originally Posted by mister_e View Post
    It protect what's in between DISABLE and ENABLE, so yes if your Gosub are in between them, they will be "protected" as well.
    Excellent. Thanks!




    Steve

  12. #12
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959

    Default

    Woohoo! Go TEAM Go!

    And just to add more info ...
    When a 16F PIC is servicing an interrupt, no other interrupts can occur until the current one is finished. The GIE bit is cleared automatically by hardware at the start of the interrupt. Global ints are then re-enabled when it executes a RETFIE (return from interrupt) at the end of the handler.

    So there's no need to try to keep a handler from being interrupted, because it can't.

    With ON INTERRUPT, the actual Hardware INTERRUPT was serviced long before it gets to the handler, so you need to disable/enable with those.
    DT

  13. #13
    Join Date
    Jan 2009
    Location
    California, USA
    Posts
    323

    Default

    Shucks, last week I cudnt even spel PIC, and now I are programin one!

    Data Sheets and Application Notes are wonderful things, but sometimes there's no substitute for a good teacher(s) to help explain things, fill in the details, or to just shove me over a hurdle that I can't find my way around...

    I really appreciate ALL the folks who've taken time to help... but especially Darrel for creating good things like DT_INTS and then having the patience to put up with all the silly questions we newbies will certainly have about it!
    THANKS!

    It's been a good day. I learned a lot.


    Steve

  14. #14
    Join Date
    Jan 2009
    Location
    Miami, Florida USA
    Posts
    626

    Default

    Hi all,
    I've been working in a project similar to byte_butcher's but using PBP only (I don't know any MPASM). My touch buttons work nicely but when I try to use GOSUB inside the ISR routine somehow PBP doesn't like it. I have my sub-routines outside the Disable-Enable of the ISR routine but it doesn't work.

    Am I missing something here?? Darrel said it is posible to call sub-routines when the interrupts are disable.

    Thanks in advance for any help.

    Robert

  15. #15
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959

    Default

    Quote Originally Posted by rsocor01 View Post
    ... My touch buttons work nicely but when I try to use GOSUB inside the ISR routine somehow PBP doesn't like it. I have my sub-routines outside the Disable-Enable of the ISR routine but it doesn't work.
    If you are putting DISABLE/ENABLE around your interrupt handler ...
    can I assume you are using ON INTERRUPT?

    With ON INTERRUPT, the handler and any subroutines called by the handler MUST be inside DISABLE/ENABLE directives.

    But if at all possible, GOSUB's should be avoided entirely in any interrupt handler.
    <br>
    DT

  16. #16
    Join Date
    Jan 2009
    Location
    Miami, Florida USA
    Posts
    626

    Default

    Thank you Darrel. That solves part of my problems in this project I'm working on.

    Robert

  17. #17
    Join Date
    Jan 2009
    Location
    Miami, Florida USA
    Posts
    626

    Default

    Attached is some of my code (without all the other stuff that nobody cares about) of the Capacitive Sensing Module (CSM) that I'm working on. My project is similar to Byte_Butcher's but I'm only using PBP. There is still some work to be done like having some arrays would be nice, but so far the touch pads work fine.

    Code:
    '****************************************************************
    '*         DEFINING VARIABLES AND SETTING INITIAL VALUES        *
    '****************************************************************
    	
    DEFINE OSC          4       	    'Define Oscillator to 4MHz 
    
    I               VAR WORD
    TRIP            VAR BYTE
    STABILIZE_CSM   VAR BYTE            'VARIABLE USED TO LET MCU STABILIZE CSM 
    BUTTON          VAR BIT 
    START_PROGRAM   VAR BIT             'ONLY USED AT START OF PROGRAM (=0 NO BUTTONS TOUCHED YET)
    RAW_0           VAR WORD
    RAW_1           VAR WORD
    AVERAGE_0       VAR WORD
    AVERAGE_1       VAR WORD
    LED_0           VAR PORTB.6
    LED_1           VAR PORTB.7
    
    TEST_VAR        VAR BYTE 
    
    STABILIZE_CSM = 2                   'LET CSM RUN 2 TIMES BEFORE TAKING READINGS
    TRIP = 50                           'TRIP USED AS (1/50)*(AVERAGE)
    
    LED_0 = 0                           'LEFT BUTTON LED 
    LED_1 = 0                           'RIGHT BUTTON LED 
    
    RAW_0 = 0
    RAW_1 = 0          
    AVERAGE_0 = 0
    AVERAGE_1 = 0       
    
    BUTTON = 0                          'START WITH BUTTON 0 (LEFT)
    
    TEST_VAR = 0
    
    '****************************************************************
    '*         CAPACITIVE SENSING MODULE INITIALIZATION             *
    '****************************************************************
    TRISA = %00000000           'Initialize ports as outputs
    ANSELA = %00000000          'Initialize as digital ports
    TRISB = %00010001           'Initialize PortB.0 and PortB.4 as inputs.
    ANSELB = %00010001          'Initialize CPS4 and CPS0 as analog inputs.   
    TRISD = %00000000           'INITIALIZE ALL PORTS AS OUTPUTS 
    ANSELD = %00000000          'INITIALIZE ALL PORTS AS DIGITAL PORTS
    TRISC = %10000000           'INITIALIZE RC7 AS INPUT (SERIAL RX)
    
    CPSCON0 = %10001111         'CAPACITIVE SENSING MODULE IS ON. OSCILLATOR IS IN HIGH RANGE.
    CPSCON1 = %00000000         'BITS 3-0, 0000= RB0/CPS0 IS THE CAPACITIVE INPUT CHANNEL.    
    
    
    '****************************************************************
    '*         TMR0 TIME BASE SETUP                                 *
    '*         ENABLE TMR0 TIMER INTERRUPTS                         *
    '****************************************************************
    OPTION_REG = %11100011       'Bit 2-0, 011= prescaler rate 1:16 (TMRO INTERRUPTS EVERY 4.096 mSec)
    INTCON = %01100000	     'enable TMR0 interrupts. enables all unmasked peripheral interrupts
    T1CON = %11000101            'Timer1 initialization
    T1GCON = %11100001           'Timer1 gate init /Toggle Mode/TMR0 time base
    PIR1.7 = 0                   'Clear Gate Interrupt Flag. Timer1 gate is active (TMR1GIF BIT)
    PIE1.7 = 1                   'Disable the Timer1 Gate Acquisition complete interrupt (TMR1GIE BIT)
                                 
    TMR0 = 0	             'TMR0 overflows every (256-TMRO)*(Prescaler rate)(4*(1/4)uS)=4096uSec.
                                
    ON INTERRUPT GOTO ISR
    INTCON = %10100000           'Enable Interrupts
    
    
    '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    '<                       MAIN PROGRAM                           >
    '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    
    START:
        '0= PROGRAM HASN'T STARTED YET. 1= PROGRAM STARTED ALREADY (TOUCH BUTTON DETECTED).
        START_PROGRAM = 0
                 
        WHILE START_PROGRAM = 0
            PAUSE 1
        WEND
    
    MAIN:    
        FOR I = 1 TO 200
            PAUSE 1           
        NEXT I        
    GOTO MAIN
    
    
    '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    '<                   INTERRUPT ROUTINE ISR                      >
    '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    DISABLE			        'Disable further interrupts
    ISR:    
        T1CON.0 = 0                 'Stop/Clears Timer1 before reading TMR1
        
        IF BUTTON = 0 THEN RAW_0.BYTE0 = TMR1L : RAW_0.BYTE1 = TMR1H 
        IF BUTTON = 1 THEN RAW_1.BYTE0 = TMR1L : RAW_1.BYTE1 = TMR1H   
                
        IF STABILIZE_CSM <> 0 THEN
            STABILIZE_CSM = STABILIZE_CSM - 1           'RUN CSM 2 TIMES BEFORE TAKING A READING 
            IF BUTTON = 0 THEN AVERAGE_0 = 0
            IF BUTTON = 1 THEN AVERAGE_1 = 0
        ENDIF
        
        'STABILIZING AVERAGE IF RAW OVERSHOOTS DURING STARTUP.
        IF BUTTON = 0 THEN
            IF AVERAGE_0 > (RAW_0 + 600) THEN AVERAGE_0 = 0
        ENDIF
        IF BUTTON = 1 THEN
            IF AVERAGE_1 > (RAW_1 + 600) THEN AVERAGE_1 = 0
        ENDIF    
        
        'SIMPLE DETECTION. IF RAW < AVERAGE*(1-2.0%)
        IF BUTTON = 0 THEN
            IF RAW_0 < (AVERAGE_0 - (AVERAGE_0/TRIP)) THEN         
                LED_0 = 1
                PAUSE 500
                LED_0 = 0
            
                AVERAGE_0 = 0               'AVOIDS SECOND FALSE READINGS 
                STABILIZE_CSM = 2           'HELPS STABILIZE CSM TO AVOID FALSE READINGS 
                START_PROGRAM = 1              'ONLY USED AT START OF PROGRAM (=0 NO BUTTONS TOUCHED YET)
                BUTTON = 1                  'SWAP BUTTON BIT 
                CPSCON1 = %00000100         'CHANGE BUTTON CAPACITIVE INPUT CHANNEL
            ELSE
                AVERAGE_0 = RAW_0
                CPSCON1 = %00000000
            ENDIF
        ELSE
            IF RAW_1 < (AVERAGE_1 - (AVERAGE_1/TRIP)) THEN         
                LED_1 = 1
                PAUSE 500
                LED_1 = 0
            
                AVERAGE_1 = 0               'AVOIDS SECOND FALSE READINGS 
                STABILIZE_CSM = 2           'HELPS STABILIZE CSM TO AVOID FALSE READINGS 
                START_PROGRAM = 1           'ONLY USED AT START OF PROGRAM (=0 NO BUTTONS TOUCHED YET)
                BUTTON = 0                  'SWAP BUTTON BIT 
                CPSCON1 = %00000000         'CHANGE BUTTON CAPACITIVE INPUT CHANNEL
            ELSE
                AVERAGE_1 = RAW_1
                CPSCON1 = %00000100
            ENDIF
        ENDIF        
    
               
        TMR1L = 0               'Reset Timer1
        TMR1H = 0
        T1CON.0 = 1             'Restart/Enable Timer1 (TMR1ON BIT)
        TMR0 = 0                'RESET TMR0 TO 0 
        INTCON.2 = 0		    'Re-enable TMR0 interrupts. Bit 2, 0= clears overflow, 1= overflow ocurred 
    
        RESUME				    'Return to main program
        ENABLE				    'Enable interrupts        
    
    
     END				        ' End of program
    One of the differences that I can see between my program and Byte_Butchers is OPTION_REG.5. I have it set to one and Byte_Butcher's have it cleared. OPTION_REG.5 set to one means that the TMR0 clock source is the CPSOSC signal and if cleared means the clock source is the internal instruction cycle clock. It works either way because I have tried it. However, AN1171 "CSM using PIC16F72x" and the datasheet suggests to clear this bit, so I guess that would be the right thing to do.

    Another difference between the two programs is CPSCON0.1. If set to 1 means the oscillator is sourcing current out of the pin and if cleared means the opposite. Again, It works either way but I don't know what would be the right way.

    By experimenting with the program and displaying the different variables in the PC monitor through a serial connection I could come up with the above detection algorithm, which I can say it's pretty accurate (so far).

    Finally, I want to say that testing this kind of CSM circuits on a breadboard (like I did) and using two adjacent pins on the MCU for CSM detection (like I also did) is not a very good idea. If you do that there will be some crosstalk interference between the two touch pads and touching one button will activate the other one. Apparently a breadboard is not good for this kind of circuits.

    Robert

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts