|
Post by turtleman on Jul 26, 2022 8:54:32 GMT -5
All I need is the software equivalent of a monostable multivibrator (one shot) to turn on an LED type display when triggered and turn back off in a few hundred milliseconds. The timer serves this function perfectly for most applications, such as indicating a button press. However, in a loop where every millisecond counts, I don't want to slow the program while waiting on the timer.
I hope there's a simple solution that makes me hit my head for not finding it sooner. Thanks a bunch!
|
|
|
Post by Rod on Jul 26, 2022 9:20:45 GMT -5
Not sure I understand the question just yet. If you use the timer statement and set a timer running and then just wait, you will get a pretty accurate 200ms delay that wont slow the program.
When I say accurate, the timer runs at a windows dictated 16ms tick interval. So 200ms to within 16ms
So how accurate do you need, and are you doing anything else while you wait?
While windows has a high resolution timer it is pretty useless because of event management an messaging delays. To get high accuracy you need to get a dongle or an Arduino board that has its own high resolution timer.
But a little more info on the project will get better advice.
|
|
|
Post by turtleman on Jul 26, 2022 9:32:59 GMT -5
Thanks Rod. Accuracy is unimportant, as I only want to turn on an LED type display for a few hundred ms and go back off. Unless I'm totally wrong, using the timer would halt the rest of the program until it times out.
|
|
|
Post by Rod on Jul 26, 2022 10:09:43 GMT -5
No, the timer sets up an event that will fire in the future. Your program can keep going or wait. If it keeps going then once the event fires a scan or wait will pick up the event and react to it. If you wait, and no other events get managed, nothing else gets processed but the program will restart and jump to the timers event handler a soon as it fires.
If you have other events waiting to be handled they can be (button presses)
So it is up to you. You can keep processing as long as you keep scanning for the event or stop and wait in good time.
The timer event is stand alone and does not need to hold you back. A call back if you like.
Remember it repeats so it needs turned off after it fires if you want a one shot delay.
|
|
|
Post by Rod on Jul 26, 2022 11:18:38 GMT -5
Lets say it another way. In Liberty you set up lots of event handlers like button presses and listbox or combobox events AND timer events. So you have all these code block handlers just waiting to be used. When an button is pressed the code jumps to the handler and does what is required. A timer event is no different. The handler just sits there waiting to be called into action.
So SCAN and WAIT are the commands to check what events are outstanding and to shoot off and action them. It might be a button press it might be a timer firing. You might handle a dozen button presses that take a few microseconds to action while you wait for a 200ms timer to fire.
So no a timer does not hold you back, it integrates well into the myriad of things Liberty might be primed to handle.
|
|
|
Post by turtleman on Jul 26, 2022 12:28:48 GMT -5
Thanks again for your explanation. Maybe I'm just not using the timer correctly, but a button press lights a "software" LED, and "timer 200, [shuffleclear]" is included in the code. The LED lights immediately, as intended, and goes off 200 ms later, as directed by [shuffleclear], which includes "timer 0". That works fine. However, when I try to integrate the timer code into a loop, which might trigger the LED dozens of times, the program has already halted after the first 200 ms. [shuffleclear]. I'd like the loop to continue, while flashing the LED as called for. To be sure, if I comment out "timer 200, [shuffleclear]" the code works as before. Somehow, the [shuffleclear] code prevents the loop from continuing. Sorry if this is totally confusing and it's way too involved to post the code. I obviously don't know what I'm doing!
|
|
|
Post by tsh73 on Jul 26, 2022 13:45:43 GMT -5
1) don't let it stop you 2) this is actually best part Have a look at this. * Busy loop, * no timer, * flag to show we have led ON, * check time$("ms") to see if time passed. nomainwin
open "busyLoop" for graphics_nsb_nf as #gr #gr "home; down; posxy cx cy" #gr "trapclose [quit]" #gr "when leftButtonUp [light]"
r=100 a=0 da=0.01 'fix this tou your computer speed #gr "color white" 'I do not need an outline, but you might
'busy loop, run in circles while 1 [inLoop] SCAN 'have ascan so rpgram reponds to your actions (and you can terminate it) 'clear old one #gr "backcolor white" #gr "place ";int(x);" ";int(y);";circlefilled 15" 'move a=a+da x=cx+r*cos(a) y=cy+r*sin(a) 'draw new one #gr "backcolor cyan" #gr "place ";int(x);" ";int(y);";circlefilled 15" 'print "place ";int(x);" ";int(y);";circlefilled 15"
'now see if we had light to clear. And this checks on each loop. if light=2 then 'still to clear if time$("ms")>t then 'if time passed, clear it #gr "backcolor white" #gr "place 20 20;circlefilled 20" light = 0 'off end if end if 'or to draw (once after mouse click) if light=1 then 'to draw #gr "backcolor red" #gr "place 20 20;circlefilled 20" light = 2 'to turn off after 200 ms end if
#gr "discard" 'to prevent graphic memory fill-up wend
[light] t=time$("ms")+400 'really 200 too small :) Do as you wish, though light = 1 'wait now, this stops 'so I guide it into the loop instead (?) goto [inLoop]
wait
[quit] timer 0 close #gr end
|
|
|
Post by tsh73 on Jul 26, 2022 13:51:23 GMT -5
Now version with timer. Happened to be even simpler/smaller
nomainwin
open "busyLoop" for graphics_nsb_nf as #gr #gr "home; down; posxy cx cy" #gr "trapclose [quit]" #gr "when leftButtonUp [light]"
r=100 a=0 da=0.01 'fix this tou your computer speed #gr "color white" 'I do not need an outline, but you might
'busy loop, run in circles while 1 [inLoop] SCAN 'have ascan so rpgram reponds to your actions (and you can terminate it) 'clear old one #gr "backcolor white" #gr "place ";int(x);" ";int(y);";circlefilled 15" 'move a=a+da x=cx+r*cos(a) y=cy+r*sin(a) 'draw new one #gr "backcolor cyan" #gr "place ";int(x);" ";int(y);";circlefilled 15" 'print "place ";int(x);" ";int(y);";circlefilled 15"
#gr "discard" 'to prevent graphic memory fill-up wend
[light] 'really 200 too small :) Do as you wish, though #gr "backcolor red" #gr "place 20 20;circlefilled 20" timer 400, [clear] 'wait now, this stops 'so I guide it into the loop instead (?) goto [inLoop]
[clear] #gr "backcolor white" #gr "place 20 20;circlefilled 20" timer 0 goto [inLoop]
wait
[quit] timer 0 close #gr end
|
|
|
Post by Rod on Jul 27, 2022 4:04:00 GMT -5
I am still confused about what the question is. Take this code, which is doing what you want, where is the loop involved?
nomainwin WindowWidth = 600 WindowHeight = 400 button #1.b, "ON", [ledon], UL, 10, 10 open "LED Timer" for graphics_nsb_nf as #1 #1 "trapclose [quit]" #1 "down ; fill black"
[ledoff] timer 0 #1 "discard ; place 100 100 ; backcolor lightgray ; circlefilled 50" wait
[ledon] timer 500,[ledoff] #1 "discard ; place 100 100 ; backcolor red ; circlefilled 50" wait
[quit] close #1 end
|
|
|
Post by Rod on Jul 27, 2022 4:05:14 GMT -5
@carl I am on pro 4.04
|
|
|
Post by turtleman on Jul 27, 2022 6:23:19 GMT -5
Thanks again Rod. I'm trying to come up with a better explanation, but until I do, here's a more generic question: In your last code example, you use "discard." I'm not familiar with discard, looked it up, but still don't understand how it's used or how it differs from "delsegment" and "flush." Then again, there are approximately a zillion other instructions I don't understand.
|
|
|
Post by turtleman on Jul 27, 2022 8:27:15 GMT -5
It appears there are more serious problems in the program than just the LED timer. The "scan" instruction in the loop seems to interfere with the timer, which of course, I don't understand. Pausing the loop with a dedicated key press never seemed overly stable, so maybe if I find a better way than "scan," the rest of the program will behave.
Now, what's an easy way to look for a "pause" button keypress when busy running in a loop? Working on it!
|
|
|
Post by tsh73 on Jul 27, 2022 9:20:17 GMT -5
turtleman, you really should try to make some examples. Or adapt some of posted. Because where we stand now - you have a problem we can't quite undestand, and you don't post code; and you have some other problem . atop that one, code of which you don't post.
There are just too many ways to write program what do not work.
Give us something to fix/work with.
|
|
|
Post by tsh73 on Jul 27, 2022 15:06:48 GMT -5
Ok I made more of something. Now it has busy loop drawing circle pattern left button click lights led, starts timer, after 400 ms timer dims led drawing pattern continues
pressing space enters pause mode this is genuine wait state - it does not use CPU, at all And in this mode left mouse button still lights led/ it dims after 400 ms
Space toggles pause mode on/off.
Nifty?
'busy loop 'tsh73 Jul 2022 nomainwin
open "Sps pause, LMB led" for graphics_nsb_nf as #gr #gr "home; down; posxy cx cy" #gr "trapclose [quit]" #gr "when leftButtonUp [light]" #gr "when characterInput [key]" #gr "setfocus"
r=140 a=0
'single pixel on a circle pi=acs(-1) 'circLen=2*pi*r 'pixels 'da=2*pi/circLen => da=1/r
call drawLed "lightgray"
'busy loop, run in circles #gr "rule xor" '#gr "home; goto ";int(x);" ";int(y) '1st line to delete while 1 [inLoop] SCAN 'have a scan so program responds to your actions (and you can terminate it) 'move a=a+da 'reset, or it will not come exactly to same points if a>2*pi then a=0 x=int(cx+r*cos(a)) y=int(cy+r*sin(a)) #gr "home; goto ";x;" ";y
#gr "discard" 'to prevent graphic memory fill-up wend
[light] 'really 200 too small :) Do as you wish, though call drawLed "red" timer 400, [clear] if pause then wait else [inLoop]
[clear] call drawLed "lightgray" timer 0 if pause then wait else [inLoop]
[key] if Inkey$=" " then if pause then pause=0: goto [inLoop] else pause=1: wait end if end if goto [inLoop]
wait
[quit] timer 0 close #gr end
sub drawLed color$ #gr "rule over" #gr "backcolor ";color$;"; color ";color$ #gr "place 20 20;circlefilled 20" #gr "rule xor" #gr "color black" '!!!! or you will have INTERESTING results, due to XOR end sub
|
|
|
Post by Walt Decker on Jul 29, 2022 16:10:21 GMT -5
' '########################################################## ' A Method for flashing a LED in response to an external ' event '##########################################################
Timed = 0 TimeEnd = 0 CurTime = 0
STYLEBITS #DMO.GFX, 0, _WS_BORDER, 0, 0 GRAPHICBOX #DMO.GFX, 5, 5, 30, 30
BUTTON #DMO.BTN, "PUSH ME", PUSH.BTN, UL, 40, 5, 65, 25
OPEN "TIMED" FOR WINDOW AS #DMO PRINT #DMO, "TRAPCLOSE DMO.END"
[WAIT.EVENT] GOTO [CHECK.EVENT]
'--------------------------------------------- '---------------------------------------------
[CHECK.EVENT]
IF Timed THEN CurTime = TIME$("ms") IF CurTime >= TimeEnd THEN PRINT #DMO.GFX, "DOWN" PRINT #DMO.GFX, "FILL WHITE" TimeEnd = Timed Timed = 0 CALLDLL #kernel32, "Sleep", TimeEnd AS LONG, RetVal AS VOID GOTO [SCAN.EVENT] ELSE GOTO [SCAN.EVENT] END IF END IF
Timed = FN.CheckEvent() IF Timed THEN TimeEnd = TIME$("ms") + Timed PRINT #DMO.GFX, "DOWN" PRINT #DMO.GFX, "FILL RED" END IF
[SCAN.EVENT] SCAN GOTO [WAIT.EVENT] [CHECK.EVENT.END]
'---------------------------------------------- '----------------------------------------------
SUB DMO.END DmoHndl$ CLOSE #DmoHndl$ END
END SUB
'---------------------------------------------- '----------------------------------------------
SUB PUSH.BTN BtnHndl$
PRINT "PUSH ME"
END SUB
'---------------------------------------------- '----------------------------------------------
FUNCTION FN.CheckEvent() '################################################################## ' Check for event. In this case the event is when a variable is ' greater than or equal to 0.50 '##################################################################
Active = 0 '<--- Event to check
Active = RND(0) IF Active < 0.50 THEN Active = 0 ELSE Active = 550 END IF
FN.CheckEvent = Active END FUNCTION '
|
|