Shop OBEX P1 Docs P2 Docs Learn Events
Is there a more efficient way to call up sub routines? — Parallax Forums

Is there a more efficient way to call up sub routines?

ctdahlectdahle Posts: 29
edited 2010-11-14 17:45 in BASIC Stamp
In an attempt to make physical computing more appealing to my students (11-year-olds) I built a BS2 controlled glockenspiel player ("ein glockenspielspieler").

It is colorful, noisy, moves around a lot, and has lots of visual appeal.

The player uses one servo to position a turntable on which a second servo is mounted. The second servo drives a hammer which strikes the note.

I wrote a series of subroutines to position the hammer over each note, for example (the positioning servo is on Pin 14):
ANOTE:  'Plays the A below middle C
DEBUG "Play A",CR
FOR counter = 1 TO 35     ' Positions hammer at A
  PULSOUT 14, 640
  PAUSE 5
NEXT
GOSUB Strike
RETURN

A second subroutine (reference GOSUB Strike above) strikes the notes (the striker servo is on Pin 15):
Strike:
FOR counter = 1 TO 10     ' Strikes note
  PULSOUT 15, 860
  PAUSE 2
NEXT
FOR counter = 1 TO 25     ' Lifts hammer to resting position
  PULSOUT 15, 760
  PAUSE 1
NEXT
RETURN

To play a song, I write list of GOSUB commands, for example, here is "Mary had a little lamb":
FOR verses = 1 TO 4

GOSUB CNOTE
GOSUB BNOTE
GOSUB ANOTE
GOSUB BNOTE
GOSUB CNOTE
GOSUB CNOTE
GOSUB CNOTE
PAUSE 400
GOSUB BNOTE
GOSUB BNOTE
GOSUB BNOTE
PAUSE 400
GOSUB CNOTE
GOSUB ENOTE
GOSUB ENOTE
PAUSE 400
GOSUB CNOTE
GOSUB BNOTE
GOSUB ANOTE
GOSUB BNOTE
GOSUB CNOTE
GOSUB CNOTE
GOSUB CNOTE
GOSUB CNOTE
GOSUB BNOTE
GOSUB BNOTE
GOSUB CNOTE
GOSUB BNOTE
GOSUB ANOTE
PAUSE 800

NEXT

I insert PAUSE commands where rests are needed. Similarly, I can moderate tempo, but this is awkward. There has got to be a better way.

What I would like to do is set "TEMPO" at the beginning of the program, and then enter a table of some kind that specifies the timing between each note to account for whole(1), half(2) and quarter notes(4) and rests (Call them "R") that might look sort of like this:

Tempo (a scale of 1-10 which would globally lengthen, or shorten one of the PAUSES or number of repeats in one of the subroutines)
Playthesenotes:
C4 B4 A4 B4 C4 C4 C4 R4
B4 B4 B4 R4 C4 E4 E4 R4
etc

I know that there are things called "Data Arrays", and I thought that was what I needed to use, but I am not finding them when I RTFM. I'd appreciate a little prodding in the right direction.

The next step, by the way is to offload the "strike" routine. I want to have the "positioning" routine begin immediately as soon as the strike command is sent. Right now the program has to wait for the hammer to strike and return to the neutral position before the positioner begins moving to the next note. I want them to move simultaneously. Since the striker routine is always the same two pulsout durations, I'm thinking I can make a simple circuit that will just do that when signaled by the BS2, freeing the micro-controller to go on with the more delicate task of positioning for the next note.

