Composing Happy Birthday song

 

                Composing Happy Birthday song

 

 

 

    As a composing example program we present Listing 1, the familiar Happy Birthday song composition. Figure 1 is the corresponding circuit for it. To decorate the birthday atmosphere, two LEDs are turned ON/OFF alternately in program.

                            

                                          Figure 1.  Song Example Circuit

 

 

    Just as for any song composing, we need to write the music note subroutines for each note that will be used in song. The basic idea on note creation is the same as described for 440 Hz music tone: find the note's frequency, then calculate its half period T/2; then drive the speaker High or Low in such half period.

 

    For example, in the 784 Hz "G5" tone subroutine, T/2 = 638 us, so the speaker needs to be driven High for 638us, then Low for 638us, and so on. To count this time, we utilize the ATtiny11's timer interrupt. This 8-bit timer is an up counter, it increases its count every clock cycle (that is 1 microsecond), when reaching count=256, it overflows to zero and generates an interrupt, and then increases one count per us again. Each interrupt causes the MCU to execute its interrupt service routine, in this case (see Listing 3) it is TIMOVF.

 

    Instead of letting the timer count from zero, we set it start at 240, so the timer will overflow each 16 us. This is equivalent to every 16 us the timer has a "tick." Therefore for T/2=638 us, the needed Ticks# = 638/16=40.

 

    Each music note takes some time to play. So the above half period High/Low must be repeated a number of times. We appropriately choose this number as 150. This number was proved appropriate by experiment. You can change it if you found it too short or too long.

 

    After writing all note subroutines, the last step is to call these notes to form a song, as shown in the main program of Listing 3.  Of course, you need to listen to it, then change it by your feeling, and do this for several iterations until you get the satisfactory music.

 

 

 

 

 

LISTING 1. Birthday Song program

 

;BDay.ASM(.bin 466 bytes)   BirthDay Song with Flashing LEDs

 

.include "TN11def.inc"      ; Port definitions here

.cseg

.org 0

        rjmp    RESET

        RETI

        RETI

        rjmp    TIMOVF

RESET:

        ldi     r16, $80

        out     SREG, r16   ; Enable any Int

        ldi     r16, $02

        out     TIMSK, r16  ; Enable Timer0 Int

        ldi     r16, $01

        out     TCCR0, r16  ; TimerControl:  CK=>trig

        sbi     DDRB, 4     ; config DDRB bit-4 as output

        sbi     DDRB, 1     ; config DDRB bit-1 as output

        sbi     DDRB, 0     ; config DDRB bit-0 as output

 

AGAIN:

   ;----------------------------------*

        cbi     PORTB, 0    ; RLED=ON  

        Sbi     PORTB, 4    ; GLED=OFF

        in      R4, PORTB

        COM     R4

        out     PORTB, R4   ; complement PortB bits

 

        rcall   Sew

        rcall   DLms

        rcall   Sew

        rcall   DLms

 

        rcall   La

        rcall   La

 

        rcall   Sew

        rcall   Sew

 

        rcall   Dos

        rcall   Dos

 

        rcall   Tea

        rcall   Tea

        rcall   Tea

        rcall   Tea

        rcall   DLhalfS

        rcall   DLhalfS

        rcall   DLhalfS

        rcall   DLhalfS

   ;----------------------------------*

        in      R4, PORTB

        COM     R4

        out     PORTB, R4   ; complement PortB bits

 

        rcall   Sew

        rcall   DLms

        rcall   Sew

        rcall   DLms

 

        rcall   La

        rcall   La

 

        rcall   Sew

        rcall   Sew

 

        rcall   Rays

        rcall   Rays

        rcall   Rays

 

        rcall   Dos

        rcall   Dos

        rcall   Dos

        rcall   Dos

        rcall   DLhalfS

        rcall   DLhalfS

        rcall   DLhalfS

        rcall   DLhalfS

   ;----------------------------------*

        in      R4, PORTB

        COM     R4

        out     PORTB, R4   ; complement PortB bits

 

        rcall   Sew

        rcall   DLms

        rcall   Sew

        rcall   DLms

 

        rcall   Sews

        rcall   Sews

        rcall   Sews

        rcall   Sews

 

        rcall   Mes

        rcall   Mes

        rcall   Mes

 

        rcall   Dos

        rcall   Dos

        rcall   Dos

 

        rcall   Tea        

        rcall   Tea        

        rcall   Tea        

 

        rcall   La

        rcall   La

        rcall   La

        rcall   La

        rcall   La

        rcall   DLhalfS

        rcall   DLhalfS

        rcall   DLhalfS

        rcall   DLhalfS

   ;----------------------------------*

        in      R4, PORTB

        COM     R4

        out     PORTB, R4   ; complement PortB bits

 

        rcall   Fars

        rcall   Fars

        rcall   DLms

        rcall   Fars

 

        rcall   Mes

        rcall   Mes

        rcall   Mes

 

        rcall   Dos

        rcall   Dos

 

        rcall   Rays

        rcall   Rays

        rcall   Rays

        rcall   Rays

 

        rcall   Dos

        rcall   Dos

        rcall   Dos

        rcall   Dos

        rcall   Dos

        rcall   Dos

        rcall   DLhalfS

        rcall   DLhalfS

        rcall   DLhalfS

        rcall   DLhalfS

        rcall   DLhalfS

        rcall   DLhalfS

        rcall   DLhalfS

 

        rjmp    AGAIN

