View Full Version : Multi-Button CSM with Pic16LF722A
  
RWright
- 11th May 2016, 21:24
Hi!
Well, I started a new thread, as not to confuse it with another previously posted thread concerning a PIC12F1822 and CSM application.
I have an application that I want to use 3 capacitive touch buttons for brightness up, brightness down, and a firmware 1/0  "on/off" button for full on and full off.
I have attached my code thus far.  It works fairly well, although I would like the on off function to be latching, where the up/down can be held to step up and down in each direction.  Currently the on/off function toggles at the same rate I am repeating the up/down function. 
'************************************************* ***************'*  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                                                *
'*  Name    : LS1236_1Z.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"     ' Included for use of CPS module interrupt
                             ' Courtesy of Derrel Taylor, PBP Wizard!
Include "modedefs.bas" 
                             
           
OSCCON = %00010000      'SETS INT OSC TO 4Mhz
WPUB = %00000000        'DISABLES WEAK PULL-UP BITS
ANSELB = %00111111      'SETS INPUTS B0-B5 AS ANALOG
TRISB = %00111111       'SETS INPUTS B0-B5 AS INPUTS
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 when TMR0 overflow occurs
pause 100                                           ; PAUSE TO GET TIMER 1 COUNT
' store away the present timer1 count for the next time we come into the interrupt routine
CPSX_PRESENT = TMR1                                 ' get 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
- 12th May 2016, 00:05
to answer your questions from the other thread
Okay. But if the timer0 source works for Heckler, why won't it work in mine? 
different chip different osc speed  @4mHz  the tmr0 int is every 65mS  the tmr1 conter may overflow , the actual free run count needs to be established and the timebase adjusted to suit
 
I thought the 100mS pause was the period that the count from timer 1 is occurring?
no the count occurs during gate interval produced by tmr0
What is happening with CPSCON1 =CPSCON1 ^ 1? 
i had used chs 2 and 3    2^1=3  3^1=2 an easy way to toggle between chs
Is the THRESH a fixed value predetermined? Just wondering where the THRESH CON 4000 comes from. Thanks. 
yes its derived by experiment and measurement ,don't you just love magic numbers
 
It does appear to be simpler when you know what you are doing! What is happening in the ccp1con=12|((PW&3)<<4) statement? 
using 10 bit pwm  thats how to set the 2 low order bits
 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? 
PIC16F722A has no latch registers so just use portb
try something like this
'************************************************* ***************
'*  Name    : CAPSENSE.BAS                                      *
'*  Author  : RICHARD                                           *
'*  Notice  : Copyright (c) 2011 [select VIEW...EDITOR OPTIONS] *
'*          : All Rights Reserved                               *
'*  Date    : 10/20/2011                                        *
'*  Version : 1.0                                               *
'*  Notes   :                                                   *
'*          :     16LF722A                                     *
 '                                                              *
'************************************************* ***************
 
'#DEFINE DBUG 1                            
#CONFIG
         __config _CONFIG1, _INTRC_OSC_NOCLKOUT & _WDTE_OFF & _BOR_OFF & _PLLEN_ON
#ENDCONFIG
define OSC 4
include "dt_ints-14.bas"
include "REENTERPBP.bas"
'      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
asm
INT_LIST macro
      INT_HANDLER T1GATE_INT, _TB1, PBP,YES
      endm
      INT_CREATE
ENDASM
 
 THRESH CON 8000   'needs to be established
 
 FLG     VAR BYTE    'GOT A KEY 
 KP      VAR BYTE     'WHICH KEY  pressed
 key_inx var byte     ;key index
 PW      VAR WORD   ; PULSEWIDTH
 
DEFINE DEBUG_REG PORTB
DEFINE DEBUG_BIT 7         ;pgd
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0             
        
        
   OSCCON = %00010000
   CPSCON0 = %10001100      'high range
   CPSCON1 = 0 'cps ch 0
   ANSELB = %00000111      'SETS INPUTS B0-B2 AS ANALOG
   TRISB = %01111111       'SETS INPUTS B0-B5 AS INPUTS  b7 output
   WPUB = %00000000        'DISABLES WEAK PULL-UP BITS
   TRISC = %11111011        'ccp1 output portc.2
   
   OPTION_REG=$86      'edge int. prescale 1:128
   PIE1.7=1   'timer1 gate interrupt
   T1GCON=$f9    ' single shot timer0 overflow as input
   T1CON=%11000101   'capsense as input no prescale no sync
   INTCON= $C0       'peripheral interrupts
   PW=512
   t2con=7 
   LED VAR portc.2
   ;up                down              off
   ;key0=portb.0=ch0, key1=portb.1=ch1, key2=portb.2=ch2
  
  
    
#IFDEF  DBUG 
    
    portb.7=1
    LED=1 
    pause 2000
    Debug "Start",13 ,10
    LED=0
    pause 500 
#ENDIF 
   ccp1con=12
   CCPR1L=128
   FLG=0 
   key_inx=0
  
 
 
