PDA

View Full Version : Multi-Button CSM with Pic16LF722A



RWright
- 11th May 2016, 20: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
- 11th May 2016, 23: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, 19: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, 15: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
- 17th May 2016, 23: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, 01: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, 18: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, 00: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, 20: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, 00: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, 12: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, 12: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
- 23rd May 2016, 23: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, 05: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, 05: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, 17: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, 00: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, 01: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, 01: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, 08: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, 14:20
Wow, you are awesome. I'll have to try it out to see what it does. Thanks!

RWright
- 25th May 2016, 14: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, 15: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, 22: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, 01: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, 04: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, 04:05
Sorry for the repeated post.

richard
- 6th June 2016, 07: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, 08: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, 09: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, 09: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, 09:33
OK, yes. It is used toi isolate the two sensors between them.

Thanks,
Ioannis