All About Circuits Forum  

Go Back   All About Circuits Forum > Software, Microcomputing, and Communications Forums > Embedded Systems and Microcontrollers

Notices

Embedded Systems and Microcontrollers Discussion forum for projects and working with embedded systems and microcontrollers (FPGAs, PICs, AVRs). Get help with hardware issues and embedded programming.

Reply   Post New Thread
 
Thread Tools Display Modes
  #1  
Old 08-11-2010, 03:30 AM
ELECTRONERD's Avatar
ELECTRONERD ELECTRONERD is offline
Senior Member
 
Join Date: May 2009
Location: Outer Space
Posts: 1,145
Default PIC Sound Generator

Hey Everyone,

I haven't been on AAC for a little while, my job has kept me busy. I still browse the other posts when I can, and I try to remain assiduous at my projects after I finish work each day, if time permits of course.

Project:

I just began programming with PICs and have run through a series of projects to exercise my skill level in programming; this particular project is entitled a "PIC Sound Generator" in which it will generate notes at my command.

Theory & Operation:

I begin with all my header files, definings, etc. until I reach my first function. This function allows me to enter a note that I previously stored into an array, and then define how long of a duration I wish it to play for.

My frequency is set by Timer0 on the PIC, in which I rapidly turn RA0 on and off depending on my TMR0L and TMR0H values, and furthermore, my array value. TMR0H and TMR0L enable me to use 16-bit mode since my lowest note is 1515μS. Remember that I wish to know my lowest frequency note since the delay is longer. If I were to use 8-bit, my maximum delay would be 128μS. Thus, equation for 16-Bit timer:



Which simplifies to:



It has already been noted to me that Timer2 would be a better choice, but I wish to become more familliar with all the PICs abilities and attributes, so I will eventually learn about Timer2 as well.

In the main() function, you see I have a long list of the playNote function commands. These, as I mentioned, give me what note I want and for how long I wish to play it. The latter statement is based on whole notes (actually quarter notes) and half notes (actually eighth notes). The music is depicted here:

http://upload.wikimedia.org/wikipedi.../4/49/Gstk.png

The time signature is 3/4; meaning there are 3 quarter (1/4) notes per measure; or section in my comments. Therefore, to make the music even, a section must eventually add up to 3 quarter notes. Otherwise, the music becomes convoluted and not very pleasant to listen to. I can, at my disposal, change how fast I want my music to play if I change my WHOLE or HALF values previously defined at the beginning. Note that they correlate with one another; if I have 800 as the WHOLE, I must have half of that for the HALF value. I was fortunate to have experience in this regard (I play classical guitar), so that made things much easier.


Code:
  • Using PIC18F1320, with C18 compiler
Code:
//
// CreatingSound2.C Song "God Save The Queen"
//
 #include <p18f1320.h>
 #include <delays.h>
 #include <stdlib.h>
 #pragma config OSC=INTIO2, WDT=OFF, LVP=OFF, DEBUG=ON
 #define PAUSE Delay1KTCYx(50);
 #define WHOLE 1000
 #define HALF 500
 #define LONG 2000
 
