diff --git a/Makefile b/Makefile index 53da343..cce8b83 100644 --- a/Makefile +++ b/Makefile @@ -44,5 +44,6 @@ smoke-test: tinygo build -size short -o ./build/test.elf -target=circuitplay-express ./examples/ws2812/main.go tinygo build -size short -o ./build/test.elf -target=trinket-m0 ./examples/bme280/main.go tinygo build -size short -o ./build/test.elf -target=circuitplay-express ./examples/microphone/main.go + tinygo build -size short -o ./build/test.elf -target=circuitplay-express ./examples/buzzer/main.go test: clean fmt-check smoke-test diff --git a/README.md b/README.md index a9b8a36..c259edc 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ func main() { | [BlinkM RGB LED](http://thingm.com/fileadmin/thingm/downloads/BlinkM_datasheet.pdf) | I2C | | [BME280 humidity/pressure sensor](https://cdn-shop.adafruit.com/datasheets/BST-BME280_DS001-10.pdf) | I2C | | [BMP180 barometer](https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf) | I2C | +| [Buzzer](https://en.wikipedia.org/wiki/Buzzer#Piezoelectric) | GPIO | | [DS1307 real time clock](https://datasheets.maximintegrated.com/en/ds/DS1307.pdf) | I2C | | [DS3231 real time clock](https://datasheets.maximintegrated.com/en/ds/DS3231.pdf) | I2C | | ["Easystepper" stepper motor controller](https://en.wikipedia.org/wiki/Stepper_motor) | GPIO | diff --git a/buzzer/buzzer.go b/buzzer/buzzer.go new file mode 100644 index 0000000..b294365 --- /dev/null +++ b/buzzer/buzzer.go @@ -0,0 +1,71 @@ +// Package buzzer provides a very simplistic driver for a connected buzzer or low-fidelity speaker. +// +package buzzer // import "tinygo.org/x/drivers/buzzer" + +import ( + "machine" + + "time" +) + +// Device wraps a GPIO connection to a buzzer. +type Device struct { + pin machine.Pin + High bool + BPM float64 +} + +// New returns a new buzzer driver given which pin to use +func New(pin machine.Pin) Device { + return Device{ + pin: pin, + High: false, + BPM: 96.0, + } +} + +// On sets the buzzer to a high state. +func (l *Device) On() (err error) { + l.pin.Set(true) + l.High = true + return +} + +// Off sets the buzzer to a low state. +func (l *Device) Off() (err error) { + l.pin.Set(false) + l.High = false + return +} + +// Toggle sets the buzzer to the opposite of it's current state +func (l *Device) Toggle() (err error) { + if l.High { + err = l.Off() + } else { + err = l.On() + } + return +} + +// Tone plays a tone of the requested frequency and duration. +func (l *Device) Tone(hz, duration float64) (err error) { + // calculation based off https://www.arduino.cc/en/Tutorial/Melody + tone := (1.0 / (2.0 * hz)) * 1000000.0 + + tempo := ((60 / l.BPM) * (duration * 1000)) + + for i := 0.0; i < tempo*1000; i += tone * 2.0 { + if err = l.On(); err != nil { + return + } + time.Sleep(time.Duration(tone) * time.Microsecond) + + if err = l.Off(); err != nil { + return + } + time.Sleep(time.Duration(tone) * time.Microsecond) + } + + return +} diff --git a/buzzer/notes.go b/buzzer/notes.go new file mode 100644 index 0000000..f75007e --- /dev/null +++ b/buzzer/notes.go @@ -0,0 +1,121 @@ +package buzzer + +const ( + Whole = 4 + Half = 2 + Quarter = 1 + Eighth = 0.500 +) + +// The values seem like they are little off, so feel free to make corrections, as needed. +const ( + Rest = 0 + C0 = 16.35 + Db0 = 17.32 + D0 = 18.35 + Eb0 = 19.45 + E0 = 20.60 + F0 = 21.83 + Gb0 = 23.12 + G0 = 24.50 + Ab0 = 25.96 + A0 = 27.50 + Bb0 = 29.14 + B0 = 30.87 + C1 = 32.70 + Db1 = 34.65 + D1 = 36.71 + Eb1 = 38.89 + E1 = 41.20 + F1 = 43.65 + Gb1 = 46.25 + G1 = 49.00 + Ab1 = 51.91 + A1 = 55.00 + Bb1 = 58.27 + B1 = 61.74 + C2 = 65.41 + Db2 = 69.30 + D2 = 73.42 + Eb2 = 77.78 + E2 = 82.41 + F2 = 87.31 + Gb2 = 92.50 + G2 = 98.00 + Ab2 = 103.83 + A2 = 110.00 + Bb2 = 116.54 + B2 = 123.47 + C3 = 130.81 + Db3 = 138.59 + D3 = 146.83 + Eb3 = 155.56 + E3 = 164.81 + F3 = 174.61 + Gb3 = 185.00 + G3 = 196.00 + Ab3 = 207.65 + A3 = 220.00 + Bb3 = 233.08 + B3 = 246.94 + C4 = 261.63 + Db4 = 277.18 + D4 = 293.66 + Eb4 = 311.13 + E4 = 329.63 + F4 = 349.23 + Gb4 = 369.99 + G4 = 392.00 + Ab4 = 415.30 + A4 = 440.00 + Bb4 = 466.16 + B4 = 493.88 + C5 = 523.25 + Db5 = 554.37 + D5 = 587.33 + Eb5 = 622.25 + E5 = 659.25 + F5 = 698.46 + Gb5 = 739.99 + G5 = 783.99 + Ab5 = 830.61 + A5 = 880.00 + Bb5 = 932.33 + B5 = 987.77 + C6 = 1046.50 + Db6 = 1108.73 + D6 = 1174.66 + Eb6 = 1244.51 + E6 = 1318.51 + F6 = 1396.91 + Gb6 = 1479.98 + G6 = 1567.98 + Ab6 = 1661.22 + A6 = 1760.00 + Bb6 = 1864.66 + B6 = 1975.53 + C7 = 2093.00 + Db7 = 2217.46 + D7 = 2349.32 + Eb7 = 2489.02 + E7 = 2637.02 + F7 = 2793.83 + Gb7 = 2959.96 + G7 = 3135.96 + Ab7 = 3322.44 + A7 = 3520.00 + Bb7 = 3729.31 + B7 = 3951.07 + C8 = 4186.01 + Db8 = 4434.92 + D8 = 4698.63 + Eb8 = 4978.03 + E8 = 5274.04 + F8 = 5587.65 + Gb8 = 5919.91 + G8 = 6271.93 + Ab8 = 6644.88 + A8 = 7040.00 + Bb8 = 7458.62 + B8 = 7902.13 +) diff --git a/examples/buzzer/main.go b/examples/buzzer/main.go new file mode 100644 index 0000000..83cc32c --- /dev/null +++ b/examples/buzzer/main.go @@ -0,0 +1,40 @@ +package main + +import ( + "machine" + "time" + + "tinygo.org/x/drivers/buzzer" +) + +type note struct { + tone float64 + duration float64 +} + +func main() { + speaker := machine.PA30 + speaker.Configure(machine.PinConfig{Mode: machine.PinOutput}) + speaker.Set(true) + + bzrPin := machine.A0 + bzrPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) + + bzr := buzzer.New(machine.A0) + + song := []note{ + {buzzer.C4, buzzer.Quarter}, + {buzzer.D4, buzzer.Quarter}, + {buzzer.E4, buzzer.Quarter}, + {buzzer.F4, buzzer.Quarter}, + {buzzer.G4, buzzer.Quarter}, + {buzzer.A4, buzzer.Quarter}, + {buzzer.B4, buzzer.Quarter}, + {buzzer.C5, buzzer.Quarter}, + } + + for _, val := range song { + bzr.Tone(val.tone, val.duration) + time.Sleep(10 * time.Millisecond) + } +}