Single push button activation

joliebrise

New Member
One of the problems in trying to do too many code routines at once is that you do not know where are the mistakes. This situation is a case in point. The problem is pressing the button does not initiate the code change immediately. I have tried do: loop until pinC.3 = 1 and while pinC.3 = 0
It seems that “Pause” is creating a time delay.
How can I circumvent the delay and get the button to act immediately?

Code:
; single push button

#picaxe 08m

b1 = 2 ; to initiate initial setup

;peek 10, b1 ; will overight b1 in previous line

pinC.3 = 0 ; switch not pressed

main:

if pinC.3 = 1 then
pause 100
let b1 = b1 + 1 ; next breath timing
endif

if b1 >6 then let b1 = 1 ; return counter to 1
endif

;poke 10, b1 ; stored for keeping data ready for next use

if b1 = 1 then beat25
if b1 = 2 then beat30
if b1 = 3 then beat35
if b1 = 4 then beat40
if b1 = 5 then beat45
if b1 = 6 then beat50

bt25: do: sound c.1, (50,50) : pause 2106 : loop while pinC.3 = 0 : goto main
bt30: do: sound c.1, (50,50) : pause 2563 : loop while pinC.3 = 0 : goto main
bt35: do: sound c.1, (50,50) : pause 3080 : loop while pinC.3 = 0 : goto main
bt40: do: sound c.1, (50,50) : pause 3554 : loop while pinC.3 = 0 : goto main
bt45: do: sound c.1, (50,50) : pause 4060 : loop while pinC.3 = 0 : goto main
bt50: do: sound c.1, (50,50) : pause 4592 : loop while pinC.3 = 0 : goto main
 

Attachments

lbenson

Senior Member
If the milliseconds are not significant, you could do something like this (adjusting if necessary for the time the inner "do: loop" takes):
bt25: do: sound c.1, (50,50) : for w13 = 1 to 210: pause 10: if pinC.3=1 then: exit: endif: next w13 : loop while pinC.3 = 0 : goto main
 

inglewoodpete

Senior Member
I tried your code. I encountered a couple of problems. First, near the top of your program, "pinC.3 = 0 ; switch not pressed" is pretty meaningless, since you cannot set the state of an input from your code. The other issue is more obvious: the branch labels do not match (bt25 vs. beat25 etc).
 

joliebrise

New Member
Corrected mistakes. Rounded up timings.
Pause time is critials as it is the breathing rate, 2100 gives 2.5sec. Why, I don't know.

Using the simulator, holding switch down ( pin3 = 1) until end of pause delay then releasing (0) allowed the beat to index to next. It was hit and miss

I want the user to press the button once for a moment unrelated to the timing.
Is it possible to hold pinc.3 =1 for the length of the pause time?

The following just locked up
beat25: do : sound c.1, (50,50) : pause 2100 : if pinC.3 = 1 then stop : endif :goto main : loop

Regards Tony

; single push button
;08m

b1 = 2 ; to initiate initial setup

main:

if pinC.3 = 1 then
pause 50
let b1 = b1 + 1 ; next breath timing
endif

if b1 >3 then let b1 = 1 ; return counter to 1
endif

if b1 = 1 then beat25
if b1 = 2 then beat35
if b1 = 3 then beat50

beat25: do : sound c.1, (50,50) : pause 2100 : loop until pinC.3 = 1 : goto main
beat35: do : sound c.1, (50,50) : pause 3040 : loop until pinC.3 = 1 : goto main
beat50: do : sound c.1, (50,50) : pause 4600 : loop until pinC.3 = 1 : goto main
 

lbenson

Senior Member
>just locked up
Worked for me in the simulator as I had it. "STOP" will indeed stop program execution.
 
Last edited:

hippy

Technical Support
Staff member
It is going to be quite tricky having perfect timing and responsive button pushing. This is possibly a good start, untested on actual hardware -
Code:
#Picaxe 08M2
#No_Data

Symbol reserveW0          = w0 ; b1:b0
Symbol interBreathPeriod  = w1 ; b3:b2
Symbol breathPeriodSelect = b4
Symbol lastPinC.3State    = b5