void playNote(unsigned int note, unsigned int timer)   // Note & Timer driver; determines which note will be played and for how long
        {    
    unsigned int times, freq, notes[] = {64021, 64105, 64185, 64260, 64331, 64398, 64462, 64522, 64578, 64632, 64682, 64730, 64774, 64817, 64856, 64895};   
                freq = notes[note];   // Determine frequency based on array value
                INTCONbits.TMR0IF = 0;   // Clear OVF Flag
                LATA = 0x01;   // Initialize LATA 
                TMR0L = freq & 0xFF;     
                TMR0H = (freq >> 8) & 0xFF;            
                T0CON|=0x80;
 
                for(times=timer;times>0;times--)   // Duration of playing
                {
                                TMR0H = (freq >> 8) & 0xFF;   //Load TMR0H byte first
                                TMR0L = freq & 0xFF;   // Load TMR0L byte next
                                while(!INTCONbits.TMR0IF);   // Wait for timer
`        INTCONbits.TMR0IF = 0;   // Clear OVF Flag
        LATA = ~LATA;   // Invert output   
                }
   PAUSE;
        }
 
 void main()
 {
 
 OSCCONbits.IRCF0=1; 
 OSCCONbits.IRCF1=1;
 OSCCONbits.IRCF2=1;
 T0CONbits.TMR0ON = 0;   // Don't turn timer on yet
 T0CONbits.T08BIT = 0;  // Timer0 is configured as 16-bit timer
 T0CONbits.T0CS = 0;   // Use internal clock
 T0CONbits.PSA = 1;   // Prescaler is not assigned
 T0CONbits.T0PS2 = 0;
 T0CONbits.T0PS1 = 0;
 T0CONbits.T0PS0 = 0;
 while(!OSCCONbits.IOFS);
 TRISA = 0b11111110;   // Use RA0 as output
 
 while(1)
 {
  playNote(3, WHOLE);  // Section 1
  playNote(3, WHOLE);
  playNote(3, WHOLE);
 
  playNote(1, WHOLE);  // Section 2
  playNote(3, HALF);
  playNote(5, WHOLE);
 
  playNote(7, WHOLE);  // Section 3
  playNote(7, WHOLE);
  playNote(8, WHOLE);
 
  playNote(5, WHOLE);  // Section 4
  playNote(7, HALF);
  playNote(8, WHOLE);
 
  playNote(12, WHOLE); // Section 5
  playNote(0, WHOLE);
  playNote(12, WHOLE);
 
  playNote(7, WHOLE);  // Section 6
  playNote(8, HALF);
  playNote(10, WHOLE);
 
  playNote(12, WHOLE); // Section 7
  playNote(12, WHOLE);
  playNote(13, WHOLE);
 
  playNote(10, WHOLE); // Section 8
  playNote(10, HALF);
  playNote(12, WHOLE);
 
  playNote(5, WHOLE);  // Section 9
  playNote(1, WHOLE);
  playNote(3, HALF);
 
  playNote(3, LONG);  // Section 10
 
  playNote(10, WHOLE); // Section 11
  playNote(10, WHOLE);
  playNote(10, WHOLE);
 
  playNote(10, WHOLE); // Section 12
  playNote(8, HALF);
  playNote(7, WHOLE);
 
  playNote(8, WHOLE);  // Section 13
  playNote(8, WHOLE);
  playNote(8, WHOLE);
 
  playNote(8, WHOLE);  // Section 14
  playNote(7, HALF);
  playNote(5, WHOLE);
 
  playNote(5, WHOLE);  // Section 15
  playNote(7, WHOLE);
  playNote(7, HALF);
 
  playNote(0, LONG);  // Section 16
 
  playNote(15, WHOLE); // Section 17
  playNote(15, WHOLE);
  playNote(15, WHOLE);
 
  playNote(15, WHOLE); // Section 18
  playNote(13, HALF);
  playNote(12, WHOLE);
 
  playNote(13, WHOLE); // Section 19
  playNote(13, WHOLE);
  playNote(13, WHOLE);
 
  playNote(13, WHOLE); // Section 20
  playNote(12, HALF);
  playNote(10, WHOLE);
 
  playNote(7, WHOLE);  // Section 21
  playNote(8, HALF);
  playNote(7, HALF);
  playNote(5, HALF);
  playNote(3, HALF);
 
  playNote(7, WHOLE);  // Section 22
  playNote(8, HALF);
  playNote(10, WHOLE);
 
  playNote(12, WHOLE); // Section 23
  playNote(5, WHOLE);
  playNote(3, HALF);
 
  playNote(3, LONG);  // Section 24
 
  playNote(12, WHOLE); // Section 25
  playNote(13, HALF);
  playNote(12, HALF);
  playNote(10, HALF);
  playNote(8, HALF);
 
  playNote(7, WHOLE);  // Section 26
  playNote(5, HALF);
  playNote(3, WHOLE);
 
  playNote(5, WHOLE);  // Section 27
  playNote(7, WHOLE);
  playNote(7, HALF);
 
  playNote(0, LONG);  // Section 28
 
  Delay100TCYx(255);
 }
}
Select All

A picture of my setup is depicted in the attachements and to see it working click the following link:

http://s974.photobucket.com/albums/a...r.mp4&newest=1

On the o'scope you'll notice that the waveform is somewhat distorted, this is due to the speaker. If I were to take that off, not only would you not have any sound (obviously), but it would then give you an adequate square wave.

I hope you all enjoyed this! If you have any suggestions or comments for me, please feel free to mention them! I would be grateful for any comments in order to edify myself.

I would like to thank 3v0 and Hayato for their help!

Austin
Attached Images
File Type: jpg PICSoundGenerator 001.jpg (281.8 KB, 48 views)
File Type: jpg PICSoundGenerator 002.jpg (276.5 KB, 35 views)

Last edited by ELECTRONERD; 08-11-2010 at 03:58 AM.
Reply With Quote
  #2  
Old 08-12-2010, 04:23 PM
russ_hensel russ_hensel is offline
Senior Member
 
Join Date: Jan 2009
Location: South Dartmouth Ma
Posts: 814
Default

and your question is?....
Reply With Quote
  #3  
Old 08-13-2010, 02:16 AM
ELECTRONERD's Avatar
ELECTRONERD ELECTRONERD is offline
Senior Member
 
Join Date: May 2009
Location: Outer Space
Posts: 1,145
Default

Quote:
Originally Posted by russ_hensel View Post
and your question is?....
I apologize, I suppose this particular thread should have been moved to the Projects forum! It is a completed project I recently did, so I thought I would share it with everyone.

Sorry for the misunderstanding!

Thanks,

Austin
Reply With Quote
  #4  
Old 08-13-2010, 09:10 AM
retched's Avatar
retched retched is offline
Senior Member
 
Join Date: Dec 2009
Location: Baltimore, MD
Posts: 5,198
Blog Entries: 14
Default

The ability to read an external file, possibly from a memory card, to enable you to compose separate 'songs' without needing separate PICs to play them would be a nice next logical step.

This is a nice project for folks who wish to get involved in PIC programming and in-circuit programming.

It gives instant feedback of a job-well-done.

Good Job.
__________________
-rm-
Reply With Quote
  #5  
Old 08-13-2010, 04:04 PM
ELECTRONERD's Avatar
ELECTRONERD ELECTRONERD is offline
Senior Member
 
Join Date: May 2009
Location: Outer Space
Posts: 1,145
Default

Thanks Retched!

Now I'm storing additional songs into 2D arrays, containing the notes and time values. I plan on having three switches which will enable me to select between the three different songs. I'll post the results here when I finish!
Reply With Quote
  #6  
Old 08-13-2010, 04:10 PM
bertus's Avatar
bertus bertus is online now
Administrator
 
Join Date: Apr 2008
Location: Amsterdam,Holland (GMT + 1)
Posts: 12,097
Default

Hello,

When you made the changes, can you also post the schematic?
Then it would be a complete project.

Bertus
__________________
You don't have to know everything, if you know where to find it.
When you do ask questions, you may look stupid.
When you do NOT ask questions, you will STAY stupid.

It would be nice to have the Timezone ( GMT +/- x ) in the location field in the profile.
(User CP -> Edit Your Details)
Reply With Quote
  #7  
Old 08-13-2010, 08:46 PM
ELECTRONERD's Avatar
ELECTRONERD ELECTRONERD is offline
Senior Member
 
Join Date: May 2009
Location: Outer Space
Posts: 1,145
Default

Hi Bertus,

It really isn't much of a schematic, simply a 47μF cap connected from the RA0 I/O pin and then to the speaker.

If you think it is necessary, I can make a schematic.
Reply With Quote
  #8  
Old 08-14-2010, 06:32 AM
retched's Avatar
retched retched is offline
Senior Member
 
Join Date: Dec 2009
Location: Baltimore, MD
Posts: 5,198
Blog Entries: 14
Default

Might as well post the schematic. Im sure this will be a popular project with first time uC users. At least that way they have a schematic to compare their build against, no matter how simple or small.
__________________
-rm-
Reply With Quote
  #9  
Old 08-15-2010, 12:29 AM
ELECTRONERD's Avatar
ELECTRONERD ELECTRONERD is offline
Senior Member
 
Join Date: May 2009
Location: Outer Space
Posts: 1,145
Default

Quote:
Originally Posted by retched View Post
Might as well post the schematic. Im sure this will be a popular project with first time uC users. At least that way they have a schematic to compare their build against, no matter how simple or small.
Alright, then I'll go ahead and post it for everyone. However, this project is a progressional type of one, thus I am currently working on it with several more features. I'll post both the schematics when I finish.

Till Then,

Austin
Reply With Quote
  #10  
Old 09-14-2010, 09:38 PM
ELECTRONERD's Avatar
ELECTRONERD ELECTRONERD is offline
Senior Member
 
Join Date: May 2009
Location: Outer Space
Posts: 1,145
Default PIC Sound Generator Schematic

Hey Everyone,

Here is the schematic, as requested in addition to the new code:

http://mufnet.net/index.php?show=1261

Code:
  1. //
  2. // CreatingSound3.C
  3. //
  4. #include <p18f1320.h>
  5. #include <delays.h>
  6. #include <adc.h>
  7. #pragma config OSC=INTIO2, WDT=OFF, LVP=OFF, DEBUG=ON
  8. #define PAUSE Delay1KTCYx(50);
  9. rom const unsigned int songs[6][80] = {
  10. {0, 5, 7, 8, 10, 8, 0, 0, 5, 7, 8, 0, 8, 5, 12, 10, 12, 17, 19, 20, 22, 20, 12, 12, 17, 19, 20, 12, 20, 17, 24, 22, 12, 12, 17, 19, 20, 17, 24, 20, 29, 17, 17, 20, 19, 17, 24, 20, 17, 12, 12, 17, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  11. {500, 1000, 1500, 250, 250, 1000, 500, 500, 1500, 250, 250, 250, 250, 250, 250, 1500, 500, 1000, 1500, 250, 250, 1000, 500, 500, 1500, 250, 250, 250, 250, 250, 250, 1500, 250, 250, 500, 250, 250, 250, 250, 250, 1000, 250, 250, 250, 250, 250, 1500, 250, 250, 500, 500, 1500, 500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  12. {7, 9, 10, 9, 10, 12, 14, 15, 14, 12, 10, 14, 15, 14, 19, 17, 19, 12, 14, 15, 14, 30, 10, 12, 14, 12, 10, 14, 9, 10, 9, 9, 10, 12, 10, 9, 7, 9, 7, 6, 10, 9, 10, 9, 7, 6, 14, 7, 12, 10, 9, 14, 15, 17, 15, 14, 12, 9, 7, 6, 7, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  13. {500, 500, 500, 250, 500, 500, 500, 500, 500, 250, 500, 500, 500, 500, 500, 250, 500, 500, 500, 500, 1500, 500, 500, 500, 500, 250, 500, 1500, 500, 250, 500, 500, 500, 500, 500, 250, 500, 500, 500, 500, 1000, 500, 500, 250, 500, 1000, 500, 500, 250, 500, 1500, 500, 250, 500, 500, 250, 500, 1500, 250, 500, 1500, 5000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  14. {5, 5, 5, 3, 5, 7, 9, 9, 10, 7, 9, 10, 14, 2, 14, 9, 10, 12, 14, 14, 158, 12, 12, 14, 7, 3, 5, 5, 12, 12, 12, 12, 10, 9, 10, 10, 10, 10, 9, 7, 7, 9, 9, 2, 17, 17, 17, 17, 15, 14, 15, 15, 15, 15, 14, 12, 9, 10, 9, 7, 5, 9, 10, 12, 14, 7, 5, 5, 14, 15, 14, 12, 10, 9, 7, 5, 7, 9, 9, 20},
  15. {500, 500, 500, 1500, 250, 500, 500, 500, 500, 1500, 250, 500, 500, 500, 500, 1500, 250, 500, 500, 500, 500, 1500, 250, 500, 500, 1000, 250, 1500, 500, 500, 500, 1500, 250, 500, 500, 500, 500, 1500, 250, 500, 500, 500, 250, 1500, 500, 500, 500, 1500, 250, 500, 500, 500, 500, 1500, 250, 500, 500, 250, 250, 250, 250, 1500, 250, 500, 500, 1500, 250, 1500, 500, 250, 250, 250, 250, 1500, 250, 500, 500, 1500, 250, 1500}
  16. };
  17. void playNote(unsigned int note, unsigned int timer) // Note & Timer driver; determines which note will be played and for how long
  18. {
  19. unsigned int times, freq, notes[] = {58725, 59107, 59468, 59809, 60131, 60434, 60720, 60990, 61245, 61486, 61714, 61928, 62131, 62322, 62502, 62672, 62833, 62985, 63128, 63263, 63391, 63511, 63625, 63732, 63833, 63929, 64019, 64104, 64104, 64184, 64260, 65536};
  20. freq = notes[note]; // Determine frequency based on array value
  21. INTCONbits.TMR0IF = 0; // Clear OVF Flag
  22. LATA = 0x01; // Initialize LATA
  23. TMR0L = freq & 0xFF;
  24. TMR0H = (freq >> 8) & 0xFF;
  25. T0CON|=0x80;
  26. for(times=timer;times>0;times--) // Duration of playing
  27. {
  28. TMR0H = (freq >> 8) & 0xFF; //Load TMR0H byte first
  29. TMR0L = freq & 0xFF; // Load TMR0L byte next
  30. while(!INTCONbits.TMR0IF); // Wait for timer
  31. ` INTCONbits.TMR0IF = 0; // Clear OVF Flag
  32. LATA = ~LATA; // Invert output
  33. }
  34. PAUSE;
  35. }
  36. void playSong(unsigned int song)
  37. {
  38. int time, note, counter;
  39. while(1)
  40. {
  41. if(song==0) // Song 1
  42. {
  43. for(counter=0;counter<53;counter++)
  44. {
  45. note = songs[0][counter]; // Song 1 notes
  46. time = songs[1][counter]; // Song 1 time values
  47. playNote(note, time); // Play through notes and times
  48. }
  49. break; // When song 1 finishes, break
  50. }
  51. else if(song==1) // Song 2
  52. {
  53. for(counter=0;counter<63;counter++)
  54. {
  55. note = songs[2][counter]; // Song 2 notes
  56. time = songs[3][counter]; // Song 2 time values
  57. playNote(note, time); // Play through notes and times
  58. }
  59. break; // When song 2 finishes, break
  60. }
  61. else if(song==2) // Song 3
  62. {
  63. for(counter=0;counter<80;counter++)
  64. {
  65. note = songs[4][counter]; // Song 3 notes
  66. time = songs[5][counter]; // Song 3 time values
  67. playNote(note, time); // Play through notes and times
  68. }
  69. break; // When song 3 finishes, break
  70. }
  71. else
  72. {
  73. LATB = 0x08; // Otherwise, LED 4
  74. }
  75. }
  76. }
  77. void main()
  78. {
  79. ADCON1 = 0x0E; // ADC Settings as digital inputs from RA1-RA3
  80. OSCCONbits.IRCF0=1;
  81. OSCCONbits.IRCF1=1;
  82. OSCCONbits.IRCF2=1;
  83. T0CONbits.TMR0ON = 0; // Don't turn timer on yet
  84. T0CONbits.T08BIT = 0; // Timer0 is configured as 16-bit timer
  85. T0CONbits.T0CS = 0; // Use internal clock
  86. T0CONbits.PSA = 1; // Prescaler is not assigned
  87. T0CONbits.T0PS2 = 0;
  88. T0CONbits.T0PS1 = 0;
  89. T0CONbits.T0PS0 = 0;
  90. while(!OSCCONbits.IOFS);
  91. TRISA = 0xFE;
  92. TRISB = 0xF0;
  93. while(1)
  94. {
  95. switch(PORTA & 0x0E)
  96. {
  97. case 0x0C:
  98. LATB = 0x01;
  99. playSong(0);
  100. break;
  101. case 0x0A:
  102. LATB = 0x02;
  103. playSong(1);
  104. break;
  105. case 0x06:
  106. LATB = 0x04;
  107. playSong(2);
  108. break;
  109. default:
  110. LATB = 0x08;
  111. }
  112. }
  113. }
Select All
I also have a video of it in action:

http://s974.photobucket.com/albums/a...C.mp4&newest=1

Thanks!
Attached Images
File Type: png PICSoundGeneratorSChematic.PNG (33.7 KB, 42 views)

Last edited by ELECTRONERD; 09-14-2010 at 09:45 PM.
Reply With Quote
Reply   Post New Thread

Tags
, ,


Related Site Pages
Section Title
Textbook Impedance transformation : Transmission Lines


Similar Threads
Thread Thread Starter Forum Replies Last Post
Pic Sound Player Art The Projects Forum 7 01-10-2010 06:54 AM
Electrical interference and sound devices on computer? sgtmattbaker General Electronics Chat 17 10-24-2009 03:25 PM
Sound using PIC Sniperchang General Electronics Chat 5 09-21-2009 05:08 PM
sound card pulse generator with 2500 Hz carrier frequency alexv The Projects Forum 12 07-15-2009 06:17 PM
PIC Sound Card CVMichael Embedded Systems and Microcontrollers 3 06-22-2008 02:57 AM

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 03:30 PM.


User-posted content, unless source quoted, is licensed under a Creative Commons Public Domain License.
Powered by vBulletin
Copyright ©2000 - 2014, vBulletin Solutions, Inc.