PDA

View Full Version : How to measure how long I pressed a button ?



fratello
- 27th March 2024, 16:52
Howdy ! I'm back on the forum after some absence (I had some personal problems).
I am trying to develop a project. I use a PIC12F675 with which I read the value of a group of 6 resistors, of different values, individually, to perform 6 specific tasks.
I am attaching the diagram. I am also attaching the code used so far, by which I try, in the first phase, to read if a button was pressed briefly or long, in order to make two different decisions depending on the duration of the press.
I wasted many hours with gemini/chatgpt, none of them managed to identify the problem of the code not working. I tried dozens of options, without any results.
What proved to me, once more, that we are superior (still?) to artificial intelligence, at least in certain aspects.

Can you help me identify and solve the problem? Thank you in advance !



@ __config _XT_OSC & _WDT_OFF & _PWRTE_ON & _MCLRE_ON & _BODEN_ON & _CP_ON

DEFINE OSC 4
INCLUDE "modedefs.bas"
CMCON = 7
TRISIO = %00001001
INTCON = 0
IOC = 0
GPIO = 0
ANSEL = %00110001



' Constante
longpress CON 5000 ' maximum press (5 sec)
shortpress CON 100 ' minimum press

' Variabile

durata var word
PressStartTime var word
overflow_counter_low var word
T1CON = %00000110 ' Prescaler 1:64, activating Timer1
TMR1H = 0 ' Resetam Timer1
TMR1L = 0

GPIO.2 = 0
ADCON0 = %10000001
PAUSEUS 100

Main:

durata = 0
overflow_counter_low = 0


ADCON0.1 = 1
While ADCON0.1 = 1 : Wend


DataW.HighByte = ADRESH
DataW.LowByte = ADRESL


if DataW < 805 then
if DataW > 50 AND DataW < 160 THEN b_level = 1
if DataW > 180 AND DataW < 270 THEN b_level = 2
if DataW > 290 AND DataW < 380 THEN b_level = 3
if DataW > 400 AND DataW < 500 THEN b_level = 4
if DataW > 540 AND DataW < 650 THEN b_level = 5
if DataW > 690 AND DataW < 800 THEN b_level = 6


if b_level <> 0 then
TMR1H = 0
TMR1L = 0
PressStartTime = TMR1L

while durata < longpress
if T1CON.0 == 1 then
overflow_counter_low = overflow_counter_low + 1
if overflow_counter_low == 65535 then
overflow_counter_low = 0
durata = durata + 65535
endif
endif

durata = durata + (TMR1H * 256 + TMR1L)
wend

