NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Project Help and Ideas » Sound Sampler Program

March 31, 2012
by 4bits4e4
4bits4e4's Avatar

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|
//                              |----|----|----|
March 31, 2012
by Ralphxyz
Ralphxyz's Avatar

4bits4e4, please add this to the Nerdkit Community Library Projects it will be a lot easier to find. Looks like it would be fun to do plus good coding practice, thank you.

Ralph

March 31, 2012
by JimFrederickson
JimFrederickson's Avatar

There are already "pull-ups" on the AVR...

If you reverse your logic levels for the Keypad then you shouldn't need the 10k pull-ups...

Less parts, simpler...

I use the internal pull-ups for my keyboards/switches, and have not had any issues...

March 31, 2012
by 4bits4e4
4bits4e4's Avatar

Ralph, Might need some advice on how to post it to the library. Feel free to copy the program and post it. Thanks

Jim, Feel free to modify the code for negative logic on the keypad. The original code used neg logic and the chips pull-ups. The pull downs are included in the kit and I chose to use them after experiencing some glitches using the internal pull-ups.

I'm still working on the memory view/edit utility. Mostly working but needs some finish work. Look for it soon!

Post a Reply

Please log in to post a reply.

Did you know that you can connect to certain car computers via the OBD-II port with a microcontroller? Learn more...