;---------------------------------------------------------

;the delay = .? sec at 1 MHz

 

DLhalfS:

        LDI     R20, 2

calop:

        LDI     R19, 235

malop:

        LDI     R21, 235

LOP1:

        DEC     R21

        brne    LOP1

        DEC     R19

        brne    malop

        DEC     R20

        brne    calop

        RET

;---------------------------------------------------------

;delay = .? msec at 1 MHz

 

DLms:

        LDI     R20, 155

LOPms:

        DEC     R20

        brne    LOPms

        RET

;-----------------------------------------------------------

TIMOVF:

        LDI     R16, 240    ;\ initialize TCNT0=240

        OUT     TCNT0, R16  ;/           256-16=240

        inc     r18         ; inc TickCount by 1

        RETI

;-----------------------------------------------------------

; 784 Hz "G5" tone; T/2 = 638 us, Ticks# = 638/16=39.875=>40

 

Sew:

Gh:

        CLR     R17

REPETGh:

        CLR     r18         ; clear TickCounter

loopGh1:

        cbi     PORTB, 1    ; PB1=LOW

        cpi     r18, 40     ; if reach 40 Ticks, then jmp

        brlo    loopGh1

 

        CLR     r18         ; clear TickCounter

loopGh2:

        sbi     PORTB, 1    ; PB1=HIGH

        cpi     r18, 40     ; if reach 40 Ticks, then jmp

        brlo    loopGh2

        INC     R17

        cpi     R17, 150   

        BRLO    REPETGh

        RET

;-----------------------------------------------------------

; 880 Hz "A5" tone; T/2 = 568 us, Ticks# = 568/16=35.5

 

La:

Ah:

        CLR     R17

REPETAh:

        CLR     r18         ; clear TickCounter

loopAh1:

        cbi     PORTB, 1    ; PB1=LOW

        cpi     r18, 36     ; if reach 36 Ticks, then jmp

        brlo    loopAh1

 

        CLR     r18         ; clear TickCounter

loopAh2:

        sbi     PORTB, 1    ; PB1=HIGH

        cpi     r18, 35     ; if reach 35 Ticks, then jmp

        brlo    loopAh2

        INC     R17

        cpi     R17, 150   

        BRLO    REPETAh

        RET

;-----------------------------------------------------------

; 988 Hz "B5" tone; T/2 = 506 us, Ticks# = 506/16=31.625

 

Tea:

Bh:

        CLR     R17

REPETBh:

        CLR     r18         ; clear TickCounter

loopBh1:

        cbi     PORTB, 1    ; PB1=LOW

        cpi     r18, 32     ; if reach 37 Ticks, then jmp

        brlo    loopBh1

 

        CLR     r18         ; clear TickCounter

loopBh2:

        sbi     PORTB, 1    ; PB1=HIGH

        cpi     r18, 31     ; if reach 36 Ticks, then jmp

        brlo    loopBh2

        INC     R17

        cpi     R17, 150   

        BRLO    REPETBh

        RET

