Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PIC Sound Generator

Status
Not open for further replies.

EN0

Member
Hey Everyone,

I hope you enjoy this project I just completed!

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:

[LATEX]Frequency Delay = ((65536 - Delay)*0.5uS)*2[/LATEX]

Which simplifies to:

[LATEX]Frequency Delay (uS) = (65536 - Delay)[/LATEX]

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 for the third song is depicted here, as an example:

**broken link removed**

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

**broken link removed**

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. }

Video in action:

uC Project :: CreatingSound3.C video by ElectroNerdy - Photobucket

I'd like to thank 3v0 and Hayato for their support!

Thanks,

Austin
 

Attachments

  • PICSoundGeneratorSChematic.PNG
    PICSoundGeneratorSChematic.PNG
    33.7 KB · Views: 601
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top