MAIN:
    IF FLG=1 THEN 
        IF KP = 0 THEN
           PW= (PW+64)  MIN 1023
        ELSEif  KP = 1 THEN     
           PW = PW-64
           IF PW.15 THEN PW=0 
         else  'MUST BE THE OTHER ONE 
            ccp1con=0       ;kill it
            led=0
        ENDIF
        CCPR1L = PW>>2;
        ccp1con=12|((PW&3)<<4);
        #IFDEF  DBUG 
            debug "KEY ",#KP,13,10 
            debug #PW,13,10 
        #ENDIF
        PAUSE 300
        FLG=0       'clr    key pressed flag
     ENDIF   
    
GOTO MAIN 
 
            
TB1: 
 #IFDEF  DBUG 
  debug #TMR1,13,10
 #ENDIF
 IF TMR1 <  THRESH  THEN    '   KEY DETECTED  
  if !flg then
   KP=key_inx 
   FLG=1         'set key pressed flag
  endif
 ENDIF
 key_inx=key_inx+1   ;check next key
 if key_inx > 2 then key_inx=0 
 CPSCON1  = key_inx
 TMR1=0
 T1GCON.3= 1 ;single shot reset
  
 
@ INT_RETURN
RWright
- 12th May 2016, 20:33
Wow!  Thanks alot for all of that great info,  much appreciated.  Gives me something to learn from, too.  I'm kind of new to this, so I haven't gotten that advanced, yet.  First time I've had to use
the capacitive touch module.  Again, much appreciated!
RWright
- 17th May 2016, 16:06
Hello again!
If I want to change the order of the keys so that key0 = 1/0 (RB2), key1 = down(RB1), and key2 = up(RB0) do I need to un-remark the
 ;key0=portb.0=ch0, key1=portb.1=ch1, key2=portb.2=ch2 statement and change it, or do I need to change the code in the main portion of the program?
Is there any way I can get the 1/0 button to toggle between off and full pwm, right now I am only getting a momentary break in the pwm when it is touched.
In the debug setup, all I need to do is monitor the pin specified with Serial Communicator or Hyperterminal? 
I still can't believe how simple you made this look compared to my listing posted above.  Thanks again!
richard
- 18th May 2016, 00:35
If I want to change the order of the keys so that key0 = 1/0 (RB2), key1 = down(RB1), and key2 = up(RB0) do I need to un-remark the
 ;key0=portb.0=ch0, key1=portb.1=ch1, key2=portb.2=ch2 statement and change it, or do I need to change the code in the main portion of the program?
comments are just that ,they only serve to show what it is that the programmer decides need an explanation . they don't get compiled or participate in the execution of the code in any way. to change the way the keys are interpreted requires a change the code .
 right now I am only getting a momentary break in the pwm when it is touched