Comments

  • bill190bill190 Posts: 769
    edited 2010-11-14 08:56
    See...
    Activity #5 : Ringtones with RTTTL..........271

    ...in the "What’s a Microcontroller?" book here...
    http://www.parallax.com/Portals/0/Downloads/docs/prod/edu/28123-WAM-v3.0.pdf

    Here are some songs listed there (along with the program)...
    RTTTL_File DATA "TwinkleTwinkle:d=4,o=7,b=120:c,c,g,g,a,a,2g,f,",
    "f,e,e,d,d,2c,g,g,f,f,e,e,2d,g,g,f,f,e,e,2d,c,c,",
    "g,g,a,a,2g,f,f,e,e,d,d,1c"
    RTTTL_File DATA "FrereJacques:d=4,o=7,b=125:c,d,e,c,c,d,e,c,e,f",
    ",2g,e,f,2g,8g,8a,8g,8f,e,c,8g,8a,8g,8f,e,c,c,g6",
    ",2c,c,g6,2c"
    RTTTL_File DATA "Beethoven5:d=8,o=7,b=125:g,g,g,2d#,p,f,f,f,2d"
    RTTTL_File DATA "ForHe'sAJollyGoodFellow:d=4,o=7,b=320:c,2e,e,e,",
    "d,e,2f.,2e,e,2d,d,d,c,d,2e.,2c,d,2e,e,e,d,e,2f,",
    "g,2a,a,g,g,g,2f,d,2c"

  • Mike GreenMike Green Posts: 23,101
    edited 2010-11-14 08:56
    You should look at the DATA and READ statements. The DATA statement stores bytes of data in the lower part of the EEPROM while the program itself is stored in the upper part of the EEPROM. The READ statement allows you to read this data.

    You want to encode the notes in one or two bytes of data. If you want a whole, half, or quarter note (considering a rest as a kind of note), you might use the hundreds digit of a byte value for the length of a note. 0-99 would be quarter notes, 100-199 would be half notes, and 200-255 would be whole notes. 0/100/200 would be a rest while 1-55/101-155/201-255 would be the notes themselves. With a glockenspiel, you're unlikely to have 55 notes, so you won't be limited there.

    You would use a separate DATA statement to translate the note number into a servo position. Look at the examples in the Stamp Manual to see how you would have a table of word (two byte) values which is what the servo needs. Alternatively, you could use a LOOKUP statement to do the same thing.

    In all of your servo positioning routines, the PAUSE statement should be PAUSE 20 (or 19) because servos expect to see a control pulse about 50 times a second. If this pulse comes too often or not often enough, the servo motion can become "twitchy".

    You could reserve note 99 to mark the end of the song.
  • stamptrolstamptrol Posts: 1,731
    edited 2010-11-14 09:03
    Great project! The kids stand to learn a lot from you.

    The statement you could use would be DATA to either store each postion and duration one after the other. Or, you could use one DATA statement to store postion and a second one to store durations. Have a look atthe Helpfile for examples.

    Off-loading the strike routine to hardware is a good technical solution. Just build a "one-shot multivibrator" circuit which will allow you to adjust the strike pulse with a capacitor. You can make the circuit with a 555 timer or the 74x123 chips.

    Cheers,
  • ctdahlectdahle Posts: 29
    edited 2010-11-14 09:35
    Thank you both. I now have a place to start.

    In regard to the pauses:
    In my ignorance, I shortened the pauses when I was trying to get the striker servo to where it was going a bit faster. I just kept shortening the PAUSE and reducing the number of pulses until the hardware failed to strike correctly. The values you see in my code all seem to work. Dumb luck maybe...

    In trying to speed up the servo response I read what I could find about servos. When I learned that the servos "expect" a pulse every 20ms, I became, and remain, quite puzzled that my servos are working despite the wide deviation from the expected pulse timing.

    I'm now thinking that it would be better to offload (am I using the correct language?) the movement of BOTH servos. I'm thinking that there is probably a circuit I could build such that the BS sends a "note position" signal to that circuit and the the circuit/chip/whatever interprets that signal as "move the servo to X position" and hold it there until the BS sends some other instruction.

    My reasoning is that if I free the micro controller from worrying about the mundane tasks of servo positioning and pulse timing, I can devote its processing power to timing the notes and controlling tempo, without the added complication that transit time to/from some notes is greater than for others. I hear there is a chip called a 555 that can do this for me...more reading....

    Mind you, this is all REALLY theoretical for me...two months ago I didn't know the difference between an anode and a cathode!
  • ctdahlectdahle Posts: 29
    edited 2010-11-14 09:52
    Thanks Tom, I was writing my reply to Mike and Bill while you were posting yours. I appreciate knowing that I am looking for a "one shot multivibrator", and am glad for the confirmation that the 555 is the next thing I need to study.

    Each year with my students, I try to dive into some field about which I know nearly NOTHING and keep them involved as I learn about it. The intent is to model the idea that THEY can learn about anything that interests them.

    This year it started out as computer programming...I was learning Python...but I got side tracked by micro controllers, robotics, and physical computing because I realized that I could create things with much greater visual impact much sooner. A blinking light and a moving servo holds the attention of kids much longer than does "Hello World".

    Next year I think it will be Bee Keeping. I try to rotate between Life Science, Physical Science, and Earth & Space Science topics, and to relate everything back to the math and science concepts we are studying in the required scope and sequence.
    stamptrol wrote: »
    Great project! The kids stand to learn a lot from you.

    The statement you could use would be DATA to either store each postion and duration one after the other. Or, you could use one DATA statement to store postion and a second one to store durations. Have a look atthe Helpfile for examples.

    Off-loading the strike routine to hardware is a good technical solution. Just build a "one-shot multivibrator" circuit which will allow you to adjust the strike pulse with a capacitor. You can make the circuit with a 555 timer or the 74x123 chips.

    Cheers,
  • Mike GreenMike Green Posts: 23,101
    edited 2010-11-14 10:07
    You might see if you can find a doorbell chime and have a look at the guts. These use a metal bar as a chime and a solenoid controlled striker. There's an iron or steel rod in a solenoid with a spring arranged around the rod holding it in position a short distance from the metal bar. The solenoid is arranged so it will pull the rod towards the metal bar. When you push the doorbell button, low voltage (24V) AC is connected to the solenoid which attracts the rod that strikes the metal bar. The spring pulls the rod back into position. There's a little more detail, but this is the basic setup.

    Parallax makes the ServoPAL which offloads the periodic pulse generation for one or two servos. There are other servo controllers, but this is the simplest and cheapest that would do the job for you.
  • ctdahlectdahle Posts: 29
    edited 2010-11-14 17:45
    Thanks Mike,

    I just happen to have this old door bell here and it runs on a couple of lantern batteries. I think the low note just might be the low F-sharp I'm missing to play Ode To Joy...

    I had given some thought to using solenoids but the task of winding them put me off. Also the "action" is concealed. Plus I already have lots of servos and there is lots of attention grabbing action with them.

    But...for version 2...If I wound my own solenoids....I could use lengths of framing nails for the strikers and old ballpoint pen springs to return them to neutral...

    One of my weird educational ideas is that for all of my little projects, I have to leave a couple of "obvious" areas for improvement so the kids can go away in the summer and out do me. I try to show really good workmanship so the kids know the level of quality I expect, but also leave some obvious design flaws so that the kids can build a better version.

    Maybe I can rig up some other gadget that uses a crude solenoid to ring a bell...maybe a warning chime that rings thirty seconds before the end of the class period...and set it up next to the glockenspieler...maybe a kid will make the connection and impress me with a computer driven vibraphone next fall.
Sign In or Register to comment.