Close

Rummaging the old archives!

A project log for Case study: A polyphonic PIC18F music box

Does this work? An online article discusses about building this music box.

nyh-workshopNYH-workshop 11/27/2017 at 13:260 Comments

Oh my goodness! I suddenly remembered that I may have still keep that program code, despite me taking apart that actual hardware. That actual program code could still tell me some stories of how it would work (or not).

So I rummaged that old archive of mine, all that paper-work from my college days in 2009 (man, how time zips past me!), a mountain of really failed PIC projects code, and finally, here it is!

The project was compiled using MPLab C18, which is no longer in use nowadays, but it can be ported to MPLab XC8 with some modifications. That PIC18F4221 was because my lecturer (and my former colleague later) advised me to buy it because he was going to use it in his new syllabus in his Microcontroller subject. After that semester ended, I 'rehomed' it on that decoration for two years.

Here is the fragment of the code that contains what made that first design (probably) work. There are errors on it of course, and this copy is not edited, or in other words - "Thus it had been written" (sic erat scriptum:

void T0_ISR(void)
{
        f_count1++;
        f_count2++;

        if (f_count1 == 0)
                TRISAbits.TRISA0 = 0;

        if (f_count1 > f_maxcount1)
        {
                TRISAbits.TRISA0 = ~TRISAbits.TRISA0;
        //        PORTAbits.RA0 = ~PORTAbits.RA0;
                f_count1 = 0;
        }

        if (f_count2 == 0)
                TRISAbits.TRISA1 = 0;

        if (f_count2 > f_maxcount2)
        {        
                TRISAbits.TRISA1 = ~TRISAbits.TRISA1;
        //        PORTAbits.RA1 = ~PORTAbits.RA1;
                f_count2 = 0;
        }

        TMR0H = 0xFF; // reload values into the TMR0H and TMR0L
        TMR0L = 0xBD;        

        INTCONbits.TMR0IF = 0;
}

void T1_ISR(void)
{
        t_count1++;
        t_count2++;
        
        if (t_count1 == 25)
                PORTBbits.RB0 = 1;

        if (t_count1 == 1250)
                PORTBbits.RB0 = 0;

        if (t_count1 == t_maxcount1)
        {
                chan1_num++;
                
                if(chan1_num == chan1_max)
                {
                        count1++;
//                        if (count1 == 2)
//                                count1 == 0;
                        chan1_sw(count1);
                                        
                                //break;
                                //default: count1 = 0;        
                        
                }        
                        
                t_count1 = 0;
                
                PORTDbits.RD0 = 0; // chip enable
                SPI(0x03);
                SPI((char)((chan1_freq_address + chan1_num) >> 8)); // send MSB address first
                SPI((char)(chan1_freq_address + chan1_num));
                f_maxcount1 = SPI(0xff);
                PORTDbits.RD0 = 1;                

                PORTDbits.RD0 = 0;
                SPI(0x03);
                SPI((char)((chan1_dur_address + chan1_num*2) >> 8)); // send MSB address first
                SPI((char)(chan1_dur_address + chan1_num*2)); // send LSB address afterwards
                buffer_lo = SPI(0xff);
                buffer_hi = SPI(0xff);
                 PORTDbits.RD0 = 1;

                duration_b =  buffer_hi;
                duration_b = (duration_b << 8) | buffer_lo;
                t_maxcount1 = duration_b;

  //f_maxcount1 = channel1_f[chan1_num]; // next frequency
//t_maxcount1 = channel1_d[chan1_num]; // next duration
        }

        if (t_count2 == 25) 
                PORTBbits.RB1 = 1;

        if (t_count2 == 1250)
                PORTBbits.RB1 = 0;

        if (t_count2 == t_maxcount2)
        {
                chan2_num++;

                if(chan2_num == chan2_max)
                {
                        count2++;
//                        if (count2 == 2)
//                                count2 == 0;
                        chan2_sw(count2);
                        
                }
                t_count2 = 0;

                PORTDbits.RD0 = 0; // chip enable
                SPI(0x03); // read
                SPI((char)((chan2_freq_address + chan2_num) >> 8)); // send MSB address first
                SPI((char)(chan2_freq_address + chan2_num)); // send LSB address afterwards
                f_maxcount2 = SPI(0xff);
                PORTDbits.RD0 = 1; // chip disable

                PORTDbits.RD0 = 0;
                SPI(0x03);
                SPI((char)((chan2_dur_address + chan2_num*2) >> 8)); // send MSB address first
                SPI((char)(chan2_dur_address + chan2_num*2)); // send LSB address afterwards
                buffer_lo2 = SPI(0xff);
                buffer_hi2 = SPI(0xff);
                PORTDbits.RD0 = 1;

                duration_b2 =  buffer_hi2;
                duration_b2 = (duration_b2 << 8) | buffer_lo2;
                t_maxcount2 = duration_b2;
        
//        f_maxcount2 = channel2_f[chan2_num]; // next frequency
//        t_maxcount2 = channel2_d[chan2_num];
        }
        TMR1H = t1_b_hi;
        TMR1L = t1_b_lo; // 0xfeff

        PIR1bits.TMR1IF = 0;
}

 There was SPI inside because the little music box draws out the music note values from an SPI EEPROM. I do not know why I did that when the microcontroller has like 4KB of space. Probably I thought of swapping that EEPROM out later to change tunes, who knows? 

Anyway, that trick was to toggle the TRIS, not the PORT bit. The code in the webpage mentioned is the same, but in BASIC flavour:

'----[INTERRUPT HANDLER]------------------------------------------------
      NOTE_INT:
      TIMER1 = 65490                      ' Load TMR1 with a preset value
      Inc NOTE_COUNTER                    ' Increment the note counter              
      If NOTE_COUNTER > NOTE Then         ' Is it time to toggle the pin ?
      TRISB = TRISB ^ 1                   ' Toggle pin PORTB.0
      Clear NOTE_COUNTER                  ' Clear the note counter
      Endif
      Clear PIR1.0                        ' Clear TMR1 interrupt flag
      Retfie FAST                         ' Exit the interrupt

I have not tested this again - since this give me some ideas, why not try it? It wouldn't hurt to try something new, right?

Note: Do not struggle to understand that code fragment I wrote earlier. It was an unorganized mess and I wrote all that when I was a college student. I will fix all that and place it in my github soon.

Discussions