my mistake the pw var should also be set to zero too when killing the light
In the debug setup, all I need to do is monitor the pin specified with Serial Communicator or Hyperterminal 
I use a pickit2 to pgm/debug with ,the debug statements suit my setup .  if you use a real rs232 port to debug then a rs232/ttl level converter needs to be used and the logic level may need to be inverted [rtfm]
Is there any way I can get the 1/0 button to toggle between off and full pwm, 
should be easy     , hint   "FINITE STATE MACHINE"
what did your  "threshold"  count need to be ?
why not explore a "limited slew rate filter" to automatically track and adjust the threshold value . or more reliable yet,  automatically track and adjust the threshold value for each individual key
RWright
- 18th May 2016, 02:18
Hi,
Thanks for the info.  Right now I am using 16000 as a threshold, and it seems to be working well.  I have a pickit2, maybe I'll try that.  I also have a usb to serial in both 3v and 5v versions.  I've been looking at the Microchip application notes concerning touch applications and ran across what you are talking about concerning the threshold value for each key.  Maybe once I get into the debugging, I can determine if I will need to do more than a fixed threshold.  Thanks again!
RWright
- 18th May 2016, 19:47
Hello again,
Okay I got the buttons to work as i wished, and I changed to 4 pwm levels.  However, I have added code to indicate which  of the 4 levels I am currently at.
There is a "pause 300" that you have in the MAIN program area that delays the led indicator change from the time that the button is pressed.  I tried to move the code for the led indicators to a point before the "pause 300", but then the program quits working.  Is this pause what determines the time between steps if a[ button is continuously pressed, or does it serve another purpose?  Another dumb thing, if I want 5 levels plus off, as shown in my previously posted example, how do I do it?  Currently I am using a value of 256 from the original 16 as you had to get 4 steps, but that works out pretty evenly.
What is "if PW.15 then PW=0" doing?  Is it checking bit 15 of PW to be high?  Please see cod attached.
Thanks.
 *
'*          : All Rights Reserved                               *
'*  Date    : 10/20/2011                                        *
'*  Version : 1.0                                               *
'*  Notes   :                                                   *
'*          :     16LF722A                                      *
 '                                                              *
'************************************************* ***************
 
'#DEFINE DBUG 1                            
#CONFIG
         __config _CONFIG1, _INTRC_OSC_NOCLKOUT & _WDTE_OFF & _BOR_OFF & _PLLEN_ON
#ENDCONFIG
define OSC 4
include "dt_ints-14.bas"
include "REENTERPBP.bas"
'      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
asm
INT_LIST macro
      INT_HANDLER T1GATE_INT, _TB1, PBP,YES
      endm
      INT_CREATE
ENDASM
 
 THRESH CON 16000   'needs to be established
 
 FLG     VAR BYTE    'GOT A KEY 
 KP      VAR BYTE    'WHICH KEY  pressed
 key_inx var byte    ;key index
 PW      VAR WORD    ;PULSEWIDTH
 
DEFINE DEBUG_REG PORTB
DEFINE DEBUG_BIT 7         ;pgd
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0             
        
        
   OSCCON = %00010000       '4 mhz
   CPSCON0 = %10001100      'high range
   CPSCON1 = 0              'cps ch 0
   
   
   ANSELB = %00000111       'SETS INPUTS B0-B2 AS ANALOG
   TRISB = %01111111        'SETS INPUTS B0-B5 AS INPUTS  b7 output
   WPUB = %00000000         'DISABLES WEAK PULL-UP BITS
   TRISC = %11111011        'ccp1 output portc.2
   
   OPTION_REG=$86           'edge int. prescale 1:128
   PIE1.7=1                 'timer1 gate interrupt
   T1GCON=$f9               'single shot timer0 overflow as input
   T1CON=%11000101          'capsense as input no prescale no sync
   INTCON= $C0              'peripheral interrupts
   PW=1023
   t2con=7 
   LED1    VAR PORTA.1      ' SET LED LEVEL INDICATORS
   LED2    VAR PORTA.2
   LED3    VAR PORTA.3
   LED4    VAR PORTA.4
   LED5    VAR PORTA.5
    
   LED VAR portc.2
   ;up                down              off
   ;key0=portb.0=ch0, key1=portb.1=ch1, key2=portb.2=ch2
  
  
    
#IFDEF  DBUG 
    
    portb.7=1
    LED=1 
    pause 2000
    Debug "Start",13 ,10
    LED=0
    pause 500 
#ENDIF 
   ccp1con=12
   CCPR1L=255     'SET TO MAX BRIGHTNESS
   FLG=0 
   key_inx=0
  
 
 
MAIN:
    IF FLG=1 THEN 
        IF KP = 0 THEN     '1/0 BUTTON PRESSED
           ccp1con=0       ;kill it
            led=0
            PW=0
            ELSEif  KP = 1 THEN   'UP BUTTON PRESSED  
            PW= (PW+256)  MIN 1023 
            else  'DOWN BUTTON PRESSED
            PW = PW-256    
            IF PW.15 THEN PW=0 
            ENDIF
            CCPR1L = PW>>2;
            ccp1con=12|((PW&3)<<4);
            #IFDEF  DBUG 
            debug "KEY ",#KP,13,10 
            debug #PW,13,10 
            #ENDIF
        
        
        
        PAUSE 300
        FLG=0       'clr    key pressed flag
    ENDIF
        
         IF pw = 1023  THEN
        HIGH LED5
        ENDIF
        IF pw = 768 or PW = 767 THEN
        HIGH LED4
        ENDIF
        IF pw = 512 or PW = 511 THEN
        HIGH LED3
        ENDIF
        IF pw = 256 or  PW = 255 THEN
        HIGH LED2
        ENDIF
        if pw = 0 THEN                               
        high LED1
        endif
   
        
GOTO MAIN 
 
            
TB1: 
 #IFDEF  DBUG 
  debug #TMR1,13,10
 #ENDIF
 IF TMR1 <  THRESH  THEN    '   KEY DETECTED  
  if !flg then
   KP=key_inx 
   FLG=1         'set key pressed flag
  endif
 ENDIF
 key_inx=key_inx+1   ;check next key
 if key_inx > 2 then key_inx=0 
 CPSCON1  = key_inx
 TMR1=0
 T1GCON.3= 1 ;single shot reset
  
 
@ INT_RETURN]
richard
- 19th May 2016, 01:10
There is a "pause 300" that you have in the MAIN program area that delays the led indicator change from the time that the button is pressed. I tried to move the code 
the pause is there to slow the key action to human speeds ,the indicator leds can go in the key pressed loop ok as far as I can see
What is "if PW.15 then PW=0" doing? Is it checking bit 15 of PW to be high? 
with any subtraction if the result is negative (ie overflowed) then the highest order bit of the result is always set.
ps can porta.3  be an output ?   
have a try like this
 