;------------------------------------------------------------

; 1047 Hz "C6" tone; T/2 = 478 us, Ticks# = 478/16=29.875=>30

 

Dos:

Cs:

        CLR     R17

REPETCs:

        CLR     r18         ; clear TickCounter

loopCs1:

        cbi     PORTB, 1    ; PB1=LOW

        cpi     r18, 30     ; if reach 30 Ticks, then jmp

        brlo    loopCs1

 

        CLR     r18         ; clear TickCounter

loopCs2:

        sbi     PORTB, 1    ; PB1=HIGH

        cpi     r18, 30     ; if reach 30 Ticks, then jmp

        brlo    loopCs2

        INC     R17

        cpi     R17, 150   

        BRLO    REPETCs

        RET

;-----------------------------------------------------------

; 1175 Hz "D6" tone; T/2 = 426 us, Ticks# = 426/16=26.625

 

Rays:

Ds:

        CLR     R17

REPETDs:

        CLR     r18         ; clear TickCounter

loopDs1:

        cbi     PORTB, 1    ; PB1=LOW

        cpi     r18, 27     ; if reach 27 Ticks, then jmp

        brlo    loopDs1

 

        CLR     r18         ; clear TickCounter

loopDs2:

        sbi     PORTB, 1    ; PB1=HIGH

        cpi     r18, 26     ; if reach 26 Ticks, then jmp

        brlo    loopDs2

        INC     R17

        cpi     R17, 150   

        BRLO    REPETDs

        RET

;-----------------------------------------------------------

; 1319 Hz "E6" tone; T/2 = 379 us, Ticks# = 379/16=23.6875

 

Mes:

Es:

        CLR     R17

REPETEs:

        CLR     r18         ; clear TickCounter

loopEs1:

        cbi     PORTB, 1    ; PB1=LOW

        cpi     r18, 24     ; if reach 24 Ticks, then jmp

        brlo    loopEs1

 

        CLR     r18         ; clear TickCounter

loopEs2:

        sbi     PORTB, 1    ; PB1=HIGH

        cpi     r18, 23     ; if reach 23 Ticks, then jmp

        brlo    loopEs2

        INC     R17

        cpi     R17, 150   

        BRLO    REPETEs

        RET

;-----------------------------------------------------------

; 1397 Hz "F6" tone; T/2 = 358 us, Ticks# = 358/16=22.375

 

Fars:

Fs:

        CLR     R17

REPETFs:

        CLR     r18         ; clear TickCounter

loopFs1:

        cbi     PORTB, 1    ; PB1=LOW

        cpi     r18, 23     ; if reach 23 Ticks, then jmp

        brlo    loopFs1

 

        CLR     r18         ; clear TickCounter

loopFs2:

        sbi     PORTB, 1    ; PB1=HIGH

        cpi     r18, 22     ; if reach 22 Ticks, then jmp

        brlo    loopFs2

        INC     R17

        cpi     R17, 150   

        BRLO    REPETFs

        RET

;------------------------------------------------------------

; 1568 Hz "G6" tone; T/2 = 319 us, Ticks# = 319/16=19.93=> 20

 

Sews:

Gs:

        CLR     R17

REPETGs:

        CLR     r18         ; clear TickCounter

loopGs1:

        cbi     PORTB, 1    ; PB1=LOW

        cpi     r18, 20     ; if reach 20 Ticks, then jmp

        brlo    loopGs1

 

        CLR     r18         ; clear TickCounter

loopGs2:

        sbi     PORTB, 1    ; PB1=HIGH

        cpi     r18, 20     ; if reach 20 Ticks, then jmp

        brlo    loopGs2

        INC     R17

        cpi     R17, 150   

        BRLO    REPETGs

        RET

;-----------------------------------------------------------

 

 

 

 

    So far we only present three example program for the ATtiny11 application. But the list can go endless. It's only limited by everybody's capability and need.

 

    Perhaps the most widely use for ATtiny11 is in chip music composing. Now that its price is so low, we won't have to care about how many chips we need. In this sense you can use as many ATtiny11 you need to build a "chip music library."