durata = durata - PressStartTime
PAUSE 100
SEROUT GPIO.2, 2, ["Press for : ", #durata, " ms", 13, 10]

endif

endif


GOTO Main



9650

richard
- 28th March 2024, 03:01
in order to measure a buttons hold time you need to either note time button was pressed then the time button was released
the duration is release time - when pressed time, or when button is pressed start a timer and then stop it when button released
you are not doing either of these things
you never start timer1, you never note when the button is released

fratello
- 28th March 2024, 09:12
Thanks for reply !
T1CON = %00000110 ; this command does not start timer1?
Or do I have to use the command: T1CON.0 = 1 'start Timer1 ?
How to see if button is released ? IF DataW.... it's not enough ?

richard
- 28th March 2024, 09:22
No it just sets it to use external clock

9651

richard
- 28th March 2024, 09:46
you have set timer1 to overflow every 16.38 mS , you never count the overflows
also adding 65535 to a word var seems very odd do you actually intend to subtract 1


i can't see how any of this can work, i makes no sense to me


while durata < longpress
if T1CON.0 == 1 then
overflow_counter_low = overflow_counter_low + 1
if overflow_counter_low == 65535 then
overflow_counter_low = 0
durata = durata + 65535
endif
endif
durata = durata + (TMR1H * 256 + TMR1L)
wend

richard
- 28th March 2024, 09:49
How to see if button is released ? IF DataW.... it's not enough ?

i possibly could be enough but you never reevaluate it until the whole timing mess has long completed

fratello
- 28th March 2024, 10:25
you have set timer1 to overflow every 16.38 mS , you never count the overflows
also adding 65535 to a word var seems very odd do you actually intend to subtract 1
....
i can't see how any of this can work, i makes no sense to me



Gemini code !

HenrikOlsson
- 28th March 2024, 16:16
What happens if more than one button is pressed at the same time?

Anyway, this might serve as starting point. It compiles but it is not tested.

Long_Press CON 5000
Short_Press con 100

cnt VAR WORD
b_level VAR BYTE
DataW VAR WORD

Main:
GOSUB ReadButton

IF b_level > 0 THEN
cnt = 0
WHILE b_level > 0
cnt = cnt + 10
if cnt > Long_Press THEN EXIT
PAUSE 10
GOSUB ReadButton
WEND

SEROUT GPIO.2, 2, ["You pressed button ", #b_level, " for ", #cnt, "ms", 13, 10]
endif
Goto Main


ReadButton:
ADCON0.1 = 1
While ADCON0.1 = 1 : Wend

DataW.HighByte = ADRESH
DataW.LowByte = ADRESL

b_level = 0
if DataW < 805 then
if DataW > 50 AND DataW < 160 THEN b_level = 1
if DataW > 180 AND DataW < 270 THEN b_level = 2
if DataW > 290 AND DataW < 380 THEN b_level = 3
if DataW > 400 AND DataW < 500 THEN b_level = 4
if DataW > 540 AND DataW < 650 THEN b_level = 5
if DataW > 690 AND DataW < 800 THEN b_level = 6
ENDIF
RETURN

fratello
- 28th March 2024, 18:10
Thanks !
But nothing on serial ...(in Proteus 8)

Ioannis
- 28th March 2024, 19:01
forget Proteus.

Also I think Henrik forgot to add the label Exit: just before the Serout command.

Ioannis

HenrikOlsson
- 29th March 2024, 09:37
No, I did not forget to add a label.
EXIT is a keyword used to break out of the current loop.

AI, simulation, virtualization.... What happened to the good old breadboard?

Do I really need to spin this up on my dev board here or can you do some troubleshooting on your own and not just say "it's not working". You did include the same setupcode used before didn't you?

fratello
- 29th March 2024, 09:53
It works ! Finally, the first program that shows me the duration. BUT .... the correct identification of the pressed button does not work ! I pressed ONLY button 0 : short or long ...It doesn't matter which button I press: if I press it briefly it indicates button 0, if I press it long it indicates button 5. Why?
Anyway thanks for pointing into a good direction !
9652


Solved !
9653

richard
- 29th March 2024, 10:59
AI, simulation, virtualization.... What happened to the good old breadboard?
the chances of AI finding well written pbp code to plagiarize from are slim at best.
afaics AI can only write code if it can plagiarize it from somewhere, the code only works if the stolen code exactly matched your circumstances.
its quite amazing that this plagiarism is tolerated just because a machine is stealing it. open source etc. does not mean you can copy it and pass it off as your own original work.
breadboard , the manual and a data sheet is at least an honest and rewarding learning experience

henriks work as it needs to be



#CONFIG
cfg = _INTRC_OSC_NOCLKOUT
cfg&= _WDT_ON
cfg&= _PWRTE_OFF
cfg&= _MCLRE_ON
cfg&= _BODEN_ON
cfg&= _CP_OFF
cfg&= _CPD_OFF
__CONFIG cfg
#ENDCONFIG


CMCON = 7
TRISIO = 111001
INTCON = $C0
PIE1.0 = 1
ANSEL = 110001
ADCON0 = 000001
Long_Press CON 5000
Short_Press con 100


cnt VAR WORD
b_level VAR BYTE
but VAR BYTE
DataW VAR WORD


Main:
GOSUB ReadButton

IF but > 0 THEN
cnt = 0
WHILE but > 0
cnt = cnt + 10
if cnt > Long_Press THEN EXIT
PAUSE 10
GOSUB ReadButton
WEND

SEROUT GPIO.2, 2, ["You pressed button ", #b_level, " for ", #cnt, "ms", 13, 10]
endif
Goto Main




ReadButton:
ADCON0.1 = 1
While ADCON0.1 = 1 : Wend

DataW.HighByte = ADRESH
DataW.LowByte = ADRESL


but = 0
if DataW < 805 then
but=1
if DataW > 50 AND DataW < 160 THEN b_level = 1
if DataW > 180 AND DataW < 270 THEN b_level = 2
if DataW > 290 AND DataW < 380 THEN b_level = 3
if DataW > 400 AND DataW < 520 THEN b_level = 4
if DataW > 540 AND DataW < 650 THEN b_level = 5
if DataW > 690 AND DataW < 800 THEN b_level = 6
ENDIF
RETURN

richard
- 29th March 2024, 11:03
a bit fancier




#CONFIGcfg = _INTRC_OSC_NOCLKOUT
cfg&= _WDT_ON
cfg&= _PWRTE_OFF
cfg&= _MCLRE_ON
cfg&= _BODEN_ON
cfg&= _CP_OFF
cfg&= _CPD_OFF
__CONFIG cfg
#ENDCONFIG
DEFINE INTHAND _TICK

DEFINE DEBUG_REG GPIO
DEFINE DEBUG_BIT 2
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0

CMCON = 7
TRISIO = 111001
INTCON = $C0
PIE1.0 = 1
ANSEL = 110001
CLEAR
' Constante
TimerReload CON 61637 ;3.906mS
' Variabile
W_TEMP VAR BYTE BANK0
STATUS_TEMP VAR BYTE BANK0
MILLIES var word BANK0
b_level var byte
b_state var byte
NOW var word
LEDT var word
buttont var word
duration var word
DataW var word


GPIO.2 = 0
ADCON0 = 000001
T1CON = 000001 'Prescaler 1:1,Timer1 ON


Main:
PIE1.0 = 0
NOW = MILLIES ;in 3.906mS ticks
PIE1.0 = 1
IF NOW - LEDT > 250 THEN ;1 sec
LEDT = NOW
TOGGLE GPIO.1
ENDIF
ADCON0.1 = 1
While ADCON0.1 = 1 : Wend
DataW.HighByte = ADRESH
DataW.LowByte = ADRESL
if DataW < 805 then
if DataW > 50 AND DataW < 160 THEN b_level = 1
if DataW > 180 AND DataW < 270 THEN b_level = 2
if DataW > 290 AND DataW < 380 THEN b_level = 3
if DataW > 400 AND DataW < 520 THEN b_level = 4
if DataW > 540 AND DataW < 650 THEN b_level = 5
if DataW > 690 AND DataW < 800 THEN b_level = 6
if b_state == 0 then
b_state = 1
buttont = now
else
DEBUG "button ",#b_level, 13, 10
endif
ELSE
if b_state then
' duration = (now - buttont)<<2
duration = now - buttont
buttont = duration.lowbyte */1000
b_state = 0
DEBUG "Pressed button ",#b_level," for : ", #duration.highbyte,".",#buttont, " S", 13, 10
' DEBUG "Pressed button ",#b_level," for : ", #duration, "mS", 13, 10
b_level = 0
endif
endif
GOTO Main




TICK: ;isr
asm
MOVWF _W_TEMP ;copy W to temp register,could be in either bank
SWAPF STATUS,W ;swap status to be saved into W
BCF STATUS,RP0 ;change to bank 0 regardless of current bank
MOVWF _STATUS_TEMP
MOVE?CT 0, T1CON, TMR1ON ; stop timer
MOVLW LOW(_TimerReload) ; Add TimerReload
ADDWF TMR1L,F
BTFSC STATUS,C
INCF TMR1H,F
MOVLW HIGH(_TimerReload)
ADDWF TMR1H,F
MOVE?CT 1, T1CON, TMR1ON ; start timer
MOVE?CT 0, PIR1, TMR1IF ; CLR timer FLAG
INCF _MILLIES ,F
BTFSC STATUS,Z
INCF _MILLIES+1 ,F
SWAPF _STATUS_TEMP,W;swap STATUS_TEMP register int W, sets bank to original state
MOVWF STATUS ;move W into STATUS register
SWAPF _W_TEMP,F ;swap W_TEMP
SWAPF _W_TEMP,W ;swap W_TEMP into W
RETFIE
endASM

fratello
- 29th March 2024, 11:09
Thank you very much !!! I can't wait to test it at the weekend !

LE : I use PBP 2.5, so TimerReload CON 61637 = WARNING Line 10: 111001 Numeric overflow, value truncated.

richard
- 29th March 2024, 11:19
I use PBP 2.5, so

i know nothing about ancient history

and the number is word sized anyway

fratello
- 29th March 2024, 11:33
Mea culpa ... I identified and corrected the errors.9654

amgen
- 31st March 2024, 23:29
I would think tighten up the adc values comparisons to fill in the gaps so reading doesn't fall off........ <160 next to >161, etc

fratello
- 2nd April 2024, 08:31
In the initial software, I use a procedure to check the pressed button; if 10 presses have the same ADC as a result, then I validate the button press. I tried to complete the code proposed above with this verification procedure. But, although the results APPEAR to be correct, on the breadboard the assembly does not work at all, none of the 6 commands are executed (of course, I commented Serout instruction and uncomment the other instruction) . Please, could you identify what exactly I did wrong?


Main:
apasat=0
adcvalue=0

GOSUB ReadButton

IF b_level > 0 THEN
cnt = 0
WHILE b_level > 0
cnt = cnt + 10
if cnt > Long_Press THEN
actiune = 1
EXIT
endif
PAUSE 5
GOSUB ReadButton
WEND
b_level = 0
if b_act = 1 then gosub comenzi ; if button pressed is OK, no error
ENDIF
Goto Main


ReadButton:
ADCON0.1 = 1
While ADCON0.1 = 1 : Wend

DataW.HighByte = ADRESH
DataW.LowByte = ADRESL
b_level = 0
actiune = 0
IF DataW < 805 then
if DataW > 50 AND DataW < 160 THEN b_level = 1
if DataW > 180 AND DataW < 270 THEN b_level = 2
if DataW > 290 AND DataW < 380 THEN b_level = 3
if DataW > 400 AND DataW < 500 THEN b_level = 4
if DataW > 540 AND DataW < 650 THEN b_level = 5
if DataW > 690 AND DataW < 800 THEN b_level = 6

apasat = b_level
adcvalue=DataW

if apasat=last_b_level then ; procedure for cheking pressed button
b_cnt=b_cnt+1
pauseus 200
if b_cnt > 10 then b_act = 1 ; button pressed is OK
endif

last_b_level=apasat
ENDIF

RETURN

;================================================= ===========================

comenzi:
SEROUT GPIO.2, 2, ["You pressed button ", #apasat, " for ", #cnt, " ms", " ACTIUNE: ", #actiune, " ok ? ", #b_act, 13, 10]
;IF b_level=1 THEN gosub comand1
;IF b_level=2 THEN gosub comand2
;IF b_level=3 THEN gosub comand3
;IF b_level=4 THEN
; if actiune = 1 then
; gosub comand1
; else
; gosub comand 4
; endif
;ENDIF
;IF b_level=5 THEN gosub comand5
;IF b_level=6 THEN gosub comand6


last_b_level=0
b_cnt=0
Return