From: Arnar B. <ar...@gm...> - 2007-03-13 23:50:58
|
Hi again, On 3/13/07, Arnar Birgisson <ar...@gm...> wrote: > I'd like to use one of the PWM outputs on the robostix to play a tone > on a very small 8ohm 0.1W speaker I pulled from an old modem. I > figured out the software side and setting up the timers, but I don't > know how to safely wire up the speaker to the pins. Any pointers to > some material on this? I took a leap of faith and wired it through a 470ohm resistor (gnd -> speaker -> resistor -> pwm signal pin). Should give me ~10mA. Seems (or rather sounds) to work very nicely - I just played F=FCr Elise on it with my midi keyboard plugged on /dev/ttyS3 :oD In the odd chance that anyone's interested here's a little python program that parses the midi and plays the note on the speaker: import sys import inspect import serial from i2c_io import I2C_IO_Device midi_cmds =3D {} def midihandler(status): def decorator(f): args =3D len(inspect.getargspec(f)[0]) midi_cmds[status] =3D (f, args-1) return f return decorator robo =3D None notemap =3D None noteplaying =3D None @midihandler(0x80) def note_off(channel, pitch, velocity): if pitch =3D=3D noteplaying: robo.write_reg('tccr1a', 0x00) robo.write_reg('portb', 0x00) @midihandler(0x90) def note_on(channel, pitch, velocity): global noteplaying if velocity =3D=3D 0: return note_off(channel, pitch, velocity) robo.write_reg('ocr1a', notemap[pitch]) robo.write_reg('tccr1a', 0x40) robo.write_reg('tccr1b', 0x0a) noteplaying =3D pitch # @midihandler(0xA0) # def aftertouch(channel, pitch, pressure): # print "Channel: %02d Aftertouch pitch=3D%d pressure=3D%d" % (channel, pitch, pressure) # # @midihandler(0xB0) # def controller_change(channel, ctrlnum, value): # print "Channel: %02d Ctrl change ctrl=3D%d val=3D%d" % (channel, ctrlnum, value) def isStatus(byte): return byte & 0x80 def parse_midi(stream): status, channel, cmd_info, data =3D None, None, None, [] b =3D stream.next() while True: if isStatus(b): status =3D b & 0xf0 channel =3D b & 0x0f data =3D [] cmd_info =3D midi_cmds.get(status, None) elif status is not None: # it's a databyte data.append(b) # if we have enough data bytes, process the command if cmd_info and len(data) =3D=3D cmd_info[1]: cmd_info[0](channel, *data) data =3D [] b =3D stream.next() def eat_stream(s): while True: s.next() def get_midi_freq(note): # see http://www.borg.com/~jglatt/tutr/notefreq.htm return (440.0 / 32) * (2 ** ((note - 9) / 12.0)) def get_ocr_value(freq): # 2000000 here is 16MHz divided by prescaler 8 return 2000000 / (freq * 2) def serialstream(s): while True: b =3D ord(s.read(1)) yield b if __name__ =3D=3D "__main__": notemap =3D [int(round(get_ocr_value(get_midi_freq(n)))) for n in range= (127)] robo =3D I2C_IO_Device(0x0b) robo.write_reg('ddrb', 0xff) s =3D serial.Serial('/dev/ttyS2', 38400) parse_midi(serialstream(s)) Arnar |