March 31, 2012
by 4bits4e4
|
Just a fun piece of code designed to make sounds and demonstrate some menu structure content. You'll need to hook-up a simple keypad to control input. You can use the nerdkit dip switch or build the simple 9 button matrix. Be sure to use 10k ohm pull down resistors on the inputs. Here is the listing, enjoy:
// 4bit Nerdkit Sound Sampler on Atmel 168.
// by 4bits4E4
//Development release: 1.1.0.20120401
//
// FREE & CLEAR license agreement: It's FREE ! That's CLEAR !
//
// Be a member of the Free Software Foundation: http://www.fsf.org/
// Respect the code: http://www.gnu.org/copyleft/gpl.html
//
// A very simple sound sampler program. Normally duration is calculated
// for each frequency in order to generate true note timings (ie: 1/4 note).
// 1/freq = period. period = time on + time off.
// The higher the frequency the longer the duration to maintain uniform length.
// 1/880hz = 1.136ms. 1.136/2 = 570us. Time on = 570us and Time off = 570us.
// CPUClock speed and instruction count is used to determine an accurate duration
// of the note. Experiment!
//////////// Load libraries //////////////
#define F_CPU 14745600
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <inttypes.h>
#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
//////////////////Header file stuff /////////////////
//Inputs
#define row0 (1<<PB3) //
#define row1 (1<<PB4) // Use 10k ohm PULL-DOWN reistors
#define row2 (1<<PB5) //
//Outputs
#define col0 (1<<PB0)
#define col1 (1<<PB1)
#define col2 (1<<PB2)
#define piezo (1<<PC0)
//Prototype declarations
void keypad(void);
void klaxon(void);
void siren(void);
void beep(void);
int blips();
void whistle(void);
//Globals
FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
uint8_t screen=1; //The screen we are working in.(Default= menu)
uint8_t scancode; //keypad return val
uint8_t position =0; //cursor[position]
uint8_t num; //number of blips
uint8_t dur; //duration of blips
uint8_t freq; //frequency of blips
//////////////////// Init routine /////////////////////////////
void init()
{
//Keypad matrix port setup
DDRB = ~(1<<DDB5)|~(1<<DDB4)|~(1<<DDB3); //rows = Inputs 10k ohm pull downs
DDRB = (1<<DDB2)|(1<<DDB1)|(1<<DDB0); // cols = outputs
PORTB = ~(1<<PB3)|~(1<<PB4)|~(1<<PB5); // pullups off
//LCD commands
lcd_init();
lcd_set_type_command();
lcd_write_byte(0x0f); //set cursor on and blinking
//Set up sound port
DDRC |= (1<<PC0);
PORTC |= piezo;
return;
}//end
/////////// SCREEN 1 ///////////////////////
////|--------------------|
////| Sound Sampler |
////| whistle klaxon | 41,4b
////| beep siren | 15,1f
////| blip(num,dur,freq) | 55,5a,5d,60
////|--------------------|
//////////////////////////
void menu()
{
init();
/*keypad();
if(scancode==0x12)
{
//Press and hold SELECT key while powering on the unit.
lcd_line_two();
lcd_write_string(PSTR(" Happy Easter!"));
while(!PINB && 0x038)
{
;;
}
}//endif
*/
blips(2,40,80);
//Array to hold cursor boundaries
uint8_t menu_screen_cursor[] = {0,0x41,0x4b,0x15,0x1f,0x55,0x5b,0x5d,0x60,0};
position=1; //cursor(position)
screen=1;
lcd_clear_and_home();
lcd_write_string(PSTR(" Sound Sampler"));
lcd_line_two();
lcd_write_string(PSTR(" whistle klaxon"));
lcd_line_three();
lcd_write_string(PSTR(" beep siren"));
lcd_line_four();
lcd_write_string(PSTR(" blips("));
lcd_goto_position(0,menu_screen_cursor[position]);
while(screen==1)
{
////////////////////////////////////////////
keypad(); //getkey
if(scancode) //if key
{
switch(scancode) //find key
{
case 0x0a: switch(position) //Key pressed = "UP"
{
case 6: num+=0x01;break;
case 7: dur+=0x10;break;
case 8: freq+=0x10;break;
}
break;
case 0x22: switch(position) //Key pressed = "DOWN"
{
case 6: num-=0x01;break;
case 7: dur-=0x10;break;
case 8: freq-=0x10;break;
}
break;
case 0x11: if(menu_screen_cursor[position-1]);
{ //Key Pressed = "LEFT"
position -=1; //Decrement position
}
break;
case 0x14: if(menu_screen_cursor[position +1]) // "RIGHT" Increment position.
{
position +=1;
}
break;
case 0x12: switch(position) //Key Pressed = "SELECT"
{
case 1: whistle();break;
case 2: klaxon();break;
case 3: beep();break;
case 4: siren();break;
case 5: blips(num,dur,freq);break;
}
break;
}//endswitch
//Update program counter display
lcd_goto_position(0,0x5b);
fprintf_P(&lcd_stream, PSTR("%x,"), num);
lcd_goto_position(0,0x5d);
fprintf_P(&lcd_stream, PSTR("%x,"), dur);
lcd_goto_position(0,0x60);
fprintf_P(&lcd_stream, PSTR("%x)"), freq);
}//endif
scancode=0;
lcd_goto_position(0,menu_screen_cursor[position]);
}//endwhile
return;
}//end
///////////////// Sounds /////////////////////////////////
void click()
{
uint8_t k;
for(k=0;k<15;k++)
{
PINC |= piezo;
delay_us(25);
PINC &= ~piezo;
delay_us(25);
}
return;
}
void beep()
{
uint16_t k;
for(k=0;k<1250;k++)
{
PINC |= piezo;
delay_us(200);
PINC &= ~piezo;
delay_us(200);
}
return;
}
void klaxon()
{
uint16_t k;
uint8_t j;
for(j=0;j<=2;j++)
{
for(k=0;k<1200;k++)
{
PINC |= piezo;
delay_us(250);
PINC &= ~piezo;
delay_us(250);
}
for(k=0;k<600;k++)
{
PINC |= piezo;
delay_us(500);
PINC &= ~piezo;
delay_us(500);
}
}
return;
}
int blips(num,dur,freq) //Beep num times, duration, frequency
{
uint8_t k;
uint8_t j;
for(j=1;j<=num;j++)
{
for(k=0;k<dur;k++)
{
PINC |= piezo;
delay_us(freq);
PINC &= ~piezo;
delay_us(freq);
}
delay_ms(freq);
}
return(0);
}
void whistle()
{
uint16_t k;
for(k=10;k<2000;k+=5)
{
PINC |= piezo;
delay_us(k);
PINC &= ~piezo;
delay_us(k);
}
for(k=1220;k>10;k-=5)
{
PINC |= piezo;
delay_us(k);
PINC &= ~piezo;
delay_us(k);
}
return;
}
void siren()
{
uint16_t k;
uint8_t j;
for(j=0;j<2;j++)
{
for(k=1220;k>40;k-=1)
{
PINC |= piezo;
delay_us(k);
PINC &= ~piezo;
delay_us(k);
}
for(k=40;k<1220;k+=1)
{
PINC |= piezo;
delay_us(k);
PINC &= ~piezo;
delay_us(k);
}
}
return;
}
////////////////////Keypad scancode generator///////////////////////////
//PORTB 0 1 2
///// |------------|
///// 3 |09 | 0A | 0C| Use 10k ohm pull-down resistors on inputs.
///// |------------|
///// 4 |11 | 12 | 14|
///// |------------|
///// 5 |21 | 22 | 24|
//// |------------|
void keypad()
{
uint8_t column;
uint8_t row;
uint8_t row_high = (PINB & 0x38);
scancode=0;
if(row_high); //then key pressed
{
delay_ms(50);
for(column=0;column<3;column++)
{
PINB |= (1<<column); //Walking 1, PB0=0 ,1 ,2
for(row=3;row<6;row++)
{
row_high = (PINB & 0x38); //Read port and mask columns
if(row_high) //then key found
{
scancode = PINB; //1 col and 1 row
click();
while(scancode == PINB)
{
;; //wait for key up
}
}//endif
}//endfor
PINB &= (1<<column); // Turn off walking one
}//endfor
}//endif
return;
}//end
int main()
{
while(1)
{
menu();
}
return(0);
}
////////////////////// * NOTES:////////////////////////////////
////////// LCD MAP //////////////////Keypad //////////////////////
///____________________
//|00000000001111111111|
//|0123456789ABCDEF0123|
//|--------------------| _PB0
//|44444444444444445555| | _PB1
//|0123456789ABCDEF0123| | | _PB2
//|--------------------| | | |
//|11111111111122222222| |----|----|----|
//|456789ABCDEF01234567| PB3--|0X09|0X0a|0x0c| NOTE: Use 10k ohm
//|--------------------| |----|----|----| PULL-DOWN resistors
//|55555555555566666666| PB4--|0x11|0x12|0x14| on PB3,4,5
//|456789ABCDEF01234567| |----|----|----|
//|--------------------| PB5--|0x21|0x22|0x24|
// |----|----|----|
|