Skip to main content

Generating Monophonic Melody using PWM of PIC18

/*Program Name: Jukebox
Author: TY Lew
This program generates a tune at the piezo speaker of PICDEM2 Plus. It uses PWM to
generate each note and timer0 interrupt to execute the time signature of each note. Thus, the
PR2 is updated with the value upon each inetrrupt. Whereas, the CCPR1L simple updated with
PR2/2 for 50-50 mark-space ratio. The CCP1CON<5:4> is ignore as we do not need such
accuracy for the tones.
The 'note' array determines the tone frequecy of the notes that will go into PR2. The number
is the MIDI notation. The 'tmsig' array determines the duration of each note and will be used
to update timer registers. The larger the value the longer is the duration. In general the sytem
goes into the ISR for every tone played. */

/* Pressing RA4 button toggles the sound tune on and off */

#include < xc.h >
#include < stdlib.h >
const char note[30]={72,74,76,78,78,79,83,81,78,81,79,78,79,76,78,74,76,78,78,79,83,81,78,81,79,78,79,76,74,0};
const char tmsig_chart[29]={2,2,2,4,4,4,4,8,4,4,6,2,4,4,10,2,2,4,4,4,4,8,4,4,6,2,4,4,16};
char sound_on=0;
char i,tmsig,ndx;
void InterruptHandlerLow(void); // Low priority interrupt service routine

#pragma code InterruptVectorLow = 0x018 // Low priority interrupt vector
void InterruptVectorLow(void) {
_asm
goto InterruptHandlerLow // Jump to interrupt routine
_endasm
}
#pragma code

unsigned char sec;

// Low priority interrupt routine
#pragma interruptlow InterruptHandlerLow

void InterruptHandlerLow() {
char note_tbl[25]={238,224,212,200,189,178,168,158,149,141,133,126,118,112,105,99,94,88,83,79,74,70,66,62,59};
// The above is just like a piano keyboard
if (INTCONbits.TMR0IF) { // Check for Timer0 overflow
CCP1CON = CCP1CON & 0b11110000; // disable CCP1
i++;
if(note[i]==0){
T0CONbits.TMR0ON = 0; // DISABLE TMR0 INTERRUPT
sound_on=0;
}
else {

ndx=note[i]-60;
PR2=note_tbl[ndx];
CCPR1L = PR2/2 ; //
CCP1CON = 0b00001111; // DC1B1 & DC1B0 = 0, PWM mode
tmsig=tmsig_chart[i];
TMR0H = (65536-4000*tmsig)/256;
TMR0L = (65536-4000*tmsig)%256;
T0CONbits.TMR0ON = 1;
INTCONbits.TMR0IF = 0; // Clear Timer0 interrupt flag
}
}
}

/* --------------------------------*/
void main()
{

ADCON1 = 0x0f;
INTCONbits.GIE = 0; // Disable all interrupt first
TRISA = 0b10110001;
TRISC = 0b11111011; // Port C as output
TRISB = 0b11110001; // bit0-3 of Port B as output
PORTB = 0b00001000; // RB3 on first
T2CON = 0b00000111; // Timer 2 On, postscaler = 1:1, prescaler = 1:16
RCONbits.IPEN = 1; // Enable priority interrupt
INTCON2bits.TMR0IP = 0; // Set Timer0 interrupt to high priority
TMR0H = 0xff; // Timer0 high byte register
TMR0L = 0x00; // Timer0 low byte register
T0CON = 0b00000011; // Off Timer0, set to 16-bit mode,
// Use internal instruction clock,
// Rising-edge trigger, set prescaler to 1:8
INTCONbits.TMR0IF = 0;
INTCONbits.TMR0IE = 1; // Enable Timer0 overflow interrupt
INTCONbits.GIEL = 1; // Enable interrupts with low priority
INTCONbits.GIE = 1; // Enable globle interrupt
while(1){
if (!PORTAbits.RA4) {
Delay1KTCYx(20);
if (!PORTAbits.RA4){
while(!PORTAbits.RA4);
sound_on=~sound_on;
if (sound_on) i=0;
}
}

if (sound_on)
T0CONbits.TMR0ON = 1;
else {
T0CONbits.TMR0ON = 0;
CCP1CON = CCP1CON & 0b11110000; // disable CCP1
}
}
}

Comments

Popular posts from this blog

JUKEBOX: Source code for Jukebox using Timer0 interrupts as time signature control and PWM for note generation. Source Code:   /*Program Name: Jukebox Author: TY Lew This program generates a tune at the piezo speaker of PICDEM2 Plus. It uses PWM to generate each note and timer0 interrupt to execute the time signature of each note. Thus, the PR2 is updated with the value upon each inetrrupt. Whereas, the CCPR1L simple updated with PR2/2 for 50-50 mark-space ratio. The CCP1CON<5:4> is ignore as we do not need such accuracy for the tones. The 'note' array determines the tone frequecy of the notes that will go into PR2. The number is the MIDI notation. The 'tmsig' array determines the duration of each note and will be used to update timer registers. The larger the value the longer is the duration. In general the sytem goes into the ISR for every tone played. */ /* Pressing RA4 button toggles the sound tune on and off */ #include <xc.h> #include <stdlib.h>

Why "PORTB=~PORTB" sometime does not work?

When performinging READ-MODIFY-WRITE action, some target board setup may encounter problems. Don't know what is this? Simple. Let's look at the following example: PORTB=~PORTB; The statement required the PORTB to be read first then invert then assign back to PORTB, when executed. This is called READ-MODIFY-WRITE. Some students (not all) encounter problem whereby the execution does not lead to the toggling port PORTB. The remedy is to change the statement to: PORTB=~LATB. Why? All the I/O ports in the PIC18F are buffered when they are configured as output ports. In this context, all the 8 bits of PORTB are directed from the output sides of the buffer. The output devices (e.g. LEDs) may have loaded heavily and causing the voltage to drop far below the VDD value. When the READ action takes place the logic states might have been read wrongly. Consider that the PORTB LEDs are currently lighted up by logic 1s. If the READ-MODIFY-WRIRE statement mentioned above is used to t