Button and buzzer for the Orangutan

For those who don’t like to waste timers
or use interrupt programming, here is an
example of a useful button and buzzer combo.
This turns the O into a three-button organ!

(Seven notes are possible, but
with fat fingers, hard to play).

Cheers, Jim

Code with tabs can be downloaded at
uoxray.uoregon.edu/orangutan/button.c

/*
button and buzzer examples for the Orangutan/WinAVR

These routines do not use the timers or interrupts

sjames_remington at yahoo dot com

*/

#define F_CPU 8000000UL 
#include <avr/io.h>
#include <util/delay.h>


// function prototypes
unsigned char button(unsigned char wait);
void buzzer(unsigned int frequency, unsigned int duration);

/*
button(wait);

returns a value corresponding to a button press
4 = rightmost button (next to power switch)
2 = center button
1 = leftmost

if wait is nonzero, wait until a button is pressed and debounce
otherwise, read and return immediately
*/

#define BTNS (7<<3)
unsigned char button(unsigned char wait)
{
	volatile unsigned char save_DDRB, btn_value;

	save_DDRB = DDRB;						//save state of DDRB for LCD display and/or motors
	DDRB |= 0;							//set PORTB all input
	PORTB &= ~BTNS;							//turn off pullups as required
	btn_value = PINB & BTNS;					//read the button pins

	if(wait==0) { 
DDRB = save_DDRB;
return (btn_value>>3);
}				//return immediately if wait=0
	
	while( (PINB & BTNS) == 0);					//otherwise, wait until a button is pressed

	do 	{
		btn_value=(PINB & BTNS);				//read the buttons again
		_delay_ms(20);						//wait 20 ms
		}
	while (btn_value != (PINB & BTNS));				//keep reading until stable
	
	DDRB=save_DDRB;							//restore DDRB
	return (btn_value>>3);						//return values in range 1-7
}

/*
buzzer(frequency, duration);
Sound a tone, this time without interrupts. CPU intensive!

call arguments:
frequency is in Hz, usable range 100-10,000 Hz
duration is in milliseconds

This routine uses _delay_loop_2() to generate timing (4 cpu cycles per loop)

For correct operation, be sure to define F_CPU in Hz!
*/

void buzzer(unsigned int frequency, unsigned int duration)
{
unsigned int wait_units, loops, i;

	DDRB |= 1;							//make PORTB.0 output
	wait_units = F_CPU/(8UL * (long int) frequency);		//half of the tone period, in delay loop units
	loops = duration*F_CPU/(8000UL*wait_units);			//number of loops to execute
	for (i=1; i<=loops; i++) {					//sound the buzzer
		PORTB |= 1;						//on
		_delay_loop_2(wait_units);				//wait 1/2 tone period
		PORTB &= ~1;						//off
		_delay_loop_2(wait_units);				//wait 1/2 tone period
		}
}

int main(void)
{
	unsigned char pressed;

	buzzer(800,1000);						//beep @ 800 Hz for 1 second
	while(1) {
		pressed=button(1);					//wait till one or more buttons pressed
	if (pressed&1) buzzer(400,200);					//play a tone
	if (pressed&2) buzzer(500,200);
	if (pressed&4) buzzer(600,1000);
	}
}
1 Like

Hey, Jim,

Do you mind if I go through your posts (like this one!) and mine them for stuff to stick into the Orangutan library? The lightweight buzzer routine looks like it’d be a handy one to have in there.

Thanks,

Tom

Be my guest! I’ve been having fun. Here is a really nice bird chirp and an even lighter weight beep.

/*
** chirp.c  make beeps and bird chirp sounds
** for the Orangutan with 1 or 8 MHz CPU
*/

#include <avr/io.h>
#define F_CPU 8000000UL  //assume 8 MHz CPU clock
#include <util/delay.h>

/*
a nice bird chirp
*/

void chirp( void )
{
	volatile int i,p,n;
	char per;
	DDRB |= 1; //make PORTB.0 output
	for (n=230; n>120; n--) {
	per=240-n;
	p = n/32;  				//number of pulses
	for (i=0; i<p; i++) {
		PORTB ^= 1;				//toggle buzzer pin
		_delay_loop_2(per<<3);  //remove the <<3 for 1 MHz CPU clock
		}
	}

}

/*
a shorter, lighter beep routine.
*/

void beep1 ( unsigned char per, unsigned char dur )
// per = tone period in units of about 8 usec. 30-250 good (30=16 kHz, 250=2 kHz).
// dur = units of 3200/per  1-30 good. 1 is very short beep.
{
		volatile int i,n;
		DDRB |= 1; 				//PORTB.0 output
		n=dur*(3200/per);		//number of pulses
		for(i=1; i<=n; i++) {
		PORTB ^= 1;				//toggle buzzer pin
		_delay_loop_2(per<<3);  //remove the <<3 for 1 MHz CPU clock
		}
	}

int main(void)
{
	chirp();
	_delay_ms(250);
	beep1(30,20);
	_delay_ms(250);
	beep1(250,20);
	return 0;
}

So it is written, so it shall be done. Thanks, man!

Figure you also wouldn’t mind, but I’ll ask anyway: Ok to put links to your site in the comments? I like to quote sources where I can.

I saw you had the completely interrupt-based song code on your web site. I need to get off my zud and finish the Wagner score!

Tom