MainLoop:
  Gosub SetInterBreathPeriod
  Do
    Sound C.1, (50,50)
    w0 = 0
    Do
      If pinC.3 <> lastPinC.3State Then
        lastPinC.3State = lastPinC.3State ^ 1
        If lastPinC.3State = 1 Then
          breathPeriodSelect = breathPeriodSelect + 1 // 6 ; 0 to 5
          Gosub SetInterBreathPeriod
        End If
      End If
      Pause 10
      w0 = w0 + 10
    Loop Until w0 >= interBreathPeriod
  Loop

SetInterBreathPeriod:
  ;                            0     1     2     3     4     5
  ;                            bt25  bt30  bt35  bt40  bt45  bt50 
  LookUp breathPeriodSelect, ( 2106, 2563, 3080, 3554, 4060, 4592 ), interBreathPeriod 
  Return
 

lbenson

Senior Member
Pause time is critials as it is the breathing rate, 2100 gives 2.5sec. Why, I don't know.
There will be overhead from the execution of the basic statements in addition to the PAUSE time.
Does this not do what you want?
Code:
#Picaxe 08M

b1 = 2 ; to initiate initial setup

;peek 10, b1 ; will overight b1 in previous line

main:

if pinC.3 = 1 then
pause 100
let b1 = b1 + 1 ; next breath timing
endif

if b1 >6 then let b1 = 1 ; return counter to 1
endif

;poke 10, b1 ; stored for keeping data ready for next use

select b1
  case 1: w5= 210
  case 2: w5= 256
  case 3: w5= 308
  case 4: w5= 355
  case 5: w5= 406
  case 6: w5= 459
end select

do
  sound c.1, (50,50)
  for w6 = 1 to w5
    pause 10
    if pinC.3=1 then
      exit
    endif
  next w6 
loop while pinC.3 = 0
goto main
You would need to adjust the pause*10ms times in the select statement because there is more overhead in checking every 10ms for a button press.
 

hippy

Technical Support
Staff member
Having read other threads on the nature of this metronome, if you want reasonably accurate timing and don't care if the inter-breath period is momentarily truncated when the button is pushed; this should do the job. AGain, untested on real hardware -
Code:
#Picaxe 08M2
#No_Data

Symbol reserveW0          = w0 ; b1:b0
Symbol interBreathPeriod  = w1 ; b3:b2
Symbol breathPeriodSelect = b4
Symbol lastPinC.3State    = b5

MainLoop:
  Gosub SetInterBreathPeriod
  Gosub Interrupt_Enable
  Do
    Sound C.1, (50,50)
    Pause interBreathPeriod
  Loop

Interrupt:
  If lastPinC.3State <> 0 Then
    breathPeriodSelect = breathPeriodSelect + 1 // 6
    Gosub SetInterBreathPeriod
  End If

Interrupt_Enable:
  lastPinC.3State = lastPinC.3State ^ %00001000
  SetInt lastPinC.3State,             %00001000
  Return

SetInterBreathPeriod:
  ;                            0     1     2     3     4     5
  ;                            bt25  bt30  bt35  bt40  bt45  bt50 
  LookUp breathPeriodSelect, ( 2106, 2563, 3080, 3554, 4060, 4592 ), interBreathPeriod 
  Return
 

joliebrise

New Member
Thanks Hippy. You have done it again.
Your codes works beautifully.
Took 10 mins to correct the timings

I understand the array at the end and interrupt/ -Enabled, just.

breathPeriodSelect = breathPeriodSelect + 1 // 6 What are the // for?
lastPinC.3State = lastPinC.3State ^ %00001000 and ^ ?

Could you tell me where to put Peek & Poke so the the users chosen time always appears turning the metronome on.

The output needs to have a volume control and I am trying to find a Digital method. I found dacsetup, daclevel, readadc but no code.

I will put this in a new post tomorrow "Digital Potentiometer" Two push buttons.


Thanks Tony
 

AllyCat

Senior Member
Hi,

- // gives the "remainder" of division (by 6) so the above gives a value between 0 and 5.
- ^ is the Exclusive Or operator so is effectively toggling bit 3.
- It's not PEEK and POKE but READ and WRITE. See my post #3 in your other (third) thread on this topic.
- The "dac" shares a pin with the Serial / Programming Output on most M2s (including the 08M2), so is of limited usefulness. It is intended to divide a dc reference voltage and has a very high output impedance (~40k), so is very unlikely to successfully drive your horrible dc coupled Darlington "amplifier". Also, of course, a "pot" can only reduce the volume level, so you need to sort out an amplifier with decent gain and stability first.

Cheers, Alan.
 
Top