Shop OBEX P1 Docs P2 Docs Learn Events
simple SX/B example of timed use? — Parallax Forums

simple SX/B example of timed use?

ChrisPChrisP Posts: 136
edited 2006-01-12 23:13 in General Discussion
Ok, I'm lost again as usual trying to update my project and bring it to a final clean state of being. What I want to do is take the pause statements out of a program and just use timing to continiously loop through. I understand the concept in theory to the point where I can get·a 10hz signal without pausing but what I need to do is turn a solenoid on and off while continiously increasing the on time, and decreasing the off time so that it maintains 10hz frequency but the duty cycle increases with time.

So, 10 cycles per second starting with say a 10% duty cycle, and ending with a 95% duty cycle at which point it simply locks on as long as input signal is maintained. On top of all that I need to be able to adjust the rate that it changes duty cycle so that I can control the period that it takes to transit from 10-95% over a range of .5 seconds or 5 pulses to 7.5 seconds or 75 pulses without pausing the program.

I'm not asking anyone to solve this for me, just point me in the right direction to an example that may help if you could.

Thanks in advance,
Chris

Comments

  • Guenther DaubachGuenther Daubach Posts: 1,321
    edited 2006-01-08 17:40
    Chris,

    what you describe can also be seen as a PWM (Pulse Width Modulated) signal, starting with a relatively short duty cycle, increasing along a timed ramp until a 95% or even 100% duty cycle (for aways on) is reached.

    Usually, PWM signals are generated at higher frequencies but there is no reason why you should not generate one at 10 Hz - it is just a matter of timing. I'm not an SX/B expert but to my understanding you can't use SX/B's PWM function for this purpose as its frequency is too high and it can't be contolled by a parameter (besides the port pin, there are only parameters for the duty cycle, and the duration of the PWM signal).

    So you will have to "hand-code" this one. In principle, you would need a counter (let's call it the PWM accumulator, or PWMA). In a constant timed loop, or better within an ISR, starting with 0, the PWMA would be incremented every 391 µs. That is, after 256 * 391 µs it would roll over to zero, i.e. after 100.1 µs which is the period of approx. 10 Hz.

    Another variable is used to hold the duty cycle - let's call it DUTY. Whenever the PWMA is incremented, its new contents is compared against DUTY. When it is greater than DUTY, the PWM output pin is cleared to low otherwise, the output pin is set to high. The greater the value in DUTY is, the longer will the PWM output pin stay high. After the PWMA has rolled over, the next PWM cycle automatically begins.

    In order to implement a ramp, you need to set DUTY to 0 at start-up, and then increment it periodically until it holds the value for the maximum duty cycle you need.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Greetings from Germany,

    Günther
  • JavalinJavalin Posts: 892
    edited 2006-01-08 19:17
    Chris,

    Have a look in the Projects section on the forums, and see Beans SX/B Servo/PWM controller.

    Might help

    James
  • pjvpjv Posts: 1,903
    edited 2006-01-09 03:15
    Hi Chris;

    I thought your requirements to be an excellent example of how to use a simple (non-preemptive) RTOS, so I coded up your program for you so others could see the benfit of using such a time-structured approach.

    But because I am somewat SX/B illiterate and for efficiency,·I wrote it in my favourite......assembler.

    Please do understand this is just one particular implementation; there are MANY ways to skin this cat....only one example is given. And not necessarily the best or fastest or shortest, just something with LOTS of comments so many people can more easily follow it.

    The main thing to understand is the scheduler. The interrupt sets a flag every 5 uSec, and the main loop simply waits for that to occur. Then all heck breaks loose. I have somewhat arbitrarily·chosen the scheduler to have 100 uSec, 1mSec, 10 mSec, 100 mSec and 1 Sec time ticks to run the various tasks that are required in·THIS rendition. Actually some of those ticks are not directly used, so they might be combinable with other time ticks. However, their inclusion does not hurt, and for generality it demonstrates the RTOS better.

    Each of those ticks is triggered by counting off the decade of faster ticks above it. They need not necessarily be what I chose, but, hey, I like nice numbers.

    So, every 1 millisecond I call the·RAMPER that controls how fast the duty cycle changes from minimum to maximum; I call the CYCLERUNCHECK to see if the input conditions (rb.2) asks that the duty cycling should operate at all; and I call the CYCLER which actually calculates and puts out the relay duty cycle on rc.0.

    Then every 10 milliseconds the RAMPADJUST is called to accept push button input (rb.0 and rb.1) to·adjust the·ramping speed slower or faster. These have limit sets from 5 units to 75 units.

    Every 100 milliseconds the CYCLETRIGGER is called to initiate yet another complete duty cycle, and it is this trigger of course that sets the 10 Hz cadence.

    So for fun, you could relocate the·1·second·LED flasher (rc.1) to·the 100 millisecond tick level and see what happens.

    The beauty of this scheme is that all these tasks are (apparently) simultaneous and independent, and one need not concern (much) about timings of one event affecting another event. That said, though NO task may hog all the processor time and lock up the system. Delay loops are an ABSOLUTE NO-NO!!!!! After all, that is why we use an RTOS!

    Run it through Guenther's simulator, and single step it in "debug" it with your SX-Key until you really get the hang of it.


    Holler if you have questions.

    Cheers,

    Peter (pjv)

    Sorry about the screen image quality, I'm still experimenting on the best way to tackle that!

    Post Edited (pjv) : 1/9/2006 3:46:29 AM GMT
    1600 x 1200 - 100K
  • ChrisPChrisP Posts: 136
    edited 2006-01-09 05:11
    Guenther, thank you very much for the reply, and your absolutely correct the PWM command will not support what I wish to do. Your outline is actually quite helpful. I'm still a little lost on running an ISR as far as timing and interfering with other functions of a program so for now running the counters in the main program is probably best for me. A quick clarification on ISR's though if I may. Using the RTCC to trigger an ISR my understanding at the moment is that wherever the program is it will jump from there to the ISR and then return to execute the next line of code. Is this correct or will it return to the program start or Main? If I understand that right then the few clock ticks it takes to increment the timers in an ISR would only have a negligable effect on whatever else I'm doing. Also thanks for the book that came with my SX Kit, the time I've spent leafing through it at this point has given me a fantastic glimpse of what the SX is capable of, and enough understanding to gain useful information of PJV's code example.



    PJV, Even though assembly is still a mostly foreign language to me your code example goes a long way to giving structure to what Guenther was describing and how to accomplish of what I am looking for. The commands I mostly dont understand but the structure and program layout seems like it would be the same in SX/B at least I didnt see anything that couldnt be implemented. Between the layout and the comments its a tremendous help, and I'm sure will go a long way toward helping me accomplish my eventual goal of getting more into assembler. Just sat and went through it for the last hour getting a feel for what its doing. It looks like the key I was missing was selecting units of time that fit in with how I wanted to ramp the duty cycle and the fact that I could basicaly run a clock not in absolute time but tailored to what I want to do, and the light hits as I sit here and reply, I was looking for the math to calculate absolute constants for the steps in percent of duty cycle to acheive the ramp rate I was looking for when in actuality all I need to do is increment a variable from 5-95 one increment at a time over a set time period and snatch the duty cycle variable from that count as time passes...... Thanks again for the example, I'm not sure of thats exactly what your doing but it helped a lot.



    Javalin,·Thanks for pointing this out, I'm off to search for his project and see what I can glean from it, if I remember right though it was controlling duty cycle through external commands via serial and the part that was stumping was basicaly ramping through a scheduler. Either way I'm sure I'll pick up something useful from it. If nothing else maybe I can puzzle out the scheduling now that its considerably later with much more reading since the last time I looked.
  • RsadeikaRsadeika Posts: 3,862
    edited 2006-01-09 12:51
    Chris,

    Your presunption is absolutely correct, the interrupt occurs, it does its thing, then it comes back to the main code and executes the next line of code. I believe the definition of an interrupt is that all other processing stops, the interrupt code runs, and then it comes back to full processing and executing the next line of main code.

    The interrupt is a very powerfull tool, but takes some time and learning before you can really use it in a pwerfull way. I am in the same situation·as you, I would like to code within SX/B, but as you probably have noticed, all the experts use asm.

    But, if we keep asking the questions·in terms of SX/B, maybe somewhere along the line we will have a break through, and get a response like ... and here is the SX/B version of the asm example.

    Ray
  • Jon WilliamsJon Williams Posts: 6,491
    edited 2006-01-09 14:33
    Maybe you'll be the one to post that response, Ray! wink.gif One can -- with a little planning -- integrate interrupts into SX/B programs.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax
  • RsadeikaRsadeika Posts: 3,862
    edited 2006-01-09 15:14
    I am in a learning process here, I try to post as much as possible, even the crappy stuff. It would not do me or anybody else any good if I just post junk, for the sake of posting. I get enough ridicule in my life as is LOL. I go on the theory of, if the experts present some good examples, then the learners have a good baseline to start from, instead of thrashing around, and then just giving up. But, that is my opinion.

    Ray
  • StarManStarMan Posts: 306
    edited 2006-01-09 20:25
    Peter,

    Thank you for posting that code with description and comments.· I am very much a beginner with SX and I am trying to learn assembler.· It is a long process for me as I have very little time to devote and very little programming background.· Studying these types of examples (with an elementary description and comments)goes a long way toward gaining an understanding about how the SX can be used.

    My primary interest is to control LED brightness with PWM.· Simple in concept, difficult in implementation.· I could probably get something started more quickly with SX/B but I know that ultimately, assembly language is what I need.· I'm working my way through Gunther's book right now.· I leave the blinky LED on my desk 24 hours a day to remind me of my goal.

    Ray, you inspire me.· Thanks.

    Chris I.

    ·
  • ChrisPChrisP Posts: 136
    edited 2006-01-12 06:23
    Well, I've gotten this far with Guenther and Peters help. Ramping duty properly to match things up is still up in the air but it feels good to get through most of the rest of it. I'm trying to linear ramp Duty from 0-255 in the number of cycles selected by DIP switches on RB0-RB3. Guenther, I think I got the idea of what you were describing, thanks again it was enough to get me kicked off anyway. Its still running pause commands but I think the continuosly running program is beyond me right now.
  • MacGeek117MacGeek117 Posts: 747
    edited 2006-01-12 15:45
    TRIS_A = %1111   'Set all pins to input
    TRIS_B = %01111111  'Set RB0-RB6 as input RB7 as output
    TRIS_C = %00000000  'Set all pins to output
    ST_B = %01111111  'Set all RB outputs to schmidt trigger
    PLP_A = %1111   'Set all pullups on
    PLP_B = %01111111  'Pullup pins RB0-RB6
    

    I just read(and this helped me alot with my own program) that the ST and PLP registers use 1 to disable, 0 to enable.

    From one SX'er to another,
    RoboGeek

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    There are·3 kinds of people in the world,

    the dreamers, the do-ers, and the "Oh, what's this button do"-ers.
    Formerly bugg.
    www.parallax.com
    www.goldmine-elec.com
    www.expresspcb.com
    www.startrek.com
    ·
  • ChrisPChrisP Posts: 136
    edited 2006-01-12 23:13
    Doh, and I labeled a bank of inputs as outputs, thanks, that would have caused problems come debug time. Corrected.
Sign In or Register to comment.