'#DEFINE DBUG 1 
 #CONFIG
 __config _CONFIG1, _INTRC_OSC_NOCLKOUT & _WDTE_OFF & _BOR_OFF & _PLLEN_ON
 #ENDCONFIG
 define OSC 4
 include "dt_ints-14.bas"
 include "REENTERPBP.bas"
 ' 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
 asm
 INT_LIST macro
 INT_HANDLER T1GATE_INT, _TB1, PBP,YES
 endm
 INT_CREATE
 ENDASM
 THRESH CON 16000 'needs to be established
 FLG VAR BYTE 'GOT A KEY 
 KP VAR BYTE 'WHICH KEY pressed
 key_inx var byte ;key index
 PW VAR WORD ;PULSEWIDTH
 p_level var byte
 DEFINE DEBUG_REG PORTB
 DEFINE DEBUG_BIT 7 ;pgd
 DEFINE DEBUG_BAUD 9600
 DEFINE DEBUG_MODE 0 
 OSCCON = %00010000 '4 mhz
 CPSCON0 = %10001100 'high range
 CPSCON1 = 0 'cps ch 0
 ANSELB = %00000111 'SETS INPUTS B0-B2 AS ANALOG
 TRISB = %01111111 'SETS INPUTS B0-B5 AS INPUTS b7 output
 WPUB = %00000000 'DISABLES WEAK PULL-UP BITS
 TRISC = %11111011 'ccp1 output portc.2
 OPTION_REG=$86 'edge int. prescale 1:128
 PIE1.7=1 'timer1 gate interrupt
 T1GCON=$f9 'single shot timer0 overflow as input
 T1CON=%11000101 'capsense as input no prescale no sync
 INTCON= $C0 'peripheral interrupts
 PW=1023
 p_level=5
 t2con=7 
 LED1 VAR PORTA.1 ' SET LED LEVEL INDICATORS
 LED2 VAR PORTA.2
 LED3 VAR PORTA.3  ;?????????????????????????????????
 LED4 VAR PORTA.4
 LED5 VAR PORTA.5
 LED VAR portc.2
 ;up down off
 ;key0=portb.0=ch0, key1=portb.1=ch1, key2=portb.2=ch2
 #IFDEF DBUG 
 portb.7=1
 LED=1 
 pause 2000
 Debug "Start",13 ,10
 LED=0
 pause 500 
 #ENDIF 
 ccp1con=12
 CCPR1L=255 'SET TO MAX BRIGHTNESS
 FLG=0 
 key_inx=0
 MAIN:
 IF FLG=1 THEN 
 IF KP = 0 THEN '1/0 BUTTON PRESSED
 ccp1con=0 ;kill it
 led=0
 p_level=0
 ELSEif KP = 1 THEN 'UP BUTTON PRESSED
 p_level= (p_level+1) min 5 
 ;PW= (PW+256) MIN 1023 
 else 'DOWN BUTTON PRESSED
 p_level= p_level-1
 ;PW = PW-256 
 IF p_level.7 THEN p_level=0 
 ;IF PW.15 THEN PW=0 
 
 
 
 lookup p_level, [0,12,48,218,586,1023],pw  'gamma 1.35,5 levels plus OFF
 CCPR1L = PW>>2;
 ccp1con=12|((PW&3)<<4);
 #IFDEF DBUG 
 debug "KEY ",#KP,13,10 
 debug #PW,13,10 
 #ENDIF
 PAUSE 300
 FLG=0 'clr key pressed flag
 ENDIF
 
 porta=0  ;all leds off
 IF p_level= 5 THEN
 HIGH LED5
 ENDIF
 IF p_level=4 THEN
 HIGH LED4
 ENDIF
 IF p_level=3 THEN
 HIGH LED3
 ENDIF
 IF p_level=2 THEN
 HIGH LED2
 ENDIF
 if p_level=1 THEN 
 high LED1
 endif
ENDIF
 GOTO MAIN 
 TB1: 
 #IFDEF DBUG 
 debug #TMR1,13,10
 #ENDIF
 IF TMR1 < THRESH THEN ' KEY DETECTED 
 if !flg then
 KP=key_inx 
 FLG=1 'set key pressed flag
 endif
 ENDIF
 key_inx=key_inx+1 ;check next key
 if key_inx > 2 then key_inx=0 
 CPSCON1 = key_inx
 TMR1=0
 T1GCON.3= 1 ;single shot reset
 @ INT_RETURN
RWright
- 19th May 2016, 21:32
Hello,
Wow, I can't believe how fast you can do this stuff.  I tried to compile the code above, but I keep getting an [ASM WARNING]  Argument out of range.  Least significant bits used.  (0)  :  Warning[202]  error.  Could it be because lookup only works with 8-bit Constants?  Usually I can tell where the problem is by the line number given, but I can't figure this one out.  Any idea?  Thanks again!  Sorry about the code above not being in the Window.  I think I lost something when I inserted it.
richard
- 20th May 2016, 01:25
QUOTE]Could it be because lookup only works with 8-bit Constants? [/QUOTE]
probably ,  I seldom use lookup(2) , try lookup2
my preferred method is to do it this way on chips that can read their own flash memory
 pw var word ;   pulse width
 pl var byte  ;  power level  0-9
 paddress       var word   ; power level array address
''''''''''''''''''''''''''''''''''''''''
goto overpwm   
my_pwm:
;10 step 0.85 gamma curve   
@ dW 3,6,13,26,50,95,177,328,600,1023 
overpwm:
'''''''''''''''''''''''''''''
@ GetAddress _my_pwm,_paddress  ;get address macro is part of dt_ints-14/18.bas
'''''''''''''''''''''''''''''''''''''
 readcode paddress+pl ,pw  ;  address + offset
Aussie Barry
- 23rd May 2016, 13:16
Hi Richard,
Would you please explain in a little more detail as to how the "GetAddress" section of code works?
Cheers
Barry
VK2XBP
richard
- 23rd May 2016, 13:45
the get address  macro is part of  dt-ints . it places the address of a label in a pbp word var.
this is the actual macro , its already there so why not use it.
ASM
;---[Returns the Address of a Label as a Word]------------------------------
GetAddress macro Label, Wout
    CHK?RP Wout
    movlw low Label          ; get low byte
    movwf Wout
;    movlw High Label         ; get high byte  MPLAB 8.53 killed high
    movlw Label >> 8         ; get high byte
    movwf Wout + 1
  endm
endasm
so 
@ GetAddress _my_pwm,_paddress  
gets the address of my_pwm:   and places it in var   paddress
the data 
my_pwm: 
@ DW 3,6,13,26,50,95,177,328,600,1023 [data stored as an array of 14 bit values]
each  flash memory  address can  hold a maximum 14 bit  piece of data 
i'm using that address plus an offset  to index the array  
readcode paddress+pl ,pw  ;  address + offset
[note pw is a word var]
so if pl= 3
readcode paddress+3, and returns  the value 26
hope that's understandable
ps I might add that in my setup that saves 44 words of code space compared to using lookup2
Aussie Barry
- 24th May 2016, 00:57
Hi Richard,
Thank you for your very clear and concise explanation.
When you store the data, what does "DW" refer to?
In the example you use "@ DW" however in previous code snippets you use "@ dW"
Can you clarify please?
Cheers
Barry
richard
- 24th May 2016, 06:41
In the example you use "@ DW" however in previous code snippets you use "@ dW"
Any line beginning with @  is a statement  for the  assembler to process  [just a shorthand way of ASM--DO STUFF ---ENDASM]
the assembler is usually case  sensitive CARE NEEDS TO TAKEN 
but for Data Directives  like  da db dw etc  it seems to have no problem with the case . I only fix typing if I have to , mpasm doesn't care about the case here so nether do i
 dW == DW == Dw  == [  dw – DECLARE DATA OF ONE WORD]
for more info google mpasm assembler directives
or
http://ww1.microchip.com/downloads/en/DeviceDoc/33014L.pdf
richard
- 24th May 2016, 06:56
in this example  I use indirect addressing to retrieve the data ,but due to the 12f1822 architecture  only the low 8 bits are retrievable .wastes a bit of space but its heaps quicker 
'************************************************* ***************
'*  Name    : ws2812.BAS                                                                              *
'*  Author  : richard                                                                                       *
'*  Notice  :                                                                                                   *
'*          :                                                                                                     *
'*  Date    : 1/11/2016                                                                                  *
'*  Version : 1.0                                                                                            *
'*  Notes   : pic12f1822  @32 mhz 3v3                                                           *
'*          : porta.5 >>>> ws2821 Din                                                             *
'************************************************* ***************
 #CONFIG
cfg1 = _FOSC_INTOSC
cfg1&= _WDTE_ON
cfg1&= _PWRTE_OFF
cfg1&= _MCLRE_ON
cfg1&= _CP_OFF
cfg1&= _CPD_OFF
cfg1&= _BOREN_ON
cfg1&= _CLKOUTEN_OFF
cfg1&= _IESO_ON
cfg1&= _FCMEN_ON
  __CONFIG _CONFIG1, cfg1
cfg2 = _WRT_OFF
cfg2&= _PLLEN_ON
cfg2&= _STVREN_ON
cfg2&= _BORV_19
cfg2&= _LVP_OFF
  __CONFIG _CONFIG2, cfg2
#ENDCONFIG
 bt VAR byte  bank0
 px VAR byte  bank0
 pc var byte bank0   ; number of rgb led to write x3
 pixels  var byte[3]    ;  rgb led  x3
 DURATION  var byte
 
 palette var word    ;address of pallet
 TEMP VAR WORD
 OFFSET VAR WORD     ;pallet index
 
 
   
 goto overpalette   ; green,red,blue data   
 my_palette:     ;  note !!!  inde read can only access the low byte of each  stored  word
 @ dw 100,120,0  ;
 @ dW 0,100,0  ; RED
 @ dW 0,80,0  ;
 @ dW 0,60,0  ;
 @ dW 0,20,0  ;
 @ dW 200,200,0  ;OR
 @ dW 160,160,0  ;
 @ dW 100,100,0  ;
 @ dW 80,80,0  ;
 @ dW 2,5,0  ; 
 @ dW 200,150,0  ;YEL
 @ dW 160,120,0  ;
 @ dW 100,75,0  ;
 @ dW 80,60,0  ;
 @ dW 40,30,0  ; 
 @ dW 150,200,0  ; ?
 @ dW 120,160,0  ;
 @ dW 75,100,0  ;
 @ dW 60,80,0  ;
 @ dW 30,40,0  ; 
 @ dW 120,100,0  ;
 @ dW 160,160,160  ; WH
 @ dW 100,100,100  ;
 @ dW 80,80,80  ;
 @ dW 30,30,30  ;
ASM  
 
;---[Returns the Address of a Label as a Word]------------------------------
GetAddress macro Label, Wout
    CHK?RP Wout
    movlw low Label          ; get low byte
    movwf Wout
    movlw Label >> 8         ; get high byte
    movwf Wout + 1
  endm     
endasm
overpalette :  
 
 goto overasm
   asm
_pram                     ;entry point to read from sram
        movlw   low _pixels
        movwf   FSR0L
        movlw   high _pixels
        movwf   FSR0H 
        goto _nxby
_prom                     ;entry point to read from flash 
        CHK?RP _OFFSET
        MOVE?WW   _OFFSET , FSR0
        BSF FSR0H ,7
_nxby   MOVIW  FSR0 ++
        movwf _px
        MOVLW 8
        movwf _bt
        RLF _px,F
_nxbt   BSF LATA ,5
        BTFSS STATUS,C
        GOTO XX
        NOP
        NOP
        NOP
XX      BCF  LATA ,5
        NOP
        RLF _px,F
        DECFSZ _bt,F
        GOTO _nxbt 
        DECFSZ _pc,F
        GOTO _nxby
        RETURN 
   
endasm
overasm:
 CLEAR
 define OSC 32
 osccon=$f0
 trisa=%011110
 @ GetAddress _my_palette,_palette  ;set pallet address
 
 
loopy: 
 GOSUB FLICKER
 PC=3    ; value is  number of rgb leds X 3 
 call prom
 pause DURATION
 goto loopy
 
 
 
 
FLICKER:
 RANDOM TEMP
 DURATION=TEMP&$7F
 RANDOM TEMP
' temp=0
 OFFSET =(TEMP //25)*3 + palette
RETURN
RWright
- 24th May 2016, 18:06
Hello,
Well after changing some  pause timing and sharing it before and after the indicator LED routine, It seems to be working pretty good now.  However, I still need to be able to use the 1/0 button as a single shot
button where pressing once shuts it down, as you have it, and pressing it again turns it back on with full pwm and level 5 selected, without the 1/0 button looping.  You mentioned a finite machine, but I'm not sure as to how that
applies.  Also, is there a quick way that I can change the pwm frequency to 1Khz, instead of 256?  Thanks.
'************************************************* ***************'*  Name    : CAPSENSE.BAS                                      *
'*  Author  : RICHARD                                           *
'*  Notice  : Copyright (c) 2011 [select VIEW...EDITOR OPTIONS] *
'*          : All Rights Reserved                               *
'*  Date    : 10/20/2011                                        *
'*  Version : 1.0                                               *
'*  Notes   :                                                   *
'*          :     16LF722A                                      *
'*                                                              *
'************************************************* ***************
'#DEFINE DBUG 1 
#CONFIG
 __config _CONFIG1, _INTRC_OSC_NOCLKOUT & _WDTE_OFF & _BOR_OFF & _PLLEN_ON
#ENDCONFIG
define OSC 4
include "dt_ints-14.bas"
include "REENTERPBP.bas"
' 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
asm
INT_LIST macro
     INT_HANDLER T1GATE_INT, _TB1, PBP,YES
     endm
     INT_CREATE
ENDASM
    THRESH CON 16000 'needs to be established
    FLG VAR BYTE 'GOT A KEY 
    KP VAR BYTE 'WHICH KEY pressed
    key_inx var byte ;key index
    PW VAR WORD ;PULSEWIDTH
    p_level var byte
DEFINE DEBUG_REG PORTB
DEFINE DEBUG_BIT 7 ;pgd
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0 
    OSCCON = 010000 '4 mhz
    CPSCON0 = 001100 'high range
    CPSCON1 = 0 'cps ch 0
    ANSELB = 000111 'SETS INPUTS B0-B2 AS ANALOG
    TRISB = 111111 'SETS INPUTS B0-B5 AS INPUTS b7 output
    WPUB = 000000 'DISABLES WEAK PULL-UP BITS
    TRISC = 111011 'ccp1 output portc.2
    OPTION_REG=$86 'edge int. prescale 1:128
    PIE1.7=1 'timer1 gate interrupt
    T1GCON=$f9 'single shot timer0 overflow as input
    T1CON=000101 'capsense as input no prescale no sync
    INTCON= $C0 'peripheral interrupts
    PW=1023
    p_level=5
    t2con=7 
    LED1 VAR PORTA.1 ' SET LED LEVEL INDICATORS
    LED2 VAR PORTA.2
    LED3 VAR PORTA.3  
    LED4 VAR PORTA.4
    LED5 VAR PORTA.5
    LED VAR portc.2
    'up                  down               off
    'key0=portb.0=ch0, key1=portb.1=ch1, key2=portb.2=ch2
#IFDEF DBUG 
    portb.7=1
    LED=1 
    pause 2000
    Debug "Start",13 ,10
    LED=0
    pause 500 
#ENDIF 
    ccp1con=12
    CCPR1L=255 'SET TO MAX BRIGHTNESS
    FLG=0 
    key_inx=0
MAIN:
    IF FLG=1 THEN 
    IF KP = 0 THEN '1/0 BUTTON PRESSED
    ccp1con=0 ;kill it
    led=0
    p_level=0
    ELSEif KP = 1 THEN 'UP BUTTON PRESSED
    p_level= (p_level+1) min 5 
    'PW= (PW+256) MIN 1023 
    else 'DOWN BUTTON PRESSED
    p_level= p_level-1
    'PW = PW-256 
    IF p_level.7 THEN p_level=0 
    'IF PW.15 THEN PW=0 
    endif
 
 
    lookup2 p_level, [0,12,48,218,586,1023],pw  'gamma 1.35,5 levels plus OFF
    CCPR1L = PW>>2;
    ccp1con=12|((PW&3)<<4);
#IFDEF DBUG 
debug "KEY ",#KP,13,10 
debug #PW,13,10 
#ENDIF
    
    
    
    
    PAUSE 50
    FLG=0 'clr key pressed flag
    ENDIF
 
    'SET DISPLAY LEDS ACCORDING TO THE BRIGHTNESS LEVEL
    IF p_level= 5 THEN
    HIGH LED5
    ENDIF
    IF p_level=4 THEN
    HIGH LED4
    ENDIF
    IF p_level=3 THEN
    HIGH LED3
    ENDIF
    IF p_level=2 THEN
    HIGH LED2
    ENDIF
    if p_level=1 THEN 
    high LED1
    endif
    if p_level=0 then
    porta = 0
    ENDIF
        
    PAUSE 250
    
    GOTO MAIN 
TB1: 
#IFDEF DBUG 
debug #TMR1,13,10
#ENDIF
    IF TMR1 < THRESH THEN ' KEY DETECTED 
    if !flg then
    KP=key_inx 
    FLG=1 'set key pressed flag
    endif
    ENDIF
    key_inx=key_inx+1 ;check next key
    if key_inx > 2 then key_inx=0 
    CPSCON1 = key_inx
    TMR1=0
    T1GCON.3= 1 ;single shot reset
@ INT_RETURN
richard
- 25th May 2016, 01:49
Also, is there a quick way that I can change the pwm frequency to 1Khz, instead of 256?  Thanks.
change  t2con=7 to  t2con=5
I still need to be able to use the 1/0 button as a single shot
 button where pressing once shuts it down, as you have it, and pressing it again turns it back on with full pwm and level 5 selected, without the 1/0 button looping
I cannot interpret that request at all
do you mean 
a single shot  , turns it off and it stays off until reset [the real meaning of a single shot]
or 
a toggle  ,  turns it off  if its on and turns it fully  on if its off [ like an on/off .. 0/1 switch]
You mentioned a finite machine
no a finite STATE machine , google it  (p_level  could be the state )
RWright
- 25th May 2016, 02:11
Hi,
Yes, sorry, I guess single-shot wouldn't be a good description.   I do mean a toggle , but without any auto-repeat function, as my earlier version had been.
I meant finite STATE machine.  Been a long day.  Thanks for your patience.   Thanks for the info on the pwm speed.  I have only used the hpwm command under
PBP to set my pwm frequencies and duty cycles in the past, I haven't got down into the nitty-gritty as much as I probably should have to get a better understanding of what's actually happening.
richard
- 25th May 2016, 02:30
you can toggle on/off like this
IF KP = 0 THEN '1/0 BUTTON PRESSED
        ;use  p_level to see what state machine is in  0=off ,non zero = on
        if  p_level then     
            ccp1con=0 ;must be on kill it
            led=0
            p_level= 0
        else         ;must be off  power to max
            p_level= 5
        endif
stoping it repeating too quickly is a bit trickier
a pause that's long enough to allow reaction time would do , its a bit klunky.
the best way is to wait for the key to be released before acting (or repeating the action)
maybe counting  three passes through main loop with flg=0  after an  I/O key press would indicate key is released
and its safe to re-enable the key
richard
- 25th May 2016, 09:12
since the isr TB1 is  an accurate timebase you can
make a new var
 kio_inhibit var byte
modify the I/o key routine
IF KP = 0 THEN '1/0 BUTTON PRESSED
        ;use  p_level to see what state machine is in  0=off ,non zero = on
        if kio_inhibit==0 then
           kio_inhibit=152    ;152*32mS = about 5 seconds
        if  p_level then     
            ccp1con=0 ;must be on kill it
            led=0
            p_level= 0
        else         ;must be off  power to max
            p_level= 5
        endif
       endif
and add this to the isr
if kio_inhibit then
    kio_inhibit =  kio_inhibit -1
    endif
now the I/O key is inhibited for 5 sec after being acted on
I like ART's quote and its so true 
PBP is very well documented, however you’ll notice all examples of command use are also examples of exactly how not to write a cyclic program.
you need to adjust your way of thinking to loops , states  and  flags   . it opens up a whole new vista
RWright
- 25th May 2016, 15:20
Wow, you are awesome.  I'll have to try it out to see what it does.  Thanks!
RWright
- 25th May 2016, 15:47
Hello again,
Was that timestamp of 3:12 as in 3:12AM?!   I did the modification as above.  It works like you explained.   It doesn't cycle now, but the 5-second delay is way too long to be able to
power it up again.  If I change the kio_inhibit value to a shorter value, will it just end up cycling again?  Is there a means that if the 1/0 button is released it resets the counter to zero so that the button can be used immediately again?  The long delay is fine for when the button is being held for an extended period of time.  Thanks!
RWright
- 3rd June 2016, 16:44
Hello again!
Just curious as to why there isn't any reference to the PR2 register in the program, for setting up the PWM?  If I wanted to increase the pwm frequency to 25Khz, I take it I would have to go to a higher oscillator frequency and use different prescaler values?!  Thanks.
richard
- 3rd June 2016, 23:42
Just curious as to why there isn't any reference to the PR2 register in the program, for setting up the PWM?
      flicker is virtually invisible to the human eye for switching frequencies above 50 Hz, switching losses increase with frequency , other than that the frequency is irrelevant . 
      fine control of the pwm frequency is possible using pr2 at the expense of resolution . since the frequency is largely irrelevant why not have maximum resolution
 
If I wanted to increase the pwm frequency to 25Khz, I take it I would have to go to a higher oscillator frequency and use different prescaler values?
      depends on required resolution, @4mHz 25kHz  is possible with 1:1 prescale and pr2=39 , however maximum duty occurs @ pwm_duty_reg = 160 ,  ie pw range is 0 to 160 (instead of 0 to 1023 steps as before)
Aussie Barry
- 4th June 2016, 02:35
Hi All,
Has anyone had any experience with a 2 channel CSM slide switch?
I would like to implement a slide switch rather than an up / down button arrangement to select the PWM output for a LED string.
In my case, the granularity is quite coarse - only eight steps of PWM selection.
Any input would be greatly appreciated.
Cheers
Barry
RWright
- 4th June 2016, 05:05
Hello,
Regarding the flicker, you know this and I know this, however, we are trying to match an existing product that is set at 25khz.  It appears at lower frequencies
it is causing their power supply to make audible noise at the PWM frequency.  And sure enough, at 1khz, at certain pwm levels, we can hear it in the power supply.  I don't have to keep the oscillator at 4khz, but I assume making any changes to the main Oscillator will also affect the touch circuit, as well.  I did see in the pwm section of the datasheet that the resolution drops depending on the oscillator frequency after I posted this.  Thanks again!
RWright
- 4th June 2016, 05:05
Sorry for the repeated post.
richard
- 6th June 2016, 08:25
for barry
Has anyone had any experience with a 2 channel CSM slide switch?
 I would like to implement a slide switch rather than an up / down button arrangement to select the PWM output for a LED string.
 In my case, the granularity is quite coarse - only eight steps of PWM selection.
have now, seems to work nicely
slider as per http://ww1.microchip.com/downloads/en/AppNotes/01250a.pdf
made on ds board the bottom side is unconnected, slider pad are 10mm*40mm the top is grounded
covered with sticky tape (durex for a sniker from the euro's)
see pic
richard
- 8th June 2016, 09:09
a slider design like this on single sided board is worth trying out,i think it would be more sensitive and the board could be painted to encourage the user to slide finger along the horizontal line.  next time i'm doing some chemical etching I will make one [if I remember]
Ioannis
- 8th June 2016, 10:04
Is it necessary to have the ground line in the middle of the two channels? Won't this affect the operation.
Ioannis
richard
- 8th June 2016, 10:26
Is it necessary to have the ground line in the middle of the two channels? Won't this affect the operation.
according to this app note it is
 http://ww1.microchip.com/downloads/e...tes/01250a.pdf (http://ww1.microchip.com/downloads/en/AppNotes/01250a.pdf)
I have not tried without it , the other way is to use  a chevron pattern which has no earth requirement
 but uses more pins [several]
Ioannis
- 8th June 2016, 10:33
OK, yes. It is used toi isolate the two sensors between them.
Thanks,
Ioannis
 
Powered by vBulletin® Version 4.1.7 Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.